Skip to content

Release 3.19.1#3030

Merged
tastybento merged 17 commits into
masterfrom
develop
Jul 11, 2026
Merged

Release 3.19.1#3030
tastybento merged 17 commits into
masterfrom
develop

Conversation

@tastybento

Copy link
Copy Markdown
Member

No description provided.

tastybento and others added 17 commits July 9, 2026 07:30
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jbkc3n7vnNbtMx3s9dbkbc
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
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
…ppression

Core structure suppression for all game modes (#116/#117/#118)
…placement

Add OraxenHook.placeBlock to expose custom block placement
…nexo-custom-blocks

Add NexoHook for Nexo custom blocks and items
New players routinely type a subcommand as if it were the whole command
(/teams or /team invite instead of /oneblock team) or mistype a
subcommand (/island invit). Instead of "Unknown command" or a help dump,
BentoBox now matches the input against every node of its command trees
and replies with a clickable suggestion the player can also accept by
typing "yes".

- CommandMatcher: pure matching engine - label/alias matching at any
  tree depth, edit-distance and prefix heuristics, world-context
  ranking, permission filtering
- SuggestionsManager: presentation and pending-intent tracking; single
  confident suggestion or a short clickable options list
- DidYouMeanListener: UnknownCommandEvent interception (fires only when
  no plugin owns the command), chat "yes" acceptance, pending cleanup
- CompositeCommand dispatch: unmatched subcommand args route through the
  suggestion engine before falling back to the old error
- Config: general.did-you-mean.unknown-commands / .subcommands (default
  on)
- Locales: new general.did-you-mean keys translated into all 22
  languages; also fills the pre-existing gap
  commands.admin.team.setowner.specify-island everywhere

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jbkc3n7vnNbtMx3s9dbkbc
In-game testing showed the clickable suggestions rendering their closing
tags as literal text, with the click event dead. Root cause: inline
[run_command]/[hover] commands were re-encoded as MiniMessage tags
wrapped around the message, but the message text contains a §r from the
legacy round-trip (any closed color emits one). §r maps to <reset>,
which closes the wrapping <click>/<hover> tags too - killing the events
and orphaning the closers, which MiniMessage renders as literal text.

Fix: extract the inline commands as data (Util.extractInlineCommands)
and apply ClickEvent/HoverEvent programmatically to the parsed
Component in User.parseToComponent. The events now cover the whole
message regardless of internal resets.
convertInlineCommandsToMiniMessage is kept (refactored over the new
extraction) for API compatibility.

Regression test asserts no literal tag text leaks and the click covers
the message on both the single-suggestion and options-list paths.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jbkc3n7vnNbtMx3s9dbkbc
NexoBlocks.place() returns void, so returning it as a boolean did not
compile and broke the develop build. Follow the same pattern as
OraxenHook.placeBlock: verify the ID is a known Nexo block, request
placement, and report whether placement was attempted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jbkc3n7vnNbtMx3s9dbkbc
- User.parseToComponent (S2637): assign nullable record accessor to a
  local so the null-check narrows it for @nonnull parseMiniMessageOrLegacy
- Util.extractInlineCommands (S6916 x2): replace the if statements inside
  the string-constant switch arms with first-wins ternary assignments
- CommandMatcher.quality (S3358): extract the nested ternary into an
  allowedDistance helper
- CommandMatcherTest (S5976): merge three identical matchCommandLine tests
  into one parameterized test

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G7UmQDCP5MGHEZqFiw44zH
@sonarqubecloud

Copy link
Copy Markdown

@tastybento tastybento merged commit dce6849 into master Jul 11, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants