Plugin API
Overview
SCS2 ships a public Java API for other plugins to integrate with the claim system — read claim data, listen to events, drive admin actions, and (since 2.5.0) declare custom flags and role-permissions.
The API is published as a separate artifact SimpleClaimSystem-API via JitPack. Add it as a provided/compileOnly dependency in your build file:
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependency>
<groupId>com.github.Xyness</groupId>
<artifactId>SimpleClaimSystem-API</artifactId>
<version>v2.5.10</version>
<scope>provided</scope>
</dependency>
Gradle (Groovy): compileOnly 'com.github.Xyness:SimpleClaimSystem-API:v2.5.10' with the JitPack repo maven { url 'https://jitpack.io' }.
Declare SimpleClaimSystem in your plugin.yml so it loads first:
depend: [SimpleClaimSystem] # or softdepend: [SimpleClaimSystem]
This page documents the whole API surface. The authoritative reference is the JitPack-generated Javadoc; the source lives in the SimpleClaimSystem-API repository.
Getting the API instance
Fetch the API once SCS2 is enabled. Always guard with isRegistered() so your plugin still loads when SCS2 is absent:
import fr.xyness.SimpleClaimSystem.API.SCS_API;
import fr.xyness.SimpleClaimSystem.API.SCS_API_Provider;
if (SCS_API_Provider.isRegistered()) {
SCS_API api = SCS_API_Provider.get();
// ... use the API
}
Every example below is called on that api instance. Types live under fr.xyness.SimpleClaimSystem.Types (Claim, PlayerData, ChunkKey) and ...Enums (ClaimRole, WorldMode).
Reading claims & players
From a chunk or location
Use the synchronous getters on hot paths inside listeners (the chunk is loaded and the claim is almost certainly cached). Use the async ones from commands, GUIs or scheduled tasks, where a cold chunk could otherwise hit the database on the calling thread.
Optional<Claim> claim = api.getClaim(player.getLocation().getChunk());
claim.ifPresent(c -> {
String owner = c.getOwnerName();
String name = c.getClaimName();
});
// Async — preferred outside listeners
api.getClaimAsync(chunk).thenAccept(opt -> opt.ifPresent(c -> { /* ... */ }));
// Batch several chunks at once
Map<ChunkKey, Optional<Claim>> claims = api.getClaims(keys);
Quick checks (no Claim object needed)
boolean claimed = api.isClaimed(player.getLocation()); // ChunkKey / Chunk / Location
boolean canBuild = api.hasPermission(chunk, playerId, "place_block");
boolean banned = api.isBanned(chunk, playerId);
boolean member = api.isMember(chunk, playerId);
String role = api.getRole(chunk, playerId); // "VISITOR" if not a member
Boolean pvp = api.getFlag(chunk, "pvp");
Players & world mode
Optional<PlayerData> data = api.getPlayer(player.getUniqueId());
data.ifPresent(pd -> { String name = pd.getName(); });
// Async: getPlayerAsync, getPlayerByNameAsync, getPlayersAsync, getPlayerNamesAsync
WorldMode mode = api.getWorldMode(world); // SURVIVAL, SURVIVAL_REQUIRING_CLAIMS, PROTECTED, DISABLEDRoles & permissions
Roles are plain Strings. The four built-ins are VISITOR, MEMBER, MODERATOR and OWNER; claim owners can also create custom roles. Permissions and flags resolve the same way for both.
String role = claim.getRole(playerId); // built-in or custom, "VISITOR" if none
boolean canBuild = claim.getPermission(role, "place_block");
boolean isDefault = ClaimRole.isDefault(role); // true for VISITOR/MEMBER/MODERATOR/OWNER
List<String> all = claim.getAllRoles(); // defaults + custom
List<String> custom = claim.getCustomRoles();
boolean explosions = claim.getFlag("creeper_explosions");
Enforce a permission in your own listener — owners are always allowed, and honour the staff bypass node:
String role = claim.getRole(player.getUniqueId());
if (!claim.getPermission(role, "my_perm")
&& !player.hasPermission("scs.bypass.my_perm")) {
event.setCancelled(true);
}Modifying claims
Two layers. Claim helpers mutate the in-memory object only — no database write, no events — handy while assembling a claim. SCS_API methods persist to the database, refresh caches and fire the matching events; most return a CompletableFuture.
// ❌ Maps from getMembers() / getFlags() / getPermissions() are unmodifiable
claim.getMembers().put(uuid, "MEMBER"); // throws UnsupportedOperationException
// ✅ In-memory only
claim.addMember(uuid, "MEMBER");
claim.setFlag("pvp", false);
claim.setPermission("MEMBER", "place_block", true);
// ✅ Persist + caches + events
api.addMember(claim, uuid, "MEMBER");
api.setMemberRole(claim, uuid, "MODERATOR");
api.removeMember(claim, uuid);
api.banPlayer(claim, uuid, LocalDateTime.now().plusDays(7));
api.unbanPlayer(claim, uuid);
api.setFlag(claim, "pvp", false);
api.setPermission(claim, "MEMBER", "place_block", true);
Bulk member ops (Factions / Kingdoms style)
api.addMemberToAllClaims(leaderUuid, newMemberUuid, "MEMBER");
api.removeMemberFromAllClaims(leaderUuid, leavingMemberUuid);
Creating & deleting claims (2.7.1)
The lifecycle methods apply the configured defaults, fire the matching events and write every table in one transaction. Player limits, world rules and economy are not checked — your plugin decides who may create what.
api.createClaim(ownerUuid, ownerName, "shop-%n", chunk) // %n = lowest free number
.thenAccept(opt -> opt.ifPresent(claim -> {
api.setSpawnLocation(claim, spawn);
api.setDescription(claim, "Server shop");
}));
api.addChunk(claim, chunk); // false if already claimed or vetoed
api.removeChunk(claim, chunk); // removing the last chunk deletes the claim
api.deleteClaim(claim);
api.setClaimName(claim, "market");
api.createRole(claim, "TRADER"); // seeded from the claim's MEMBER permissions
api.deleteRole(claim, "TRADER"); // members holding it fall back to MEMBER
Warps & economy (2.7.1)
boolean open = api.isWarpOpen(claim);
double price = api.getVisitPrice(claim);
api.setWarp(claim, true); // fires ClaimWarpToggleEvent
api.setVisitPrice(claim, 250.0);
Set<UUID> owners = api.getOpenWarpOwners();
boolean sale = api.isForSale(claim);
double asked = api.getSalePrice(claim);
api.setForSale(claim, true, 10000.0); // fires ClaimSaleEventPlayer limits & stats
int maxClaims = api.getMaxClaims(player);
int maxChunks = api.getMaxChunks(player);
int maxRadius = api.getMaxRadius(player);
int maxMembers = api.getMaxMembers(player);
double cost = api.getChunkCost(player);
double multiplier = api.getCostMultiplier(player);
int claims = api.getClaimCount(playerId); // current totals
int chunks = api.getChunkCount(playerId);
// 2.7.1
int perClaim = api.getMaxChunksPerClaim(player);
int maxRoles = api.getMaxRoles(player);
int delay = api.getTeleportDelay(player);
int distance = api.getMinDistance(player);
long flyTime = api.getFlyTime(playerId); // remaining claim-fly secondsQuerying claims by owner
List<Claim> claims = api.getClaimsByOwner(ownerUuid); // also getClaimsByOwnerAsync
List<String> names = api.getClaimNamesByOwner(ownerUuid);
Optional<Claim> one = api.getClaimByOwnerAndName(ownerUuid, "My Base");
Map<UUID, String> members = api.getClaimMembers(ownerUuid, "My Base");
Map<UUID, LocalDateTime> banned = api.getClaimBanned(ownerUuid, "My Base");Favourites
boolean added = api.addFavorite(playerUuid, claim);
boolean removed = api.removeFavorite(playerUuid, claim);
boolean fav = api.isFavorite(playerUuid, claim.getId());
List<Integer> ids = api.getFavoriteClaimIds(playerUuid);
List<Claim> live = api.getFavoriteClaims(playerUuid); // ids that no longer resolve are dropped
React to changes with ClaimFavoriteEvent — getAction() returns FAVORITE or UNFAVORITE.
Reading plugin settings
Read any resolved config.yml value through the API — useful when your integration needs to respect the same options the plugin uses (economy toggles, default icon, tax settings, ...). Keys are the dot-separated config.yml paths.
Object raw = api.getSetting("claims.default.icon"); // null if unset
boolean tax = api.getBooleanSetting("claims.tax.enabled", false);
String icon = api.getStringSetting("claims.default.icon", "FARMLAND");
int delay = api.getIntSetting("claims.confirmation-delay", 30);
double visit = api.getDoubleSetting("claims.default.visitPrice", 0.0);
// Permissions and flags applied to unclaimed chunks in the two special world modes:
Map<String, Boolean> protectedPerms = api.getPermissionsForProtectedMode();
Map<String, Boolean> srcPerms = api.getPermissionsForSurvivalRequiringClaimsMode();
Map<String, Boolean> protectedFlags = api.getFlagsForProtectedMode();
Map<String, Boolean> srcFlags = api.getFlagsForSurvivalRequiringClaimsMode();
The typed getters return your fallback when the key is absent; getSetting returns the raw Object (or null). The four mode maps are read-only views of the plugin's live settings. They were named getSettingsFor*Mode() before 2.7.1, where they returned null; the flag variants are new.