Release 3.16.0
Release Highlights
- ⚙️🔡🔺 Per-world team disable +
admin team disbandall— Game modes can now opt out of the team subsystem entirely. Trust and coop remain available as the supported alternative, and a new admin command strips pre-existing members from every island in one pass. - 🔺 Setowner cap enforcement — Transferring island ownership now respects the recipient's
concurrent-islandscap andisland.number.<n>permission, closing a clean bypass that previously allowed admins (and team setowner) to push players over their limit. - 🐛 Safe respawn fallback —
ISLAND_RESPAWNno longer drops players at world spawn (0,0) when their home block has been removed; it now walks a fallback chain ending inSafeSpotTeleportto find a real safe spot on the island. - 🐛 Offline growth: vines & trees —
OFFLINE_GROWTHnow correctly blocks every spreading plant (vines, weeping vines, etc.) and every tree growing from a sapling — not just kelp and bamboo. - 🐛 Dynmap marker Y range — Area/polygon markers now use the world's full min/max height instead of always rendering at y=64.
- CraftEngine hook helpers —
getItemStack(id)andgetItemId(item)let addons render and recognise CraftEngine custom items without depending on CraftEngine directly.
Compatibility
✔️ Paper Minecraft 1.21.5 – 26.1.2
✔️ Java 21+
Upgrading
- As always, take backups just in case. (Make a copy of everything!)
- Stop the server.
- Replace the BentoBox jar with this one.
- Restart the server.
- If you intend to enable
isTeamsDisabledin a game mode, run/[admin] team disbandallonce after the upgrade to clean up pre-existing teams (see the callout below). - You should be good to go!
⚙️🔺 Teams-disabled is opt-in per game mode. A new
WorldSettings#isTeamsDisabled()method (defaultfalse) lets a game mode disable team commands in its world. Existing servers see no behaviour change unless a game mode adopts the setting. Trust and coop relationships are intentionally unaffected — they're the supported alternative when teams are off.
🔺 Setowner cap is now enforced. Both
/island team setownerand/[admin] team setownerrefuse the transfer if the recipient is already at their concurrent-islands cap. Previously, admin setowner only emitted a warning after the bypass and/island team setownerhad no check at all. Adjust the recipient's permission first if you really intend to allow more islands.
🔡 Locale changes: New keys for
commands.admin.team.disbandall.{description,confirmation,success},commands.island.team.errors.teams-disabled,commands.admin.team.setowner.errors.at-max, and an updatedcommands.admin.team.kick.cannot-kick-ownermessage that points admins tosetowner/disband. The deadcommands.admin.team.kick.success-allkey has been removed. All 22 bundled translations are in sync.
Legend
- 🔡 locale files may need to be regenerated or updated.
- ⚙️ config options have been removed, renamed, or added.
- 🔺 special attention needed.
New Features
⚙️🔡🔺 Per-world Team Disable + admin team disbandall
A new WorldSettings#isTeamsDisabled() (default false) lets a game mode opt out of the team subsystem on a per-world basis. When enabled, the action commands that add, remove or reorganise team members refuse to run with commands.island.team.errors.teams-disabled:
/island team inviteandinvite accept(TEAM invitations only — COOP and TRUST invitations remain accepted)/island team kick,leave,promote,demote,setowner/[admin] team add
Read-only commands (/island team panel, info, invites, invite reject), trust/coop relationships (trust, coop, untrust, uncoop), and admin commands that operate on existing teams (kick, disband, disbandall, setowner, fix, maxsize) all remain available.
A new admin command /[admin] team disbandall strips every member and sub-owner from every island in the current world in one confirmable pass. Trusted and coop players are intentionally untouched. Use it once after flipping isTeamsDisabled on to clean up pre-existing teams.
🔌 CraftEngine Hook Helpers
Two new helpers on CraftEngineHook, mirroring the equivalents on OraxenHook and ItemsAdderHook:
getItemStack(String id)returns anOptional<ItemStack>for the registered CraftEngine custom item — useful for rendering the correct icon and display name in panels and GUIs.getItemId(ItemStack item)returns the namespaced ID of a CraftEngine custom item (ornull) — useful for command handlers (e.g. Level addon's/is value hand) that need to recognise a held custom item.
Both helpers let addons interoperate with CraftEngine without compiling against it directly.
Bug Fixes
🔺 Setowner Bypassed concurrent-islands Cap
AdminTeamSetownerCommand previously allowed transfers to a player who already owned their maximum allowed concurrent islands and only emitted a warning afterwards; IslandTeamSetownerCommand had no check at all. Both now compute the recipient's current concurrent-islands count and permission-aware cap in canExecute and refuse the transfer when at or above the limit. The user path uses the existing commands.island.team.setowner.errors.at-max locale entry; the admin path uses a new commands.admin.team.setowner.errors.at-max that includes the count and limit.
ISLAND_RESPAWN Sent Players to 0,0 When Home Was Unsafe
[PR #2962]
When ISLAND_RESPAWN was enabled and the player's home block had been removed, isSafeLocation() returned false and the respawn fell through to world spawn. IslandRespawnListener now walks a fallback chain — try one block above the home (covers slabs/stairs), then a quick sync check around the island protection center, then anchor the respawn at the protection center and schedule SafeSpotTeleport on the next tick to find a real safe spot. cancelIfFail(true) ensures the player isn't yanked elsewhere if the comprehensive scan also fails.
OFFLINE_GROWTH: Vines and Trees from Saplings Were Ignored
[PR #2968]
OFFLINE_GROWTH previously only blocked kelp, bamboo and bamboo saplings on BlockSpreadEvent — vines, cave vines, twisting/weeping vines and any other spreading plant slipped through. Trees and mushrooms growing from a sapling didn't fire BlockGrowEvent at all, so they were never blocked. The listener now uses the source block location for BlockSpreadEvent (so plants growing outward from an island are correctly attributed) and adds a StructureGrowEvent handler for trees/mushrooms.
Admin team kick on Multi-island Players
[PR #2967]
AdminTeamKickCommand previously iterated every team island the target was on and silently kicked them from each. With concurrent islands enabled, that's a footgun. The command now defaults to the single team island the target is on and, when there are several, requires an explicit x,y,z coordinate (with tab completion suggesting the candidates). Owner-islands are also excluded from kick targets — if the target only owns the matched island(s), the command refuses with commands.admin.team.kick.cannot-kick-owner and points the admin to setowner or disband instead.
Dynmap Area Markers Always Rendered at y=64
[PR #2972]
DynmapHook was creating area markers without a configured Y range, so Dynmap rendered them at the default y=64 regardless of the actual world height. Both setMarker and the public addPolygonMarker now call area.setRangeY(world.getMaxHeight(), world.getMinHeight()) so markers cover the full vertical extent of the world.
Other Improvements
- Regression test for the island home location bug fix from 3.15.0 [PR #2969]
WorldSettings#isTeamsDisabled()Javadoc rewritten with explicit lists of which commands are blocked vs. unaffected- Locale sync across all 22 bundled translations for new keys + the updated
cannot-kick-ownermessage; removed the deadsuccess-allkey
What's Changed
- 🐛 fix: ISLAND_RESPAWN sends players to 0,0 when home block is removed by @tastybento in #2962
- 🔺 Refuse setowner when recipient is at the concurrent-islands cap by @tastybento in #2966
- 🐛 AdminTeamKick: require x,y,z coordinates when player is on multiple islands by @tastybento in #2967
- 🐛 Fix OFFLINE_GROWTH: block vine spread and tree growth from saplings by @tastybento in #2968
- Add regression test confirming island home location is set on the correct island during concurrent creation by @tastybento in #2969
- 🔌 Add CraftEngineHook.getItemStack(id) lookup by @tastybento in #2970
- 🐛 Fix Dynmap area markers always rendering at y=64 by @tastybento in #2972
- 🔌 feat(hooks): add CraftEngineHook.getItemId(item) lookup by @tastybento in #2973
- ⚙️🔡🔺 feat: per-world team disable + admin team disbandall (#2965) by @tastybento in #2975
Full Changelog: 3.15.0...3.16.0