Skip to content

Release 3.23.1 - #3091

Merged
tastybento merged 14 commits into
masterfrom
develop
Sep 25, 2026
Merged

tastybento merged 14 commits into
masterfrom
develop

Conversation

@tastybento

Copy link
Copy Markdown
Member

Release Highlights

  • 🎮 Minecraft 26.3 "Wilderness Bound" support — BentoBox now runs on Paper 26.3, and protects the new content: cushions (place, break and sit) and straw beds are covered by the existing PLACE_BLOCKS, BREAK_BLOCKS, RIDING and BED flags. The poplar wood set, poplar boats and shelves, wool and concrete stairs and slabs, shelf mushrooms, red shrubs and the new explorer maps needed no new flags.
  • ⚙️🔡 Customisable settings panels — /island settings and /admin settings are now template-driven panels, laid out by panels/settings_panel.yml and panels/admin_settings_panel.yml, like the other BentoBox menus. Tab layout, pinned flags, the panel title and the order of a flag's lore can all be customised. Defaults are pixel-identical to the old panels.
  • 🐛 Deleted islands no longer count against a player — after an island reset or admin delete, the island stayed in the per-player index until restart, blocking transfers and confusing /admin delete.

Compatibility

✔️ Paper Minecraft 1.21.5 – 26.3
✔️ Java 25+

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. The two new panel templates are written to plugins/BentoBox/panels/ on first run.
  5. You should be good to go!

⚙️ Panel note: the settings panels are only customisable once the templates exist in your data folder. If you keep your own edited copies of the other panel templates, the new settings_panel.yml and admin_settings_panel.yml are additional files; nothing existing is overwritten. A game mode addon may also ship its own copy in its panels/ folder.

🔡 Locale note: one new key, panels.settings.title, sets the title of the settings panel separately from the tab button names. Custom locale files without it fall back to the bundled text; the flag lore layout (protection.panel.flag-item.description-layout) is unchanged unless you opt into the new [ranks] and [tooltips] placeholders.

🔺 Paper 26.3 note: at the time of this release Paper 26.3 is only available as alpha builds. BentoBox compiles against and was tested on build 41. Older 1.21.x and 26.x servers are unaffected.

Full release notes are in the draft GitHub release for 3.23.1.

🤖 Generated with Claude Code

daniel-skopek and others added 14 commits September 20, 2026 21:36
Deleting an island (reset or /obadmin delete) cleared its owner but left
it in the per-player UUID cache index. Until the next restart the island
still counted towards the ex-owner's concurrent islands and was returned
by getIslands(world, uuid). This blocked island transfers with the
"already owns N islands" error, even though /obadmin delete said the
player had no island.

Drop the island from the UUID index when it is soft-deleted. It stays
cached and in the grid so the region purge can still find and reap it.
The /island settings panel is now rendered by SettingsPanel from
panels/settings_panel.yml, like the other customizable panels, so admins
can lay it out as they wish (#3081). The template places tab buttons,
the paged flag list, pinned flags (data.flag), the mode switch, reset and
paging buttons. The panel title is a separate locale entry
(panels.settings.title) translated with [tab] and [world_name], so it can
be styled independently of the tab buttons.

Flag lore layouts gain optional [ranks] and [tooltips] placeholders. A
layout without them renders as before, with the rank list appended, so
customised locale files are unaffected.

Behaviour is unchanged by default: the shipped template reproduces the
old layout slot for slot, saves are deferred while the panel is open, the
panel refreshes in place after a click, and the click cooldown applies.
If the template cannot be loaded the legacy TabbedPanel is shown.

API additions: TemplatedPanelBuilder.island(), TemplatedPanel.regenerate(),
PanelListener.hasClickCooldown()/isActionableSlot(), Flag.toPanelItem()
with a template, Flag.getRankLines(), SettingsTab.getIsland(Panel). The
flag click handlers resolve the island through the panel instead of
casting it to a TabbedPanel. TemplatedPanel's fallback buttons now render
the fallback itself rather than the fallback's own fallback.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
/admin settings now uses SettingsPanel laid out by
panels/admin_settings_panel.yml, completing #3081. The world form has
the world settings, world protections and island defaults tabs in expert
mode; the island form has the island's protection and settings tabs. In
the template each world tab names an island tab as its fallback, so one
file lays out both forms. The two defaults tabs need the
admin.set-world-defaults permission and are hidden without it, as before.

Flag.toPanelItemForRank() renders a protection flag at a given rank and
replaces the rank-description code that IslandDefaultSettingsTab had
duplicated. If the template cannot be loaded the legacy TabbedPanel is
shown.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…s-panel

Make the island settings panel template-driven (#3081)
…ettings-panel

Make the admin settings panel template-driven (#3081)
…ndex

Fix soft-deleted islands still counting towards a player's islands
Minecraft 26.3 "Wilderness Bound" (2026-09-15) is now the default client
version. Add runtime support and the protections its new content needs.

Runtime 26.3 support:
- ServerCompatibility: add V26_3 (COMPATIBLE). The existing ".build.N" strip
  already parses Paper's "26.3.build.NN-alpha" version string.
- Modrinth / Hangar / CurseForge game versions: add 26.3.
- buildVersion -> 3.23.1.

Build: compile against 26.3, test on 26.2. Paper 26.3 is alpha-only and
MockBukkit has no v26.3 artifact yet (MockBukkit#1655 is a draft), so the
build is split: paperVersion (dev bundle, compileOnly, testCompileOnly) is
26.3.build.41-alpha while a new testPaperVersion (testRuntimeOnly, forced on
testRuntimeClasspath) stays at 26.2.build.111-stable. The dev bundle's server
jar only feeds compileOnly, which is what makes this work; the full suite
passes with the split. Documented in .claude/rules/build-toolchain.md.
Main code must therefore still guard 26.3-only API because the plugin runs
on 26.2 servers.

Cushion protection (new 26.3 block-attached entity). Cushions are neither
blocks, Hanging nor Vehicle, so no existing listener saw them:
- CushionListener: EntityPlaceEvent -> PLACE_BLOCKS; Paper's
  EntityBreakByEntityEvent (the only event a cushion break fires) ->
  BREAK_BLOCKS for players and player projectiles; sitting
  (PlayerInteractEntityEvent) -> RIDING. Hanging entities are skipped so
  item frames are not double-reported.
- Registered from BentoBoxListenerRegistrar behind a Class.forName guard.
  The listener's method signatures name 26.3 classes, so the JVM cannot
  verify it on an older server; nothing else may reference the class.

Straw bed: vanilla keeps STRAW_BED out of the #beds tag (villagers must not
claim it), so Tag.BEDS missed it. Resolve it via Enums.getIfPresent and add
it to the BED check in BlockInteractionListener.

Everything else new in 26.3 is already covered: the poplar wood set, poplar
boats and shelf are tag-matched (doors, gates, buttons, plates, signs,
ITEMS_BOATS, WOODEN_SHELVES); wool/concrete stairs and slabs, red shrub,
explorer maps and shelf mushrooms are generic break/place (shelf mushrooms
have no right-click harvest, only bone meal, which is already PLACE_BLOCKS).
No new flags, so no locale changes. The API diff 26.2 -> 26.3 removed
nothing BentoBox uses.

Tests: CushionListenerTest and a straw-bed test in
BlockInteractionListenerTest are @EnabledIf the 26.3 API is on the test
runtime classpath, so they are skipped (13 tests) until MockBukkit ships
v26.3 - verified that running them on a 26.3 runtime with MockBukkit v26.2
fails at Registry init. Test classes keep 26.3 types out of method
signatures, otherwise JUnit's class scan throws NoClassDefFoundError before
the condition is evaluated.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…olves

Every build has failed at configuration time since this morning, on Jenkins
(builds 350, 351) and GitHub Actions alike:

  Could not resolve io.papermc.paperweight:paperweight-userdev:2.0.0-SNAPSHOT
  ... 'org.gradle.plugin.api-version' with value '9.7.1' and the consumer
  needed ... '9.0.0'

Paper's repo keeps only the latest timestamped paperweight snapshot. Today's
(2.0.0-20260925.030446-220) was built with Gradle 9.7.1 and carries that as
its plugin api-version attribute, which Gradle 9.0.0 refuses. There is no
older snapshot left to pin and still no stable paperweight that reads the
data-version-8 dev bundles, so the wrapper has to follow: 9.0.0 -> 9.8.0
(current release). Full build and test suite pass on 9.8.0.

Documented the coupling in .claude/rules/build-toolchain.md.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
master holds only the release merge commits of develop -> master PRs (no content of its own),
but because they were never merged back, GitHub showed master as 16 commits ahead of develop.
This merge brings that ancestry into develop; it changes no files.
# Conflicts:
#	.claude/rules/build-toolchain.md
…pport

Support Minecraft 26.3 and protect cushions and straw beds
The template-driven settings panel PRs (#3087, #3088) were written before 3.23.0 shipped on
2026-09-19 but merged after it, so the API they added first appears in 3.23.1.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@tastybento
tastybento merged commit dd8df6e into master Sep 25, 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