Skip to content
Events & custom flags

Events & custom flags

Events

Every event except ClaimTaxEvent extends ClaimEvent (getClaim()) and fires before the database write, so cancelling a cancellable event vetoes the whole operation — no DB change, no cache update. Bulk actions fire one event per claim.

Available events

EventKey dataCancel
ClaimCreateEvent / ClaimDeleteEventgetPlayerId()
ClaimExpireEventgetOwnerUuid() — fired per claim by the auto-purge, off the main thread (cancellable since 2.7.1)
ClaimEnterEvent / ClaimLeaveEventgetPlayer()Enter only
ClaimMemberEventgetMemberId(), getAction(), getRoleName()
ClaimOwnerTransferEventgetOldOwner(), getNewOwner()
ClaimSaleEventgetAction(), getPrice(), getPlayerId()
ClaimChunkEventgetChunkKey(), getAction()
ClaimMergeEventgetMergedClaims()
ClaimFlagChangeEventgetFlag(), getValue()
ClaimPermissionChangeEventgetRoleName(), getPermission(), getValue()
ClaimRenameEventgetOldName(), getNewName()
ClaimDescriptionChangeEventgetOldDescription(), getNewDescription()
ClaimSpawnChangeEventgetNewSpawn()
ClaimWarpToggleEventgetNewState()
ClaimVisitEventgetVisitorId()
ClaimFavoriteEventgetPlayerId(), getAction()
ClaimTaxEventgetOwnerUuid(), getChunks(), getPeriods(), getAmount() / setAmount() — fired once per owner per tax run, off the main thread (2.7.1)

Action enums

  • ClaimMemberEvent.Action — ADD, REMOVE, PROMOTE, DEMOTE, KICK, BAN, UNBAN, ROLE_CHANGE
  • ClaimSaleEvent.Action — LISTED, CANCELLED, BOUGHT
  • ClaimChunkEvent.Action — ADD, REMOVE
  • ClaimFavoriteEvent.Action — FAVORITE, UNFAVORITE

Listening

import fr.xyness.SimpleClaimSystem.Events.*;

@EventHandler
public void onCreate(ClaimCreateEvent event) {
    Claim claim = event.getClaim();
    getLogger().info(claim.getOwnerName() + " created " + claim.getClaimName());
}

// Veto a deletion from your own protection logic
@EventHandler
public void onDelete(ClaimDeleteEvent event) {
    if (event.getClaim().getClaimName().equalsIgnoreCase("spawn")) {
        event.setCancelled(true);
    }
}

@EventHandler
public void onMember(ClaimMemberEvent event) {
    if (event.getAction() == ClaimMemberEvent.Action.ADD) {
        getLogger().info("Added as " + event.getRoleName());
    }
}

// Halve the claim tax during a week-end event
@EventHandler
public void onTax(ClaimTaxEvent event) {
    if (isWeekend()) event.setAmount(event.getAmount() / 2);
}

Custom flags & permissions (2.5.0)

External plugins can declare their own claim flags and role-permissions. Data-only: SCS2 stores the per-claim value and exposes it through claim.getFlag(key) / claim.getPermission(role, key). You write the @EventHandler that checks the value and cancels events — SCS does NOT invoke any handler tied to your definition.

Registering a custom flag

Register in your plugin's onLoad() so SCS's startup migration sees your flag and seeds the default value on existing claims. Runtime registration (in onEnable or later) also works — SCS backfills cached claims and persists to DB — but claims that loaded before the registration are missing the key until the next plugin reload.

import fr.xyness.SimpleClaimSystem.API.FlagDefinition;
import fr.xyness.SimpleClaimSystem.API.SCS_FlagRegistry;

public class MyPlugin extends JavaPlugin {

    @Override
    public void onLoad() {
        SCS_FlagRegistry.registerFlag(FlagDefinition.builder("my_flag")
            .defaultValue(true)
            // Optional: separate defaults for PROTECTED / SURVIVAL_REQUIRING_CLAIMS world modes
            .protectedModeDefault(false)
            .survivalRequiringClaimsModeDefault(true)
            // Optional metadata used by the GUI (you provide the lang strings)
            .titleKey("my_flag-title")
            .loreKey("my_flag-lore")
            .iconMaterial("DIAMOND")
            // Used in diagnostics + SCS_FlagRegistry.unregisterAllOwnedBy(pluginName)
            .owningPluginName(getName())
            .build());
    }

    @Override
    public void onDisable() {
        // Optional cleanup on plugin reload
        SCS_FlagRegistry.unregisterAllOwnedBy(getName());
    }

    // Your own listener checks the flag and cancels the event
    @EventHandler
    public void onSomething(SomeBukkitEvent event) {
        SCS_API api = SCS_API_Provider.get();
        api.getClaim(event.getLocation().getChunk()).ifPresent(claim -> {
            if (!claim.getFlag("my_flag")) event.setCancelled(true);
        });
    }
}

Registering a custom role-permission

Same shape, but with per-role defaults. Role names are matched case-insensitively (uppercase-normalized internally). Roles not explicitly listed fall back to fallbackDefault — important for custom roles created by claim owners.

import fr.xyness.SimpleClaimSystem.API.PermissionDefinition;
import fr.xyness.SimpleClaimSystem.API.SCS_FlagRegistry;

@Override
public void onLoad() {
    SCS_FlagRegistry.registerPermission(PermissionDefinition.builder("my_perm")
        .defaultPerRole("VISITOR", false)
        .defaultPerRole("MEMBER", true)
        .defaultPerRole("MODERATOR", true)
        .fallbackDefault(false)  // used by custom claim roles
        .titleKey("my_perm-title")
        .loreKey("my_perm-lore")
        .iconMaterial("DIAMOND")
        .owningPluginName(getName())
        .build());
}

@EventHandler
public void onSomething(SomeBukkitEvent event) {
    Player player = event.getPlayer();
    SCS_API api = SCS_API_Provider.get();
    api.getClaim(event.getLocation().getChunk()).ifPresent(claim -> {
        String role = claim.getRole(player.getUniqueId());
        if (!claim.getPermission(role, "my_perm")
                && !player.hasPermission("scs.bypass.my_perm")) {
            event.setCancelled(true);
        }
    });
}

Auto-registered Bukkit permissions

When you register a custom key, SCS automatically declares the matching Bukkit permissions via PluginManager.addPermission:

Permission nodeDefaultPurpose
scs.bypass.<key>opBypass the per-claim check (you read it in your own listener).
scs.flag.<key> (flags only)opAllow toggling this flag in the GUI.
scs.permission.<key> (permissions only)opAllow toggling this permission row in the GUI.

You don't need to declare these in your own plugin.yml. They're cleaned up on unregister.

Runtime registration via SCS_API

The same operations are mirrored on the runtime SCS_API:

SCS_API api = SCS_API_Provider.get();
api.registerCustomFlag(FlagDefinition.builder("dynamic").build());
api.unregisterCustomFlag("dynamic");
api.registerCustomPermission(PermissionDefinition.builder("dynamic_perm").build());
api.unregisterCustomPermission("dynamic_perm");

Runtime registration triggers an immediate backfill on every cached claim (default value written to claims that don't yet have the key, batched into a single DB write). Runtime unregistration strips the key from cached claims.

Caveats

  • Default value source-of-truth: the defaultValue in the builder is used to seed claims that don't have your key yet. After that, the per-claim stored value wins — changing the builder default later won't update existing claims.
  • No automatic gating: SCS doesn't call your code on any event. The flag is a stored boolean; you write the listener.
  • Definition not persisted: only the per-claim value is stored in the DB. If your plugin is uninstalled and SCS restarts, the unknown key is stripped at the next startup migration (same behavior as a removed built-in flag).