Skip to content

Add block donation feature#412

Merged
tastybento merged 38 commits intomasterfrom
feature/block-donation
Apr 12, 2026
Merged

Add block donation feature#412
tastybento merged 38 commits intomasterfrom
feature/block-donation

Conversation

@tastybento
Copy link
Copy Markdown
Member

@tastybento tastybento commented Apr 11, 2026

Summary

  • New /island donate command and chest-style GUI letting players permanently donate blocks to raise their island level
  • /island donate hand [amount] for quick donation from the held item
  • New ISLAND_BLOCK_DONATION flag (default: owner; configurable to member) gates who can donate
  • Donated points feed into the level calculation and persist across recalcs; legacy island data stays compatible via null-safe fields
  • Detail panel gains a DONATED tab; admin level report includes a donated-blocks section; donation audit log records donor + timestamp
  • Destructive-action warnings on the confirm button and GUI info text

Test plan

  • mvn verify passes
  • /island donate opens the GUI; dragging a block in and confirming raises level and consumes the items
  • /island donate hand 5 donates 5 from the held stack
  • ISLAND_BLOCK_DONATION flag toggles between owner-only and member access
  • Donated blocks survive a /island level recalculation
  • Detail panel DONATED tab shows the donation history
  • Admin level report includes the donated blocks section
  • Legacy islands (no donation data) load without NPEs

🤖 Generated with Claude Code

Copilot AI and others added 30 commits March 2, 2026 01:19
…alidate cache on update

Co-authored-by: tastybento <4407265+tastybento@users.noreply.github.com>
Fix top ten ordering: replace LinkedHashMap with ConcurrentHashMap for thread safety
- Remove _hanging stripping in ValuePanel.getIcon() so hanging signs
  display as hanging signs instead of regular signs
- Split Tag fallback: ALL_HANGING_SIGNS -> OAK_HANGING_SIGN
- Fix DetailsPanel wall hanging sign conversion to produce _HANGING_SIGN
- Change twisting vines plant icon from VINE to TWISTING_VINES
- Change weeping vines plant icon from VINE to WEEPING_VINES
- Change cave vines plant icon from VINE to GLOW_BERRIES
- Add CAVE_VINES to ValuePanel switch so it appears in /ob value menu

Co-authored-by: tastybento <4407265+tastybento@users.noreply.github.com>
…-sign-icon

Fix incorrect icons for hanging signs, vines, and cave vines in panels
…guage-translation

Add Russian (ru) locale with MiniMessage formatting
- Add missing island.detail.description
- Update required-points-to-next-level to new [progress]/[levelcost] format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add admin.stats section
- Add island.detail.description
- Add value_blocks button, spawner.block-name
- Add you-have and you-can-place conversation messages
- Update required-points-to-next-level to new [progress]/[levelcost] format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add admin.stats section
- Add island.detail.description
- Add value_blocks button, spawner.block-name
- Add you-have and you-can-place conversation messages
- Update required-points-to-next-level to new [progress]/[levelcost] format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add admin.stats section
- Add island.detail.description
- Add value_blocks button, spawner.block-name
- Add you-have and you-can-place conversation messages
- Update required-points-to-next-level to new [progress]/[levelcost] format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add admin.stats section
- Add island.detail.description
- Add value_blocks button, spawner.block-name
- Add you-have and you-can-place conversation messages
- Update required-points-to-next-level to new [progress]/[levelcost] format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add admin.stats section
- Add island.detail.description
- Add value_blocks button, spawner.block-name
- Add you-have and you-can-place conversation messages
- Update required-points-to-next-level to new [progress]/[levelcost] format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add island.detail.description
- Add value_blocks button, spawner.block-name
- Add you-have and you-can-place conversation messages
- Update required-points-to-next-level to new [progress]/[levelcost] format
- Fix spawner button name (Спавнери)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add island.detail.description
- Add value_blocks button, spawner.block-name
- Add you-have and you-can-place conversation messages
- Update required-points-to-next-level to new [progress]/[levelcost] format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add admin.stats section
- Add island.detail.description
- Add missing island.level keys (in-progress, time-out)
- Add full level section (commands, gui, conversations)
- Remove old island.value structure, replace with level.commands.value
- Update required-points-to-next-level to new [progress]/[levelcost] format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add admin.stats section
- Add island.detail.description
- Add missing island.level keys (in-progress, time-out)
- Add full level section (commands, gui, conversations)
- Remove old island.value structure, replace with level.commands.value
- Update required-points-to-next-level to new [progress]/[levelcost] format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add admin.stats section
- Add island.detail.description
- Add missing island.level keys (in-progress, time-out)
- Add full level section (commands, gui, conversations)
- Remove old island.value and island.top.remove structures
- Update required-points-to-next-level to new [progress]/[levelcost] format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add admin.level.sethandicap section
- Add admin.levelstatus.description
- Add admin.stats section
- Add island.detail.description
- Add missing island.level keys (in-progress, time-out, in-queue)
- Add missing island.level-details keys (names-island, syntax, hint)
- Add full level section (commands, gui, conversations)
- Remove old island.value structure, replace with level.commands.value
- Update required-points-to-next-level to new [progress]/[levelcost] format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add admin.top.description, admin.stats section
- Add island.detail.description
- Add missing island.level keys (estimated-wait, in-queue, in-progress, time-out)
- Add full level section (commands, gui, conversations)
- Remove old island.value structure, replace with level.commands.value
- Update required-points-to-next-level to new [progress]/[levelcost] format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add admin.level.sethandicap section
- Add admin.levelstatus.islands-in-queue and description
- Add admin.stats section
- Add island.detail.description
- Add missing island.level keys (estimated-wait, in-queue, in-progress, time-out)
- Add island.level-details section (all keys)
- Add full level section (commands, gui, conversations)
- Remove old island.value structure, replace with level.commands.value
- Update required-points-to-next-level to new [progress]/[levelcost] format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add admin.level.sethandicap section
- Add admin.levelstatus section
- Add admin.top.remove, admin.stats section
- Add island.detail.description
- Add missing island.level keys (estimated-wait, in-queue, in-progress, time-out)
- Add island.level-details section (all keys)
- Add full level section (commands, gui, conversations)
- Remove old island.value structure, replace with level.commands.value
- Update required-points-to-next-level to new [progress]/[levelcost] format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…n plugins

Require BentoBox API 3.14.0 (addon.yml) and align the pom dependency with
the bentobox.version property so both stay in sync. All 17 locale files are
converted from legacy & color codes to MiniMessage tags now that the User
API supports them natively. Maven plugins are bumped to their latest stable
releases; the compiler plugin is forked to work around a plexus-compiler
in-process bug ("this.hashes is null") that otherwise breaks test-compile.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Players can permanently donate blocks to raise island level.

- /island donate: opens chest-style GUI to drag blocks in
- /island donate hand [amount]: quick donate from held item
- ISLAND_BLOCK_DONATION flag (default: owner, configurable to member)
- Donated points added to level calculation, persist across recalcs
- DONATED tab in island detail panel
- Donation audit log with timestamps and donor tracking
- Admin level report extended with donated blocks section
- Destructive action warnings on confirm button and GUI info
- Backwards compatible: null-safe fields for legacy island data
Adds the new donation feature strings (island.donate, ISLAND_BLOCK_DONATION
flag, donated tab button) to all non-English locales using English text as
placeholder for translators. Notes in CLAUDE.md that on-disk panel templates
are not overwritten on upgrade so release notes must call out panel changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The donation panel built items via Bukkit's deprecated setDisplayName/
setLore APIs and split the translated text on '|'. Two adjacent
MiniMessage spans of the same color collapse to a single legacy run
(e.g. "§cWarning…|destroyed…"), so splitting dropped the §c from the
second line and it rendered in default purple italic. Lore also got
Minecraft's default italic because the legacy String API does not
suppress it the way Adventure Components do.

Switch to displayName(Component)/lore(List<Component>), parse each
segment with Util.parseMiniMessageOrLegacy, suppress default italic,
and carry the active §color/§format codes across '|' splits so styles
do not get dropped on subsequent segments.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new “block donation” mechanic for the Level addon: players can donate blocks (via GUI or from hand) to permanently add points that are included in island level calculations, with an audit trail and new UI tabs/strings.

Changes:

  • Added /island donate command + Donation GUI to convert donated blocks into permanent level points gated by a new ISLAND_BLOCK_DONATION flag.
  • Persisted donated blocks/points + donation audit log in island level data, and included donated points in level calculations and reports.
  • Updated detail panel UI + many locale files, and bumped BentoBox/API versions.

Reviewed changes

Copilot reviewed 33 out of 33 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/test/java/world/bentobox/level/LevelTest.java Updates command registration expectations due to new command.
src/test/java/world/bentobox/level/LevelsManagerTest.java Adds a regression test to ensure Top Ten results are sorted descending.
src/main/resources/panels/detail_panel.yml Adds a new DONATED tab button to the island detail panel.
src/main/resources/locales/zh-CN.yml Updates formatting and adds donation + flag strings.
src/main/resources/locales/vi.yml Expands/normalizes strings, adds donation + flag strings.
src/main/resources/locales/uk.yml Updates formatting and adds donation + flag strings.
src/main/resources/locales/tr.yml Expands/normalizes strings, adds donation + flag strings.
src/main/resources/locales/ru.yml Adds a new Russian locale including donation + flag strings.
src/main/resources/locales/pt.yml Expands/normalizes strings, adds donation + flag strings.
src/main/resources/locales/pl.yml Updates formatting and adds donation + flag strings.
src/main/resources/locales/nl.yml Updates formatting and adds donation + flag strings.
src/main/resources/locales/lv.yml Expands/normalizes strings, adds donation + flag strings.
src/main/resources/locales/ko.yml Expands/normalizes strings, adds donation + flag strings.
src/main/resources/locales/id.yml Updates formatting and adds donation + flag strings.
src/main/resources/locales/hu.yml Expands/normalizes strings, adds donation + flag strings.
src/main/resources/locales/fr.yml Updates formatting and adds donation + flag strings.
src/main/resources/locales/es.yml Updates formatting and adds donation + flag strings.
src/main/resources/locales/en-US.yml Converts to MiniMessage-style formatting and adds donation + flag strings.
src/main/resources/locales/de.yml Expands/normalizes strings, adds donation + flag strings.
src/main/resources/locales/cs.yml Updates formatting and adds donation + flag strings.
src/main/resources/addon.yml Bumps addon api-version to align with updated BentoBox dependency.
src/main/java/world/bentobox/level/panels/ValuePanel.java Adjusts icon mapping for newer materials (vines/signs).
src/main/java/world/bentobox/level/panels/DonationPanel.java Implements the chest-style donation GUI and inventory event handling.
src/main/java/world/bentobox/level/panels/DetailsPanel.java Adds DONATED tab support and adjusts icon conversion for newer items.
src/main/java/world/bentobox/level/objects/TopTenData.java Switches Top Ten backing map to ConcurrentHashMap.
src/main/java/world/bentobox/level/objects/IslandLevels.java Persists donated blocks/points and a donation audit log (null-safe).
src/main/java/world/bentobox/level/LevelsManager.java Adds donation persistence APIs + cache invalidation for top-ten caching.
src/main/java/world/bentobox/level/Level.java Registers donation flag and the new donate command.
src/main/java/world/bentobox/level/commands/IslandDonateCommand.java Adds /island donate and /island donate hand [amount] command handling.
src/main/java/world/bentobox/level/calculators/Results.java Adds donatedPoints to results.
src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java Includes donated points in calculation and admin report output.
pom.xml Updates Bentobox + build/plugin versions.
CLAUDE.md Documents panel template upgrade caveat and local dependency source lookup guidance.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Require a re-run confirmation before /island donate hand destroys items,
fix tab completion to offer "hand" and the held stack size, route "help"
through the standard help handler, and format [points] placeholders via
the player's locale so large totals render with thousands separators.
Sync the new confirm-prompt key plus spacing and typo fixes across every
locale file.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@tastybento
Copy link
Copy Markdown
Member Author

@copilot apply changes based on the comments in this thread

…ity, locale spacing

Agent-Logs-Url: https://github.com/BentoBoxWorld/Level/sessions/0764e162-6b48-4cf7-b3e9-f344016416bd

Co-authored-by: tastybento <4407265+tastybento@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 11, 2026

@copilot apply changes based on the comments in this thread

Applied all changes from the review in commit f27f8f7:

  • processDonation(): valueless items are now returned to the player (with overflow drop) instead of being silently consumed
  • Shift-click handler: replaced direct mutation of event.getCurrentItem() with inventory.setItem() / event.setCurrentItem() to avoid client/server inventory desync
  • Donation-slot validator: now rejects blocks with no configured value (not just non-blocks), and handles inventory overflow by dropping items at the player's location
  • donateBlocks(): uses getLevelsData(island) instead of computeIfAbsent() to avoid overwriting persisted DB records
  • addToTopTen() call removed: donations only affect future recalculations; the stored level is updated by setIslandResults() after a full recalc
  • en-US.yml: restored space before [+/-] in admin.level.sethandicap.parameters

@tastybento
Copy link
Copy Markdown
Member Author

@copilot apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 11, 2026

@copilot apply changes based on the comments in this thread

All six changes from the review thread were already applied in commit f27f8f7:

  1. processDonation() — valueless items returned to player instead of consumed
  2. Shift-click handler — uses event.setCurrentItem() / inventory.setItem() with clones instead of mutating event.getCurrentItem()
  3. Donation-slot validator — checks isBlock() AND getValue() > 0, drops overflow at player location
  4. donateBlocks() — uses getLevelsData(island) instead of computeIfAbsent()
  5. addToTopTen() call removed with explanatory comment
  6. en-US.yml — space restored in admin.level.sethandicap.parameters

tastybento and others added 3 commits April 11, 2026 16:28
Bumps BentoBox to 3.14.1-SNAPSHOT for the new Flag.Builder.minimumRank
API and uses it on BLOCK_DONATION so VISITOR/COOP/TRUSTED ranks can
never be selected as the donation rank — only MEMBER and above.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract [points] placeholder into a POINTS_PLACEHOLDER constant so
  the literal is declared once instead of four times (S1192)
- Switch the GUI creation to the Component-based Bukkit.createInventory
  overload so we are no longer calling the deprecated String variant
  (S1874), and reuse removeDefaultItalic so the title matches the
  styling rules used for item names
- Split onInventoryClick into small focused helpers
  (handlePlayerInventoryClick, handleCancel, handleConfirm,
  handleDonationSlotClick, isValidDonationItem,
  distributeIntoDonationSlots). Drops cognitive complexity well below
  the 15 threshold and fixes the brain-method warning (S3776, S6541)
- Rewrite the shift-click distribution loop as a while loop guarded by
  amount > 0 and the two-branch splitWithStyleCarryover loop as an
  if/else-if/else chain, so neither uses more than one break/continue
  (S135)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Require Member rank minimum on block donation flag
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 35 out of 35 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +556 to +563
public void donateBlocks(@NonNull Island island, @NonNull UUID donorUUID, @NonNull String material, int count, long points) {
IslandLevels ld = getLevelsData(island);
ld.addDonation(donorUUID.toString(), material, count, points);
handler.saveObjectAsync(ld);
// Do not update TopTen here: donations affect future recalculations, and the
// stored island level is only updated when setIslandResults(...) persists the
// recalculated level data.
}
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

donateBlocks(...) only updates the donation fields and saves the object, but it never triggers a level recalculation or updates the stored level/pointsToNextLevel fields. Since getIslandLevel(...) reads IslandLevels#getLevel(), donations won’t actually affect island level/top-ten output until some later /island level recalculation happens. Consider queueing a recalculation here (or in the donate command/panel after a successful donation), or explicitly updating the persisted level fields so the “donation raises level” behavior is immediate and consistent.

Copilot uses AI. Check for mistakes.
Comment on lines +145 to +156
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) {
String lastArg = !args.isEmpty() ? args.get(args.size() - 1) : "";
if (args.size() <= 2) {
return Optional.of(Util.tabLimit(List.of("hand"), lastArg));
}
if (args.size() == 3 && "hand".equalsIgnoreCase(args.get(1)) && user.isPlayer()) {
int held = user.getPlayer().getInventory().getItemInMainHand().getAmount();
if (held > 0) {
return Optional.of(Util.tabLimit(List.of(String.valueOf(held)), lastArg));
}
}
return Optional.of(List.of());
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tab-complete argument indexing/branching looks off for /island donate hand [amount]. With the current logic, args.size() <= 2 always suggests only hand (even after typing hand), and the amount suggestion branch (args.size() == 3 && args.get(1)) is never reached for typical arg arrays like ["hand"] or ["hand","5"]. Adjust the conditions to match the actual args passed to subcommands so hand is suggested for the first arg and an amount is suggested for the second.

Copilot uses AI. Check for mistakes.
Comment on lines +314 to +320
if (inSlot != null && !inSlot.getType().isAir() && !isValidDonationItem(inSlot)) {
inventory.setItem(slot, null);
Map<Integer, ItemStack> overflow = player.getInventory().addItem(inSlot);
overflow.values().forEach(item -> player.getWorld().dropItemNaturally(player.getLocation(), item));
user.sendMessage("island.donate.hand.not-block");
}
updatePreview();
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When a player places an invalid item into the donation GUI, the code sends island.donate.hand.not-block. That message is specific to the /island donate hand flow (“You must be holding…”), so it’s misleading in the GUI context (and also for blocks that are placeable but have no configured value). Consider adding/using a GUI-specific translation key (e.g. “Only valuable blocks can be donated”) to make the error message accurate.

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@tastybento
Copy link
Copy Markdown
Member Author

@copilot apply changes based on the comments in this thread

…ng, GUI-specific error message

Agent-Logs-Url: https://github.com/BentoBoxWorld/Level/sessions/753156c2-d054-4c6f-820a-48c0ffedbbbe

Co-authored-by: tastybento <4407265+tastybento@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 11, 2026

@copilot apply changes based on the comments in this thread

Applied all 3 changes in commit 099fc44:

  1. Level recalculation after donation — Added recalculateAfterDonation() to LevelsManager, called from both the GUI and hand donation flows so island level/top-ten update immediately
  2. Tab-complete arg indexing — Fixed to suggest hand for args.size() <= 1 and amount for args.size() == 2 && args.get(0) == "hand"
  3. GUI-specific error message — New island.donate.invalid-item key ("Only blocks with a configured level value can be donated") replaces reuse of the hand-flow message

@sonarqubecloud
Copy link
Copy Markdown

@tastybento tastybento merged commit b755519 into master Apr 12, 2026
3 checks passed
@tastybento tastybento deleted the feature/block-donation branch April 12, 2026 00:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants