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
| Event | Key data | Cancel |
|---|---|---|
ClaimCreateEvent / ClaimDeleteEvent | getPlayerId() | ✔ |
ClaimExpireEvent | getOwnerUuid() — fired per claim by the auto-purge, off the main thread (cancellable since 2.7.1) | ✔ |
ClaimEnterEvent / ClaimLeaveEvent | getPlayer() | Enter only |
ClaimMemberEvent | getMemberId(), getAction(), getRoleName() | ✔ |
ClaimOwnerTransferEvent | getOldOwner(), getNewOwner() | ✔ |
ClaimSaleEvent | getAction(), getPrice(), getPlayerId() | ✔ |
ClaimChunkEvent | getChunkKey(), getAction() | ✔ |
ClaimMergeEvent | getMergedClaims() | ✔ |
ClaimFlagChangeEvent | getFlag(), getValue() | ✔ |
ClaimPermissionChangeEvent | getRoleName(), getPermission(), getValue() | ✔ |
ClaimRenameEvent | getOldName(), getNewName() | ✔ |
ClaimDescriptionChangeEvent | getOldDescription(), getNewDescription() | ✔ |
ClaimSpawnChangeEvent | getNewSpawn() | ✔ |
ClaimWarpToggleEvent | getNewState() | ✔ |
ClaimVisitEvent | getVisitorId() | ✔ |
ClaimFavoriteEvent | getPlayerId(), getAction() | ✔ |
ClaimTaxEvent | getOwnerUuid(), 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_CHANGEClaimSaleEvent.Action— LISTED, CANCELLED, BOUGHTClaimChunkEvent.Action— ADD, REMOVEClaimFavoriteEvent.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 node | Default | Purpose |
|---|---|---|
scs.bypass.<key> | op | Bypass the per-claim check (you read it in your own listener). |
scs.flag.<key> (flags only) | op | Allow toggling this flag in the GUI. |
scs.permission.<key> (permissions only) | op | Allow 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
defaultValuein 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).
Requirements & links
Requirements: Java 21+, Spigot / Paper / Folia 1.21+, with SimpleClaimSystem installed on the server.
- Source & README — github.com/Xyness/SimpleClaimSystem-API
- Javadoc — generated by JitPack for the published
v2.5.10tag