## 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-islands` cap and `island.number.<n>` permission, closing a clean bypass that previously allowed admins (and team setowner) to push players over their limit.
* 🐛 **Safe respawn fallback** — `ISLAND_RESPAWN` no longer drops players at world spawn (0,0) when their home block has been removed; it now walks a fallback chain ending in `SafeSpotTeleport` to find a real safe spot on the island.
* 🐛 **Offline growth: vines & trees** — `OFFLINE_GROWTH` now 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)` and `getItemId(item)` let addons render and recognise CraftEngine custom items without depending on CraftEngine directly.
### Compatibility
✔️ Paper Minecraft 1.21.5 – 1.21.12
✔️ Java 21+
### Upgrading
1. **As always, take backups just in case.** (Make a copy of everything!)
2. Stop the server.
3. Replace the BentoBox jar with this one.
4. Restart the server.
5. If you intend to enable `isTeamsDisabled` in a game mode, run `/[admin] team disbandall` once after the upgrade to clean up pre-existing teams (see the callout below).
6. You should be good to go!
> ⚙️🔺 **Teams-disabled is opt-in per game mode.** A new `WorldSettings#isTeamsDisabled()` method (default `false`) 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 setowner` and `/[admin] team setowner` refuse 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 setowner` had 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 updated `commands.admin.team.kick.cannot-kick-owner` message that points admins to `setowner`/`disband`. The dead `commands.admin.team.kick.success-all` key 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`
[[PR #2975](https://github.com/BentoBoxWorld/BentoBox/pull/2975)] Closes [#2965](https://github.com/BentoBoxWorld/BentoBox/issues/2965)
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 invite` and `invite 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
[[PR #2970](https://github.com/BentoBoxWorld/BentoBox/pull/2970)] [[PR #2973](https://github.com/BentoBoxWorld/BentoBox/pull/2973)]
Two new helpers on `CraftEngineHook`, mirroring the equivalents on `OraxenHook` and `ItemsAdderHook`:
- `getItemStack(String id)` returns an `Optional<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 (or `null`) — 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
[[PR #2966](https://github.com/BentoBoxWorld/BentoBox/pull/2966)] Fixes [#2908](https://github.com/BentoBoxWorld/BentoBox/issues/2908)
`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](https://github.com/BentoBoxWorld/BentoBox/pull/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](https://github.com/BentoBoxWorld/BentoBox/pull/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](https://github.com/BentoBoxWorld/BentoBox/pull/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](https://github.com/BentoBoxWorld/BentoBox/pull/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](https://github.com/BentoBoxWorld/BentoBox/pull/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-owner` message; removed the dead `success-all` key
---
## What's Changed
* 🐛 fix: ISLAND_RESPAWN sends players to 0,0 when home block is removed by @tastybento in https://github.com/BentoBoxWorld/BentoBox/pull/2962
* 🔺 Refuse setowner when recipient is at the concurrent-islands cap by @tastybento in https://github.com/BentoBoxWorld/BentoBox/pull/2966
* 🐛 AdminTeamKick: require x,y,z coordinates when player is on multiple islands by @tastybento in https://github.com/BentoBoxWorld/BentoBox/pull/2967
* 🐛 Fix OFFLINE_GROWTH: block vine spread and tree growth from saplings by @tastybento in https://github.com/BentoBoxWorld/BentoBox/pull/2968
* Add regression test confirming island home location is set on the correct island during concurrent creation by @tastybento in https://github.com/BentoBoxWorld/BentoBox/pull/2969
* 🔌 Add CraftEngineHook.getItemStack(id) lookup by @tastybento in https://github.com/BentoBoxWorld/BentoBox/pull/2970
* 🐛 Fix Dynmap area markers always rendering at y=64 by @tastybento in https://github.com/BentoBoxWorld/BentoBox/pull/2972
* 🔌 feat(hooks): add CraftEngineHook.getItemId(item) lookup by @tastybento in https://github.com/BentoBoxWorld/BentoBox/pull/2973
* ⚙️🔡🔺 feat: per-world team disable + admin team disbandall (#2965) by @tastybento in https://github.com/BentoBoxWorld/BentoBox/pull/2975
**Full Changelog**: https://github.com/BentoBoxWorld/BentoBox/compare/3.15.0...3.16.0
Developer information
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle.
maven { name = "Modrinth"; url = "https://api.modrinth.com/maven" }