Configuration
General Settings
The main configuration file is located at /plugins/SimpleClaimSystem/config.yml. Reload after editing with /scs reload.
# Logger verbosity
logger: NORMAL # NORMAL | DEBUG
# Language file (from /langs)
lang: "en_US.yml"
# Update checks
update:
check: true # poll for new versions on startup
notifications: true # notify in-game on join (requires scs.update.notifications)
# Command aliases — add extra command names that invoke the same handler
command-aliases:
claim: []
parea: []
unclaim: []
claims: []
scs: []
Key reference
| Key | Description |
|---|---|
logger | NORMAL = standard info/warn/error. DEBUG = verbose (cache hits, Redis SETEX, DAO inserts). Only turn on when troubleshooting; produces a lot of console noise. |
lang | Filename of the language file inside /langs. Shipped with en_US.yml and fr_FR.yml. Drop your own file in the folder to add a translation. |
update.check | On startup, the plugin contacts the release feed to detect newer versions. |
update.notifications | When a newer version is detected, notify players who have scs.update.notifications on join. |
command-aliases.* | Extra command names mapped to each built-in command. Example: claim: [c, protect] makes /c and /protect behave like /claim. |
Database
SCS2 uses SQLite by default but supports MySQL / MariaDB for larger servers and multi-server setups:
database:
enabled: false # false = SQLite (local), true = use the MySQL block below
hostname: localhost
port: 3306
name: database_name # schema (must already exist on the server)
username: root
password: pass
hikari:
# Connection-leak threshold (ms). Hikari logs a stack trace identifying the borrower
# if a connection is held longer than this without being returned. Useful to surface
# accidental synchronous DB calls on hot paths. 0 disables the check.
leak-detection-ms: 5000
Key reference
| Key | Description |
|---|---|
enabled | false = SQLite at /plugins/SimpleClaimSystem/storage.db. true = connect to MySQL using the fields below. Switch is safe to flip — use the transfer commands to migrate data. |
hostname / port | MySQL host/port. Defaults to localhost:3306. |
name | Database (schema) name. Must already exist and the user below must have DDL rights on it (the plugin creates its own tables). |
username / password | Credentials for the account the plugin connects with. Change the default root/pass before deploying. |
hikari.leak-detection-ms | If a borrowed connection isn't returned within this many milliseconds, Hikari logs a stack trace pointing at the borrower. Catch synchronous DB calls on hot paths quickly. Set 0 to disable. |
Database transfer
You can transfer data between local (SQLite) and distant (MySQL) databases at any time:
/scs transferLocalToDistant— Copy all SQLite data to MySQL/scs transferDistantToLocal— Copy all MySQL data to SQLite
The connection pool is managed by HikariCP internally. For large servers MySQL is strongly recommended over SQLite — concurrent writes are faster.
Redis (Optional Cache Layer)
Redis is an optional third caching layer between the in-memory cache (Caffeine) and the SQL database. It does not replace MySQL and is not a cross-server synchronization bus — it's purely a performance optimization.
How the cache stack works
Every claim / player read follows this order:
- Caffeine (in-memory, per-server) — hit: returned instantly.
- Redis (if enabled) — miss in Caffeine ⇒ check Redis. Hit: the value is deserialised and cached in Caffeine. Miss: fall through.
- MySQL / SQLite — miss everywhere ⇒ query the database. The result is written to Redis (if enabled) and Caffeine for subsequent reads.
Writes go to the database first, then to Redis, then to Caffeine, and will invalidate both caches if any step fails to avoid stale reads.
redis:
enabled: false
hostname: localhost
port: 6379
password: "" # empty = no auth; set on any internet-facing Redis
database: 0 # Redis logical db (0-15 by default)
command-timeout-seconds: 30 # bump on slow/remote Redis; 0 = no client-side timeout
Key reference
| Key | Description |
|---|---|
enabled | When true, the plugin opens a Redis connection at startup and treats it as cache layer 2. Leaving this off is fine — Caffeine alone handles most workloads. |
hostname / port | Redis host/port. Defaults are the vanilla Redis install. |
password | Optional AUTH password. Leave empty for unauthenticated Redis (only safe on localhost). |
database | Logical database number. Use distinct numbers if you're sharing one Redis between several plugins. |
command-timeout-seconds | Per-command timeout for Lettuce. Bump if you see "Command timed out" on joins with many visible claimed chunks, or on a slow/remote Redis. Set to 0 to disable the client-side timeout entirely. |
Storage schema
Since v2.2.4 the plugin stores claims under a two-key layout: one scs:claim:<id> key holds the JSON for the entire claim (chunks, members, bans, perms, flags), and every chunk gets a lightweight scs:chunk:<worldUuid>;<x>;<z> pointer containing just the claim id. This makes a radius claim O(chunks) on the wire instead of O(chunks²) and avoids the SETEX timeouts that earlier layouts could trigger.
When should I enable it?
Redis is worth enabling when:
- Caffeine evicts frequently (very large claim counts, a lot of Caffeine misses). Redis keeps deserialised claims close to the server.
- You want claim reloads after a
/scs reloadto be fast (Redis survives the restart; Caffeine does not).
For small/medium servers, Caffeine alone is enough. Redis adds operational overhead (another service to run) without meaningful gains.
Use /scs clearRedis to flush the plugin's Redis keys (e.g., after a manual MySQL edit). It does not touch other plugins' keys in the same logical database.
Redis is not a cross-server synchronization mechanism. If you modify a claim on server A, server B's Caffeine will still hold the old value until it expires — the plugin does not publish invalidation messages to other servers. For true cross-server coherence you'd need an additional pub/sub layer, which the plugin does not implement.
Cache Thread Pool
Both the claim cache and the player cache share a tunable executor. It controls how many concurrent DB/Redis lookups the cache layer can fire when something misses Caffeine. Defaults are usually fine — only change this if you see "executor saturated" warnings or if your server is particularly large.
cache:
thread-pool:
# automatic = suitable for the machine (max(2, CPU cores / 2)).
# manual = use core-size below.
mode: automatic
core-size: 4
queue-size: 5000
Key reference
| Key | Description |
|---|---|
mode | automatic scales the pool against the host's CPU count. manual uses the configured core-size verbatim. |
core-size | Always-alive threads per cache (claim + player). Only read in manual mode. Range 2–8 is typical. |
queue-size | How many pending lookups the executor buffers before overflow. Overflow runs on the caller thread — visible as a brief stall rather than a lost task. |
The claim cache and the player cache use independent executors but read the same config, so both stay sized consistently. Change it once, both are affected on next reload.
Discord Webhook
SCS2 can send notifications to a Discord channel when claim events occur (claims, unclaims, sales, purchases, etc.):
discord-webhook:
enabled: false
url: ""
Set enabled: true and paste your Discord webhook URL. Events like claiming, unclaiming, buying, selling, ban/kick actions, and new /requnclaim submissions are sent as embeds to the configured channel.
Web Dashboard
The admin web dashboard provides remote management of claims and players through a browser interface:
web-dashboard:
enabled: false
port: 8095
# Public URL appended with ?token=<...> in the in-game login link.
# Change this when the dashboard is behind a reverse proxy or a custom domain.
url: "http://localhost:8095"
# Token lifetime in hours. 0 = tokens never expire.
token-ttl-hours: 24
# Allowed CORS origins. Fallback: localhost + 127.0.0.1 on the configured port.
# "*" means "any origin": insecure, only for local trusted setups.
cors-origins:
- "http://localhost:8095"
- "http://127.0.0.1:8095"
Key reference
| Key | Description |
|---|---|
enabled | Starts the embedded HTTP server on plugin load. |
port | TCP port the dashboard listens on. |
url | Public URL sent in the in-game /scs dashboard click-to-open link. The plain auth token is appended as a ?token=... query parameter so the player lands signed in. Change this when the dashboard is behind a reverse proxy or a custom domain. |
token-ttl-hours | How long an issued admin token stays valid, in hours. 0 disables expiration so a token only stops working when manually rotated. |
cors-origins | Whitelist of Origin header values the dashboard will send CORS-allow headers for. Incoming requests whose Origin doesn't match are silently denied at the browser level. |
Generate a login link
Run /scs dashboard in-game. The plugin sends a clickable [Click here] link in chat that opens the dashboard URL (from web-dashboard.url above) with the auth token already baked into the query string, so you land directly inside the dashboard. The token is also persisted in the browser's localStorage so a manual refresh keeps you signed in.
Tokens are stored hashed in web-tokens.json and persist across restarts.
Built-in abuse protection
- Rate limiting — the
/authendpoint accepts at most 5 attempts per IP per minute. Further requests returnHTTP 429with aRetry-Afterheader, making brute-force token guessing impractical. - Path traversal — static file requests are canonicalised;
../~are rejected. - Prepared statements — all dashboard DB access goes through the same DAO layer, no raw SQL concatenation.
The dashboard uses plain HTTP (no built-in TLS). Tokens travel in clear text in the Authorization header, so never expose the port to the internet. Keep it bound to localhost (default) or put it behind a reverse proxy that terminates TLS.
On filesystems with multi-user access, consider restricting the web-tokens.json file (e.g., chmod 640). The tokens grant admin access to the dashboard.
Audit Logs
Track every action performed on claims for accountability and moderation:
audit-logs:
enabled: false
retention-days: 30
# Buffer flush cadence (seconds). Lower = less data loss on a JVM crash, higher = fewer DB
# roundtrips. The buffer is also flushed when batch-size entries accumulate, on /scs reload,
# and on plugin disable.
flush-interval-seconds: 5
# Max entries kept in the in-memory buffer before forcing a flush.
batch-size: 20
When enabled, all claim actions (permission changes, flag changes, member management, etc.) are logged with timestamps and player information. Logs older than retention-days are automatically purged.
Buffering
Writes do not hit the database one row at a time. Entries are buffered in memory and flushed in two cases: every flush-interval-seconds on a timer, or as soon as batch-size rows accumulate — whichever comes first. The buffer is also drained synchronously on /scs reload and on shutdown, so the only realistic data-loss window is a hard JVM crash within the last flush-interval-seconds seconds.
Exporting logs to CSV
/scs exportAuditLogs <claimId|*>
Dumps the audit log of a specific claim — or all claims with * — into a CSV file under plugins/SimpleClaimSystem/audit-exports/. Useful for external review, compliance, or just keeping a copy before retention-days drops old rows.
Claims Settings
claims:
# Auto-purge inactive claims
auto-purge:
enabled: true
checker: 1h
time-without-login: 90d
# Days before purge to start warning the affected owner on join. 0 = no warning.
warn-days-before: 7
# Allow /claim respawn (see Claiming > Respawn in Claim)
respawn-in-claim:
enabled: false
# /claim back scope. false = any visited claim. true = only the player's own claims.
claim-back:
only-own-claims: false
# Confirmation prompts — action must be run twice to execute
confirmation:
claim: false
unclaim: false
addchunk: false
delchunk: false
merge: false
owner: true
confirmation-delay: 30
# Protection violation delivery: CHAT | ACTIONBAR | TITLE | NONE
protection-message: CHAT
# Particles
show-particles: true
show-particles-for-bedrock: false
# Names & descriptions
template-name: "claim-%n"
max-length-name: 32
allowed-regex-name: "^[a-zA-Z0-9]+$"
max-length-description: 64
allowed-regex-description: "^[a-zA-Z0-9\\s]+$"
blocked-words: ["fuck", "asshole"]
invitation-delay: 120 # seconds before an invite expires
only-adjacent-chunks: false
addchunk-instead-if-possible: false
# Default metadata applied to every new claim
default:
isBuyable: false
price: 0.0
icon: FARMLAND
particles: false
warp: false # public warp closed by default (toggle via /claim settings)
visitPrice: 0.0 # /claim visit fee charged to visitors (0 = free)
# Plugin message channels — each has independent enter / leave toggles.
messages:
chat:
enter: false
leave: false
actionbar:
enter: true
leave: true
title:
enter: false
leave: false
# Claim economy (requires Vault)
economy:
enabled: true
max-price: 1_000_000_000
formatted-number: true
# /claim sell broadcast channels.
announce:
chat: true
actionbar: false
title: false
bossbar:
enabled: true
color: YELLOW
overlay: PROGRESS
Key reference
| Key | Description |
|---|---|
auto-purge.enabled | Run the periodic purge job that deletes claims from long-inactive owners (players with auto-purge-bypass = true are skipped). |
auto-purge.checker | How often the purge runs. Format: 30m, 1h, 12h, 1d. |
auto-purge.time-without-login | Inactivity threshold. Same format as above. |
auto-purge.warn-days-before | How many days before purge a doomed owner gets an in-game warning on join. 0 disables the warning. |
respawn-in-claim.enabled | Master toggle for the /claim respawn feature (see Respawn in Claim). |
claim-back.only-own-claims | false: /claim back can teleport to any claim the player walked into this session. true: only their own. |
messages.<channel>.enter / messages.<channel>.leave | Claim enter/leave notification toggles, per channel (chat, actionbar, title). Each channel × direction is independent — e.g. greet players on enter via actionbar.enter: true without spamming them again on leave by leaving actionbar.leave: false. Any combination can be enabled. Schema change in 2.5.0: the old single-boolean form (messages.chat: true) was replaced by a nested enter/leave pair. Existing installs are auto-migrated by the config updater — the old leaf is replaced with the new section seeded from the bundled defaults. |
confirmation.* | Per-action confirmation prompts. When true, the player must re-run the command within confirmation-delay seconds. |
confirmation-delay | Seconds after which a pending confirmation expires. |
protection-message | Where the "you don't have permission" message appears when a player's action is blocked. CHAT, ACTIONBAR, TITLE or NONE. |
show-particles | Global on/off for the continuous claim-boundary particles shown to claim members. |
show-particles-for-bedrock | When false, Bedrock clients (Geyser/Floodgate) never receive the continuous particles. They can stutter with dense particle loads. |
template-name | Default auto-generated name for new claims. %n → claim id, %player% → owner name. |
max-length-name / allowed-regex-name | Hard cap and regex enforced on claim names (same validation is applied by /claim create <name> and /claim setname). |
max-length-description / allowed-regex-description | Same rules for claim descriptions. The default regex allows spaces. |
blocked-words | List of substrings: any claim name or description containing one of these is rejected. |
invitation-delay | Seconds before a pending /claim invite expires. |
only-adjacent-chunks | When true, a new chunk added to a claim must touch one of the claim's existing chunks. Prevents scattered layouts. |
addchunk-instead-if-possible | When true, running /claim next to an existing owned claim adds the current chunk to that claim instead of creating a new one. |
default.isBuyable / default.price | Sale flags auto-applied to new claims. Usually kept at false / 0.0; the owner toggles with /claim sell. |
default.icon | Material shown as the claim icon in the claim-list GUI. Any Material enum. |
default.particles | Whether the boundary-particle display is on by default for new claims. |
default.warp | Whether new claims open as public warps (visitable through /claim visit). Usually false — owners opt in via /claim settings. |
default.visitPrice | Default Vault fee charged on every /claim visit, paid to the owner. 0.0 = free. Owners override per claim with /claim setvisitprice. |
economy.enabled | Master toggle for claim economy. Requires Vault + an economy plugin. |
economy.max-price | Hard cap on any /claim sell price. |
economy.formatted-number | When true, large prices display as 1,000,000 instead of 1000000. |
economy.announce.chat / actionbar / title / bossbar | Per-channel toggles for the /claim sell broadcast. The bossbar sub-block also takes color and overlay. |
BossBar & Sounds
A BossBar is displayed when players are inside a claim (one color per role) and, optionally, when they are outside any claim (one color per world mode). Available colors: PINK, BLUE, RED, GREEN, YELLOW, PURPLE, WHITE. Available overlays: PROGRESS, NOTCHED_6, NOTCHED_10, NOTCHED_12, NOTCHED_20.
claims:
bossbar:
enabled: true
# Outside any claim. Color/overlay/progress are configured per world mode.
always-visible:
survival-mode:
enabled: true
color: WHITE
overlay: PROGRESS
progress: 1.0
survival_requiring_claims-mode:
enabled: true
color: WHITE
overlay: PROGRESS
progress: 1.0
protected-mode:
enabled: true
color: GREEN
overlay: PROGRESS
progress: 1.0
disabled-mode:
enabled: true
color: RED
overlay: PROGRESS
progress: 1.0
# Inside a claim — one block per role.
visitor:
color: WHITE
overlay: PROGRESS
progress: 1.0
member:
color: GREEN
overlay: PROGRESS
progress: 1.0
moderator:
color: PURPLE
overlay: PROGRESS
progress: 1.0
owner:
color: BLUE
overlay: PROGRESS
progress: 1.0
Sounds
SCS2 ships 38 configurable sounds for every action: claiming, unclaiming, teleporting, entering/leaving claims, banning, kicking, merging, flying, inviting, and more. Each sound can be individually configured or disabled in claims.sounds.*.
Sound keys use Minecraft's dot notation (e.g., minecraft:ui.button.click, minecraft:entity.experience_orb.pickup). Set a sound to empty or remove it to disable it for that action.
Map Integration
SCS2 supports Dynmap, BlueMap, Pl3xMap, and squaremap with fully customizable visual styles:
dynmap:
enabled: true
show-labels: true
styles:
normal:
line-weight: 2
line-opacity: 0.8
line-color: "00FF00"
fill-opacity: 0.3
fill-color: "00FF00"
label-format: "%claim_name%"
for-sale:
line-color: "FFCC00"
fill-color: "FFCC00"
Normal claims and for-sale claims can have different visual styles on the map. The same structure applies for bluemap, pl3xmap, and squaremap sections.
Default Player Settings
Values under players.default are copied to each player the first time they join. Existing players are migrated lazily — when their data is loaded, any missing key from this block is added automatically (no server-wide scan needed).
players:
default:
# Auto-actions — toggle via /claim auto-*
auto-claim: false
auto-unclaim: false
auto-addchunk: false
auto-delchunk: false
auto-merge: false
auto-fly: false
auto-map: false
# Hard ownership limits (0 = unlimited)
max-claims: 0
max-chunks: 1
max-radius: 1
# Default radius applied to /claim with no argument (and /claim create <name>).
# 0 = single chunk. 1+ = behave like /claim radius N. Capped at max-radius.
default-claim-radius: 0
# Internal — id of the claim selected with /claim respawn. 0 = none. Do not edit by hand.
respawn-claim-id: 0
# Internal — sentinel for the last successful tax debit. The default is the literal
# string "none" (player never taxed); the job replaces it with an epoch ms timestamp
# after the first debit. Do not edit by hand.
last-tax-paid: "none"
# Economy (only active when claims.economy.enabled = true)
chunk-cost: 0.0
cost-multiplier: 1.0
max-claim-price: 0.0
# Membership / role limits (per claim)
max-members: 3
max-roles: 3
# Misc gameplay
distance: 1 # min chunk distance between this player's claims and other players'
delay: 5 # teleport delay in seconds (/claim tp, menu tp, etc.)
fly: 0 # remaining claim-fly seconds; replenished via /scs player commands
# /claim auto-X anti-abuse timers (seconds). 0 disables.
auto-default-timer: 0 # default timer when no [seconds] passed
auto-max-timer: 0 # hard cap on player-supplied [seconds]
# When true, the auto-purge job skips this player even if inactive
auto-purge-bypass: false
Key reference
| Key | Type | Description |
|---|---|---|
auto-* | boolean | Player-opt-in modes. Keep at false — players toggle them with /claim auto-*. |
max-claims | int | Maximum number of separate claims. 0 = unlimited. |
max-chunks | int | Maximum total chunks across all claims. 0 = unlimited. |
max-radius | int | Maximum value for /claim radius <n>. The claimed bounding box has side = 2n+1. |
default-claim-radius | int | Player's default radius when typing /claim alone. 0 = single chunk. Capped at max-radius so raising it cannot bypass the limit. |
respawn-claim-id | int | Internal — id of the claim the player respawns in (set via /claim respawn). 0 = no respawn claim. Do not edit manually. |
last-tax-paid | string / long | Internal — sentinel for the last successful tax debit (see Daily Tax / Rent). Defaults to the literal string "none" for players who have never been taxed; replaced with an epoch ms timestamp after the first debit. Do not edit manually. |
chunk-cost | double | Flat economy cost per chunk claimed/added. |
cost-multiplier | double | Cost multiplier applied as the claim grows (see Chunk Costs). |
max-claim-price | double | Hard cap on /claim sell price. 0 = no cap. |
max-members | int | Maximum members per claim. 0 = unlimited. |
max-roles | int | Maximum custom roles per claim. 0 = unlimited. |
distance | int | Minimum chunk distance enforced between this player's claims and other players' claims. |
delay | int | Teleport delay in seconds before /claim tp / menu teleports execute. |
fly | int | Remaining claim-fly time in seconds; replenished via admin commands. |
auto-default-timer | int | Anti-abuse default timer (seconds) applied when the player runs /claim auto-X without an explicit [seconds]. 0 = no timer (mode stays on until toggled off). Permission override: scs.limit.auto-default-timer.<n>. |
auto-max-timer | int | Hard cap on the [seconds] a player can pass to /claim auto-X. 0 = no cap. Permission override: scs.limit.auto-max-timer.<n>. |
auto-purge-bypass | boolean | When true, the player is skipped by the claims.auto-purge job even if inactive. |
Any of these can be overridden per player via permissions or admin commands — see the Limits page.
Plugin Hooks
Every optional integration can be disabled with a single flag in config.yml. Useful when another plugin is installed for its own reasons and you don't want SCS2 talking to it, or when troubleshooting ("does this still happen with the Dynmap hook off?").
hooks:
vault: true # economy (claim buy/sell, tax)
worldguard: true # registers the scs-claim custom flag
placeholderapi: true # %scs_*% placeholders
geyser: true # Bedrock client detection
floodgate: true # Bedrock UUID mapping
dynmap: true
bluemap: true
pl3xmap: true
squaremap: true
quickshop-hikari: true
griefprevention: true
lands: true
towny: true
nexo: true # <glyph:...> and <shift:N> tags
oraxen: true
itemsadder: true
Set any hook to false and SCS2 skips the entire setup — no retry timer, no listener registration, no performance cost. PacketEvents is a hard dependency and cannot be disabled here.
Disabling the vault hook automatically forces claims.economy.enabled to false (can't have economy features without an economy provider). Disabling map hooks removes the overlay; it doesn't delete stored claim geometry.
Bedrock Players
When Geyser/Floodgate is installed, SCS2 detects Bedrock clients and routes them through native forms (SimpleForm / CustomForm) instead of the Java chest GUIs. Two knobs control this:
bedrock:
# true → Bedrock players see the Java chest GUIs (translated by Geyser).
# false → Bedrock players see the native forms defined under bedrock-guis/*.yml.
force-java-menus: false
When to enable force-java-menus
- Your resource pack uses Nexo/Oraxen glyphs that don't render on native Bedrock forms.
- You want visual parity between Java and Bedrock clients.
- You've customized Java GUIs heavily and don't want to maintain two separate UI trees.
Caveat
Chest GUIs translated by Geyser have quirks: shift-click doesn't always fire, some items render without custom model data, and closing via "E" vs the native close button behaves differently. For anything complex, the native Bedrock forms (below) give a better UX.