Skip to content

Release 3.22.4 - #3078

Merged
tastybento merged 33 commits into
masterfrom
develop
Sep 6, 2026
Merged

tastybento merged 33 commits into
masterfrom
develop

Conversation

@tastybento

Copy link
Copy Markdown
Member

Release 3.22.4 — bug fix and performance release.

Draft release notes: https://github.com/BentoBoxWorld/BentoBox/releases (tag 3.22.4, draft)

🤖 Generated with Claude Code

https://claude.ai/code/session_01XZRwXXfTUJLJFwSnzSgeRb

tastybento and others added 30 commits August 26, 2026 20:54
Addons like TopBlock ask BentoBox for player heads by name, and the
resolver always went to the web (mc-heads or the Mojang API) even when
the server already had the answer. On busy servers the web calls get
rate limited and panels show default Steve heads.

Two-tier fix in HeadGetter:

- getHead() now short-circuits on the main thread when the player is
  online: Player#getPlayerProfile() is already complete with textures,
  so the head is cached and delivered synchronously. This also removes
  the async-callback race against a GUI that has since been redrawn.
- The async resolver first asks the server to complete the profile via
  Bukkit.createPlayerProfile(...).update(), which Paper serves from its
  own session-service cache for any player who has logged in, with
  proper rate limiting for the rest. The mc-heads / Mojang HTTP paths
  remain as fallbacks for names the server cannot resolve.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018whk2Jwzd7iqEKFnwWqgQY
…ead-profiles

Use server-provided player profiles for heads
zh-TW.yml was created from a copy of en-US.yml and kept its banner — the
red/white stripes with a blue canton — so the language panel showed the
US flag for Traditional Chinese. Replace it with a red field and blue
canton, the closest banner-pattern approximation of the ROC flag. Every
other locale already has its own design; this was the only copy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PtmXKNJ5fSZ9sEumeFDEBc
fix: give zh-TW its own locale banner instead of the US flag
- S8786: replace super-linear \s*+ regex prefixes with linear
  alternatives in PlaceholderGrouper.stripTrailingHashNumber and the
  AddonClassLoader depend/softdepend splitting (split on the literal
  comma and strip each entry)
- S9365: explicitly initialize commandRanks and metaData in the Island
  copy constructor instead of leaving them conditionally unassigned
- Fix a genuine bug found alongside: the Island copy constructor wrote
  cloned spawn points back into the source island's map instead of the
  copy's, so spawn points were never copied

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018PgvHCn8nEPbF2MhZeebY2
Revert "fix: give zh-TW its own locale banner instead of the US flag"
… name] arg

`/[admin] info <player>` used IslandsManager.getIsland(world, uuid), which only
returns the player's primary/active island, so admins looking up a player with
several islands only ever saw one of them.

- `/[admin] info <player>` now loops over getIslands(world, uuid) and prints the
  admin info block for each island (own and team islands), matching what
  `/[admin] tp <player> <name>` already considers reachable.
- New optional `[island name]` argument: `/[admin] info <player> <island name>`
  resolves island and home names via IslandGoCommand.getNameIslandMap with the
  same forgiving matching as `/[player] go` (exact, then case/space-insensitive,
  then unique prefix). Unknown names list the valid ones, as `tp` does.
- Tab completion offers the target player's island/home names for arg 2.
- Admin info now prints the island name (new `commands.admin.info.island-name`
  key) so the blocks can be told apart; translated into all bundled locales.
- IslandGoCommand.resolveName is now public so admin commands can share it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WjU4tEg1H9fbcdErGLATAj
…lands

feat(admin): show every island in /[admin] info <player>, add [island name] arg
- S2789: replace the null-assigned Optional in
  LockAndBanListener.onVehicleMove with Optional.empty() plus an
  islandResolved flag, keeping the lazy single lookup per vehicle
- S2583: drop the @nonnull generic annotations on IslandCache#grids -
  Map#get legitimately returns null for worlds with no grid, and the
  value annotation made those null checks look impossible
- S2637: pass Objects.requireNonNull(p.getLocation()) to getIslandAt in
  InvincibleVisitorsListener - a live player's location is never null
- S2184: cast the chunk coordinate additions to double in
  ClosestSafeSpotTeleport#scanAndPopulateBlockQueue before the implicit
  widening in BoundingBox#contains

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018PgvHCn8nEPbF2MhZeebY2
The setting was added after the 3.22.4 version bump, so 3.22.3 was
stale on the @ConfigEntry and the getter/setter javadocs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018PgvHCn8nEPbF2MhZeebY2
- S6322: the flag/mob-limit click handlers mutated the lists returned by
  IWM#getHiddenFlags/getMobLimitSettings/getGeoLimitSettings, which are
  Collections.emptyList() (immutable) when the world is not a game world.
  Mutate the game mode's live WorldSettings list inside getAddon(world)
  .ifPresent(...) and save there - one addon lookup instead of several
  (CycleClick, IslandToggleClick, CommandCycleClick, GeoMobLimitTab)
- S2259: User#closeInventory dereferenced the nullable player field;
  now a no-op for non-players
- S2259: IslandResetCommand#resetIsland passed a possibly-null island to
  deleteOldIsland with only a post-hoc assert; replaced with a proper
  null guard and error message
- S2259: IslandTeamGUI#leave used clickingUser.getUniqueId().equals(...)
  which NPEs for non-player users; switched to Objects.equals
- S2259 (false positives): annotate the user parameter @nonnull on the
  command entry points the analyzer flagged - it assumed user could be
  null because IslandsManager#getIsland null-checks its parameter, then
  reported the user.sendMessage calls in the island==null branches. The
  framework never passes a null User here.
- tests: stub GameModeAddon#getWorldSettings in the click-handler tests
  to carry the mutable lists the handlers now edit

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018PgvHCn8nEPbF2MhZeebY2
CompositeCommand.getCommandFromArgs called setLabel(arg) on the shared
sub-command object while walking the typed arguments. After any player
used /island h, every other player's tab completion advertised "h" in
place of "go", and it flipped again whenever someone typed another alias.
Brigadier made this far more visible because tabComplete now runs on
every keystroke, so merely typing the alias was enough.

execute() already derives the typed alias from the args array and passes
it to call(), so the mutation was redundant. Drop it and add a
regression test.

Fixes #3075

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QTSR5y1ScxFzCqcXiAXXFT
tastybento and others added 3 commits September 5, 2026 15:14
…-mutation

Stop renaming sub-commands to the alias a player typed (#3075)
PurgeRegionsService.delete() is dispatched from an async task by both the
admin purge command and the housekeeping auto-purge, but it fired
IslandEvent (DELETED / PURGED) directly from that thread. Paper rejects
synchronous events fired off the main thread, so the age sweep crashed with
"IslandEvent may only be triggered synchronously" after the region files
had already been deleted, leaving island DB rows orphaned and reporting the
purge as failed.

Split delete() into two phases: disk I/O (region files, residual check,
player data) stays on the calling thread, and the event firing plus
cache/database removal is hopped onto the main thread via the scheduler
and awaited, so the return value and summary log still reflect the final
state. When already on the main thread the finalization runs inline.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XZRwXXfTUJLJFwSnzSgeRb
@tastybento
tastybento merged commit 237321a into master Sep 6, 2026
5 checks passed
@sonarqubecloud

sonarqubecloud Bot commented Sep 6, 2026

Copy link
Copy Markdown

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.

3 participants