Release 1.27.0 - #552

Merged
tastybento merged 10 commits into
masterfrom
develop
Aug 8, 2026
Merged

Release 1.27.0#552
tastybento merged 10 commits into
masterfrom
develop

Conversation

@tastybento

Copy link
Copy Markdown
Member

Release 1.27.0.

Headline

Island progress is no longer lost when the server restarts. Reported on Discord as "it's not saving the progress" — a player online through a restart came back with their block count rolled back to the last checkpoint, up to 49 blocks undone, every restart. The shutdown save was queued rather than written, and every BentoBox before 3.22.0 discarded that queue on the way out.

Also in this release: MiniMessage and hex colours in phase text (holograms, action bar, locale strings), a new island.save-every setting, and a rewritten reference phase file.

🔺 This release raises the minimum BentoBox version

bentobox.version and addon.ymlapi-version both move to 3.22.0, because the shutdown fix uses saveObjectNow() which was added there. Without the api-version bump the addon would load on an older core and throw NoSuchMethodError at shutdown — worse than the bug being fixed. It now refuses to load with "Please update BentoBox".

Knock-on effect for admins: BentoBox 3.18.0+ requires a Java 25 server, so 1.27.0 does too. This is called out prominently in the release notes.

What's in it

PRChange
#550🔺⚙️ Shutdown save writes directly; new island.save-every (default 10, was a hardcoded 50)
#551MiniMessage, hex and gradient support in phase text; fixes § codes rendering literally
#548Reference phase file now explains weights vs positions vs start block
#547CI: publish-platforms pin bumped to the multipart-JSON fix

Also on this branch: a CI fix moving the build to JDK 25. BentoBox 3.18.0+ ships Java 25 class files, which a JDK 21 javac cannot read at all — the build failed against every BentoBox type until the runner moved to 25. The addon still targets Java 21 via <release>.

Verification

  • Full suite green on develop.
  • Boot-tested on two real servers: BentoBox 3.15.1 refuses to load the addon with the intended message and no linkage error; BentoBox 3.22.1-SNAPSHOT enables, runs, and disables cleanly.
  • Not verified in-game: a real block count surviving a restart, and hologram rendering. Both are covered by unit tests through the real code paths, but neither was watched on a live server with a player.

Release notes for the draft release are prepared separately.

🤖 Generated with Claude Code

https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ

tastybentoand others added 10 commits July 29, 2026 09:00
The pinned SHA (ca2dcd16, 2026-07-03) predates BentoBoxWorld/.github#13,
which moved the CurseForge `metadata` and Hangar `versionUpload` JSON out of
inline `-F` values and into files. curl treats `;` in an inline -F value as
the start of a `type=`/`filename=` attribute, so a release body containing a
semicolon truncates the JSON: the 1.26.3 publish failed with CurseForge
"Error in field `metadata`: Invalid JSON" and Hangar "Failed to read request".
Earlier releases only passed because their notes happened to contain no
semicolons.
Pin moved to master HEAD 1f91a0e, which contains the fix.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SAQ3YQkcfRoCZEwa6SPJcp
ci: bump publish-platforms pin to the multipart-JSON fix
0_plains.yml is the reference file admins read first, but it never said
what the numbers after a Material or EntityType are. An admin asked, and
they were right to guess weighting: they are relative weights in a single
raffle - not counts and not percentages - and blocks, mobs and
custom-blocks all draw from that same pool, so a mob weight is directly
comparable to a block weight and pushes every block's share down.
The header now separates the three distinct kinds of number a phase file
contains, since that is the real source of the confusion:
1. blocks/mobs/custom-blocks values are weights, one shared pool
2. fixedBlocks and holograms keys are positions within the phase, from 0
3. the top-level key is the section name - phases_index.yml has owned
phase order and length since 1.26.0
Each section then gets its own explanation with the real Plains numbers
worked out (11450 block weights + 665 mob weights = 12115, so
GRASS_BLOCK: 2000 is 16.5% and COW: 150 is 1.2%), plus the CHEST
two-stage roll, the mob/custom-block types that were missing from the
list, and version gating.
Comments only - every block, mob and weight is unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017zwLryefnJ6wG76JmYNamx
docs: rewrite the phase 0 comments to explain what the numbers mean
A player breaking blocks and then sitting through a restart would come back
to their block count rolled back to the last checkpoint - up to 49 blocks of
progress gone, repeatedly, on every restart.
The shutdown save was queued, not written. onDisable() called saveCache(),
which uses saveObjectAsync(), and this addon is a Pladdon: the server disables
it before BentoBox, so the write landed in a queue that BentoBox had to drain
on its way out. BentoBox 3.22.0 added that drain (flushAll), but every earlier
version discarded it silently.
Write directly on shutdown instead, via a new saveCacheNow() using
saveObjectNow(). That removes the dependency on core behaviour entirely rather
than relying on a specific BentoBox version getting it right.
saveObjectNow() is BentoBox 3.22.0 API, so bump the dependency and raise
api-version to match. Without the api-version bump the addon would still load
on an older core and throw NoSuchMethodError at shutdown, which is worse than
the bug being fixed. It now refuses to load with "Please update BentoBox".
Also make the periodic save interval configurable as island.save-every,
defaulting to 10 rather than the hardcoded 50. Nothing helps if the server is
SIGKILLed, but this caps what an unclean kill can cost at 9 blocks.
Reported on Discord: progress reverting on every restart, BentoBox 3.15.0.
Test notes: the BentoBox bump broke 5 PhasesPanelTest tests, and fixing those
exposed 2 more. None were regressions - all 7 called
when(user.getTranslation(...)) on a real User rather than a mock, which stubs
nothing on the User and instead attaches to whichever mock the real method
last touched. 3.22.0's getTranslation(World, ...) calls getIWM().getAddon()
first, moving the target. Added a stubTranslation() helper that stubs the
LocalesManager these actually read from. The same pattern remains elsewhere in
that class and is worth a follow-up sweep.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
An admin coloured a phase hologram with <green><bold>...</green> and got white
text with the tags shown literally.
Holograms deserialized with LegacyComponentSerializer.legacyAmpersand(), which
understands the 16 legacy & codes and nothing else - Adventure builds that
instance with hexColours=false, so even &#RRGGBB did not work. The action bar
used a second, separately configured serializer that did support hex but not
MiniMessage. Two display paths, two different answers to "what formatting can
I use here", neither documented where anyone would look.
Both now go through Util.parseMiniMessageOrLegacy, which accepts MiniMessage,
& and section codes, hex, and any mixture, and is cached on the BentoBox side.
This also fixes section codes being rendered as literal text. Translations come
back from User.getTranslation already converted to section codes, so anything
locale-sourced was being handed to a serializer bound to '&' - the starting
hologram (aoneblock.island.starting-hologram) and the action bar both took that
path. Phase file hologram lines never see the translation layer, which is why
the reported case showed raw MiniMessage tags rather than raw section codes.
The boss bar title is untouched: it uses the String-based Bukkit BossBar API
and BentoBox has already resolved its formatting by then.
Existing configs are unaffected. BentoBox's MiniMessage instance is the
non-strict one, so text containing stray angle brackets is left as literal
text rather than throwing.
Documented the accepted syntax in the phase file, next to the holograms
section where the admin was already looking.
Util.parseMiniMessageOrLegacy is BentoBox 3.2.0 API, so this needs no
dependency bump.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
BentoBox 3.18.0 onwards is compiled for Java 25 (Minecraft 26.x), so its class
files are version 69. A JDK 21 javac cannot parse those at all, and the build
died with "class file has wrong version 69.0, should be 65.0" against every
BentoBox type before it reached any of our code.
This only surfaced once the dependency moved to 3.22.0. It did not show up
locally because the dev machine is already on JDK 25 - the compiler reads the
newer class files happily and <release>21</release> still emits Java 21
bytecode, which is what the addon ships.
The addon's own target is unchanged: still Java 21 via <release> in the pom.
Only the JDK doing the compiling moves.
Also moves setup-java to v4 and the 'adopt' distribution to 'temurin', since
neither v3 nor adopt offers a Java 25 build.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
fix: do not lose island progress when the server restarts
feat: support MiniMessage and hex colours in phase text
@sonarqubecloud

Copy link
Copy Markdown

@tastybento
tastybento merged commit 7339721 into masterAug 8, 2026
5 checks passed
Sign up for freeto 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.

1 participant

@tastybento
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Release 1.27.0 - #552

Merged
tastybento merged 10 commits into
masterfrom
develop
Aug 8, 2026
Merged

Release 1.27.0#552
tastybento merged 10 commits into
masterfrom
develop

Conversation

@tastybento

Copy link
Copy Markdown
Member

Release 1.27.0.

Headline

Island progress is no longer lost when the server restarts. Reported on Discord as "it's not saving the progress" — a player online through a restart came back with their block count rolled back to the last checkpoint, up to 49 blocks undone, every restart. The shutdown save was queued rather than written, and every BentoBox before 3.22.0 discarded that queue on the way out.

Also in this release: MiniMessage and hex colours in phase text (holograms, action bar, locale strings), a new island.save-every setting, and a rewritten reference phase file.

🔺 This release raises the minimum BentoBox version

bentobox.version and addon.ymlapi-version both move to 3.22.0, because the shutdown fix uses saveObjectNow() which was added there. Without the api-version bump the addon would load on an older core and throw NoSuchMethodError at shutdown — worse than the bug being fixed. It now refuses to load with "Please update BentoBox".

Knock-on effect for admins: BentoBox 3.18.0+ requires a Java 25 server, so 1.27.0 does too. This is called out prominently in the release notes.

What's in it

PRChange
#550🔺⚙️ Shutdown save writes directly; new island.save-every (default 10, was a hardcoded 50)
#551MiniMessage, hex and gradient support in phase text; fixes § codes rendering literally
#548Reference phase file now explains weights vs positions vs start block
#547CI: publish-platforms pin bumped to the multipart-JSON fix

Also on this branch: a CI fix moving the build to JDK 25. BentoBox 3.18.0+ ships Java 25 class files, which a JDK 21 javac cannot read at all — the build failed against every BentoBox type until the runner moved to 25. The addon still targets Java 21 via <release>.

Verification

  • Full suite green on develop.
  • Boot-tested on two real servers: BentoBox 3.15.1 refuses to load the addon with the intended message and no linkage error; BentoBox 3.22.1-SNAPSHOT enables, runs, and disables cleanly.
  • Not verified in-game: a real block count surviving a restart, and hologram rendering. Both are covered by unit tests through the real code paths, but neither was watched on a live server with a player.

Release notes for the draft release are prepared separately.

🤖 Generated with Claude Code

https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ

tastybentoand others added 10 commits July 29, 2026 09:00
The pinned SHA (ca2dcd16, 2026-07-03) predates BentoBoxWorld/.github#13,
which moved the CurseForge `metadata` and Hangar `versionUpload` JSON out of
inline `-F` values and into files. curl treats `;` in an inline -F value as
the start of a `type=`/`filename=` attribute, so a release body containing a
semicolon truncates the JSON: the 1.26.3 publish failed with CurseForge
"Error in field `metadata`: Invalid JSON" and Hangar "Failed to read request".
Earlier releases only passed because their notes happened to contain no
semicolons.
Pin moved to master HEAD 1f91a0e, which contains the fix.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SAQ3YQkcfRoCZEwa6SPJcp
ci: bump publish-platforms pin to the multipart-JSON fix
0_plains.yml is the reference file admins read first, but it never said
what the numbers after a Material or EntityType are. An admin asked, and
they were right to guess weighting: they are relative weights in a single
raffle - not counts and not percentages - and blocks, mobs and
custom-blocks all draw from that same pool, so a mob weight is directly
comparable to a block weight and pushes every block's share down.
The header now separates the three distinct kinds of number a phase file
contains, since that is the real source of the confusion:
1. blocks/mobs/custom-blocks values are weights, one shared pool
2. fixedBlocks and holograms keys are positions within the phase, from 0
3. the top-level key is the section name - phases_index.yml has owned
phase order and length since 1.26.0
Each section then gets its own explanation with the real Plains numbers
worked out (11450 block weights + 665 mob weights = 12115, so
GRASS_BLOCK: 2000 is 16.5% and COW: 150 is 1.2%), plus the CHEST
two-stage roll, the mob/custom-block types that were missing from the
list, and version gating.
Comments only - every block, mob and weight is unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017zwLryefnJ6wG76JmYNamx
docs: rewrite the phase 0 comments to explain what the numbers mean
A player breaking blocks and then sitting through a restart would come back
to their block count rolled back to the last checkpoint - up to 49 blocks of
progress gone, repeatedly, on every restart.
The shutdown save was queued, not written. onDisable() called saveCache(),
which uses saveObjectAsync(), and this addon is a Pladdon: the server disables
it before BentoBox, so the write landed in a queue that BentoBox had to drain
on its way out. BentoBox 3.22.0 added that drain (flushAll), but every earlier
version discarded it silently.
Write directly on shutdown instead, via a new saveCacheNow() using
saveObjectNow(). That removes the dependency on core behaviour entirely rather
than relying on a specific BentoBox version getting it right.
saveObjectNow() is BentoBox 3.22.0 API, so bump the dependency and raise
api-version to match. Without the api-version bump the addon would still load
on an older core and throw NoSuchMethodError at shutdown, which is worse than
the bug being fixed. It now refuses to load with "Please update BentoBox".
Also make the periodic save interval configurable as island.save-every,
defaulting to 10 rather than the hardcoded 50. Nothing helps if the server is
SIGKILLed, but this caps what an unclean kill can cost at 9 blocks.
Reported on Discord: progress reverting on every restart, BentoBox 3.15.0.
Test notes: the BentoBox bump broke 5 PhasesPanelTest tests, and fixing those
exposed 2 more. None were regressions - all 7 called
when(user.getTranslation(...)) on a real User rather than a mock, which stubs
nothing on the User and instead attaches to whichever mock the real method
last touched. 3.22.0's getTranslation(World, ...) calls getIWM().getAddon()
first, moving the target. Added a stubTranslation() helper that stubs the
LocalesManager these actually read from. The same pattern remains elsewhere in
that class and is worth a follow-up sweep.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
An admin coloured a phase hologram with <green><bold>...</green> and got white
text with the tags shown literally.
Holograms deserialized with LegacyComponentSerializer.legacyAmpersand(), which
understands the 16 legacy & codes and nothing else - Adventure builds that
instance with hexColours=false, so even &#RRGGBB did not work. The action bar
used a second, separately configured serializer that did support hex but not
MiniMessage. Two display paths, two different answers to "what formatting can
I use here", neither documented where anyone would look.
Both now go through Util.parseMiniMessageOrLegacy, which accepts MiniMessage,
& and section codes, hex, and any mixture, and is cached on the BentoBox side.
This also fixes section codes being rendered as literal text. Translations come
back from User.getTranslation already converted to section codes, so anything
locale-sourced was being handed to a serializer bound to '&' - the starting
hologram (aoneblock.island.starting-hologram) and the action bar both took that
path. Phase file hologram lines never see the translation layer, which is why
the reported case showed raw MiniMessage tags rather than raw section codes.
The boss bar title is untouched: it uses the String-based Bukkit BossBar API
and BentoBox has already resolved its formatting by then.
Existing configs are unaffected. BentoBox's MiniMessage instance is the
non-strict one, so text containing stray angle brackets is left as literal
text rather than throwing.
Documented the accepted syntax in the phase file, next to the holograms
section where the admin was already looking.
Util.parseMiniMessageOrLegacy is BentoBox 3.2.0 API, so this needs no
dependency bump.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
BentoBox 3.18.0 onwards is compiled for Java 25 (Minecraft 26.x), so its class
files are version 69. A JDK 21 javac cannot parse those at all, and the build
died with "class file has wrong version 69.0, should be 65.0" against every
BentoBox type before it reached any of our code.
This only surfaced once the dependency moved to 3.22.0. It did not show up
locally because the dev machine is already on JDK 25 - the compiler reads the
newer class files happily and <release>21</release> still emits Java 21
bytecode, which is what the addon ships.
The addon's own target is unchanged: still Java 21 via <release> in the pom.
Only the JDK doing the compiling moves.
Also moves setup-java to v4 and the 'adopt' distribution to 'temurin', since
neither v3 nor adopt offers a Java 25 build.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
fix: do not lose island progress when the server restarts
feat: support MiniMessage and hex colours in phase text
@sonarqubecloud

Copy link
Copy Markdown

@tastybento
tastybento merged commit 7339721 into masterAug 8, 2026
5 checks passed
Sign up for freeto 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.

1 participant

@tastybento
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Release 1.27.0 - #552

Merged
tastybento merged 10 commits into
masterfrom
develop
Aug 8, 2026
Merged

Release 1.27.0#552
tastybento merged 10 commits into
masterfrom
develop

Conversation

@tastybento

Copy link
Copy Markdown
Member

Release 1.27.0.

Headline

Island progress is no longer lost when the server restarts. Reported on Discord as "it's not saving the progress" — a player online through a restart came back with their block count rolled back to the last checkpoint, up to 49 blocks undone, every restart. The shutdown save was queued rather than written, and every BentoBox before 3.22.0 discarded that queue on the way out.

Also in this release: MiniMessage and hex colours in phase text (holograms, action bar, locale strings), a new island.save-every setting, and a rewritten reference phase file.

🔺 This release raises the minimum BentoBox version

bentobox.version and addon.ymlapi-version both move to 3.22.0, because the shutdown fix uses saveObjectNow() which was added there. Without the api-version bump the addon would load on an older core and throw NoSuchMethodError at shutdown — worse than the bug being fixed. It now refuses to load with "Please update BentoBox".

Knock-on effect for admins: BentoBox 3.18.0+ requires a Java 25 server, so 1.27.0 does too. This is called out prominently in the release notes.

What's in it

PRChange
#550🔺⚙️ Shutdown save writes directly; new island.save-every (default 10, was a hardcoded 50)
#551MiniMessage, hex and gradient support in phase text; fixes § codes rendering literally
#548Reference phase file now explains weights vs positions vs start block
#547CI: publish-platforms pin bumped to the multipart-JSON fix

Also on this branch: a CI fix moving the build to JDK 25. BentoBox 3.18.0+ ships Java 25 class files, which a JDK 21 javac cannot read at all — the build failed against every BentoBox type until the runner moved to 25. The addon still targets Java 21 via <release>.

Verification

  • Full suite green on develop.
  • Boot-tested on two real servers: BentoBox 3.15.1 refuses to load the addon with the intended message and no linkage error; BentoBox 3.22.1-SNAPSHOT enables, runs, and disables cleanly.
  • Not verified in-game: a real block count surviving a restart, and hologram rendering. Both are covered by unit tests through the real code paths, but neither was watched on a live server with a player.

Release notes for the draft release are prepared separately.

🤖 Generated with Claude Code

https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ

tastybentoand others added 10 commits July 29, 2026 09:00
The pinned SHA (ca2dcd16, 2026-07-03) predates BentoBoxWorld/.github#13,
which moved the CurseForge `metadata` and Hangar `versionUpload` JSON out of
inline `-F` values and into files. curl treats `;` in an inline -F value as
the start of a `type=`/`filename=` attribute, so a release body containing a
semicolon truncates the JSON: the 1.26.3 publish failed with CurseForge
"Error in field `metadata`: Invalid JSON" and Hangar "Failed to read request".
Earlier releases only passed because their notes happened to contain no
semicolons.
Pin moved to master HEAD 1f91a0e, which contains the fix.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SAQ3YQkcfRoCZEwa6SPJcp
ci: bump publish-platforms pin to the multipart-JSON fix
0_plains.yml is the reference file admins read first, but it never said
what the numbers after a Material or EntityType are. An admin asked, and
they were right to guess weighting: they are relative weights in a single
raffle - not counts and not percentages - and blocks, mobs and
custom-blocks all draw from that same pool, so a mob weight is directly
comparable to a block weight and pushes every block's share down.
The header now separates the three distinct kinds of number a phase file
contains, since that is the real source of the confusion:
1. blocks/mobs/custom-blocks values are weights, one shared pool
2. fixedBlocks and holograms keys are positions within the phase, from 0
3. the top-level key is the section name - phases_index.yml has owned
phase order and length since 1.26.0
Each section then gets its own explanation with the real Plains numbers
worked out (11450 block weights + 665 mob weights = 12115, so
GRASS_BLOCK: 2000 is 16.5% and COW: 150 is 1.2%), plus the CHEST
two-stage roll, the mob/custom-block types that were missing from the
list, and version gating.
Comments only - every block, mob and weight is unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017zwLryefnJ6wG76JmYNamx
docs: rewrite the phase 0 comments to explain what the numbers mean
A player breaking blocks and then sitting through a restart would come back
to their block count rolled back to the last checkpoint - up to 49 blocks of
progress gone, repeatedly, on every restart.
The shutdown save was queued, not written. onDisable() called saveCache(),
which uses saveObjectAsync(), and this addon is a Pladdon: the server disables
it before BentoBox, so the write landed in a queue that BentoBox had to drain
on its way out. BentoBox 3.22.0 added that drain (flushAll), but every earlier
version discarded it silently.
Write directly on shutdown instead, via a new saveCacheNow() using
saveObjectNow(). That removes the dependency on core behaviour entirely rather
than relying on a specific BentoBox version getting it right.
saveObjectNow() is BentoBox 3.22.0 API, so bump the dependency and raise
api-version to match. Without the api-version bump the addon would still load
on an older core and throw NoSuchMethodError at shutdown, which is worse than
the bug being fixed. It now refuses to load with "Please update BentoBox".
Also make the periodic save interval configurable as island.save-every,
defaulting to 10 rather than the hardcoded 50. Nothing helps if the server is
SIGKILLed, but this caps what an unclean kill can cost at 9 blocks.
Reported on Discord: progress reverting on every restart, BentoBox 3.15.0.
Test notes: the BentoBox bump broke 5 PhasesPanelTest tests, and fixing those
exposed 2 more. None were regressions - all 7 called
when(user.getTranslation(...)) on a real User rather than a mock, which stubs
nothing on the User and instead attaches to whichever mock the real method
last touched. 3.22.0's getTranslation(World, ...) calls getIWM().getAddon()
first, moving the target. Added a stubTranslation() helper that stubs the
LocalesManager these actually read from. The same pattern remains elsewhere in
that class and is worth a follow-up sweep.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
An admin coloured a phase hologram with <green><bold>...</green> and got white
text with the tags shown literally.
Holograms deserialized with LegacyComponentSerializer.legacyAmpersand(), which
understands the 16 legacy & codes and nothing else - Adventure builds that
instance with hexColours=false, so even &#RRGGBB did not work. The action bar
used a second, separately configured serializer that did support hex but not
MiniMessage. Two display paths, two different answers to "what formatting can
I use here", neither documented where anyone would look.
Both now go through Util.parseMiniMessageOrLegacy, which accepts MiniMessage,
& and section codes, hex, and any mixture, and is cached on the BentoBox side.
This also fixes section codes being rendered as literal text. Translations come
back from User.getTranslation already converted to section codes, so anything
locale-sourced was being handed to a serializer bound to '&' - the starting
hologram (aoneblock.island.starting-hologram) and the action bar both took that
path. Phase file hologram lines never see the translation layer, which is why
the reported case showed raw MiniMessage tags rather than raw section codes.
The boss bar title is untouched: it uses the String-based Bukkit BossBar API
and BentoBox has already resolved its formatting by then.
Existing configs are unaffected. BentoBox's MiniMessage instance is the
non-strict one, so text containing stray angle brackets is left as literal
text rather than throwing.
Documented the accepted syntax in the phase file, next to the holograms
section where the admin was already looking.
Util.parseMiniMessageOrLegacy is BentoBox 3.2.0 API, so this needs no
dependency bump.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
BentoBox 3.18.0 onwards is compiled for Java 25 (Minecraft 26.x), so its class
files are version 69. A JDK 21 javac cannot parse those at all, and the build
died with "class file has wrong version 69.0, should be 65.0" against every
BentoBox type before it reached any of our code.
This only surfaced once the dependency moved to 3.22.0. It did not show up
locally because the dev machine is already on JDK 25 - the compiler reads the
newer class files happily and <release>21</release> still emits Java 21
bytecode, which is what the addon ships.
The addon's own target is unchanged: still Java 21 via <release> in the pom.
Only the JDK doing the compiling moves.
Also moves setup-java to v4 and the 'adopt' distribution to 'temurin', since
neither v3 nor adopt offers a Java 25 build.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
fix: do not lose island progress when the server restarts
feat: support MiniMessage and hex colours in phase text
@sonarqubecloud

Copy link
Copy Markdown

@tastybento
tastybento merged commit 7339721 into masterAug 8, 2026
5 checks passed
Sign up for freeto 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.

1 participant

@tastybento
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Release 1.27.0 - #552

Merged
tastybento merged 10 commits into
masterfrom
develop
Aug 8, 2026
Merged

Release 1.27.0#552
tastybento merged 10 commits into
masterfrom
develop

Conversation

@tastybento

Copy link
Copy Markdown
Member

Release 1.27.0.

Headline

Island progress is no longer lost when the server restarts. Reported on Discord as "it's not saving the progress" — a player online through a restart came back with their block count rolled back to the last checkpoint, up to 49 blocks undone, every restart. The shutdown save was queued rather than written, and every BentoBox before 3.22.0 discarded that queue on the way out.

Also in this release: MiniMessage and hex colours in phase text (holograms, action bar, locale strings), a new island.save-every setting, and a rewritten reference phase file.

🔺 This release raises the minimum BentoBox version

bentobox.version and addon.ymlapi-version both move to 3.22.0, because the shutdown fix uses saveObjectNow() which was added there. Without the api-version bump the addon would load on an older core and throw NoSuchMethodError at shutdown — worse than the bug being fixed. It now refuses to load with "Please update BentoBox".

Knock-on effect for admins: BentoBox 3.18.0+ requires a Java 25 server, so 1.27.0 does too. This is called out prominently in the release notes.

What's in it

PRChange
#550🔺⚙️ Shutdown save writes directly; new island.save-every (default 10, was a hardcoded 50)
#551MiniMessage, hex and gradient support in phase text; fixes § codes rendering literally
#548Reference phase file now explains weights vs positions vs start block
#547CI: publish-platforms pin bumped to the multipart-JSON fix

Also on this branch: a CI fix moving the build to JDK 25. BentoBox 3.18.0+ ships Java 25 class files, which a JDK 21 javac cannot read at all — the build failed against every BentoBox type until the runner moved to 25. The addon still targets Java 21 via <release>.

Verification

  • Full suite green on develop.
  • Boot-tested on two real servers: BentoBox 3.15.1 refuses to load the addon with the intended message and no linkage error; BentoBox 3.22.1-SNAPSHOT enables, runs, and disables cleanly.
  • Not verified in-game: a real block count surviving a restart, and hologram rendering. Both are covered by unit tests through the real code paths, but neither was watched on a live server with a player.

Release notes for the draft release are prepared separately.

🤖 Generated with Claude Code

https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ

tastybentoand others added 10 commits July 29, 2026 09:00
The pinned SHA (ca2dcd16, 2026-07-03) predates BentoBoxWorld/.github#13,
which moved the CurseForge `metadata` and Hangar `versionUpload` JSON out of
inline `-F` values and into files. curl treats `;` in an inline -F value as
the start of a `type=`/`filename=` attribute, so a release body containing a
semicolon truncates the JSON: the 1.26.3 publish failed with CurseForge
"Error in field `metadata`: Invalid JSON" and Hangar "Failed to read request".
Earlier releases only passed because their notes happened to contain no
semicolons.
Pin moved to master HEAD 1f91a0e, which contains the fix.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SAQ3YQkcfRoCZEwa6SPJcp
ci: bump publish-platforms pin to the multipart-JSON fix
0_plains.yml is the reference file admins read first, but it never said
what the numbers after a Material or EntityType are. An admin asked, and
they were right to guess weighting: they are relative weights in a single
raffle - not counts and not percentages - and blocks, mobs and
custom-blocks all draw from that same pool, so a mob weight is directly
comparable to a block weight and pushes every block's share down.
The header now separates the three distinct kinds of number a phase file
contains, since that is the real source of the confusion:
1. blocks/mobs/custom-blocks values are weights, one shared pool
2. fixedBlocks and holograms keys are positions within the phase, from 0
3. the top-level key is the section name - phases_index.yml has owned
phase order and length since 1.26.0
Each section then gets its own explanation with the real Plains numbers
worked out (11450 block weights + 665 mob weights = 12115, so
GRASS_BLOCK: 2000 is 16.5% and COW: 150 is 1.2%), plus the CHEST
two-stage roll, the mob/custom-block types that were missing from the
list, and version gating.
Comments only - every block, mob and weight is unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017zwLryefnJ6wG76JmYNamx
docs: rewrite the phase 0 comments to explain what the numbers mean
A player breaking blocks and then sitting through a restart would come back
to their block count rolled back to the last checkpoint - up to 49 blocks of
progress gone, repeatedly, on every restart.
The shutdown save was queued, not written. onDisable() called saveCache(),
which uses saveObjectAsync(), and this addon is a Pladdon: the server disables
it before BentoBox, so the write landed in a queue that BentoBox had to drain
on its way out. BentoBox 3.22.0 added that drain (flushAll), but every earlier
version discarded it silently.
Write directly on shutdown instead, via a new saveCacheNow() using
saveObjectNow(). That removes the dependency on core behaviour entirely rather
than relying on a specific BentoBox version getting it right.
saveObjectNow() is BentoBox 3.22.0 API, so bump the dependency and raise
api-version to match. Without the api-version bump the addon would still load
on an older core and throw NoSuchMethodError at shutdown, which is worse than
the bug being fixed. It now refuses to load with "Please update BentoBox".
Also make the periodic save interval configurable as island.save-every,
defaulting to 10 rather than the hardcoded 50. Nothing helps if the server is
SIGKILLed, but this caps what an unclean kill can cost at 9 blocks.
Reported on Discord: progress reverting on every restart, BentoBox 3.15.0.
Test notes: the BentoBox bump broke 5 PhasesPanelTest tests, and fixing those
exposed 2 more. None were regressions - all 7 called
when(user.getTranslation(...)) on a real User rather than a mock, which stubs
nothing on the User and instead attaches to whichever mock the real method
last touched. 3.22.0's getTranslation(World, ...) calls getIWM().getAddon()
first, moving the target. Added a stubTranslation() helper that stubs the
LocalesManager these actually read from. The same pattern remains elsewhere in
that class and is worth a follow-up sweep.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
An admin coloured a phase hologram with <green><bold>...</green> and got white
text with the tags shown literally.
Holograms deserialized with LegacyComponentSerializer.legacyAmpersand(), which
understands the 16 legacy & codes and nothing else - Adventure builds that
instance with hexColours=false, so even &#RRGGBB did not work. The action bar
used a second, separately configured serializer that did support hex but not
MiniMessage. Two display paths, two different answers to "what formatting can
I use here", neither documented where anyone would look.
Both now go through Util.parseMiniMessageOrLegacy, which accepts MiniMessage,
& and section codes, hex, and any mixture, and is cached on the BentoBox side.
This also fixes section codes being rendered as literal text. Translations come
back from User.getTranslation already converted to section codes, so anything
locale-sourced was being handed to a serializer bound to '&' - the starting
hologram (aoneblock.island.starting-hologram) and the action bar both took that
path. Phase file hologram lines never see the translation layer, which is why
the reported case showed raw MiniMessage tags rather than raw section codes.
The boss bar title is untouched: it uses the String-based Bukkit BossBar API
and BentoBox has already resolved its formatting by then.
Existing configs are unaffected. BentoBox's MiniMessage instance is the
non-strict one, so text containing stray angle brackets is left as literal
text rather than throwing.
Documented the accepted syntax in the phase file, next to the holograms
section where the admin was already looking.
Util.parseMiniMessageOrLegacy is BentoBox 3.2.0 API, so this needs no
dependency bump.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
BentoBox 3.18.0 onwards is compiled for Java 25 (Minecraft 26.x), so its class
files are version 69. A JDK 21 javac cannot parse those at all, and the build
died with "class file has wrong version 69.0, should be 65.0" against every
BentoBox type before it reached any of our code.
This only surfaced once the dependency moved to 3.22.0. It did not show up
locally because the dev machine is already on JDK 25 - the compiler reads the
newer class files happily and <release>21</release> still emits Java 21
bytecode, which is what the addon ships.
The addon's own target is unchanged: still Java 21 via <release> in the pom.
Only the JDK doing the compiling moves.
Also moves setup-java to v4 and the 'adopt' distribution to 'temurin', since
neither v3 nor adopt offers a Java 25 build.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
fix: do not lose island progress when the server restarts
feat: support MiniMessage and hex colours in phase text
@sonarqubecloud

Copy link
Copy Markdown

@tastybento
tastybento merged commit 7339721 into masterAug 8, 2026
5 checks passed
Sign up for freeto 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.

1 participant

@tastybento
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Release 1.27.0 - #552

Merged
tastybento merged 10 commits into
masterfrom
develop
Aug 8, 2026
Merged

Release 1.27.0#552
tastybento merged 10 commits into
masterfrom
develop

Conversation

@tastybento

Copy link
Copy Markdown
Member

Release 1.27.0.

Headline

Island progress is no longer lost when the server restarts. Reported on Discord as "it's not saving the progress" — a player online through a restart came back with their block count rolled back to the last checkpoint, up to 49 blocks undone, every restart. The shutdown save was queued rather than written, and every BentoBox before 3.22.0 discarded that queue on the way out.

Also in this release: MiniMessage and hex colours in phase text (holograms, action bar, locale strings), a new island.save-every setting, and a rewritten reference phase file.

🔺 This release raises the minimum BentoBox version

bentobox.version and addon.ymlapi-version both move to 3.22.0, because the shutdown fix uses saveObjectNow() which was added there. Without the api-version bump the addon would load on an older core and throw NoSuchMethodError at shutdown — worse than the bug being fixed. It now refuses to load with "Please update BentoBox".

Knock-on effect for admins: BentoBox 3.18.0+ requires a Java 25 server, so 1.27.0 does too. This is called out prominently in the release notes.

What's in it

PRChange
#550🔺⚙️ Shutdown save writes directly; new island.save-every (default 10, was a hardcoded 50)
#551MiniMessage, hex and gradient support in phase text; fixes § codes rendering literally
#548Reference phase file now explains weights vs positions vs start block
#547CI: publish-platforms pin bumped to the multipart-JSON fix

Also on this branch: a CI fix moving the build to JDK 25. BentoBox 3.18.0+ ships Java 25 class files, which a JDK 21 javac cannot read at all — the build failed against every BentoBox type until the runner moved to 25. The addon still targets Java 21 via <release>.

Verification

  • Full suite green on develop.
  • Boot-tested on two real servers: BentoBox 3.15.1 refuses to load the addon with the intended message and no linkage error; BentoBox 3.22.1-SNAPSHOT enables, runs, and disables cleanly.
  • Not verified in-game: a real block count surviving a restart, and hologram rendering. Both are covered by unit tests through the real code paths, but neither was watched on a live server with a player.

Release notes for the draft release are prepared separately.

🤖 Generated with Claude Code

https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ

tastybentoand others added 10 commits July 29, 2026 09:00
The pinned SHA (ca2dcd16, 2026-07-03) predates BentoBoxWorld/.github#13,
which moved the CurseForge `metadata` and Hangar `versionUpload` JSON out of
inline `-F` values and into files. curl treats `;` in an inline -F value as
the start of a `type=`/`filename=` attribute, so a release body containing a
semicolon truncates the JSON: the 1.26.3 publish failed with CurseForge
"Error in field `metadata`: Invalid JSON" and Hangar "Failed to read request".
Earlier releases only passed because their notes happened to contain no
semicolons.
Pin moved to master HEAD 1f91a0e, which contains the fix.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SAQ3YQkcfRoCZEwa6SPJcp
ci: bump publish-platforms pin to the multipart-JSON fix
0_plains.yml is the reference file admins read first, but it never said
what the numbers after a Material or EntityType are. An admin asked, and
they were right to guess weighting: they are relative weights in a single
raffle - not counts and not percentages - and blocks, mobs and
custom-blocks all draw from that same pool, so a mob weight is directly
comparable to a block weight and pushes every block's share down.
The header now separates the three distinct kinds of number a phase file
contains, since that is the real source of the confusion:
1. blocks/mobs/custom-blocks values are weights, one shared pool
2. fixedBlocks and holograms keys are positions within the phase, from 0
3. the top-level key is the section name - phases_index.yml has owned
phase order and length since 1.26.0
Each section then gets its own explanation with the real Plains numbers
worked out (11450 block weights + 665 mob weights = 12115, so
GRASS_BLOCK: 2000 is 16.5% and COW: 150 is 1.2%), plus the CHEST
two-stage roll, the mob/custom-block types that were missing from the
list, and version gating.
Comments only - every block, mob and weight is unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017zwLryefnJ6wG76JmYNamx
docs: rewrite the phase 0 comments to explain what the numbers mean
A player breaking blocks and then sitting through a restart would come back
to their block count rolled back to the last checkpoint - up to 49 blocks of
progress gone, repeatedly, on every restart.
The shutdown save was queued, not written. onDisable() called saveCache(),
which uses saveObjectAsync(), and this addon is a Pladdon: the server disables
it before BentoBox, so the write landed in a queue that BentoBox had to drain
on its way out. BentoBox 3.22.0 added that drain (flushAll), but every earlier
version discarded it silently.
Write directly on shutdown instead, via a new saveCacheNow() using
saveObjectNow(). That removes the dependency on core behaviour entirely rather
than relying on a specific BentoBox version getting it right.
saveObjectNow() is BentoBox 3.22.0 API, so bump the dependency and raise
api-version to match. Without the api-version bump the addon would still load
on an older core and throw NoSuchMethodError at shutdown, which is worse than
the bug being fixed. It now refuses to load with "Please update BentoBox".
Also make the periodic save interval configurable as island.save-every,
defaulting to 10 rather than the hardcoded 50. Nothing helps if the server is
SIGKILLed, but this caps what an unclean kill can cost at 9 blocks.
Reported on Discord: progress reverting on every restart, BentoBox 3.15.0.
Test notes: the BentoBox bump broke 5 PhasesPanelTest tests, and fixing those
exposed 2 more. None were regressions - all 7 called
when(user.getTranslation(...)) on a real User rather than a mock, which stubs
nothing on the User and instead attaches to whichever mock the real method
last touched. 3.22.0's getTranslation(World, ...) calls getIWM().getAddon()
first, moving the target. Added a stubTranslation() helper that stubs the
LocalesManager these actually read from. The same pattern remains elsewhere in
that class and is worth a follow-up sweep.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
An admin coloured a phase hologram with <green><bold>...</green> and got white
text with the tags shown literally.
Holograms deserialized with LegacyComponentSerializer.legacyAmpersand(), which
understands the 16 legacy & codes and nothing else - Adventure builds that
instance with hexColours=false, so even &#RRGGBB did not work. The action bar
used a second, separately configured serializer that did support hex but not
MiniMessage. Two display paths, two different answers to "what formatting can
I use here", neither documented where anyone would look.
Both now go through Util.parseMiniMessageOrLegacy, which accepts MiniMessage,
& and section codes, hex, and any mixture, and is cached on the BentoBox side.
This also fixes section codes being rendered as literal text. Translations come
back from User.getTranslation already converted to section codes, so anything
locale-sourced was being handed to a serializer bound to '&' - the starting
hologram (aoneblock.island.starting-hologram) and the action bar both took that
path. Phase file hologram lines never see the translation layer, which is why
the reported case showed raw MiniMessage tags rather than raw section codes.
The boss bar title is untouched: it uses the String-based Bukkit BossBar API
and BentoBox has already resolved its formatting by then.
Existing configs are unaffected. BentoBox's MiniMessage instance is the
non-strict one, so text containing stray angle brackets is left as literal
text rather than throwing.
Documented the accepted syntax in the phase file, next to the holograms
section where the admin was already looking.
Util.parseMiniMessageOrLegacy is BentoBox 3.2.0 API, so this needs no
dependency bump.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
BentoBox 3.18.0 onwards is compiled for Java 25 (Minecraft 26.x), so its class
files are version 69. A JDK 21 javac cannot parse those at all, and the build
died with "class file has wrong version 69.0, should be 65.0" against every
BentoBox type before it reached any of our code.
This only surfaced once the dependency moved to 3.22.0. It did not show up
locally because the dev machine is already on JDK 25 - the compiler reads the
newer class files happily and <release>21</release> still emits Java 21
bytecode, which is what the addon ships.
The addon's own target is unchanged: still Java 21 via <release> in the pom.
Only the JDK doing the compiling moves.
Also moves setup-java to v4 and the 'adopt' distribution to 'temurin', since
neither v3 nor adopt offers a Java 25 build.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
fix: do not lose island progress when the server restarts
feat: support MiniMessage and hex colours in phase text
@sonarqubecloud

Copy link
Copy Markdown

@tastybento
tastybento merged commit 7339721 into masterAug 8, 2026
5 checks passed
Sign up for freeto 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.

1 participant

@tastybento
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Release 1.27.0 - #552

Merged
tastybento merged 10 commits into
masterfrom
develop
Aug 8, 2026
Merged

Release 1.27.0#552
tastybento merged 10 commits into
masterfrom
develop

Conversation

@tastybento

Copy link
Copy Markdown
Member

Release 1.27.0.

Headline

Island progress is no longer lost when the server restarts. Reported on Discord as "it's not saving the progress" — a player online through a restart came back with their block count rolled back to the last checkpoint, up to 49 blocks undone, every restart. The shutdown save was queued rather than written, and every BentoBox before 3.22.0 discarded that queue on the way out.

Also in this release: MiniMessage and hex colours in phase text (holograms, action bar, locale strings), a new island.save-every setting, and a rewritten reference phase file.

🔺 This release raises the minimum BentoBox version

bentobox.version and addon.ymlapi-version both move to 3.22.0, because the shutdown fix uses saveObjectNow() which was added there. Without the api-version bump the addon would load on an older core and throw NoSuchMethodError at shutdown — worse than the bug being fixed. It now refuses to load with "Please update BentoBox".

Knock-on effect for admins: BentoBox 3.18.0+ requires a Java 25 server, so 1.27.0 does too. This is called out prominently in the release notes.

What's in it

PRChange
#550🔺⚙️ Shutdown save writes directly; new island.save-every (default 10, was a hardcoded 50)
#551MiniMessage, hex and gradient support in phase text; fixes § codes rendering literally
#548Reference phase file now explains weights vs positions vs start block
#547CI: publish-platforms pin bumped to the multipart-JSON fix

Also on this branch: a CI fix moving the build to JDK 25. BentoBox 3.18.0+ ships Java 25 class files, which a JDK 21 javac cannot read at all — the build failed against every BentoBox type until the runner moved to 25. The addon still targets Java 21 via <release>.

Verification

  • Full suite green on develop.
  • Boot-tested on two real servers: BentoBox 3.15.1 refuses to load the addon with the intended message and no linkage error; BentoBox 3.22.1-SNAPSHOT enables, runs, and disables cleanly.
  • Not verified in-game: a real block count surviving a restart, and hologram rendering. Both are covered by unit tests through the real code paths, but neither was watched on a live server with a player.

Release notes for the draft release are prepared separately.

🤖 Generated with Claude Code

https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ

tastybentoand others added 10 commits July 29, 2026 09:00
The pinned SHA (ca2dcd16, 2026-07-03) predates BentoBoxWorld/.github#13,
which moved the CurseForge `metadata` and Hangar `versionUpload` JSON out of
inline `-F` values and into files. curl treats `;` in an inline -F value as
the start of a `type=`/`filename=` attribute, so a release body containing a
semicolon truncates the JSON: the 1.26.3 publish failed with CurseForge
"Error in field `metadata`: Invalid JSON" and Hangar "Failed to read request".
Earlier releases only passed because their notes happened to contain no
semicolons.
Pin moved to master HEAD 1f91a0e, which contains the fix.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SAQ3YQkcfRoCZEwa6SPJcp
ci: bump publish-platforms pin to the multipart-JSON fix
0_plains.yml is the reference file admins read first, but it never said
what the numbers after a Material or EntityType are. An admin asked, and
they were right to guess weighting: they are relative weights in a single
raffle - not counts and not percentages - and blocks, mobs and
custom-blocks all draw from that same pool, so a mob weight is directly
comparable to a block weight and pushes every block's share down.
The header now separates the three distinct kinds of number a phase file
contains, since that is the real source of the confusion:
1. blocks/mobs/custom-blocks values are weights, one shared pool
2. fixedBlocks and holograms keys are positions within the phase, from 0
3. the top-level key is the section name - phases_index.yml has owned
phase order and length since 1.26.0
Each section then gets its own explanation with the real Plains numbers
worked out (11450 block weights + 665 mob weights = 12115, so
GRASS_BLOCK: 2000 is 16.5% and COW: 150 is 1.2%), plus the CHEST
two-stage roll, the mob/custom-block types that were missing from the
list, and version gating.
Comments only - every block, mob and weight is unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017zwLryefnJ6wG76JmYNamx
docs: rewrite the phase 0 comments to explain what the numbers mean
A player breaking blocks and then sitting through a restart would come back
to their block count rolled back to the last checkpoint - up to 49 blocks of
progress gone, repeatedly, on every restart.
The shutdown save was queued, not written. onDisable() called saveCache(),
which uses saveObjectAsync(), and this addon is a Pladdon: the server disables
it before BentoBox, so the write landed in a queue that BentoBox had to drain
on its way out. BentoBox 3.22.0 added that drain (flushAll), but every earlier
version discarded it silently.
Write directly on shutdown instead, via a new saveCacheNow() using
saveObjectNow(). That removes the dependency on core behaviour entirely rather
than relying on a specific BentoBox version getting it right.
saveObjectNow() is BentoBox 3.22.0 API, so bump the dependency and raise
api-version to match. Without the api-version bump the addon would still load
on an older core and throw NoSuchMethodError at shutdown, which is worse than
the bug being fixed. It now refuses to load with "Please update BentoBox".
Also make the periodic save interval configurable as island.save-every,
defaulting to 10 rather than the hardcoded 50. Nothing helps if the server is
SIGKILLed, but this caps what an unclean kill can cost at 9 blocks.
Reported on Discord: progress reverting on every restart, BentoBox 3.15.0.
Test notes: the BentoBox bump broke 5 PhasesPanelTest tests, and fixing those
exposed 2 more. None were regressions - all 7 called
when(user.getTranslation(...)) on a real User rather than a mock, which stubs
nothing on the User and instead attaches to whichever mock the real method
last touched. 3.22.0's getTranslation(World, ...) calls getIWM().getAddon()
first, moving the target. Added a stubTranslation() helper that stubs the
LocalesManager these actually read from. The same pattern remains elsewhere in
that class and is worth a follow-up sweep.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
An admin coloured a phase hologram with <green><bold>...</green> and got white
text with the tags shown literally.
Holograms deserialized with LegacyComponentSerializer.legacyAmpersand(), which
understands the 16 legacy & codes and nothing else - Adventure builds that
instance with hexColours=false, so even &#RRGGBB did not work. The action bar
used a second, separately configured serializer that did support hex but not
MiniMessage. Two display paths, two different answers to "what formatting can
I use here", neither documented where anyone would look.
Both now go through Util.parseMiniMessageOrLegacy, which accepts MiniMessage,
& and section codes, hex, and any mixture, and is cached on the BentoBox side.
This also fixes section codes being rendered as literal text. Translations come
back from User.getTranslation already converted to section codes, so anything
locale-sourced was being handed to a serializer bound to '&' - the starting
hologram (aoneblock.island.starting-hologram) and the action bar both took that
path. Phase file hologram lines never see the translation layer, which is why
the reported case showed raw MiniMessage tags rather than raw section codes.
The boss bar title is untouched: it uses the String-based Bukkit BossBar API
and BentoBox has already resolved its formatting by then.
Existing configs are unaffected. BentoBox's MiniMessage instance is the
non-strict one, so text containing stray angle brackets is left as literal
text rather than throwing.
Documented the accepted syntax in the phase file, next to the holograms
section where the admin was already looking.
Util.parseMiniMessageOrLegacy is BentoBox 3.2.0 API, so this needs no
dependency bump.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
BentoBox 3.18.0 onwards is compiled for Java 25 (Minecraft 26.x), so its class
files are version 69. A JDK 21 javac cannot parse those at all, and the build
died with "class file has wrong version 69.0, should be 65.0" against every
BentoBox type before it reached any of our code.
This only surfaced once the dependency moved to 3.22.0. It did not show up
locally because the dev machine is already on JDK 25 - the compiler reads the
newer class files happily and <release>21</release> still emits Java 21
bytecode, which is what the addon ships.
The addon's own target is unchanged: still Java 21 via <release> in the pom.
Only the JDK doing the compiling moves.
Also moves setup-java to v4 and the 'adopt' distribution to 'temurin', since
neither v3 nor adopt offers a Java 25 build.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
fix: do not lose island progress when the server restarts
feat: support MiniMessage and hex colours in phase text
@sonarqubecloud

Copy link
Copy Markdown

@tastybento
tastybento merged commit 7339721 into masterAug 8, 2026
5 checks passed
Sign up for freeto 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.

1 participant

@tastybento
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Release 1.27.0 - #552

Merged
tastybento merged 10 commits into
masterfrom
develop
Aug 8, 2026
Merged

Release 1.27.0#552
tastybento merged 10 commits into
masterfrom
develop

Conversation

@tastybento

Copy link
Copy Markdown
Member

Release 1.27.0.

Headline

Island progress is no longer lost when the server restarts. Reported on Discord as "it's not saving the progress" — a player online through a restart came back with their block count rolled back to the last checkpoint, up to 49 blocks undone, every restart. The shutdown save was queued rather than written, and every BentoBox before 3.22.0 discarded that queue on the way out.

Also in this release: MiniMessage and hex colours in phase text (holograms, action bar, locale strings), a new island.save-every setting, and a rewritten reference phase file.

🔺 This release raises the minimum BentoBox version

bentobox.version and addon.ymlapi-version both move to 3.22.0, because the shutdown fix uses saveObjectNow() which was added there. Without the api-version bump the addon would load on an older core and throw NoSuchMethodError at shutdown — worse than the bug being fixed. It now refuses to load with "Please update BentoBox".

Knock-on effect for admins: BentoBox 3.18.0+ requires a Java 25 server, so 1.27.0 does too. This is called out prominently in the release notes.

What's in it

PRChange
#550🔺⚙️ Shutdown save writes directly; new island.save-every (default 10, was a hardcoded 50)
#551MiniMessage, hex and gradient support in phase text; fixes § codes rendering literally
#548Reference phase file now explains weights vs positions vs start block
#547CI: publish-platforms pin bumped to the multipart-JSON fix

Also on this branch: a CI fix moving the build to JDK 25. BentoBox 3.18.0+ ships Java 25 class files, which a JDK 21 javac cannot read at all — the build failed against every BentoBox type until the runner moved to 25. The addon still targets Java 21 via <release>.

Verification

  • Full suite green on develop.
  • Boot-tested on two real servers: BentoBox 3.15.1 refuses to load the addon with the intended message and no linkage error; BentoBox 3.22.1-SNAPSHOT enables, runs, and disables cleanly.
  • Not verified in-game: a real block count surviving a restart, and hologram rendering. Both are covered by unit tests through the real code paths, but neither was watched on a live server with a player.

Release notes for the draft release are prepared separately.

🤖 Generated with Claude Code

https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ

tastybentoand others added 10 commits July 29, 2026 09:00
The pinned SHA (ca2dcd16, 2026-07-03) predates BentoBoxWorld/.github#13,
which moved the CurseForge `metadata` and Hangar `versionUpload` JSON out of
inline `-F` values and into files. curl treats `;` in an inline -F value as
the start of a `type=`/`filename=` attribute, so a release body containing a
semicolon truncates the JSON: the 1.26.3 publish failed with CurseForge
"Error in field `metadata`: Invalid JSON" and Hangar "Failed to read request".
Earlier releases only passed because their notes happened to contain no
semicolons.
Pin moved to master HEAD 1f91a0e, which contains the fix.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SAQ3YQkcfRoCZEwa6SPJcp
ci: bump publish-platforms pin to the multipart-JSON fix
0_plains.yml is the reference file admins read first, but it never said
what the numbers after a Material or EntityType are. An admin asked, and
they were right to guess weighting: they are relative weights in a single
raffle - not counts and not percentages - and blocks, mobs and
custom-blocks all draw from that same pool, so a mob weight is directly
comparable to a block weight and pushes every block's share down.
The header now separates the three distinct kinds of number a phase file
contains, since that is the real source of the confusion:
1. blocks/mobs/custom-blocks values are weights, one shared pool
2. fixedBlocks and holograms keys are positions within the phase, from 0
3. the top-level key is the section name - phases_index.yml has owned
phase order and length since 1.26.0
Each section then gets its own explanation with the real Plains numbers
worked out (11450 block weights + 665 mob weights = 12115, so
GRASS_BLOCK: 2000 is 16.5% and COW: 150 is 1.2%), plus the CHEST
two-stage roll, the mob/custom-block types that were missing from the
list, and version gating.
Comments only - every block, mob and weight is unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017zwLryefnJ6wG76JmYNamx
docs: rewrite the phase 0 comments to explain what the numbers mean
A player breaking blocks and then sitting through a restart would come back
to their block count rolled back to the last checkpoint - up to 49 blocks of
progress gone, repeatedly, on every restart.
The shutdown save was queued, not written. onDisable() called saveCache(),
which uses saveObjectAsync(), and this addon is a Pladdon: the server disables
it before BentoBox, so the write landed in a queue that BentoBox had to drain
on its way out. BentoBox 3.22.0 added that drain (flushAll), but every earlier
version discarded it silently.
Write directly on shutdown instead, via a new saveCacheNow() using
saveObjectNow(). That removes the dependency on core behaviour entirely rather
than relying on a specific BentoBox version getting it right.
saveObjectNow() is BentoBox 3.22.0 API, so bump the dependency and raise
api-version to match. Without the api-version bump the addon would still load
on an older core and throw NoSuchMethodError at shutdown, which is worse than
the bug being fixed. It now refuses to load with "Please update BentoBox".
Also make the periodic save interval configurable as island.save-every,
defaulting to 10 rather than the hardcoded 50. Nothing helps if the server is
SIGKILLed, but this caps what an unclean kill can cost at 9 blocks.
Reported on Discord: progress reverting on every restart, BentoBox 3.15.0.
Test notes: the BentoBox bump broke 5 PhasesPanelTest tests, and fixing those
exposed 2 more. None were regressions - all 7 called
when(user.getTranslation(...)) on a real User rather than a mock, which stubs
nothing on the User and instead attaches to whichever mock the real method
last touched. 3.22.0's getTranslation(World, ...) calls getIWM().getAddon()
first, moving the target. Added a stubTranslation() helper that stubs the
LocalesManager these actually read from. The same pattern remains elsewhere in
that class and is worth a follow-up sweep.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
An admin coloured a phase hologram with <green><bold>...</green> and got white
text with the tags shown literally.
Holograms deserialized with LegacyComponentSerializer.legacyAmpersand(), which
understands the 16 legacy & codes and nothing else - Adventure builds that
instance with hexColours=false, so even &#RRGGBB did not work. The action bar
used a second, separately configured serializer that did support hex but not
MiniMessage. Two display paths, two different answers to "what formatting can
I use here", neither documented where anyone would look.
Both now go through Util.parseMiniMessageOrLegacy, which accepts MiniMessage,
& and section codes, hex, and any mixture, and is cached on the BentoBox side.
This also fixes section codes being rendered as literal text. Translations come
back from User.getTranslation already converted to section codes, so anything
locale-sourced was being handed to a serializer bound to '&' - the starting
hologram (aoneblock.island.starting-hologram) and the action bar both took that
path. Phase file hologram lines never see the translation layer, which is why
the reported case showed raw MiniMessage tags rather than raw section codes.
The boss bar title is untouched: it uses the String-based Bukkit BossBar API
and BentoBox has already resolved its formatting by then.
Existing configs are unaffected. BentoBox's MiniMessage instance is the
non-strict one, so text containing stray angle brackets is left as literal
text rather than throwing.
Documented the accepted syntax in the phase file, next to the holograms
section where the admin was already looking.
Util.parseMiniMessageOrLegacy is BentoBox 3.2.0 API, so this needs no
dependency bump.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
BentoBox 3.18.0 onwards is compiled for Java 25 (Minecraft 26.x), so its class
files are version 69. A JDK 21 javac cannot parse those at all, and the build
died with "class file has wrong version 69.0, should be 65.0" against every
BentoBox type before it reached any of our code.
This only surfaced once the dependency moved to 3.22.0. It did not show up
locally because the dev machine is already on JDK 25 - the compiler reads the
newer class files happily and <release>21</release> still emits Java 21
bytecode, which is what the addon ships.
The addon's own target is unchanged: still Java 21 via <release> in the pom.
Only the JDK doing the compiling moves.
Also moves setup-java to v4 and the 'adopt' distribution to 'temurin', since
neither v3 nor adopt offers a Java 25 build.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
fix: do not lose island progress when the server restarts
feat: support MiniMessage and hex colours in phase text
@sonarqubecloud

Copy link
Copy Markdown

@tastybento
tastybento merged commit 7339721 into masterAug 8, 2026
5 checks passed
Sign up for freeto 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.

1 participant

@tastybento
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Release 1.27.0 - #552

Merged
tastybento merged 10 commits into
masterfrom
develop
Aug 8, 2026
Merged

Release 1.27.0#552
tastybento merged 10 commits into
masterfrom
develop

Conversation

@tastybento

Copy link
Copy Markdown
Member

Release 1.27.0.

Headline

Island progress is no longer lost when the server restarts. Reported on Discord as "it's not saving the progress" — a player online through a restart came back with their block count rolled back to the last checkpoint, up to 49 blocks undone, every restart. The shutdown save was queued rather than written, and every BentoBox before 3.22.0 discarded that queue on the way out.

Also in this release: MiniMessage and hex colours in phase text (holograms, action bar, locale strings), a new island.save-every setting, and a rewritten reference phase file.

🔺 This release raises the minimum BentoBox version

bentobox.version and addon.ymlapi-version both move to 3.22.0, because the shutdown fix uses saveObjectNow() which was added there. Without the api-version bump the addon would load on an older core and throw NoSuchMethodError at shutdown — worse than the bug being fixed. It now refuses to load with "Please update BentoBox".

Knock-on effect for admins: BentoBox 3.18.0+ requires a Java 25 server, so 1.27.0 does too. This is called out prominently in the release notes.

What's in it

PRChange
#550🔺⚙️ Shutdown save writes directly; new island.save-every (default 10, was a hardcoded 50)
#551MiniMessage, hex and gradient support in phase text; fixes § codes rendering literally
#548Reference phase file now explains weights vs positions vs start block
#547CI: publish-platforms pin bumped to the multipart-JSON fix

Also on this branch: a CI fix moving the build to JDK 25. BentoBox 3.18.0+ ships Java 25 class files, which a JDK 21 javac cannot read at all — the build failed against every BentoBox type until the runner moved to 25. The addon still targets Java 21 via <release>.

Verification

  • Full suite green on develop.
  • Boot-tested on two real servers: BentoBox 3.15.1 refuses to load the addon with the intended message and no linkage error; BentoBox 3.22.1-SNAPSHOT enables, runs, and disables cleanly.
  • Not verified in-game: a real block count surviving a restart, and hologram rendering. Both are covered by unit tests through the real code paths, but neither was watched on a live server with a player.

Release notes for the draft release are prepared separately.

🤖 Generated with Claude Code

https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ

tastybentoand others added 10 commits July 29, 2026 09:00
The pinned SHA (ca2dcd16, 2026-07-03) predates BentoBoxWorld/.github#13,
which moved the CurseForge `metadata` and Hangar `versionUpload` JSON out of
inline `-F` values and into files. curl treats `;` in an inline -F value as
the start of a `type=`/`filename=` attribute, so a release body containing a
semicolon truncates the JSON: the 1.26.3 publish failed with CurseForge
"Error in field `metadata`: Invalid JSON" and Hangar "Failed to read request".
Earlier releases only passed because their notes happened to contain no
semicolons.
Pin moved to master HEAD 1f91a0e, which contains the fix.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SAQ3YQkcfRoCZEwa6SPJcp
ci: bump publish-platforms pin to the multipart-JSON fix
0_plains.yml is the reference file admins read first, but it never said
what the numbers after a Material or EntityType are. An admin asked, and
they were right to guess weighting: they are relative weights in a single
raffle - not counts and not percentages - and blocks, mobs and
custom-blocks all draw from that same pool, so a mob weight is directly
comparable to a block weight and pushes every block's share down.
The header now separates the three distinct kinds of number a phase file
contains, since that is the real source of the confusion:
1. blocks/mobs/custom-blocks values are weights, one shared pool
2. fixedBlocks and holograms keys are positions within the phase, from 0
3. the top-level key is the section name - phases_index.yml has owned
phase order and length since 1.26.0
Each section then gets its own explanation with the real Plains numbers
worked out (11450 block weights + 665 mob weights = 12115, so
GRASS_BLOCK: 2000 is 16.5% and COW: 150 is 1.2%), plus the CHEST
two-stage roll, the mob/custom-block types that were missing from the
list, and version gating.
Comments only - every block, mob and weight is unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017zwLryefnJ6wG76JmYNamx
docs: rewrite the phase 0 comments to explain what the numbers mean
A player breaking blocks and then sitting through a restart would come back
to their block count rolled back to the last checkpoint - up to 49 blocks of
progress gone, repeatedly, on every restart.
The shutdown save was queued, not written. onDisable() called saveCache(),
which uses saveObjectAsync(), and this addon is a Pladdon: the server disables
it before BentoBox, so the write landed in a queue that BentoBox had to drain
on its way out. BentoBox 3.22.0 added that drain (flushAll), but every earlier
version discarded it silently.
Write directly on shutdown instead, via a new saveCacheNow() using
saveObjectNow(). That removes the dependency on core behaviour entirely rather
than relying on a specific BentoBox version getting it right.
saveObjectNow() is BentoBox 3.22.0 API, so bump the dependency and raise
api-version to match. Without the api-version bump the addon would still load
on an older core and throw NoSuchMethodError at shutdown, which is worse than
the bug being fixed. It now refuses to load with "Please update BentoBox".
Also make the periodic save interval configurable as island.save-every,
defaulting to 10 rather than the hardcoded 50. Nothing helps if the server is
SIGKILLed, but this caps what an unclean kill can cost at 9 blocks.
Reported on Discord: progress reverting on every restart, BentoBox 3.15.0.
Test notes: the BentoBox bump broke 5 PhasesPanelTest tests, and fixing those
exposed 2 more. None were regressions - all 7 called
when(user.getTranslation(...)) on a real User rather than a mock, which stubs
nothing on the User and instead attaches to whichever mock the real method
last touched. 3.22.0's getTranslation(World, ...) calls getIWM().getAddon()
first, moving the target. Added a stubTranslation() helper that stubs the
LocalesManager these actually read from. The same pattern remains elsewhere in
that class and is worth a follow-up sweep.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
An admin coloured a phase hologram with <green><bold>...</green> and got white
text with the tags shown literally.
Holograms deserialized with LegacyComponentSerializer.legacyAmpersand(), which
understands the 16 legacy & codes and nothing else - Adventure builds that
instance with hexColours=false, so even &#RRGGBB did not work. The action bar
used a second, separately configured serializer that did support hex but not
MiniMessage. Two display paths, two different answers to "what formatting can
I use here", neither documented where anyone would look.
Both now go through Util.parseMiniMessageOrLegacy, which accepts MiniMessage,
& and section codes, hex, and any mixture, and is cached on the BentoBox side.
This also fixes section codes being rendered as literal text. Translations come
back from User.getTranslation already converted to section codes, so anything
locale-sourced was being handed to a serializer bound to '&' - the starting
hologram (aoneblock.island.starting-hologram) and the action bar both took that
path. Phase file hologram lines never see the translation layer, which is why
the reported case showed raw MiniMessage tags rather than raw section codes.
The boss bar title is untouched: it uses the String-based Bukkit BossBar API
and BentoBox has already resolved its formatting by then.
Existing configs are unaffected. BentoBox's MiniMessage instance is the
non-strict one, so text containing stray angle brackets is left as literal
text rather than throwing.
Documented the accepted syntax in the phase file, next to the holograms
section where the admin was already looking.
Util.parseMiniMessageOrLegacy is BentoBox 3.2.0 API, so this needs no
dependency bump.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
BentoBox 3.18.0 onwards is compiled for Java 25 (Minecraft 26.x), so its class
files are version 69. A JDK 21 javac cannot parse those at all, and the build
died with "class file has wrong version 69.0, should be 65.0" against every
BentoBox type before it reached any of our code.
This only surfaced once the dependency moved to 3.22.0. It did not show up
locally because the dev machine is already on JDK 25 - the compiler reads the
newer class files happily and <release>21</release> still emits Java 21
bytecode, which is what the addon ships.
The addon's own target is unchanged: still Java 21 via <release> in the pom.
Only the JDK doing the compiling moves.
Also moves setup-java to v4 and the 'adopt' distribution to 'temurin', since
neither v3 nor adopt offers a Java 25 build.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014t1DSo2wMbTWZLcwXpwUmQ
fix: do not lose island progress when the server restarts
feat: support MiniMessage and hex colours in phase text
@sonarqubecloud

Copy link
Copy Markdown

@tastybento
tastybento merged commit 7339721 into masterAug 8, 2026
5 checks passed
Sign up for freeto 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.

1 participant

@tastybento