fix: register economy command permissions and save synchronously on shutdown (1.19.2) - #63

Merged
tastybento merged 2 commits into
developfrom
fix/economy-permissions-and-shutdown-save
Aug 1, 2026
Merged

fix: register economy command permissions and save synchronously on shutdown (1.19.2)#63
tastybento merged 2 commits into
developfrom
fix/economy-permissions-and-shutdown-save

Conversation

@tastybento

Copy link
Copy Markdown
Member

Two fixes, released as 1.19.2.

Economy command permissions were never declared

Reported in testing: a normal player running /<gamemode> balance got a permission error for <gamemode>.invswitcher.balance, even though InvSwitcher was the economy provider.

BalanceCommand.setup() calls setPermission("invswitcher.balance"). Because the command is attached to the game mode's player command, CompositeCommand prepends the parent's permission prefix, producing e.g. bskyblock.invswitcher.balance. But addon.yml had no permissions: section at all, so that node was never registered with a default — and an undeclared node means hasPermission() is false for everyone but ops.

Fixed by declaring the nodes in addon.yml using BentoBox's [gamemode] placeholder, which AddonsManager.registerPermission() expands into every game mode's permission prefix (the same pattern Level and Bank use):

PermissionDefault
[gamemode].invswitcher.balancetrue
[gamemode].invswitcher.paytrue
[gamemode].invswitcher.admin.eco (+ .balance / .give / .take / .set)op

The commands themselves are already gated correctly — registerEconomyCommands() only runs when options.money is enabled and Vault is installed, and only for game modes whose overworld InvSwitcher manages. So with money off, the commands simply do not exist.

Shutdown saves are now synchronous

BentoBox closes its database immediately after addons are disabled and only kicks players afterwards, so the async write issued from saveOnShutdown() lost the race and was silently dropped. The PlayerQuitEvent that would otherwise have saved them fired after the database was already closed.

The visible effect: everything a player did since their last world change went unsaved when the server stopped, and because PlayerListener.onPlayerJoin re-applies the stored inventory on login, the stale snapshot then overwrote their real inventory — players were rolled back to their last world change.

Both save paths (including the early-returning statistics branch) now route through a persist() helper that writes synchronously when shutting down and stays async otherwise.

Testing

  • Confirmed working on a live server by the reporter.
  • mvn test — 128 tests, all passing. Three new StoreTest cases cover the shutdown path: synchronous save with and without statistics enabled, and normal saves staying asynchronous.

🤖 Generated with Claude Code

https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs

tastybentoand others added 2 commits August 1, 2026 10:43
…hutdown
Two fixes, released as 1.19.2.
Economy command permissions were never declared. The commands set permissions
like "invswitcher.balance", which CompositeCommand prefixes with the parent
game mode's permission prefix, giving e.g. "bskyblock.invswitcher.balance".
addon.yml had no permissions section, so those nodes were never registered with
a default and hasPermission() was false for every non-op player - /<gm> balance
and /<gm> pay failed with a permission error. Declare them in addon.yml using
BentoBox's [gamemode] placeholder, which AddonsManager expands into every game
mode's prefix. User commands default to true, admin eco commands to op.
Shutdown saves are now synchronous. BentoBox closes its database immediately
after addons are disabled and only kicks players afterwards, so the async write
issued from saveOnShutdown() lost the race and was silently dropped, and the
PlayerQuitEvent that would otherwise save fired after the database was closed.
Everything a player did since their last world change went unsaved on server
stop, and because onPlayerJoin re-applies the stored inventory, the stale
snapshot then overwrote their real inventory on the next login. Route both save
paths through a persist() helper that writes synchronously when shutting down.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs
JaCoCo 0.8.12 cannot read class file major version 69, so instrumenting the
classes Mockito generates at runtime failed with "Error while instrumenting ...
Unsupported class file major version 69" whenever the build ran on a JDK 25
toolchain - which is what the CodeMC CI agent (OpenJDK_25) uses. 0.8.15 adds
Java 25 class file support.
Verified on JDK 25: mvn test now runs all 128 tests green with the agent
attached, and jacoco:report analyzes the bundle and writes the report.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs
@sonarqubecloud

Copy link
Copy Markdown

@tastybento
tastybento merged commit a1eabf6 into developAug 1, 2026
3 checks passed
@tastybento
tastybento deleted the fix/economy-permissions-and-shutdown-save branch August 1, 2026 17:48
@tastybentotastybento mentioned this pull request Aug 1, 2026
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

fix: register economy command permissions and save synchronously on shutdown (1.19.2) - #63

Merged
tastybento merged 2 commits into
developfrom
fix/economy-permissions-and-shutdown-save
Aug 1, 2026
Merged

fix: register economy command permissions and save synchronously on shutdown (1.19.2)#63
tastybento merged 2 commits into
developfrom
fix/economy-permissions-and-shutdown-save

Conversation

@tastybento

Copy link
Copy Markdown
Member

Two fixes, released as 1.19.2.

Economy command permissions were never declared

Reported in testing: a normal player running /<gamemode> balance got a permission error for <gamemode>.invswitcher.balance, even though InvSwitcher was the economy provider.

BalanceCommand.setup() calls setPermission("invswitcher.balance"). Because the command is attached to the game mode's player command, CompositeCommand prepends the parent's permission prefix, producing e.g. bskyblock.invswitcher.balance. But addon.yml had no permissions: section at all, so that node was never registered with a default — and an undeclared node means hasPermission() is false for everyone but ops.

Fixed by declaring the nodes in addon.yml using BentoBox's [gamemode] placeholder, which AddonsManager.registerPermission() expands into every game mode's permission prefix (the same pattern Level and Bank use):

PermissionDefault
[gamemode].invswitcher.balancetrue
[gamemode].invswitcher.paytrue
[gamemode].invswitcher.admin.eco (+ .balance / .give / .take / .set)op

The commands themselves are already gated correctly — registerEconomyCommands() only runs when options.money is enabled and Vault is installed, and only for game modes whose overworld InvSwitcher manages. So with money off, the commands simply do not exist.

Shutdown saves are now synchronous

BentoBox closes its database immediately after addons are disabled and only kicks players afterwards, so the async write issued from saveOnShutdown() lost the race and was silently dropped. The PlayerQuitEvent that would otherwise have saved them fired after the database was already closed.

The visible effect: everything a player did since their last world change went unsaved when the server stopped, and because PlayerListener.onPlayerJoin re-applies the stored inventory on login, the stale snapshot then overwrote their real inventory — players were rolled back to their last world change.

Both save paths (including the early-returning statistics branch) now route through a persist() helper that writes synchronously when shutting down and stays async otherwise.

Testing

  • Confirmed working on a live server by the reporter.
  • mvn test — 128 tests, all passing. Three new StoreTest cases cover the shutdown path: synchronous save with and without statistics enabled, and normal saves staying asynchronous.

🤖 Generated with Claude Code

https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs

tastybentoand others added 2 commits August 1, 2026 10:43
…hutdown
Two fixes, released as 1.19.2.
Economy command permissions were never declared. The commands set permissions
like "invswitcher.balance", which CompositeCommand prefixes with the parent
game mode's permission prefix, giving e.g. "bskyblock.invswitcher.balance".
addon.yml had no permissions section, so those nodes were never registered with
a default and hasPermission() was false for every non-op player - /<gm> balance
and /<gm> pay failed with a permission error. Declare them in addon.yml using
BentoBox's [gamemode] placeholder, which AddonsManager expands into every game
mode's prefix. User commands default to true, admin eco commands to op.
Shutdown saves are now synchronous. BentoBox closes its database immediately
after addons are disabled and only kicks players afterwards, so the async write
issued from saveOnShutdown() lost the race and was silently dropped, and the
PlayerQuitEvent that would otherwise save fired after the database was closed.
Everything a player did since their last world change went unsaved on server
stop, and because onPlayerJoin re-applies the stored inventory, the stale
snapshot then overwrote their real inventory on the next login. Route both save
paths through a persist() helper that writes synchronously when shutting down.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs
JaCoCo 0.8.12 cannot read class file major version 69, so instrumenting the
classes Mockito generates at runtime failed with "Error while instrumenting ...
Unsupported class file major version 69" whenever the build ran on a JDK 25
toolchain - which is what the CodeMC CI agent (OpenJDK_25) uses. 0.8.15 adds
Java 25 class file support.
Verified on JDK 25: mvn test now runs all 128 tests green with the agent
attached, and jacoco:report analyzes the bundle and writes the report.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs
@sonarqubecloud

Copy link
Copy Markdown

@tastybento
tastybento merged commit a1eabf6 into developAug 1, 2026
3 checks passed
@tastybento
tastybento deleted the fix/economy-permissions-and-shutdown-save branch August 1, 2026 17:48
@tastybentotastybento mentioned this pull request Aug 1, 2026
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

fix: register economy command permissions and save synchronously on shutdown (1.19.2) - #63

Merged
tastybento merged 2 commits into
developfrom
fix/economy-permissions-and-shutdown-save
Aug 1, 2026
Merged

fix: register economy command permissions and save synchronously on shutdown (1.19.2)#63
tastybento merged 2 commits into
developfrom
fix/economy-permissions-and-shutdown-save

Conversation

@tastybento

Copy link
Copy Markdown
Member

Two fixes, released as 1.19.2.

Economy command permissions were never declared

Reported in testing: a normal player running /<gamemode> balance got a permission error for <gamemode>.invswitcher.balance, even though InvSwitcher was the economy provider.

BalanceCommand.setup() calls setPermission("invswitcher.balance"). Because the command is attached to the game mode's player command, CompositeCommand prepends the parent's permission prefix, producing e.g. bskyblock.invswitcher.balance. But addon.yml had no permissions: section at all, so that node was never registered with a default — and an undeclared node means hasPermission() is false for everyone but ops.

Fixed by declaring the nodes in addon.yml using BentoBox's [gamemode] placeholder, which AddonsManager.registerPermission() expands into every game mode's permission prefix (the same pattern Level and Bank use):

PermissionDefault
[gamemode].invswitcher.balancetrue
[gamemode].invswitcher.paytrue
[gamemode].invswitcher.admin.eco (+ .balance / .give / .take / .set)op

The commands themselves are already gated correctly — registerEconomyCommands() only runs when options.money is enabled and Vault is installed, and only for game modes whose overworld InvSwitcher manages. So with money off, the commands simply do not exist.

Shutdown saves are now synchronous

BentoBox closes its database immediately after addons are disabled and only kicks players afterwards, so the async write issued from saveOnShutdown() lost the race and was silently dropped. The PlayerQuitEvent that would otherwise have saved them fired after the database was already closed.

The visible effect: everything a player did since their last world change went unsaved when the server stopped, and because PlayerListener.onPlayerJoin re-applies the stored inventory on login, the stale snapshot then overwrote their real inventory — players were rolled back to their last world change.

Both save paths (including the early-returning statistics branch) now route through a persist() helper that writes synchronously when shutting down and stays async otherwise.

Testing

  • Confirmed working on a live server by the reporter.
  • mvn test — 128 tests, all passing. Three new StoreTest cases cover the shutdown path: synchronous save with and without statistics enabled, and normal saves staying asynchronous.

🤖 Generated with Claude Code

https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs

tastybentoand others added 2 commits August 1, 2026 10:43
…hutdown
Two fixes, released as 1.19.2.
Economy command permissions were never declared. The commands set permissions
like "invswitcher.balance", which CompositeCommand prefixes with the parent
game mode's permission prefix, giving e.g. "bskyblock.invswitcher.balance".
addon.yml had no permissions section, so those nodes were never registered with
a default and hasPermission() was false for every non-op player - /<gm> balance
and /<gm> pay failed with a permission error. Declare them in addon.yml using
BentoBox's [gamemode] placeholder, which AddonsManager expands into every game
mode's prefix. User commands default to true, admin eco commands to op.
Shutdown saves are now synchronous. BentoBox closes its database immediately
after addons are disabled and only kicks players afterwards, so the async write
issued from saveOnShutdown() lost the race and was silently dropped, and the
PlayerQuitEvent that would otherwise save fired after the database was closed.
Everything a player did since their last world change went unsaved on server
stop, and because onPlayerJoin re-applies the stored inventory, the stale
snapshot then overwrote their real inventory on the next login. Route both save
paths through a persist() helper that writes synchronously when shutting down.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs
JaCoCo 0.8.12 cannot read class file major version 69, so instrumenting the
classes Mockito generates at runtime failed with "Error while instrumenting ...
Unsupported class file major version 69" whenever the build ran on a JDK 25
toolchain - which is what the CodeMC CI agent (OpenJDK_25) uses. 0.8.15 adds
Java 25 class file support.
Verified on JDK 25: mvn test now runs all 128 tests green with the agent
attached, and jacoco:report analyzes the bundle and writes the report.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs
@sonarqubecloud

Copy link
Copy Markdown

@tastybento
tastybento merged commit a1eabf6 into developAug 1, 2026
3 checks passed
@tastybento
tastybento deleted the fix/economy-permissions-and-shutdown-save branch August 1, 2026 17:48
@tastybentotastybento mentioned this pull request Aug 1, 2026
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

fix: register economy command permissions and save synchronously on shutdown (1.19.2) - #63

Merged
tastybento merged 2 commits into
developfrom
fix/economy-permissions-and-shutdown-save
Aug 1, 2026
Merged

fix: register economy command permissions and save synchronously on shutdown (1.19.2)#63
tastybento merged 2 commits into
developfrom
fix/economy-permissions-and-shutdown-save

Conversation

@tastybento

Copy link
Copy Markdown
Member

Two fixes, released as 1.19.2.

Economy command permissions were never declared

Reported in testing: a normal player running /<gamemode> balance got a permission error for <gamemode>.invswitcher.balance, even though InvSwitcher was the economy provider.

BalanceCommand.setup() calls setPermission("invswitcher.balance"). Because the command is attached to the game mode's player command, CompositeCommand prepends the parent's permission prefix, producing e.g. bskyblock.invswitcher.balance. But addon.yml had no permissions: section at all, so that node was never registered with a default — and an undeclared node means hasPermission() is false for everyone but ops.

Fixed by declaring the nodes in addon.yml using BentoBox's [gamemode] placeholder, which AddonsManager.registerPermission() expands into every game mode's permission prefix (the same pattern Level and Bank use):

PermissionDefault
[gamemode].invswitcher.balancetrue
[gamemode].invswitcher.paytrue
[gamemode].invswitcher.admin.eco (+ .balance / .give / .take / .set)op

The commands themselves are already gated correctly — registerEconomyCommands() only runs when options.money is enabled and Vault is installed, and only for game modes whose overworld InvSwitcher manages. So with money off, the commands simply do not exist.

Shutdown saves are now synchronous

BentoBox closes its database immediately after addons are disabled and only kicks players afterwards, so the async write issued from saveOnShutdown() lost the race and was silently dropped. The PlayerQuitEvent that would otherwise have saved them fired after the database was already closed.

The visible effect: everything a player did since their last world change went unsaved when the server stopped, and because PlayerListener.onPlayerJoin re-applies the stored inventory on login, the stale snapshot then overwrote their real inventory — players were rolled back to their last world change.

Both save paths (including the early-returning statistics branch) now route through a persist() helper that writes synchronously when shutting down and stays async otherwise.

Testing

  • Confirmed working on a live server by the reporter.
  • mvn test — 128 tests, all passing. Three new StoreTest cases cover the shutdown path: synchronous save with and without statistics enabled, and normal saves staying asynchronous.

🤖 Generated with Claude Code

https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs

tastybentoand others added 2 commits August 1, 2026 10:43
…hutdown
Two fixes, released as 1.19.2.
Economy command permissions were never declared. The commands set permissions
like "invswitcher.balance", which CompositeCommand prefixes with the parent
game mode's permission prefix, giving e.g. "bskyblock.invswitcher.balance".
addon.yml had no permissions section, so those nodes were never registered with
a default and hasPermission() was false for every non-op player - /<gm> balance
and /<gm> pay failed with a permission error. Declare them in addon.yml using
BentoBox's [gamemode] placeholder, which AddonsManager expands into every game
mode's prefix. User commands default to true, admin eco commands to op.
Shutdown saves are now synchronous. BentoBox closes its database immediately
after addons are disabled and only kicks players afterwards, so the async write
issued from saveOnShutdown() lost the race and was silently dropped, and the
PlayerQuitEvent that would otherwise save fired after the database was closed.
Everything a player did since their last world change went unsaved on server
stop, and because onPlayerJoin re-applies the stored inventory, the stale
snapshot then overwrote their real inventory on the next login. Route both save
paths through a persist() helper that writes synchronously when shutting down.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs
JaCoCo 0.8.12 cannot read class file major version 69, so instrumenting the
classes Mockito generates at runtime failed with "Error while instrumenting ...
Unsupported class file major version 69" whenever the build ran on a JDK 25
toolchain - which is what the CodeMC CI agent (OpenJDK_25) uses. 0.8.15 adds
Java 25 class file support.
Verified on JDK 25: mvn test now runs all 128 tests green with the agent
attached, and jacoco:report analyzes the bundle and writes the report.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs
@sonarqubecloud

Copy link
Copy Markdown

@tastybento
tastybento merged commit a1eabf6 into developAug 1, 2026
3 checks passed
@tastybento
tastybento deleted the fix/economy-permissions-and-shutdown-save branch August 1, 2026 17:48
@tastybentotastybento mentioned this pull request Aug 1, 2026
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

fix: register economy command permissions and save synchronously on shutdown (1.19.2) - #63

Merged
tastybento merged 2 commits into
developfrom
fix/economy-permissions-and-shutdown-save
Aug 1, 2026
Merged

fix: register economy command permissions and save synchronously on shutdown (1.19.2)#63
tastybento merged 2 commits into
developfrom
fix/economy-permissions-and-shutdown-save

Conversation

@tastybento

Copy link
Copy Markdown
Member

Two fixes, released as 1.19.2.

Economy command permissions were never declared

Reported in testing: a normal player running /<gamemode> balance got a permission error for <gamemode>.invswitcher.balance, even though InvSwitcher was the economy provider.

BalanceCommand.setup() calls setPermission("invswitcher.balance"). Because the command is attached to the game mode's player command, CompositeCommand prepends the parent's permission prefix, producing e.g. bskyblock.invswitcher.balance. But addon.yml had no permissions: section at all, so that node was never registered with a default — and an undeclared node means hasPermission() is false for everyone but ops.

Fixed by declaring the nodes in addon.yml using BentoBox's [gamemode] placeholder, which AddonsManager.registerPermission() expands into every game mode's permission prefix (the same pattern Level and Bank use):

PermissionDefault
[gamemode].invswitcher.balancetrue
[gamemode].invswitcher.paytrue
[gamemode].invswitcher.admin.eco (+ .balance / .give / .take / .set)op

The commands themselves are already gated correctly — registerEconomyCommands() only runs when options.money is enabled and Vault is installed, and only for game modes whose overworld InvSwitcher manages. So with money off, the commands simply do not exist.

Shutdown saves are now synchronous

BentoBox closes its database immediately after addons are disabled and only kicks players afterwards, so the async write issued from saveOnShutdown() lost the race and was silently dropped. The PlayerQuitEvent that would otherwise have saved them fired after the database was already closed.

The visible effect: everything a player did since their last world change went unsaved when the server stopped, and because PlayerListener.onPlayerJoin re-applies the stored inventory on login, the stale snapshot then overwrote their real inventory — players were rolled back to their last world change.

Both save paths (including the early-returning statistics branch) now route through a persist() helper that writes synchronously when shutting down and stays async otherwise.

Testing

  • Confirmed working on a live server by the reporter.
  • mvn test — 128 tests, all passing. Three new StoreTest cases cover the shutdown path: synchronous save with and without statistics enabled, and normal saves staying asynchronous.

🤖 Generated with Claude Code

https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs

tastybentoand others added 2 commits August 1, 2026 10:43
…hutdown
Two fixes, released as 1.19.2.
Economy command permissions were never declared. The commands set permissions
like "invswitcher.balance", which CompositeCommand prefixes with the parent
game mode's permission prefix, giving e.g. "bskyblock.invswitcher.balance".
addon.yml had no permissions section, so those nodes were never registered with
a default and hasPermission() was false for every non-op player - /<gm> balance
and /<gm> pay failed with a permission error. Declare them in addon.yml using
BentoBox's [gamemode] placeholder, which AddonsManager expands into every game
mode's prefix. User commands default to true, admin eco commands to op.
Shutdown saves are now synchronous. BentoBox closes its database immediately
after addons are disabled and only kicks players afterwards, so the async write
issued from saveOnShutdown() lost the race and was silently dropped, and the
PlayerQuitEvent that would otherwise save fired after the database was closed.
Everything a player did since their last world change went unsaved on server
stop, and because onPlayerJoin re-applies the stored inventory, the stale
snapshot then overwrote their real inventory on the next login. Route both save
paths through a persist() helper that writes synchronously when shutting down.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs
JaCoCo 0.8.12 cannot read class file major version 69, so instrumenting the
classes Mockito generates at runtime failed with "Error while instrumenting ...
Unsupported class file major version 69" whenever the build ran on a JDK 25
toolchain - which is what the CodeMC CI agent (OpenJDK_25) uses. 0.8.15 adds
Java 25 class file support.
Verified on JDK 25: mvn test now runs all 128 tests green with the agent
attached, and jacoco:report analyzes the bundle and writes the report.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs
@sonarqubecloud

Copy link
Copy Markdown

@tastybento
tastybento merged commit a1eabf6 into developAug 1, 2026
3 checks passed
@tastybento
tastybento deleted the fix/economy-permissions-and-shutdown-save branch August 1, 2026 17:48
@tastybentotastybento mentioned this pull request Aug 1, 2026
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

fix: register economy command permissions and save synchronously on shutdown (1.19.2) - #63

Merged
tastybento merged 2 commits into
developfrom
fix/economy-permissions-and-shutdown-save
Aug 1, 2026
Merged

fix: register economy command permissions and save synchronously on shutdown (1.19.2)#63
tastybento merged 2 commits into
developfrom
fix/economy-permissions-and-shutdown-save

Conversation

@tastybento

Copy link
Copy Markdown
Member

Two fixes, released as 1.19.2.

Economy command permissions were never declared

Reported in testing: a normal player running /<gamemode> balance got a permission error for <gamemode>.invswitcher.balance, even though InvSwitcher was the economy provider.

BalanceCommand.setup() calls setPermission("invswitcher.balance"). Because the command is attached to the game mode's player command, CompositeCommand prepends the parent's permission prefix, producing e.g. bskyblock.invswitcher.balance. But addon.yml had no permissions: section at all, so that node was never registered with a default — and an undeclared node means hasPermission() is false for everyone but ops.

Fixed by declaring the nodes in addon.yml using BentoBox's [gamemode] placeholder, which AddonsManager.registerPermission() expands into every game mode's permission prefix (the same pattern Level and Bank use):

PermissionDefault
[gamemode].invswitcher.balancetrue
[gamemode].invswitcher.paytrue
[gamemode].invswitcher.admin.eco (+ .balance / .give / .take / .set)op

The commands themselves are already gated correctly — registerEconomyCommands() only runs when options.money is enabled and Vault is installed, and only for game modes whose overworld InvSwitcher manages. So with money off, the commands simply do not exist.

Shutdown saves are now synchronous

BentoBox closes its database immediately after addons are disabled and only kicks players afterwards, so the async write issued from saveOnShutdown() lost the race and was silently dropped. The PlayerQuitEvent that would otherwise have saved them fired after the database was already closed.

The visible effect: everything a player did since their last world change went unsaved when the server stopped, and because PlayerListener.onPlayerJoin re-applies the stored inventory on login, the stale snapshot then overwrote their real inventory — players were rolled back to their last world change.

Both save paths (including the early-returning statistics branch) now route through a persist() helper that writes synchronously when shutting down and stays async otherwise.

Testing

  • Confirmed working on a live server by the reporter.
  • mvn test — 128 tests, all passing. Three new StoreTest cases cover the shutdown path: synchronous save with and without statistics enabled, and normal saves staying asynchronous.

🤖 Generated with Claude Code

https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs

tastybentoand others added 2 commits August 1, 2026 10:43
…hutdown
Two fixes, released as 1.19.2.
Economy command permissions were never declared. The commands set permissions
like "invswitcher.balance", which CompositeCommand prefixes with the parent
game mode's permission prefix, giving e.g. "bskyblock.invswitcher.balance".
addon.yml had no permissions section, so those nodes were never registered with
a default and hasPermission() was false for every non-op player - /<gm> balance
and /<gm> pay failed with a permission error. Declare them in addon.yml using
BentoBox's [gamemode] placeholder, which AddonsManager expands into every game
mode's prefix. User commands default to true, admin eco commands to op.
Shutdown saves are now synchronous. BentoBox closes its database immediately
after addons are disabled and only kicks players afterwards, so the async write
issued from saveOnShutdown() lost the race and was silently dropped, and the
PlayerQuitEvent that would otherwise save fired after the database was closed.
Everything a player did since their last world change went unsaved on server
stop, and because onPlayerJoin re-applies the stored inventory, the stale
snapshot then overwrote their real inventory on the next login. Route both save
paths through a persist() helper that writes synchronously when shutting down.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs
JaCoCo 0.8.12 cannot read class file major version 69, so instrumenting the
classes Mockito generates at runtime failed with "Error while instrumenting ...
Unsupported class file major version 69" whenever the build ran on a JDK 25
toolchain - which is what the CodeMC CI agent (OpenJDK_25) uses. 0.8.15 adds
Java 25 class file support.
Verified on JDK 25: mvn test now runs all 128 tests green with the agent
attached, and jacoco:report analyzes the bundle and writes the report.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs
@sonarqubecloud

Copy link
Copy Markdown

@tastybento
tastybento merged commit a1eabf6 into developAug 1, 2026
3 checks passed
@tastybento
tastybento deleted the fix/economy-permissions-and-shutdown-save branch August 1, 2026 17:48
@tastybentotastybento mentioned this pull request Aug 1, 2026
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

fix: register economy command permissions and save synchronously on shutdown (1.19.2) - #63

Merged
tastybento merged 2 commits into
developfrom
fix/economy-permissions-and-shutdown-save
Aug 1, 2026
Merged

fix: register economy command permissions and save synchronously on shutdown (1.19.2)#63
tastybento merged 2 commits into
developfrom
fix/economy-permissions-and-shutdown-save

Conversation

@tastybento

Copy link
Copy Markdown
Member

Two fixes, released as 1.19.2.

Economy command permissions were never declared

Reported in testing: a normal player running /<gamemode> balance got a permission error for <gamemode>.invswitcher.balance, even though InvSwitcher was the economy provider.

BalanceCommand.setup() calls setPermission("invswitcher.balance"). Because the command is attached to the game mode's player command, CompositeCommand prepends the parent's permission prefix, producing e.g. bskyblock.invswitcher.balance. But addon.yml had no permissions: section at all, so that node was never registered with a default — and an undeclared node means hasPermission() is false for everyone but ops.

Fixed by declaring the nodes in addon.yml using BentoBox's [gamemode] placeholder, which AddonsManager.registerPermission() expands into every game mode's permission prefix (the same pattern Level and Bank use):

PermissionDefault
[gamemode].invswitcher.balancetrue
[gamemode].invswitcher.paytrue
[gamemode].invswitcher.admin.eco (+ .balance / .give / .take / .set)op

The commands themselves are already gated correctly — registerEconomyCommands() only runs when options.money is enabled and Vault is installed, and only for game modes whose overworld InvSwitcher manages. So with money off, the commands simply do not exist.

Shutdown saves are now synchronous

BentoBox closes its database immediately after addons are disabled and only kicks players afterwards, so the async write issued from saveOnShutdown() lost the race and was silently dropped. The PlayerQuitEvent that would otherwise have saved them fired after the database was already closed.

The visible effect: everything a player did since their last world change went unsaved when the server stopped, and because PlayerListener.onPlayerJoin re-applies the stored inventory on login, the stale snapshot then overwrote their real inventory — players were rolled back to their last world change.

Both save paths (including the early-returning statistics branch) now route through a persist() helper that writes synchronously when shutting down and stays async otherwise.

Testing

  • Confirmed working on a live server by the reporter.
  • mvn test — 128 tests, all passing. Three new StoreTest cases cover the shutdown path: synchronous save with and without statistics enabled, and normal saves staying asynchronous.

🤖 Generated with Claude Code

https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs

tastybentoand others added 2 commits August 1, 2026 10:43
…hutdown
Two fixes, released as 1.19.2.
Economy command permissions were never declared. The commands set permissions
like "invswitcher.balance", which CompositeCommand prefixes with the parent
game mode's permission prefix, giving e.g. "bskyblock.invswitcher.balance".
addon.yml had no permissions section, so those nodes were never registered with
a default and hasPermission() was false for every non-op player - /<gm> balance
and /<gm> pay failed with a permission error. Declare them in addon.yml using
BentoBox's [gamemode] placeholder, which AddonsManager expands into every game
mode's prefix. User commands default to true, admin eco commands to op.
Shutdown saves are now synchronous. BentoBox closes its database immediately
after addons are disabled and only kicks players afterwards, so the async write
issued from saveOnShutdown() lost the race and was silently dropped, and the
PlayerQuitEvent that would otherwise save fired after the database was closed.
Everything a player did since their last world change went unsaved on server
stop, and because onPlayerJoin re-applies the stored inventory, the stale
snapshot then overwrote their real inventory on the next login. Route both save
paths through a persist() helper that writes synchronously when shutting down.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs
JaCoCo 0.8.12 cannot read class file major version 69, so instrumenting the
classes Mockito generates at runtime failed with "Error while instrumenting ...
Unsupported class file major version 69" whenever the build ran on a JDK 25
toolchain - which is what the CodeMC CI agent (OpenJDK_25) uses. 0.8.15 adds
Java 25 class file support.
Verified on JDK 25: mvn test now runs all 128 tests green with the agent
attached, and jacoco:report analyzes the bundle and writes the report.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs
@sonarqubecloud

Copy link
Copy Markdown

@tastybento
tastybento merged commit a1eabf6 into developAug 1, 2026
3 checks passed
@tastybento
tastybento deleted the fix/economy-permissions-and-shutdown-save branch August 1, 2026 17:48
@tastybentotastybento mentioned this pull request Aug 1, 2026
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

fix: register economy command permissions and save synchronously on shutdown (1.19.2) - #63

Merged
tastybento merged 2 commits into
developfrom
fix/economy-permissions-and-shutdown-save
Aug 1, 2026
Merged

fix: register economy command permissions and save synchronously on shutdown (1.19.2)#63
tastybento merged 2 commits into
developfrom
fix/economy-permissions-and-shutdown-save

Conversation

@tastybento

Copy link
Copy Markdown
Member

Two fixes, released as 1.19.2.

Economy command permissions were never declared

Reported in testing: a normal player running /<gamemode> balance got a permission error for <gamemode>.invswitcher.balance, even though InvSwitcher was the economy provider.

BalanceCommand.setup() calls setPermission("invswitcher.balance"). Because the command is attached to the game mode's player command, CompositeCommand prepends the parent's permission prefix, producing e.g. bskyblock.invswitcher.balance. But addon.yml had no permissions: section at all, so that node was never registered with a default — and an undeclared node means hasPermission() is false for everyone but ops.

Fixed by declaring the nodes in addon.yml using BentoBox's [gamemode] placeholder, which AddonsManager.registerPermission() expands into every game mode's permission prefix (the same pattern Level and Bank use):

PermissionDefault
[gamemode].invswitcher.balancetrue
[gamemode].invswitcher.paytrue
[gamemode].invswitcher.admin.eco (+ .balance / .give / .take / .set)op

The commands themselves are already gated correctly — registerEconomyCommands() only runs when options.money is enabled and Vault is installed, and only for game modes whose overworld InvSwitcher manages. So with money off, the commands simply do not exist.

Shutdown saves are now synchronous

BentoBox closes its database immediately after addons are disabled and only kicks players afterwards, so the async write issued from saveOnShutdown() lost the race and was silently dropped. The PlayerQuitEvent that would otherwise have saved them fired after the database was already closed.

The visible effect: everything a player did since their last world change went unsaved when the server stopped, and because PlayerListener.onPlayerJoin re-applies the stored inventory on login, the stale snapshot then overwrote their real inventory — players were rolled back to their last world change.

Both save paths (including the early-returning statistics branch) now route through a persist() helper that writes synchronously when shutting down and stays async otherwise.

Testing

  • Confirmed working on a live server by the reporter.
  • mvn test — 128 tests, all passing. Three new StoreTest cases cover the shutdown path: synchronous save with and without statistics enabled, and normal saves staying asynchronous.

🤖 Generated with Claude Code

https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs

tastybentoand others added 2 commits August 1, 2026 10:43
…hutdown
Two fixes, released as 1.19.2.
Economy command permissions were never declared. The commands set permissions
like "invswitcher.balance", which CompositeCommand prefixes with the parent
game mode's permission prefix, giving e.g. "bskyblock.invswitcher.balance".
addon.yml had no permissions section, so those nodes were never registered with
a default and hasPermission() was false for every non-op player - /<gm> balance
and /<gm> pay failed with a permission error. Declare them in addon.yml using
BentoBox's [gamemode] placeholder, which AddonsManager expands into every game
mode's prefix. User commands default to true, admin eco commands to op.
Shutdown saves are now synchronous. BentoBox closes its database immediately
after addons are disabled and only kicks players afterwards, so the async write
issued from saveOnShutdown() lost the race and was silently dropped, and the
PlayerQuitEvent that would otherwise save fired after the database was closed.
Everything a player did since their last world change went unsaved on server
stop, and because onPlayerJoin re-applies the stored inventory, the stale
snapshot then overwrote their real inventory on the next login. Route both save
paths through a persist() helper that writes synchronously when shutting down.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs
JaCoCo 0.8.12 cannot read class file major version 69, so instrumenting the
classes Mockito generates at runtime failed with "Error while instrumenting ...
Unsupported class file major version 69" whenever the build ran on a JDK 25
toolchain - which is what the CodeMC CI agent (OpenJDK_25) uses. 0.8.15 adds
Java 25 class file support.
Verified on JDK 25: mvn test now runs all 128 tests green with the agent
attached, and jacoco:report analyzes the bundle and writes the report.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0183f7bfWoU9rmXxRCRwvrAs
@sonarqubecloud

Copy link
Copy Markdown

@tastybento
tastybento merged commit a1eabf6 into developAug 1, 2026
3 checks passed
@tastybento
tastybento deleted the fix/economy-permissions-and-shutdown-save branch August 1, 2026 17:48
@tastybentotastybento mentioned this pull request Aug 1, 2026
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