Core structure suppression for all game modes (#116/#117/#118)#3019
Merged
Conversation
Ports the CaveBlock structure-suppression fix into core BentoBox so every game mode with vanilla-generated worlds (Boxed, SkyGrid, CaveBlock, ...) can disable structures without the /locate freeze and spawn-area leak. Two config layers: - Global default: world.disabled-structures in config.yml (Settings), applied to every game mode world. Empty by default, so behaviour is unchanged. - Per-world override: new WorldSettings.getStructureSettings() default method (binary-compatible) letting a game mode disable more structures or force- enable one the global list disables. StructureListener handles both halves: - AsyncStructureSpawnEvent -> stops the structure being placed - StructuresLocateEvent -> narrows/cancels searches (/locate, Eyes of Ender, explorer/treasure maps, dolphins, cartographer trades) so they no longer scan to the border and freeze the main thread (#117) One listener is registered per GameModeAddon in AddonsManager, immediately before createWorlds(), so it is active for the initial spawn-area generation (#118). Worlds are matched by configured name (overworld/nether/end) because they are not yet registered with the world manager during createWorlds(). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jbkc3n7vnNbtMx3s9dbkbc
Contributor
There was a problem hiding this comment.
Pull request overview
Moves vanilla structure suppression into BentoBox core so all game modes that rely on vanilla world generation can both (a) prevent disabled structures from being placed and (b) prevent /locate (and related structure searches) from scanning forever for structures that will never generate.
Changes:
- Add global configuration
world.disabled-structures(empty by default) andSettings#getDisabledStructures(). - Introduce per-world override hook
WorldSettings#getStructureSettings()(default empty map) and implement suppression in newStructureListenerfor both spawn and locate paths. - Register the listener early (before
createWorlds()) and add unit tests covering global/override behavior and locate filtering/cancellation.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
src/main/java/world/bentobox/bentobox/managers/AddonsManager.java |
Registers structure suppression listener prior to world creation. |
src/main/java/world/bentobox/bentobox/listeners/StructureListener.java |
Implements spawn cancellation + locate filtering/cancellation for disabled structures. |
src/main/java/world/bentobox/bentobox/Settings.java |
Adds world.disabled-structures config entry + accessor methods. |
src/main/java/world/bentobox/bentobox/api/configuration/WorldSettings.java |
Adds default per-world structure override map API. |
src/test/java/world/bentobox/bentobox/listeners/StructureListenerTest.java |
Adds test coverage for suppression logic and world matching. |
Use AddonsManager.registerListener(addon, listener) instead of a raw PluginManager.registerEvents call so the listener is tracked in the listeners map and unregistered when the game mode addon is disabled or unloaded. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jbkc3n7vnNbtMx3s9dbkbc
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Problem
Disabling a vanilla structure in a BentoBox game mode has, so far, been a per-addon job. CaveBlock solved it in #117 and #118, but any game mode whose worlds delegate to vanilla generation (Boxed, SkyGrid, CaveBlock, custom worlds) can hit the same two problems:
/locatefreeze (ASkyblock vs BSkyblock #117). CancellingAsyncStructureSpawnEventstops a structure being placed but leaves the world's placement rules intact. Every structure search —/locate, Eyes of Ender, explorer/treasure maps, dolphins, villager cartographer trades (perStructuresLocateEvent's own javadoc) — keeps proposing candidate positions that all get cancelled, scanning to the radius cap and freezing the main thread (62 s in CaveBlock's test, tripping the Paper Watchdog).createWorlds(), before a listener registered inonEnable()exists.This moves the fix into core so every game mode gets it for free.
Design
Two config layers
world.disabled-structuresinconfig.yml(Settings), applied to every BentoBox game mode world (overworld/nether/end). Empty by default → no behaviour change on upgrade.WorldSettings.getStructureSettings()default method (binary-compatible), aMap<String,Boolean>(structure → should-generate) letting a game mode both disable extra structures (false) and force-enable one the global list disables (true). Absent entry → inherit global.Effective decision: a per-world entry always wins; otherwise the global list applies. Keys are normalised (lower-case,
-→_) so casing/separators don't matter.StructureListenerhandles both halves:AsyncStructureSpawnEvent→ cancel placement of a disabled structure.StructuresLocateEvent→ drop disabled structures from the search; cancel outright when nothing enabled remains, so the scan is skipped.Timing (#118): one listener is registered per
GameModeAddoninAddonsManager, immediately beforecreateWorlds(), so it is active for the initial spawn-area generation. Worlds are matched by configured name (overworld /_nether/_the_end) rather than the world manager, because they are not yet registered duringcreateWorlds().Testing
StructureListenerTest(11 tests, all pass): global-default disable, per-world override disable, override force-enable-over-global, unlisted passthrough, nether name-match, out-of-world ignore, and the/locateall-disabled/mixed/all-enabled/out-of-world cases. ExistingAddonsManager/Settingstests unaffected.Follow-ups (separate PRs)
getStructureSettings()to return itsgenerateStructuresmap and delete its now-redundantStructureGenerationListener+ early registration.world.disabled-structuresand the newWorldSettingsmethod.🤖 Generated with Claude Code
https://claude.ai/code/session_01Jbkc3n7vnNbtMx3s9dbkbc