From b064a9f51561dfb87c11c222a4d2a5f4184fc024 Mon Sep 17 00:00:00 2001 From: Matt Date: Sat, 23 May 2026 13:40:29 +0000 Subject: [PATCH] pack: KubeJS Waystones policy (1-per-player + ban share/portstones) Adds pack/overrides/kubejs/server_scripts/waystones_policy.js which: - Caps regular waystones at 1 per player. Per-player count is stored in player.persistentData and decremented on break (works correctly because restrictedWaystones = ["PLAYER"] means only owners can break). - Bans all 16 sharestone variants. They defeat the "build transport" intent (solo pair-teleport) and can be placed just outside a claim for stealth proximity access. - Bans all 16 portstone variants pending separate design review. - Leaves warp plates and warp scrolls untouched. Bumps to 0.17.0 so launcher re-syncs. --- .../kubejs/server_scripts/waystones_policy.js | 93 +++++++++++++++++++ pack/pack.lock.json | 2 +- 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 pack/overrides/kubejs/server_scripts/waystones_policy.js diff --git a/pack/overrides/kubejs/server_scripts/waystones_policy.js b/pack/overrides/kubejs/server_scripts/waystones_policy.js new file mode 100644 index 0000000..21e2ba4 --- /dev/null +++ b/pack/overrides/kubejs/server_scripts/waystones_policy.js @@ -0,0 +1,93 @@ +// Brass & Sigil — Waystones placement policy +// +// Rules: +// - Regular waystones (6 stone variants): 1 per player. Forces players to +// build actual transport infrastructure (trains/roads/canals) for +// long-distance routes instead of waystone-spamming. +// - Sharestones (16 colors): banned. Pair-teleport between solo-placed +// sharestones defeats the "build transport" intent, and a sharestone +// placed just outside someone's claim gives an unrestricted teleport- +// adjacent vector. +// - Portstones (16 colors): banned pending separate design discussion. +// - Warp plates: not restricted (single-block teleport pad; revisit if +// it becomes a workaround). +// - Warp scrolls / warp stones: untouched (consumable / cooldown-bound). +// +// Per-player count lives in player.persistentData.bnsWaystoneCount. +// Decrement on break works because waystones-common.toml has +// restrictedWaystones = ["PLAYER"] -- only the owner can break their own +// waystone, so breaker == owner in normal play. + +const WAYSTONE_CAP = 1; + +const REGULAR_WAYSTONES = new Set([ + 'waystones:waystone', + 'waystones:mossy_waystone', + 'waystones:sandy_waystone', + 'waystones:blackstone_waystone', + 'waystones:deepslate_waystone', + 'waystones:end_stone_waystone', +]); + +// Build the colored-block ban list once instead of typing 32 strings. +const COLORS = [ + 'white', 'orange', 'magenta', 'light_blue', 'yellow', 'lime', + 'pink', 'gray', 'light_gray', 'cyan', 'purple', 'blue', + 'brown', 'green', 'red', 'black', +]; +const BANNED_BLOCKS = new Set(); +COLORS.forEach(c => { + BANNED_BLOCKS.add(`waystones:${c}_sharestone`); + BANNED_BLOCKS.add(`waystones:${c}_portstone`); +}); + +// Helper: replace the just-placed block with air and refund the item. +function refund(event, blockId) { + event.block.set('minecraft:air'); + if (event.player) { + event.player.give(Item.of(blockId)); + } +} + +BlockEvents.placed(event => { + const blockId = event.block.id; + const player = event.player; + + // Skip non-player placements (dispensers, mob events) -- nothing to refund. + if (!player) return; + + if (BANNED_BLOCKS.has(blockId)) { + refund(event, blockId); + player.tell(Text.red( + 'That block is disabled. Use a regular Waystone (1 per player) ' + + 'and build transport between distant bases.' + )); + return; + } + + if (REGULAR_WAYSTONES.has(blockId)) { + const data = player.persistentData; + const current = data.getInt('bnsWaystoneCount'); + if (current >= WAYSTONE_CAP) { + refund(event, blockId); + player.tell(Text.red( + `You already have ${WAYSTONE_CAP} waystone. Break your existing one ` + + `to relocate, or build infrastructure to reach distant bases.` + )); + return; + } + data.putInt('bnsWaystoneCount', current + 1); + } +}); + +BlockEvents.broken(event => { + const blockId = event.block.id; + if (!REGULAR_WAYSTONES.has(blockId)) return; + const player = event.player; + if (!player) return; // explosion / world clear -- accept count drift, rare + const data = player.persistentData; + const current = data.getInt('bnsWaystoneCount'); + if (current > 0) { + data.putInt('bnsWaystoneCount', current - 1); + } +}); diff --git a/pack/pack.lock.json b/pack/pack.lock.json index a0ba0ce..db37f49 100644 --- a/pack/pack.lock.json +++ b/pack/pack.lock.json @@ -1,7 +1,7 @@ { "$schema": "Brass-and-Sigil pack.lock.json - generated, do not edit by hand unless you know what you are doing", "name": "Brass and Sigil", - "version": "0.16.3", + "version": "0.17.0", "minecraft": "1.21.1", "loader": { "type": "neoforge",