
BentoBox
SkyBlock, OneBlock, Boxed, SkyGrid, AcidIsland, CaveBlock, Poseidon, StrangerRealms - and more! These are just some of the island-based game modes that BentoBox powers. From the author of the original ASkyBlock.
Список изменений
BentoBox 3.22.2
A bug-fix patch on top of 3.22.0. Four fixes, all of them for things players hit directly: name lookups resolving to the wrong account, Bedrock players' panel clicks being swallowed, an addon whose dependency is missing leaving broken commands behind, and nether returns dropping players on somebody else's island.
No new features, no config keys, no locale changes. If you are on 3.22.0, this is a drop-in replacement.
There is no 3.22.1 release. The version was incremented twice during development; 3.22.2 is the first build published from it.
Compatibility
✔️ Paper Minecraft 1.21.5 – 26.2 ✔️ Java 25+
Upgrading
- As always, take backups just in case. (Make a copy of everything!)
- Stop the server.
- Replace the BentoBox jar with this one.
- Start the server.
- 🔺 BentoBox now deletes stale
Namesrecords — old name→UUID entries that were dropped from memory but never removed from the database. Existing databases heal themselves as players log in; no manual migration is needed, but take the backup in step 1 before you let it run.
Highlights
- 🔺 Player name lookups no longer resolve to a stale account —
/is team trust <name>and/is info <name>could silently answer for a UUID that had not held that name in months. - Bedrock players can use panels again — Geyser expands one tap into several Java click packets, and the click cooldown was eating the one that mattered.
- A disabled addon no longer leaves live, broken commands behind — an addon dropped for a missing dependency kept its commands registered, and every subcommand threw an NPE.
- Returning from a standard nether puts you on your own island — not on whichever island sits nearest 0,0.
Bug Fixes
🔺 Player names resolve to the right account
[PR #3057] — Fixes #3052
/ob team trust Oli713664 reported no such player, and /ob info Oli713664 answered "that player does not have an island" for a player who has one.
Capitalization was the visible symptom but not the cause. setPlayerName removed the superseded Names record from the in-memory cache and never deleted it from the database, so every leftover was reloaded on restart, and getUUID took findFirst() over an unordered list — a name could resolve to a UUID that had not held it for months. On a case-sensitive file system a leftover oli713664.json and the current Oli713664.json both matched, and whichever the directory listing yielded first won. That also explains the misleading second symptom: the lookup returned a stale UUID rather than null.
Three changes:
nameCacheis keyed on the lower-cased name. Minecraft names are unique ignoring case, so there is exactly one entry per name and the match no longer depends on how it was spelled when stored. It also moves from anArrayList— mutated by the join listener while commands read it — to aConcurrentHashMap, turning a linear scan of every name ever seen into a single hash lookup.- Stale records are deleted.
setPlayerNameremoves any record still pointing at this player under another spelling, andremovePlayerdrops the name lookup too. getUUIDconsults the online player first, then the cache, then the server's own user cache for players BentoBox has never recorded.
Every step is in-memory, so resolving a name still never blocks the caller — the getOfflinePlayerIfCached variant is used deliberately, as it returns null on a miss instead of asking Mojang.
🔺 Data note: the stale-record purge runs on login and only when a player's stored name actually differs from their current one — once per rename, not once per join.
Bedrock players' panel clicks are no longer eaten
[PR #3058] — Fixes #3049
A Bedrock player opened /is settings, tapped any button, and got general.errors.slow-down with nothing happening — on the first tap, even after waiting, with the default 250 ms panel.click-cooldown-ms.
Bedrock's inventory model sends a whole transaction per tap, and Geyser expands it into a sequence of Java click packets that arrive in the same tick. Packet 1 opened the cooldown window; packet 2 hit it. This became fatal in 3.22.0 when the check moved to PanelListenerManager as an early return ahead of the click handler, so whichever packet lost the race was discarded outright — and the packet that landed on the button was not necessarily the one that arrived first.
Clicks in the same tick as the window opened are now treated as one physical gesture: the first click that can actually do work is let through, the rest are dropped silently, and a no-op click on a filler icon or the player's own inventory no longer consumes the window the real click needs. Clicks in a later tick but still inside the cooldown are unchanged — rejected, with the notice sent at most once per window. Spam protection is intact at one action-bearing click per tick.
onTimeout(User, Panel) keeps its signature and behaviour; a three-argument overload carries the new flag, and TabbedPanel.isActionableSlot(int) is new. Both additive.
A dropped addon no longer leaves broken commands registered
[PR #3060] — Fixes #3059
Reported on Discord: /ch on a server with ChunkBlock installed but not the Level addon it depends on answered "An unexpected error occurred while running the command" with an NPE, for every subcommand.
A game mode addon builds its commands in onLoad(), and CompositeCommand's constructor registers them with the Bukkit command map immediately — but the world is only attached later, in enableAddon. sortAddons() spots the missing dependency after onLoad() has run: it unregistered the addon's flags and dropped it from the addon list, but left the commands registered. /ch stayed live with a null world, and getWorldSettings(null) threw on the first lookup. The same hole existed for an addon abandoned as incompatible, or one that threw during load or enable.
AddonsManager#withdrawAddonnow takes back listeners, flags and commands, and is called from all three abandonment paths. Previously only flags were unregistered, and only on the missing-dependency path.CommandsManager#unregisterCommands(Addon)is the new method backing it. Brigadier keeps its nodes — it has no removal API — but a node whose label no longer resolves is refused by itsrequirespredicate, so it disappears from clients too.CompositeCommand#callrefuses outright when a command belongs to aGameModeAddonand has no world, logging which addon is not enabled. BentoBox's own world-less commands such as/bentoboxare unaffected.IslandWorldManager#getWorldSettingsbuilds its "non-game world" message lazily; it used to evaluateworld.getName()eagerly, so a null world threw inside the very string meant to explain the problem.
CommandsManager#unregisterCommands(Addon) is new and additive, so binary compatibility is unaffected.
Returning from a standard nether lands you on your own island
[PR #3061] — Fixes AOneBlock#549
With a shared nether and create-and-link-portals: false — AOneBlock's default — a player who went through a nether portal and came back was always dumped on the island near 0,0, usually somebody else's, where they had no build rights. /ob home worked fine, so the island data was never the problem.
handleFromStandardNetherOrEnd resolved the destination from the island's spawn point only, and Optional.map collapses to empty when the mapper returns null — so an island with no spawn point was indistinguishable from having no island at all, and execution fell through to the world-spawn fallback. An island only gets a spawn point when its blueprint contains a {spawn here} sign; AOneBlock's default blueprint is a single bedrock block, so the fallback fired every single time. BSkyBlock was unaffected because it defaults to island nethers and never reaches this branch.
The destination now falls back to the island's home location, which is @NonNull and defaults to the protection centre. The end-exit-portal path already did the equivalent via getSafeRespawnLocation.
Other Improvements
- Local builds no longer stamp a doubled
-LOCALmarker intoplugin.yml—/bentobox versionon a local build reported…-SNAPSHOT-LOCAL-LOCAL. Development-only; CI and release builds were never affected (fa401ee). - Expanded the Building from Source section of the README (
5124f00). - Corrected the version-numbering notes in
CLAUDE.md(dcfe89f).
Legend
| Marker | Meaning |
|---|---|
| 🔡 | Locale files may need regenerating or updating |
| ⚙️ | Config options added, renamed or removed |
| 🔺 | Special attention needed |
What's Changed
- 🔺 Resolve player names without depending on stored capitalization by @tastybento in https://github.com/BentoBoxWorld/BentoBox/pull/3057
- Stop the panel click cooldown eating Bedrock players' clicks by @tastybento in https://github.com/BentoBoxWorld/BentoBox/pull/3058
- Withdraw an addon's commands when the addon never enables by @tastybento in https://github.com/BentoBoxWorld/BentoBox/pull/3060
- Send players returning from a standard nether to their own island by @tastybento in https://github.com/BentoBoxWorld/BentoBox/pull/3061
Full Changelog: https://github.com/BentoBoxWorld/BentoBox/compare/3.22.0...3.22.2
