diff --git a/pom.xml b/pom.xml
index 8d7473b..5ebe28a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -69,7 +69,7 @@
-LOCAL
- 2.26.0
+ 2.27.0
BentoBoxWorld_Level
bentobox-world
https://sonarcloud.io
diff --git a/src/main/java/world/bentobox/level/commands/IslandDonateCommand.java b/src/main/java/world/bentobox/level/commands/IslandDonateCommand.java
index fa76d70..d4d603e 100644
--- a/src/main/java/world/bentobox/level/commands/IslandDonateCommand.java
+++ b/src/main/java/world/bentobox/level/commands/IslandDonateCommand.java
@@ -1,10 +1,13 @@
package world.bentobox.level.commands;
+import java.util.EnumMap;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.PlayerInventory;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
@@ -17,13 +20,17 @@
import world.bentobox.level.util.Utils;
/**
- * Command: /island donate [hand [amount]]
- * Opens a donation GUI or donates blocks from hand.
+ * Command: /island donate [hand [amount]] [inv]
+ * Opens a donation GUI, or donates blocks from the player's hand, or
+ * donates every donatable block from the player's inventory.
*
* @author tastybento
*/
public class IslandDonateCommand extends ConfirmableCommand {
+ private static final String MATERIAL_PLACEHOLDER = "[material]";
+ private static final String POINTS_PLACEHOLDER = "[points]";
+
private final Level addon;
public IslandDonateCommand(Level addon, CompositeCommand parent) {
@@ -65,6 +72,11 @@ public boolean execute(User user, String label, List args) {
return handleHandDonation(user, island, args);
}
+ // Handle "inv" subcommand (accepts English "inv" or the localized keyword)
+ if (!args.isEmpty() && isInvKeyword(user, args.get(0))) {
+ return handleInvDonation(user, island);
+ }
+
// No args - open GUI
DonationPanel.openPanel(addon, getWorld(), user, island);
return true;
@@ -111,8 +123,8 @@ private boolean handleHandDonation(User user, Island island, List args)
String prompt = user.getTranslation("island.donate.hand.confirm-prompt",
TextVariables.NUMBER, String.valueOf(previewAmount),
- "[material]", Utils.prettifyObject(material, user),
- "[points]", Utils.formatNumber(user, previewPoints));
+ MATERIAL_PLACEHOLDER, Utils.prettifyObject(material, user),
+ POINTS_PLACEHOLDER, Utils.formatNumber(user, previewPoints));
askConfirmation(user, prompt, () -> performHandDonation(user, island, material, blockValue, finalRequested));
return true;
@@ -138,18 +150,110 @@ private void performHandDonation(User user, Island island, Material material, in
user.sendMessage("island.donate.hand.success",
TextVariables.NUMBER, String.valueOf(amount),
- "[material]", Utils.prettifyObject(material, user),
- "[points]", Utils.formatNumber(user, points));
+ MATERIAL_PLACEHOLDER, Utils.prettifyObject(material, user),
+ POINTS_PLACEHOLDER, Utils.formatNumber(user, points));
+ }
+
+ /**
+ * Handle the /island donate inv subcommand. Scans the player's inventory for
+ * blocks with a positive donation value, shows a per-material breakdown plus
+ * the total, and asks for confirmation. Items with no value or that aren't
+ * donatable blocks remain in the inventory.
+ */
+ private boolean handleInvDonation(User user, Island island) {
+ Map totals = collectDonatableTotals(user.getPlayer().getInventory());
+
+ if (totals.isEmpty()) {
+ user.sendMessage("island.donate.empty");
+ return false;
+ }
+
+ long totalPoints = 0L;
+ StringBuilder prompt = new StringBuilder(
+ user.getTranslation("island.donate.inv.confirm-header"));
+ for (Map.Entry e : totals.entrySet()) {
+ int value = addon.getBlockConfig().getValue(getWorld(), e.getKey());
+ long points = (long) value * e.getValue();
+ totalPoints += points;
+ prompt.append('\n').append(user.getTranslation("island.donate.inv.confirm-line",
+ TextVariables.NUMBER, String.valueOf(e.getValue()),
+ MATERIAL_PLACEHOLDER, Utils.prettifyObject(e.getKey(), user),
+ POINTS_PLACEHOLDER, Utils.formatNumber(user, points)));
+ }
+ prompt.append('\n').append(user.getTranslation("island.donate.inv.confirm-total",
+ POINTS_PLACEHOLDER, Utils.formatNumber(user, totalPoints)));
+
+ askConfirmation(user, prompt.toString(), () -> performInvDonation(user, island));
+ return true;
+ }
+
+ private void performInvDonation(User user, Island island) {
+ PlayerInventory pInv = user.getPlayer().getInventory();
+ ItemStack[] contents = pInv.getStorageContents();
+ Map donated = new EnumMap<>(Material.class);
+ long totalPoints = 0L;
+
+ for (int i = 0; i < contents.length; i++) {
+ ItemStack item = contents[i];
+ Integer value = donationValue(item);
+ if (value == null) {
+ continue;
+ }
+ int amount = item.getAmount();
+ long points = (long) value * amount;
+ donated.merge(item.getType(), amount, Integer::sum);
+ totalPoints += points;
+ addon.getManager().donateBlocks(island, user.getUniqueId(), item.getType().name(), amount, points);
+ contents[i] = null;
+ }
+ pInv.setStorageContents(contents);
+
+ if (donated.isEmpty()) {
+ user.sendMessage("island.donate.empty");
+ return;
+ }
+ int totalBlocks = donated.values().stream().mapToInt(Integer::intValue).sum();
+ user.sendMessage("island.donate.success",
+ POINTS_PLACEHOLDER, Utils.formatNumber(user, totalPoints),
+ TextVariables.NUMBER, String.valueOf(totalBlocks));
+ addon.getManager().recalculateAfterDonation(island);
+ }
+
+ private Map collectDonatableTotals(PlayerInventory pInv) {
+ Map totals = new EnumMap<>(Material.class);
+ for (ItemStack item : pInv.getStorageContents()) {
+ if (donationValue(item) != null) {
+ totals.merge(item.getType(), item.getAmount(), Integer::sum);
+ }
+ }
+ return totals;
+ }
+
+ /**
+ * @return the per-block donation value if the item is a donatable block with a
+ * positive configured value, or null otherwise
+ */
+ private Integer donationValue(ItemStack item) {
+ if (item == null || item.getType().isAir() || !item.getType().isBlock()) {
+ return null;
+ }
+ Integer value = addon.getBlockConfig().getValue(getWorld(), item.getType());
+ return (value != null && value > 0) ? value : null;
}
@Override
public Optional> tabComplete(User user, String alias, List args) {
+ // BentoBox includes the command label as args.get(0); the user-typed args start at index 1.
String lastArg = !args.isEmpty() ? args.get(args.size() - 1) : "";
String handKeyword = user.getTranslation("island.donate.hand.keyword");
- if (args.size() <= 1) {
- return Optional.of(Util.tabLimit(List.of(handKeyword), lastArg));
+ String invKeyword = user.getTranslation("island.donate.inv.keyword");
+
+ // First user-arg slot: suggest "hand" and "inv".
+ if (args.size() <= 2) {
+ return Optional.of(Util.tabLimit(List.of(handKeyword, invKeyword), lastArg));
}
- if (args.size() == 2 && isHandKeyword(user, args.get(0)) && user.isPlayer()) {
+ // Second user-arg slot after "hand": suggest the held count.
+ if (args.size() == 3 && isHandKeyword(user, 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));
@@ -162,4 +266,9 @@ private boolean isHandKeyword(User user, String arg) {
String localized = user.getTranslation("island.donate.hand.keyword");
return "hand".equalsIgnoreCase(arg) || localized.equalsIgnoreCase(arg);
}
+
+ private boolean isInvKeyword(User user, String arg) {
+ String localized = user.getTranslation("island.donate.inv.keyword");
+ return "inv".equalsIgnoreCase(arg) || localized.equalsIgnoreCase(arg);
+ }
}
diff --git a/src/main/resources/locales/cs.yml b/src/main/resources/locales/cs.yml
index 35ec78b..7c1da5b 100644
--- a/src/main/resources/locales/cs.yml
+++ b/src/main/resources/locales/cs.yml
@@ -67,6 +67,11 @@ island:
success: "Donated [number] x [material] for [points] permanent points!"
not-block: "You must be holding a placeable block to donate."
confirm-prompt: "About to DESTROY [number] x [material] for [points] permanent points."
+ inv:
+ keyword: "inv"
+ confirm-header: "Tyto bloky budou ZNIČENY z tvého inventáře:"
+ confirm-line: "[number] x [material] = [points] bodů"
+ confirm-total: "Celkem: [points] trvalých bodů."
detail:
description: "zobrazit podrobnosti o blocích vašeho ostrova"
top:
diff --git a/src/main/resources/locales/de.yml b/src/main/resources/locales/de.yml
index b05dab9..75ebec9 100644
--- a/src/main/resources/locales/de.yml
+++ b/src/main/resources/locales/de.yml
@@ -68,6 +68,11 @@ island:
success: "Donated [number] x [material] for [points] permanent points!"
not-block: "You must be holding a placeable block to donate."
confirm-prompt: "About to DESTROY [number] x [material] for [points] permanent points."
+ inv:
+ keyword: "inv"
+ confirm-header: "Diese Blöcke werden aus deinem Inventar ZERSTÖRT:"
+ confirm-line: "[number] x [material] = [points] Punkte"
+ confirm-total: "Gesamt: [points] permanente Punkte."
detail:
description: "zeigt Details der Blöcke deiner Insel"
top:
diff --git a/src/main/resources/locales/en-US.yml b/src/main/resources/locales/en-US.yml
index ff81550..e18ba4a 100755
--- a/src/main/resources/locales/en-US.yml
+++ b/src/main/resources/locales/en-US.yml
@@ -52,7 +52,7 @@ island:
in-progress: "Island level calculation is in progress..."
time-out: "The level calculation took too long. Please try again later."
donate:
- parameters: "[hand [amount]]"
+ parameters: "[hand [amount]] [inv]"
description: "donate blocks to permanently raise island level"
must-be-on-island: "You must be on your island to donate blocks."
no-permission: "You do not have permission to donate blocks on this island."
@@ -72,6 +72,11 @@ island:
success: "Donated [number] x [material] for [points] permanent points!"
not-block: "You must be holding a placeable block to donate."
confirm-prompt: "About to DESTROY [number] x [material] for [points] permanent points."
+ inv:
+ keyword: "inv"
+ confirm-header: "About to DESTROY these blocks from your inventory:"
+ confirm-line: "[number] x [material] = [points] points"
+ confirm-total: "Total: [points] permanent points."
detail:
description: "shows detail of your island blocks"
top:
diff --git a/src/main/resources/locales/es.yml b/src/main/resources/locales/es.yml
index 0d93e3f..8571223 100644
--- a/src/main/resources/locales/es.yml
+++ b/src/main/resources/locales/es.yml
@@ -65,6 +65,11 @@ island:
success: "Donated [number] x [material] for [points] permanent points!"
not-block: "You must be holding a placeable block to donate."
confirm-prompt: "About to DESTROY [number] x [material] for [points] permanent points."
+ inv:
+ keyword: "inv"
+ confirm-header: "Estos bloques serán DESTRUIDOS de tu inventario:"
+ confirm-line: "[number] x [material] = [points] puntos"
+ confirm-total: "Total: [points] puntos permanentes."
detail:
description: "muestra el detalle de los bloques de tu isla"
top:
diff --git a/src/main/resources/locales/fr.yml b/src/main/resources/locales/fr.yml
index e1265d1..d939b6b 100644
--- a/src/main/resources/locales/fr.yml
+++ b/src/main/resources/locales/fr.yml
@@ -67,6 +67,11 @@ island:
success: "Donated [number] x [material] for [points] permanent points!"
not-block: "You must be holding a placeable block to donate."
confirm-prompt: "About to DESTROY [number] x [material] for [points] permanent points."
+ inv:
+ keyword: "inv"
+ confirm-header: "Ces blocs vont être DÉTRUITS de votre inventaire :"
+ confirm-line: "[number] x [material] = [points] points"
+ confirm-total: "Total : [points] points permanents."
top:
description: affiche le top 10
gui-title: "Top 10"
diff --git a/src/main/resources/locales/hu.yml b/src/main/resources/locales/hu.yml
index 7be400a..e9113e5 100644
--- a/src/main/resources/locales/hu.yml
+++ b/src/main/resources/locales/hu.yml
@@ -68,6 +68,11 @@ island:
success: "Donated [number] x [material] for [points] permanent points!"
not-block: "You must be holding a placeable block to donate."
confirm-prompt: "About to DESTROY [number] x [material] for [points] permanent points."
+ inv:
+ keyword: "inv"
+ confirm-header: "Ezeket a blokkokat MEGSEMMISÍTI a leltáradból:"
+ confirm-line: "[number] x [material] = [points] pont"
+ confirm-total: "Összesen: [points] állandó pont."
detail:
description: "megmutatja a szigeted blokkjainak részleteit"
top:
diff --git a/src/main/resources/locales/id.yml b/src/main/resources/locales/id.yml
index 539666b..ff360f0 100644
--- a/src/main/resources/locales/id.yml
+++ b/src/main/resources/locales/id.yml
@@ -65,6 +65,11 @@ island:
success: "Donated [number] x [material] for [points] permanent points!"
not-block: "You must be holding a placeable block to donate."
confirm-prompt: "About to DESTROY [number] x [material] for [points] permanent points."
+ inv:
+ keyword: "inv"
+ confirm-header: "Akan MENGHANCURKAN blok-blok ini dari inventaris Anda:"
+ confirm-line: "[number] x [material] = [points] poin"
+ confirm-total: "Total: [points] poin permanen."
top:
description: menunjukkan Sepuluh Besar
gui-title: " Sepuluh Besar"
diff --git a/src/main/resources/locales/ko.yml b/src/main/resources/locales/ko.yml
index f846737..073e26c 100644
--- a/src/main/resources/locales/ko.yml
+++ b/src/main/resources/locales/ko.yml
@@ -68,6 +68,11 @@ island:
success: "Donated [number] x [material] for [points] permanent points!"
not-block: "You must be holding a placeable block to donate."
confirm-prompt: "About to DESTROY [number] x [material] for [points] permanent points."
+ inv:
+ keyword: "inv"
+ confirm-header: "인벤토리에서 다음 블록을 파괴합니다:"
+ confirm-line: "[number] x [material] = [points] 점"
+ confirm-total: "총: [points] 영구 점수."
detail:
description: "섬 블록의 세부 정보를 표시합니다"
top:
diff --git a/src/main/resources/locales/lv.yml b/src/main/resources/locales/lv.yml
index 7ec2474..a9f6feb 100644
--- a/src/main/resources/locales/lv.yml
+++ b/src/main/resources/locales/lv.yml
@@ -68,6 +68,11 @@ island:
success: "Donated [number] x [material] for [points] permanent points!"
not-block: "You must be holding a placeable block to donate."
confirm-prompt: "About to DESTROY [number] x [material] for [points] permanent points."
+ inv:
+ keyword: "inv"
+ confirm-header: "Šie bloki tiks IZNĪCINĀTI no tavas somas:"
+ confirm-line: "[number] x [material] = [points] punkti"
+ confirm-total: "Kopā: [points] pastāvīgi punkti."
detail:
description: "rāda tavas salas bloku detaļas"
top:
diff --git a/src/main/resources/locales/nl.yml b/src/main/resources/locales/nl.yml
index 324b896..9ddd410 100644
--- a/src/main/resources/locales/nl.yml
+++ b/src/main/resources/locales/nl.yml
@@ -65,6 +65,11 @@ island:
success: "Donated [number] x [material] for [points] permanent points!"
not-block: "You must be holding a placeable block to donate."
confirm-prompt: "About to DESTROY [number] x [material] for [points] permanent points."
+ inv:
+ keyword: "inv"
+ confirm-header: "Deze blokken worden VERNIETIGD uit je inventaris:"
+ confirm-line: "[number] x [material] = [points] punten"
+ confirm-total: "Totaal: [points] permanente punten."
top:
description: Toon de Top tien
gui-title: " Top tien"
diff --git a/src/main/resources/locales/pl.yml b/src/main/resources/locales/pl.yml
index da6ad80..67b6940 100644
--- a/src/main/resources/locales/pl.yml
+++ b/src/main/resources/locales/pl.yml
@@ -65,6 +65,11 @@ island:
success: "Donated [number] x [material] for [points] permanent points!"
not-block: "You must be holding a placeable block to donate."
confirm-prompt: "About to DESTROY [number] x [material] for [points] permanent points."
+ inv:
+ keyword: "inv"
+ confirm-header: "Te bloki zostaną ZNISZCZONE z twojego ekwipunku:"
+ confirm-line: "[number] x [material] = [points] punktów"
+ confirm-total: "Łącznie: [points] punktów stałych."
top:
description: pokauje Top 10 wysp
gui-title: "Top 10"
diff --git a/src/main/resources/locales/pt.yml b/src/main/resources/locales/pt.yml
index 57fbabe..ffb289c 100644
--- a/src/main/resources/locales/pt.yml
+++ b/src/main/resources/locales/pt.yml
@@ -68,6 +68,11 @@ island:
success: "Donated [number] x [material] for [points] permanent points!"
not-block: "You must be holding a placeable block to donate."
confirm-prompt: "About to DESTROY [number] x [material] for [points] permanent points."
+ inv:
+ keyword: "inv"
+ confirm-header: "Estes blocos serão DESTRUÍDOS do seu inventário:"
+ confirm-line: "[number] x [material] = [points] pontos"
+ confirm-total: "Total: [points] pontos permanentes."
detail:
description: "mostra os detalhes dos blocos da sua ilha"
top:
diff --git a/src/main/resources/locales/ru.yml b/src/main/resources/locales/ru.yml
index 2dc53da..e483b21 100644
--- a/src/main/resources/locales/ru.yml
+++ b/src/main/resources/locales/ru.yml
@@ -68,6 +68,11 @@ island:
success: "Donated [number] x [material] for [points] permanent points!"
not-block: "You must be holding a placeable block to donate."
confirm-prompt: "About to DESTROY [number] x [material] for [points] permanent points."
+ inv:
+ keyword: "inv"
+ confirm-header: "Эти блоки будут УНИЧТОЖЕНЫ из вашего инвентаря:"
+ confirm-line: "[number] x [material] = [points] очков"
+ confirm-total: "Всего: [points] постоянных очков."
detail:
description: показать информацию о блоках на вашем острове
top:
diff --git a/src/main/resources/locales/tr.yml b/src/main/resources/locales/tr.yml
index 689f9b8..2f8ae2b 100644
--- a/src/main/resources/locales/tr.yml
+++ b/src/main/resources/locales/tr.yml
@@ -72,6 +72,11 @@ island:
success: "Donated [number] x [material] for [points] permanent points!"
not-block: "You must be holding a placeable block to donate."
confirm-prompt: "About to DESTROY [number] x [material] for [points] permanent points."
+ inv:
+ keyword: "inv"
+ confirm-header: "Envanterinizden bu bloklar YOK EDİLECEK:"
+ confirm-line: "[number] x [material] = [points] puan"
+ confirm-total: "Toplam: [points]