From 9d58d8f3770f594683e9d2aef0cc758010e7797a Mon Sep 17 00:00:00 2001 From: adrian Date: Thu, 1 Jan 2026 00:12:14 -0300 Subject: [PATCH 01/12] Added support for Ender Chest item lookup. --- .../io/github/adrianvic/itemeconomy/Main.java | 95 +++++++++++++++---- .../adrianvic/itemeconomy/VaultLayer.java | 17 ++-- 2 files changed, 83 insertions(+), 29 deletions(-) diff --git a/src/main/java/io/github/adrianvic/itemeconomy/Main.java b/src/main/java/io/github/adrianvic/itemeconomy/Main.java index 63b19f9..219be38 100644 --- a/src/main/java/io/github/adrianvic/itemeconomy/Main.java +++ b/src/main/java/io/github/adrianvic/itemeconomy/Main.java @@ -1,13 +1,12 @@ package io.github.adrianvic.itemeconomy; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; +import java.util.*; + import net.milkbowl.vault.economy.Economy; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.ServicePriority; import org.bukkit.plugin.java.JavaPlugin; @@ -22,29 +21,87 @@ public class Main extends JavaPlugin { super.onDisable(); } - public static List getInventory(Player player) { - return Arrays.stream(player.getInventory().getContents()).map((o) -> { + public enum InventoryID { + INVENTORY, + ENDER_CHEST + } + + public static List getInventory(Player player, InventoryID inventory) { + Inventory inv = player.getInventory(); + + switch (inventory) { + case INVENTORY -> { + inv = player.getInventory(); + } + case ENDER_CHEST -> { + inv = player.getEnderChest(); + } + } + + return Arrays.stream(inv.getContents()).map((o) -> { return o == null ? new ItemStack(Material.AIR) : o; }).toList(); } - public static boolean removeItems(Player player, Material type, int amount) { - if (player.getInventory().all(type).values().stream().mapToInt(ItemStack::getAmount).sum() < amount) { - return false; - } else { - player.getInventory().removeItem(new ItemStack[]{new ItemStack(type, amount)}); - return true; - } + public static List getInventory(Player player) { + return getInventory(player, InventoryID.INVENTORY); } + public static double getBalance(Player player, InventoryID inventory) { + return (double)getInventory(player, inventory).stream().filter(Objects::nonNull).filter((i) -> { + return i.getType().equals(Config.ITEM); + }).mapToInt(ItemStack::getAmount).sum(); + } + + public static double getBalance(Player player) { + Double total = 0.0D; + + for (InventoryID id : InventoryID.values()) { + total += getBalance(player, id); + } + + return total; + } + + public static double getBalance(String player) { + return getBalance(Bukkit.getPlayer(player)); + } + + public static boolean removeItems(Player player, Material type, int amount) { + int remaining = amount; + + remaining = removeFrom(player.getInventory(), type, remaining); + if (remaining > 0) { + remaining = removeFrom(player.getEnderChest(), type, remaining); + } + + return remaining == 0; + } + + private static int removeFrom(Inventory inv, Material type, int amount) { + if (amount <= 0) return 0; + + for (ItemStack stack : inv.all(type).values()) { + int take = Math.min(stack.getAmount(), amount); + stack.setAmount(stack.getAmount() - take); + amount -= take; + if (amount == 0) break; + } + + return amount; + } + + public static void addItems(Player player, Material type, int amount) { - HashMap nope = player.getInventory().addItem(new ItemStack[]{new ItemStack(type, amount)}); - Iterator var4 = nope.values().iterator(); + HashMap invOverflow = player.getInventory().addItem(new ItemStack(type, amount)); + HashMap echestOverflow = player.getEnderChest().addItem(new ItemStack(type, invOverflow.values() + .stream() + .mapToInt(ItemStack::getAmount) + .sum())); - while(var4.hasNext()) { - ItemStack v = (ItemStack)var4.next(); - player.getWorld().dropItemNaturally(player.getLocation(), v); + + for (ItemStack overflow : echestOverflow.values()){ + player.getWorld().dropItemNaturally(player.getLocation(), overflow); } - } } diff --git a/src/main/java/io/github/adrianvic/itemeconomy/VaultLayer.java b/src/main/java/io/github/adrianvic/itemeconomy/VaultLayer.java index cc1260d..665dc8c 100644 --- a/src/main/java/io/github/adrianvic/itemeconomy/VaultLayer.java +++ b/src/main/java/io/github/adrianvic/itemeconomy/VaultLayer.java @@ -16,7 +16,7 @@ public class VaultLayer implements Economy { } public String getName() { - return "ItemEconomy"; + return "ItemEconomy II"; } public boolean hasBankSupport() { @@ -44,14 +44,11 @@ public class VaultLayer implements Economy { } public double getBalance(String playerName) { - Player player = Bukkit.getPlayer(playerName); - return player != null ? (double)Main.getInventory(player).stream().filter(Objects::nonNull).filter((i) -> { - return i.getType().equals(Config.ITEM); - }).mapToInt(ItemStack::getAmount).sum() : 0.0D; + return Main.getBalance(playerName); } public boolean has(String playerName, double amount) { - return this.getBalance(playerName) >= amount; + return Main.getBalance(playerName) >= amount; } public EconomyResponse withdrawPlayer(String playerName, double amount) { @@ -60,13 +57,13 @@ public class VaultLayer implements Economy { } else if (amount < 0.0D) { return this.depositPlayer(playerName, -amount); } else if (!this.has(playerName, amount)) { - return new EconomyResponse(amount, this.getBalance(playerName), ResponseType.FAILURE, "Недостаточно средств"); + return new EconomyResponse(amount, this.getBalance(playerName), ResponseType.FAILURE, "Insufficient founds."); } else { Player player; if ((player = Bukkit.getPlayer(playerName)) == null) { - return new EconomyResponse(amount, this.getBalance(playerName), ResponseType.FAILURE, "Игрок офлайн"); + return new EconomyResponse(amount, this.getBalance(playerName), ResponseType.FAILURE, "This player is offline."); } else { - return !Main.removeItems(player, Config.ITEM, (int)amount) ? new EconomyResponse(amount, this.getBalance(playerName), ResponseType.FAILURE, "Недостаточно средств") : new EconomyResponse(amount, this.getBalance(playerName), ResponseType.SUCCESS, (String)null); + return !Main.removeItems(player, Config.ITEM, (int)amount) ? new EconomyResponse(amount, this.getBalance(playerName), ResponseType.FAILURE, "Insufficient founds.") : new EconomyResponse(amount, this.getBalance(playerName), ResponseType.SUCCESS, (String)null); } } } @@ -79,7 +76,7 @@ public class VaultLayer implements Economy { } else { Player player; if ((player = Bukkit.getPlayer(playerName)) == null) { - return new EconomyResponse(amount, this.getBalance(playerName), ResponseType.FAILURE, "Игрок офлайн"); + return new EconomyResponse(amount, this.getBalance(playerName), ResponseType.FAILURE, "This player is offline."); } else { Main.addItems(player, Config.ITEM, (int)amount); return new EconomyResponse(amount, this.getBalance(playerName), ResponseType.SUCCESS, (String)null); From f04001176aa6d144b1be917446dcce3a18a379f8 Mon Sep 17 00:00:00 2001 From: adrian Date: Thu, 1 Jan 2026 15:35:46 -0300 Subject: [PATCH 02/12] Bumped version to `1.1`. Rewrite of config loading to support automatic missing field writing, reloading. Economy item Material is now provided by Config. Ender Chest support can now be disabled, `getInventory` (renamed to `getInventoryList`, the old method now returns an instance of Inventory) now returns an empty Inventory instance if Ender Chest is disabled. --- README.md | 13 ++-- .../github/adrianvic/itemeconomy/Config.java | 66 +++++++++++++++---- .../io/github/adrianvic/itemeconomy/Main.java | 38 +++++++---- .../adrianvic/itemeconomy/VaultLayer.java | 12 ++-- .../itemeconomy/commands/Reload.java | 22 +++++++ src/main/resources/plugin.yml | 7 +- 6 files changed, 123 insertions(+), 35 deletions(-) create mode 100644 src/main/java/io/github/adrianvic/itemeconomy/commands/Reload.java diff --git a/README.md b/README.md index f2fa45e..2da59ea 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,22 @@ # ItemEconomy II -ItemEconomy II is a fork of [ItemEconomy](https://modrinth.com/plugin/itemeconomy), keeping it updated to later versions of Minecraft. +ItemEconomy II is a fork of [ItemEconomy](https://modrinth.com/plugin/itemeconomy), keeping it updated to later versions of Minecraft and adding new features. This PaperMC plugin integrates with Vault to provide a unique, item-based economy system for your Minecraft server. Instead of relying solely on virtual balances, players use in-game items as physical currency, adding a layer of immersion and realism to your economy. Features: - Item-Based Currency: Set any Minecraft item as your server's currency (default: diamonds). -- Vault Integration: Fully compatible with Vault, enabling seamless interaction with other economy-based plugins. +- VaultUnlocked Integration: Fully compatible with VaultUnlocked, enabling seamless interaction with other economy-based plugins. +- Simple logic: Just checks if the user has the item/how many when queried. - Customizable Formatting: Define how your currency is displayed, including singular and plural forms. +- Ender Chest support: Items on Ender Chests are counted in the user balance. ## Configuration Example: ```yaml -item: "diamond" # Define the item to be used as currency. -singular: "diamond" # Singular form of the currency. -plural: "diamonds" # Plural form of the currency. +item: diamond # Define the item to be used as currency. +singular: diamond # Singular form of the currency. +plural: diamonds # Plural form of the currency. format: "{}$" # Customize how the currency is displayed in messages. +ender_chest: balance # Either none or balance ``` This configuration will use diamonds as the currency, displayed as {amount}$, e.g., "5 diamonds" or "1 diamond". diff --git a/src/main/java/io/github/adrianvic/itemeconomy/Config.java b/src/main/java/io/github/adrianvic/itemeconomy/Config.java index 2f2bb4f..f564ac4 100644 --- a/src/main/java/io/github/adrianvic/itemeconomy/Config.java +++ b/src/main/java/io/github/adrianvic/itemeconomy/Config.java @@ -2,16 +2,60 @@ package io.github.adrianvic.itemeconomy; import org.bukkit.Material; -public class Config { - public static Material ITEM; - public static String FORMAT; - public static String PLURAL; - public static String SINGULAR; +import java.util.HashMap; +import java.util.Map; - public static void loadConfig(UnrealConfig conf) { - ITEM = Material.valueOf(((String)conf.get("item")).toUpperCase()); - FORMAT = (String)conf.get("format"); - PLURAL = (String)conf.get("plural"); - SINGULAR = (String)conf.get("singular"); - } +public class Config { + private static Map entries = new HashMap<>(); + private static UnrealConfig uConf; + + public static void loadConfig(UnrealConfig conf) { + uConf = conf; + entries.put("item", "diamond"); + entries.put("format", "{}$"); + entries.put("plural", "diamonds"); + entries.put("singular", "diamond"); + entries.put("ender_chest", "balance"); + + Map missingValues = new HashMap<>(); + + for (Map.Entry e : entries.entrySet()) { + String val = (String) conf.get(e.getKey()); + + if (val != null) { + entries.put(e.getKey(), val); + } else { + missingValues.put(e.getKey(), e.getValue()); + } + } + + missingValues.forEach((key, value) -> { + conf.put(key, value); + Main.getInstance().getLogger().info("Generating new config entry that was missing: %s: %s".formatted(key, value)); + }); + conf.save(); + } + + public static String get(String entry) { + return entries.get(entry); + } + + public static boolean is(String entry, String value) { + return entries.get(entry).equals(value); + } + + public static UnrealConfig getuConf() { + return uConf; + } + + public static Material ecoItem() { + try { + return Material.valueOf(Config.get("item").toUpperCase()); + } catch (IllegalArgumentException e) { + Main.getInstance().getLogger().warning("Invalid item was set as economy item, disabling."); + Main.getInstance().getServer().getPluginManager().disablePlugin(Main.getInstance()); + } + + return Material.DIAMOND; + } } diff --git a/src/main/java/io/github/adrianvic/itemeconomy/Main.java b/src/main/java/io/github/adrianvic/itemeconomy/Main.java index 219be38..4ff0506 100644 --- a/src/main/java/io/github/adrianvic/itemeconomy/Main.java +++ b/src/main/java/io/github/adrianvic/itemeconomy/Main.java @@ -2,6 +2,7 @@ package io.github.adrianvic.itemeconomy; import java.util.*; +import io.github.adrianvic.itemeconomy.commands.Reload; import net.milkbowl.vault.economy.Economy; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -12,9 +13,17 @@ import org.bukkit.plugin.ServicePriority; import org.bukkit.plugin.java.JavaPlugin; public class Main extends JavaPlugin { + private static Main instance; + public void onEnable() { + instance = this; Config.loadConfig(new UnrealConfig(this, this.getDataFolder(), "config.yml")); Bukkit.getServicesManager().register(Economy.class, new VaultLayer(), this, ServicePriority.High); + getCommand("itecoreload").setExecutor(new Reload()); + } + + public static JavaPlugin getInstance() { + return instance; } public void onDisable() { @@ -26,7 +35,7 @@ public class Main extends JavaPlugin { ENDER_CHEST } - public static List getInventory(Player player, InventoryID inventory) { + public static Inventory getInventory(Player player, InventoryID inventory) { Inventory inv = player.getInventory(); switch (inventory) { @@ -34,22 +43,29 @@ public class Main extends JavaPlugin { inv = player.getInventory(); } case ENDER_CHEST -> { - inv = player.getEnderChest(); + if (Config.is("ender_chest", "balance")) { + inv = player.getEnderChest(); + } else { + inv = getInstance().getServer().createInventory(null, 9); + } } } - return Arrays.stream(inv.getContents()).map((o) -> { - return o == null ? new ItemStack(Material.AIR) : o; - }).toList(); + return inv; } - public static List getInventory(Player player) { - return getInventory(player, InventoryID.INVENTORY); + public static List getInventoryList(Player player, InventoryID inventory) { + Inventory inv = getInventory(player, inventory); + return Arrays.stream(inv.getContents()).map((o) -> o == null ? new ItemStack(Material.AIR) : o).toList(); + } + + public static List getInventoryList(Player player) { + return getInventoryList(player, InventoryID.INVENTORY); } public static double getBalance(Player player, InventoryID inventory) { - return (double)getInventory(player, inventory).stream().filter(Objects::nonNull).filter((i) -> { - return i.getType().equals(Config.ITEM); + return (double) getInventoryList(player, inventory).stream().filter(Objects::nonNull).filter((i) -> { + return i.getType().equals(Config.ecoItem()); }).mapToInt(ItemStack::getAmount).sum(); } @@ -93,8 +109,8 @@ public class Main extends JavaPlugin { public static void addItems(Player player, Material type, int amount) { - HashMap invOverflow = player.getInventory().addItem(new ItemStack(type, amount)); - HashMap echestOverflow = player.getEnderChest().addItem(new ItemStack(type, invOverflow.values() + HashMap invOverflow = getInventory(player, InventoryID.INVENTORY).addItem(new ItemStack(type, amount)); + HashMap echestOverflow = getInventory(player, InventoryID.ENDER_CHEST).addItem(new ItemStack(type, invOverflow.values() .stream() .mapToInt(ItemStack::getAmount) .sum())); diff --git a/src/main/java/io/github/adrianvic/itemeconomy/VaultLayer.java b/src/main/java/io/github/adrianvic/itemeconomy/VaultLayer.java index 665dc8c..1dc88eb 100644 --- a/src/main/java/io/github/adrianvic/itemeconomy/VaultLayer.java +++ b/src/main/java/io/github/adrianvic/itemeconomy/VaultLayer.java @@ -1,14 +1,12 @@ package io.github.adrianvic.itemeconomy; import java.util.List; -import java.util.Objects; import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.economy.EconomyResponse; import net.milkbowl.vault.economy.EconomyResponse.ResponseType; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; public class VaultLayer implements Economy { public boolean isEnabled() { @@ -28,15 +26,15 @@ public class VaultLayer implements Economy { } public String format(double amount) { - return Config.FORMAT.replace("{}", String.valueOf(amount)); + return Config.get("format").replace("{}", String.valueOf(amount)); } public String currencyNamePlural() { - return Config.PLURAL; + return Config.get("plural"); } public String currencyNameSingular() { - return Config.SINGULAR; + return Config.get("singular"); } public boolean hasAccount(String playerName) { @@ -63,7 +61,7 @@ public class VaultLayer implements Economy { if ((player = Bukkit.getPlayer(playerName)) == null) { return new EconomyResponse(amount, this.getBalance(playerName), ResponseType.FAILURE, "This player is offline."); } else { - return !Main.removeItems(player, Config.ITEM, (int)amount) ? new EconomyResponse(amount, this.getBalance(playerName), ResponseType.FAILURE, "Insufficient founds.") : new EconomyResponse(amount, this.getBalance(playerName), ResponseType.SUCCESS, (String)null); + return !Main.removeItems(player, Config.ecoItem(), (int)amount) ? new EconomyResponse(amount, this.getBalance(playerName), ResponseType.FAILURE, "Insufficient founds.") : new EconomyResponse(amount, this.getBalance(playerName), ResponseType.SUCCESS, (String)null); } } } @@ -78,7 +76,7 @@ public class VaultLayer implements Economy { if ((player = Bukkit.getPlayer(playerName)) == null) { return new EconomyResponse(amount, this.getBalance(playerName), ResponseType.FAILURE, "This player is offline."); } else { - Main.addItems(player, Config.ITEM, (int)amount); + Main.addItems(player, Config.ecoItem(), (int)amount); return new EconomyResponse(amount, this.getBalance(playerName), ResponseType.SUCCESS, (String)null); } } diff --git a/src/main/java/io/github/adrianvic/itemeconomy/commands/Reload.java b/src/main/java/io/github/adrianvic/itemeconomy/commands/Reload.java new file mode 100644 index 0000000..804e6ed --- /dev/null +++ b/src/main/java/io/github/adrianvic/itemeconomy/commands/Reload.java @@ -0,0 +1,22 @@ +package io.github.adrianvic.itemeconomy.commands; + +import io.github.adrianvic.itemeconomy.Config; +import io.github.adrianvic.itemeconomy.Main; +import io.github.adrianvic.itemeconomy.UnrealConfig; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; + +public class Reload implements CommandExecutor { + + @Override + public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String @NotNull [] strings) { + try { + Config.loadConfig(new UnrealConfig(Main.getInstance(), Main.getInstance().getDataFolder(), "config.yml")); + return true; + } catch (Exception e) { + return false; + } + } +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 60f5404..eeb2443 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,6 +1,11 @@ name: ItemEconomy main: io.github.adrianvic.itemeconomy.Main -version: 1.0 +version: 1.1 depend: - Vault api-version: '1.21' +commands: + itecoreload: + description: Reloads the config for ItemEconomy + usage: /itecoreload + permission: iteco.reload \ No newline at end of file From 6d06921b21e54430e4f749ce08fa6b62998a02c7 Mon Sep 17 00:00:00 2001 From: Tenkuma <85490958+adrianvic@users.noreply.github.com> Date: Thu, 1 Jan 2026 17:57:52 -0300 Subject: [PATCH 03/12] Better formatting of README.md. --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2da59ea..2fcbe6d 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ # ItemEconomy II ItemEconomy II is a fork of [ItemEconomy](https://modrinth.com/plugin/itemeconomy), keeping it updated to later versions of Minecraft and adding new features. -This PaperMC plugin integrates with Vault to provide a unique, item-based economy system for your Minecraft server. Instead of relying solely on virtual balances, players use in-game items as physical currency, adding a layer of immersion and realism to your economy. +This PaperMC plugin integrates with VaultUnlocked to provide a unique, item-based economy system for your Minecraft server. Instead of relying solely on virtual balances, players use in-game items as physical currency, adding a layer of immersion and realism to your economy. Features: -- Item-Based Currency: Set any Minecraft item as your server's currency (default: diamonds). -- VaultUnlocked Integration: Fully compatible with VaultUnlocked, enabling seamless interaction with other economy-based plugins. -- Simple logic: Just checks if the user has the item/how many when queried. -- Customizable Formatting: Define how your currency is displayed, including singular and plural forms. -- Ender Chest support: Items on Ender Chests are counted in the user balance. +- **Item-Based Currency:** Set any Minecraft item as your server's currency (default: diamonds). +- **VaultUnlocked Integration:** Fully compatible with VaultUnlocked, enabling seamless interaction with other economy-based plugins. +- **Simple logic:** Just checks if the user has the item/how many when queried. +- **Customizable Formatting:** Define how your currency is displayed, including singular and plural forms. +- **Ender Chest support:** Items on Ender Chests are counted in the user balance. ## Configuration Example: ```yaml From 717f1b9a1a7fe430975a06d667c5187d75d74b45 Mon Sep 17 00:00:00 2001 From: adrian Date: Fri, 2 Jan 2026 20:55:50 -0300 Subject: [PATCH 04/12] Bumped version to `1.2`. Added `/balance` and `/pay` commands and a config option to enable them. Added safeIs method to Config to match values without case sensitivity. Added getCurrencyText method to Config to generate a formatted string from a currency amount. Value 'format' from config file now supports amount-name replacement. Main now stores the instance of VaultLayer for further use. --- README.md | 5 +- .../github/adrianvic/itemeconomy/Config.java | 14 +- .../io/github/adrianvic/itemeconomy/Main.java | 176 +++++++++--------- .../adrianvic/itemeconomy/VaultLayer.java | 2 +- .../itemeconomy/commands/Balance.java | 49 +++++ .../adrianvic/itemeconomy/commands/Pay.java | 74 ++++++++ src/main/resources/config.yml | 3 +- src/main/resources/plugin.yml | 31 ++- 8 files changed, 261 insertions(+), 93 deletions(-) create mode 100644 src/main/java/io/github/adrianvic/itemeconomy/commands/Balance.java create mode 100644 src/main/java/io/github/adrianvic/itemeconomy/commands/Pay.java diff --git a/README.md b/README.md index 2da59ea..e0fae43 100644 --- a/README.md +++ b/README.md @@ -9,15 +9,18 @@ Features: - Simple logic: Just checks if the user has the item/how many when queried. - Customizable Formatting: Define how your currency is displayed, including singular and plural forms. - Ender Chest support: Items on Ender Chests are counted in the user balance. +- Built-int optional balance and pay commands with support for permissions. ## Configuration Example: ```yaml item: diamond # Define the item to be used as currency. singular: diamond # Singular form of the currency. plural: diamonds # Plural form of the currency. -format: "{}$" # Customize how the currency is displayed in messages. +format: "{} $" # {} will be replaced with the amount and $ either with singular or plural ender_chest: balance # Either none or balance +commands: true # Disabling this will disable /balance and /pay ``` + This configuration will use diamonds as the currency, displayed as {amount}$, e.g., "5 diamonds" or "1 diamond". ## Usage: diff --git a/src/main/java/io/github/adrianvic/itemeconomy/Config.java b/src/main/java/io/github/adrianvic/itemeconomy/Config.java index f564ac4..4b57e6f 100644 --- a/src/main/java/io/github/adrianvic/itemeconomy/Config.java +++ b/src/main/java/io/github/adrianvic/itemeconomy/Config.java @@ -3,6 +3,7 @@ package io.github.adrianvic.itemeconomy; import org.bukkit.Material; import java.util.HashMap; +import java.util.Locale; import java.util.Map; public class Config { @@ -12,10 +13,11 @@ public class Config { public static void loadConfig(UnrealConfig conf) { uConf = conf; entries.put("item", "diamond"); - entries.put("format", "{}$"); + entries.put("format", "{} $"); entries.put("plural", "diamonds"); entries.put("singular", "diamond"); entries.put("ender_chest", "balance"); + entries.put("commands", "true"); Map missingValues = new HashMap<>(); @@ -44,6 +46,16 @@ public class Config { return entries.get(entry).equals(value); } + public static boolean safeIs(String entry, String value) { + return is(entry.toLowerCase(Locale.ROOT), value.toLowerCase(Locale.ROOT)); + } + + public static String getCurrencyText(int amount) { + return entries.get("format") + .replace("{}", String.valueOf(amount)) + .replace("$", (amount != 1) ? entries.get("plural") : entries.get("singular")); + } + public static UnrealConfig getuConf() { return uConf; } diff --git a/src/main/java/io/github/adrianvic/itemeconomy/Main.java b/src/main/java/io/github/adrianvic/itemeconomy/Main.java index 4ff0506..18dc263 100644 --- a/src/main/java/io/github/adrianvic/itemeconomy/Main.java +++ b/src/main/java/io/github/adrianvic/itemeconomy/Main.java @@ -2,6 +2,8 @@ package io.github.adrianvic.itemeconomy; import java.util.*; +import io.github.adrianvic.itemeconomy.commands.Balance; +import io.github.adrianvic.itemeconomy.commands.Pay; import io.github.adrianvic.itemeconomy.commands.Reload; import net.milkbowl.vault.economy.Economy; import org.bukkit.Bukkit; @@ -13,111 +15,117 @@ import org.bukkit.plugin.ServicePriority; import org.bukkit.plugin.java.JavaPlugin; public class Main extends JavaPlugin { - private static Main instance; + private static Main instance; + private static Economy economy; - public void onEnable() { - instance = this; - Config.loadConfig(new UnrealConfig(this, this.getDataFolder(), "config.yml")); - Bukkit.getServicesManager().register(Economy.class, new VaultLayer(), this, ServicePriority.High); - getCommand("itecoreload").setExecutor(new Reload()); - } + public void onEnable() { + instance = this; + Config.loadConfig(new UnrealConfig(this, this.getDataFolder(), "config.yml")); + economy = new VaultLayer(); + Bukkit.getServicesManager().register(Economy.class, economy, this, ServicePriority.High); - public static JavaPlugin getInstance() { - return instance; - } + getCommand("itecoreload").setExecutor(new Reload()); + if (Config.safeIs("commands", "true")) { + getCommand("balance").setExecutor(new Balance()); + getCommand("pay").setExecutor(new Pay()); + } + } - public void onDisable() { - super.onDisable(); - } + public void onDisable() { + super.onDisable(); + } - public enum InventoryID { - INVENTORY, - ENDER_CHEST - } + public static JavaPlugin getInstance() { + return instance; + } - public static Inventory getInventory(Player player, InventoryID inventory) { - Inventory inv = player.getInventory(); + public static Economy getEconomy() { + return economy; + } - switch (inventory) { - case INVENTORY -> { - inv = player.getInventory(); - } - case ENDER_CHEST -> { - if (Config.is("ender_chest", "balance")) { - inv = player.getEnderChest(); - } else { - inv = getInstance().getServer().createInventory(null, 9); + public enum InventoryID { + INVENTORY, + ENDER_CHEST + } + + public static Inventory getInventory(Player player, InventoryID inventory) { + Inventory inv = player.getInventory(); + + switch (inventory) { + case INVENTORY -> inv = player.getInventory(); + case ENDER_CHEST -> { + if (Config.is("ender_chest", "balance")) { + inv = player.getEnderChest(); + } else { + inv = getInstance().getServer().createInventory(null, 9); + } } - } - } + } - return inv; - } + return inv; + } - public static List getInventoryList(Player player, InventoryID inventory) { - Inventory inv = getInventory(player, inventory); - return Arrays.stream(inv.getContents()).map((o) -> o == null ? new ItemStack(Material.AIR) : o).toList(); - } + public static List getInventoryList(Player player, InventoryID inventory) { + Inventory inv = getInventory(player, inventory); + return Arrays.stream(inv.getContents()).map((o) -> o == null ? new ItemStack(Material.AIR) : o).toList(); + } - public static List getInventoryList(Player player) { - return getInventoryList(player, InventoryID.INVENTORY); - } + public static List getInventoryList(Player player) { + return getInventoryList(player, InventoryID.INVENTORY); + } - public static double getBalance(Player player, InventoryID inventory) { - return (double) getInventoryList(player, inventory).stream().filter(Objects::nonNull).filter((i) -> { - return i.getType().equals(Config.ecoItem()); - }).mapToInt(ItemStack::getAmount).sum(); - } + public static double getBalance(Player player, InventoryID inventory) { + return getInventoryList(player, inventory).stream().filter(Objects::nonNull).filter((i) -> i.getType().equals(Config.ecoItem())).mapToInt(ItemStack::getAmount).sum(); + } - public static double getBalance(Player player) { - Double total = 0.0D; + public static double getBalance(Player player) { + double total = 0.0D; - for (InventoryID id : InventoryID.values()) { - total += getBalance(player, id); - } + for (InventoryID id : InventoryID.values()) { + total += getBalance(player, id); + } - return total; - } + return total; + } - public static double getBalance(String player) { - return getBalance(Bukkit.getPlayer(player)); - } + public static double getBalance(String player) { + return getBalance(Bukkit.getPlayer(player)); + } - public static boolean removeItems(Player player, Material type, int amount) { - int remaining = amount; + public static boolean removeItems(Player player, Material type, int amount) { + int remaining = amount; - remaining = removeFrom(player.getInventory(), type, remaining); - if (remaining > 0) { - remaining = removeFrom(player.getEnderChest(), type, remaining); - } + remaining = removeFrom(player.getInventory(), type, remaining); + if (remaining > 0) { + remaining = removeFrom(player.getEnderChest(), type, remaining); + } - return remaining == 0; - } + return remaining == 0; + } - private static int removeFrom(Inventory inv, Material type, int amount) { - if (amount <= 0) return 0; + private static int removeFrom(Inventory inv, Material type, int amount) { + if (amount <= 0) return 0; - for (ItemStack stack : inv.all(type).values()) { - int take = Math.min(stack.getAmount(), amount); - stack.setAmount(stack.getAmount() - take); - amount -= take; - if (amount == 0) break; - } + for (ItemStack stack : inv.all(type).values()) { + int take = Math.min(stack.getAmount(), amount); + stack.setAmount(stack.getAmount() - take); + amount -= take; + if (amount == 0) break; + } - return amount; - } + return amount; + } + + public static void addItems(Player player, Material type, int amount) { + HashMap invOverflow = getInventory(player, InventoryID.INVENTORY).addItem(new ItemStack(type, amount)); + HashMap echestOverflow = getInventory(player, InventoryID.ENDER_CHEST).addItem(new ItemStack(type, invOverflow.values() + .stream() + .mapToInt(ItemStack::getAmount) + .sum())); - public static void addItems(Player player, Material type, int amount) { - HashMap invOverflow = getInventory(player, InventoryID.INVENTORY).addItem(new ItemStack(type, amount)); - HashMap echestOverflow = getInventory(player, InventoryID.ENDER_CHEST).addItem(new ItemStack(type, invOverflow.values() - .stream() - .mapToInt(ItemStack::getAmount) - .sum())); - - - for (ItemStack overflow : echestOverflow.values()){ - player.getWorld().dropItemNaturally(player.getLocation(), overflow); - } - } + for (ItemStack overflow : echestOverflow.values()) { + player.getWorld().dropItemNaturally(player.getLocation(), overflow); + } + } } diff --git a/src/main/java/io/github/adrianvic/itemeconomy/VaultLayer.java b/src/main/java/io/github/adrianvic/itemeconomy/VaultLayer.java index 1dc88eb..7810800 100644 --- a/src/main/java/io/github/adrianvic/itemeconomy/VaultLayer.java +++ b/src/main/java/io/github/adrianvic/itemeconomy/VaultLayer.java @@ -26,7 +26,7 @@ public class VaultLayer implements Economy { } public String format(double amount) { - return Config.get("format").replace("{}", String.valueOf(amount)); + return Config.getCurrencyText((int) amount); } public String currencyNamePlural() { diff --git a/src/main/java/io/github/adrianvic/itemeconomy/commands/Balance.java b/src/main/java/io/github/adrianvic/itemeconomy/commands/Balance.java new file mode 100644 index 0000000..e42b456 --- /dev/null +++ b/src/main/java/io/github/adrianvic/itemeconomy/commands/Balance.java @@ -0,0 +1,49 @@ +package io.github.adrianvic.itemeconomy.commands; + +import io.github.adrianvic.itemeconomy.Config; +import io.github.adrianvic.itemeconomy.Main; +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.stream.Collectors; + +public class Balance implements CommandExecutor, TabCompleter { + @Override + public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String @NotNull [] strings) { + if ((commandSender.isOp() || commandSender.hasPermission("iteco.balance.others")) && strings.length > 0) { + double amount = Main.getEconomy().getBalance(strings[0]); + commandSender.sendMessage("%s has %s.".formatted( + strings[0], + Config.getCurrencyText((int) amount) + )); + } else { + if (commandSender instanceof Player player) { + double amount = Main.getEconomy().getBalance(player); + commandSender.sendMessage("You have %s.".formatted( + Config.getCurrencyText((int) amount) + )); + } else { + commandSender.sendMessage("One must be a player to have a balance."); + } + } + return true; + } + + @Override + public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String @NotNull [] args) { + if ((sender.isOp() || sender.hasPermission("iteco.balance.others")) && args.length == 1) { + return Bukkit.getOnlinePlayers() + .stream() + .map(Player::getName) + .collect(Collectors.toList()); + } + return List.of(); + } +} diff --git a/src/main/java/io/github/adrianvic/itemeconomy/commands/Pay.java b/src/main/java/io/github/adrianvic/itemeconomy/commands/Pay.java new file mode 100644 index 0000000..f71a679 --- /dev/null +++ b/src/main/java/io/github/adrianvic/itemeconomy/commands/Pay.java @@ -0,0 +1,74 @@ +package io.github.adrianvic.itemeconomy.commands; + +import io.github.adrianvic.itemeconomy.Config; +import io.github.adrianvic.itemeconomy.Main; +import net.milkbowl.vault.economy.EconomyResponse; +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.stream.Collectors; + +public class Pay implements CommandExecutor, TabCompleter { + @Override + public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String @NotNull [] strings) { + if (strings.length < 2) { + commandSender.sendMessage(command.getUsage()); + return false; + } + + int amount; + + try { + amount = Integer.parseInt(strings[1]); + String amountString = Config.getCurrencyText(amount); + + if (commandSender instanceof Player player && Main.getEconomy().has(player, amount)) { + if (Bukkit.getPlayer(strings[0]) instanceof Player target) { + EconomyResponse withdrawResponse = Main.getEconomy().withdrawPlayer(player.getName(), amount); + if (withdrawResponse.transactionSuccess()) { + EconomyResponse depositResponse = Main.getEconomy().depositPlayer(target.getName(), amount); + if (depositResponse.transactionSuccess()) { + commandSender.sendMessage("Transaction of %s to %s was successfully realized.".formatted(amountString, target.getName())); + target.sendMessage("You received %s from %s.".formatted(amountString, player.getName())); + } else { + commandSender.sendMessage("Could not realize transaction: %s".formatted(depositResponse.errorMessage)); + Main.getEconomy().depositPlayer(player.getName(), amount); + } + } else { + commandSender.sendMessage("Could not realize transaction: %s".formatted(withdrawResponse.errorMessage)); + } + } else { + commandSender.sendMessage("Could not find target player."); + } + } else { + commandSender.sendMessage("You don't have enough money."); + } + } catch (NumberFormatException nfe) { + commandSender.sendMessage("The amount you tried to pay is not valid."); + return true; + } + + return true; + } + + @Override + public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String @NotNull [] args) { + if (sender instanceof Player player) { + if (args.length == 1) { + return Bukkit.getOnlinePlayers() + .stream() + .map(Player::getName) + .collect(Collectors.toList()); + } + } + + return List.of(); + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index f4834d2..49262a7 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,4 +1,5 @@ item: "diamond" singular: "diamond" plural: "diamonds" -format: "{}$" \ No newline at end of file +format: "{} $" +commands: "true" \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index eeb2443..e78d2d1 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,11 +1,32 @@ name: ItemEconomy main: io.github.adrianvic.itemeconomy.Main -version: 1.1 -depend: -- Vault +version: 1.2 +depend: [Vault] api-version: '1.21' commands: itecoreload: description: Reloads the config for ItemEconomy - usage: /itecoreload - permission: iteco.reload \ No newline at end of file + usage: "/itecoreload" + permission: iteco.reload + default: op + balance: + description: Prints your balance + usage: "/balance" + aliases: [bal] + permission: iteco.balance + pay: + description: Transfers money from your balance to other player + usage: "/pay " + permission: iteco.pay +permissions: + iteco.reload: + description: "Permission to use the command '/itecoreload'." + default: false + iteco.balance: + description: "Permission to use the command '/balance'." + default: true + children: + iteco.balance.others: false + iteco.pay: + description: "Permission to use the command '/pay'." + default: true \ No newline at end of file From d64bc1a14446a0322026c72ab7a6232401125fac Mon Sep 17 00:00:00 2001 From: Tenkuma <85490958+adrianvic@users.noreply.github.com> Date: Fri, 2 Jan 2026 21:25:41 -0300 Subject: [PATCH 05/12] Added logo to README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 341faa1..23e865b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,8 @@ # ItemEconomy II +

+image +

+ ItemEconomy II is a fork of [ItemEconomy](https://modrinth.com/plugin/itemeconomy), keeping it updated to later versions of Minecraft and adding new features. This PaperMC plugin integrates with VaultUnlocked to provide a unique, item-based economy system for your Minecraft server. Instead of relying solely on virtual balances, players use in-game items as physical currency, adding a layer of immersion and realism to your economy. @@ -21,7 +25,7 @@ ender_chest: balance # Either none or balance commands: true # Disabling this will disable /balance and /pay ``` -This configuration will use diamonds as the currency, displayed as {amount}$, e.g., "5 diamonds" or "1 diamond". +This configuration will use diamonds as the currency, displayed as {amount} {name}, e.g., "5 diamonds" or "1 diamond". ## Usage: From dfbf218aba3f8ec37c844db7d9ebc1865a8e264f Mon Sep 17 00:00:00 2001 From: adrian Date: Sat, 3 Jan 2026 23:16:57 -0300 Subject: [PATCH 06/12] Added support for localization and localization for Portuguese. Added support for item name localization. --- .../github/adrianvic/itemeconomy/Config.java | 59 +++++++++++++++++-- .../io/github/adrianvic/itemeconomy/Main.java | 5 ++ .../adrianvic/itemeconomy/Messages.java | 47 +++++++++++++++ .../itemeconomy/commands/Balance.java | 16 ++--- .../adrianvic/itemeconomy/commands/Pay.java | 21 ++++--- .../adrianvic/itemeconomy/commands/Utils.java | 15 +++++ src/main/resources/config.yml | 8 ++- src/main/resources/messages.properties | 10 ++++ src/main/resources/messages_en.properties | 10 ++++ src/main/resources/messages_pt.properties | 10 ++++ 10 files changed, 176 insertions(+), 25 deletions(-) create mode 100644 src/main/java/io/github/adrianvic/itemeconomy/Messages.java create mode 100644 src/main/java/io/github/adrianvic/itemeconomy/commands/Utils.java create mode 100644 src/main/resources/messages.properties create mode 100644 src/main/resources/messages_en.properties create mode 100644 src/main/resources/messages_pt.properties diff --git a/src/main/java/io/github/adrianvic/itemeconomy/Config.java b/src/main/java/io/github/adrianvic/itemeconomy/Config.java index 4b57e6f..b5dac25 100644 --- a/src/main/java/io/github/adrianvic/itemeconomy/Config.java +++ b/src/main/java/io/github/adrianvic/itemeconomy/Config.java @@ -1,10 +1,10 @@ package io.github.adrianvic.itemeconomy; +import org.bukkit.ChatColor; import org.bukkit.Material; +import org.bukkit.entity.Player; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; +import java.util.*; public class Config { private static Map entries = new HashMap<>(); @@ -18,6 +18,10 @@ public class Config { entries.put("singular", "diamond"); entries.put("ender_chest", "balance"); entries.put("commands", "true"); + entries.put("player", "&a{}"); + entries.put("localization", "default"); + getAvailableLocales().forEach(l -> entries.put("plural_%s".formatted(l.getLanguage()), entries.get("plural"))); + getAvailableLocales().forEach(l -> entries.put("singular_%s".formatted(l.getLanguage()), entries.get("singular"))); Map missingValues = new HashMap<>(); @@ -50,10 +54,38 @@ public class Config { return is(entry.toLowerCase(Locale.ROOT), value.toLowerCase(Locale.ROOT)); } - public static String getCurrencyText(int amount) { - return entries.get("format") + public static String getCurrencyText(int amount, String lang) { + String plural = entries.get("plural_%s".formatted(lang)); + String singular = entries.get("singular_%s".formatted(lang)); + + if (plural == null || singular == null) { + plural = entries.get("plural"); + singular = entries.get("singular"); + } + + return ChatColor.translateAlternateColorCodes('&', entries.get("format") .replace("{}", String.valueOf(amount)) - .replace("$", (amount != 1) ? entries.get("plural") : entries.get("singular")); + .replace("$", (amount != 1) ? plural : singular) + + ChatColor.RESET + ); + } + + public static String getCurrencyText(int amount, Locale locale) { + return getCurrencyText(amount, locale.getLanguage()); + } + + public static String getCurrencyText(int amount) { + return getCurrencyText(amount, getServerLocale().getLanguage()); + } + + + public static Locale getServerLocale() { + Locale locale = Locale.forLanguageTag(entries.get("localization")); + if (locale.getCountry().isEmpty()) { + locale = Locale.getDefault(); + } + + return locale; } public static UnrealConfig getuConf() { @@ -70,4 +102,19 @@ public class Config { return Material.DIAMOND; } + + public static String playerPrefix(String playerName) { + return ChatColor.translateAlternateColorCodes('&', entries.get("player").replace("{}", playerName)) + ChatColor.RESET; + } + + public static String playerPrefix(Player player) { + return playerPrefix(player.getName()); + } + + public static Set getAvailableLocales() { + return Set.of( + Locale.forLanguageTag("en"), + Locale.forLanguageTag("pt") + ); + } } diff --git a/src/main/java/io/github/adrianvic/itemeconomy/Main.java b/src/main/java/io/github/adrianvic/itemeconomy/Main.java index 18dc263..bb524d2 100644 --- a/src/main/java/io/github/adrianvic/itemeconomy/Main.java +++ b/src/main/java/io/github/adrianvic/itemeconomy/Main.java @@ -21,6 +21,11 @@ public class Main extends JavaPlugin { public void onEnable() { instance = this; Config.loadConfig(new UnrealConfig(this, this.getDataFolder(), "config.yml")); + getLogger().info(Messages.ENABLING.get( + "ItemEconomy", + getDescription().getVersion(), + Config.getServerLocale() + )); economy = new VaultLayer(); Bukkit.getServicesManager().register(Economy.class, economy, this, ServicePriority.High); diff --git a/src/main/java/io/github/adrianvic/itemeconomy/Messages.java b/src/main/java/io/github/adrianvic/itemeconomy/Messages.java new file mode 100644 index 0000000..d9ee83c --- /dev/null +++ b/src/main/java/io/github/adrianvic/itemeconomy/Messages.java @@ -0,0 +1,47 @@ +package io.github.adrianvic.itemeconomy; + +import io.github.adrianvic.itemeconomy.commands.Utils; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +import java.util.Locale; +import java.util.ResourceBundle; + +public enum Messages { + ENABLING("enabling"), + BALANCE_SUCCESSFUL("balance-successful"), + BALANCE_OTHER_SUCCESSFUL("balance-other-successful"), + MUST_BE_PLAYER_TO_ISSUE_COMMAND("must-be-player-to-issue-command"), + PAY_SUCCESSFUL("pay-successful"), + PAY_RECEIVED("pay-received"), + PAY_COULD_NOT_REALIZE_TRANSACTION("pay-could-not-realize-transaction"), + PAY_COULD_NOT_FIND_TARGET("pay-could-not-find-target"), + PAY_NOT_ENOUGH_MONEY("pay-not-enough-money"), + PAY_INVALID_AMOUNT("pay-invalid-amount"); + + private final String path; + Messages(String path) { this.path = path; } + + private String raw(Locale locale) { + ResourceBundle bundle = ResourceBundle.getBundle("messages", locale); + return bundle.getString(path); + } + + public String get(Locale locale, Object... args) { + String pattern = raw(locale); + try { + return ChatColor.translateAlternateColorCodes('&', args.length == 0 ? pattern : String.format(pattern, args)); + } catch (Exception e) { + return pattern; + } + } + + public String get(Player player, Object... args) { + Locale locale = Utils.localeOrDefault(player); + return get(locale, args); + } + + public String get(Object... args) { + return get(Config.getServerLocale(), args); + } +} diff --git a/src/main/java/io/github/adrianvic/itemeconomy/commands/Balance.java b/src/main/java/io/github/adrianvic/itemeconomy/commands/Balance.java index e42b456..e5e93f7 100644 --- a/src/main/java/io/github/adrianvic/itemeconomy/commands/Balance.java +++ b/src/main/java/io/github/adrianvic/itemeconomy/commands/Balance.java @@ -2,6 +2,7 @@ package io.github.adrianvic.itemeconomy.commands; import io.github.adrianvic.itemeconomy.Config; import io.github.adrianvic.itemeconomy.Main; +import io.github.adrianvic.itemeconomy.Messages; import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -19,18 +20,17 @@ public class Balance implements CommandExecutor, TabCompleter { public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String @NotNull [] strings) { if ((commandSender.isOp() || commandSender.hasPermission("iteco.balance.others")) && strings.length > 0) { double amount = Main.getEconomy().getBalance(strings[0]); - commandSender.sendMessage("%s has %s.".formatted( - strings[0], - Config.getCurrencyText((int) amount) - )); + commandSender.sendMessage(Messages.BALANCE_OTHER_SUCCESSFUL.get( + Utils.localeOrDefault(commandSender), + Config.playerPrefix(strings[0]), + Config.getCurrencyText((int) amount, Utils.localeOrDefault(commandSender)) + )); } else { if (commandSender instanceof Player player) { double amount = Main.getEconomy().getBalance(player); - commandSender.sendMessage("You have %s.".formatted( - Config.getCurrencyText((int) amount) - )); + commandSender.sendMessage(Messages.BALANCE_SUCCESSFUL.get(player, Config.getCurrencyText((int) amount, Utils.localeOrDefault(commandSender)))); } else { - commandSender.sendMessage("One must be a player to have a balance."); + commandSender.sendMessage(Messages.MUST_BE_PLAYER_TO_ISSUE_COMMAND.get()); } } return true; diff --git a/src/main/java/io/github/adrianvic/itemeconomy/commands/Pay.java b/src/main/java/io/github/adrianvic/itemeconomy/commands/Pay.java index f71a679..f87cb38 100644 --- a/src/main/java/io/github/adrianvic/itemeconomy/commands/Pay.java +++ b/src/main/java/io/github/adrianvic/itemeconomy/commands/Pay.java @@ -2,6 +2,7 @@ package io.github.adrianvic.itemeconomy.commands; import io.github.adrianvic.itemeconomy.Config; import io.github.adrianvic.itemeconomy.Main; +import io.github.adrianvic.itemeconomy.Messages; import net.milkbowl.vault.economy.EconomyResponse; import org.bukkit.Bukkit; import org.bukkit.command.Command; @@ -13,6 +14,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.Locale; import java.util.stream.Collectors; public class Pay implements CommandExecutor, TabCompleter { @@ -27,7 +29,7 @@ public class Pay implements CommandExecutor, TabCompleter { try { amount = Integer.parseInt(strings[1]); - String amountString = Config.getCurrencyText(amount); + String amountString = Config.getCurrencyText(amount, Utils.localeOrDefault(commandSender)); if (commandSender instanceof Player player && Main.getEconomy().has(player, amount)) { if (Bukkit.getPlayer(strings[0]) instanceof Player target) { @@ -35,23 +37,26 @@ public class Pay implements CommandExecutor, TabCompleter { if (withdrawResponse.transactionSuccess()) { EconomyResponse depositResponse = Main.getEconomy().depositPlayer(target.getName(), amount); if (depositResponse.transactionSuccess()) { - commandSender.sendMessage("Transaction of %s to %s was successfully realized.".formatted(amountString, target.getName())); - target.sendMessage("You received %s from %s.".formatted(amountString, player.getName())); + commandSender.sendMessage(Messages.PAY_SUCCESSFUL.get( + Utils.localeOrDefault(commandSender), + amountString, + Config.playerPrefix(target))); + target.sendMessage(Messages.PAY_RECEIVED.get(target, amountString, Config.playerPrefix(player))); } else { - commandSender.sendMessage("Could not realize transaction: %s".formatted(depositResponse.errorMessage)); + commandSender.sendMessage(Messages.PAY_COULD_NOT_REALIZE_TRANSACTION.get(Utils.localeOrDefault(commandSender), depositResponse.errorMessage)); Main.getEconomy().depositPlayer(player.getName(), amount); } } else { - commandSender.sendMessage("Could not realize transaction: %s".formatted(withdrawResponse.errorMessage)); + commandSender.sendMessage(Messages.PAY_COULD_NOT_REALIZE_TRANSACTION.get(Utils.localeOrDefault(commandSender), withdrawResponse.errorMessage));; } } else { - commandSender.sendMessage("Could not find target player."); + commandSender.sendMessage(Messages.PAY_COULD_NOT_FIND_TARGET.get(Utils.localeOrDefault(commandSender))); } } else { - commandSender.sendMessage("You don't have enough money."); + commandSender.sendMessage(Messages.PAY_NOT_ENOUGH_MONEY.get(Utils.localeOrDefault(commandSender))); } } catch (NumberFormatException nfe) { - commandSender.sendMessage("The amount you tried to pay is not valid."); + commandSender.sendMessage(Messages.PAY_INVALID_AMOUNT.get(Utils.localeOrDefault(commandSender))); return true; } diff --git a/src/main/java/io/github/adrianvic/itemeconomy/commands/Utils.java b/src/main/java/io/github/adrianvic/itemeconomy/commands/Utils.java new file mode 100644 index 0000000..aceb749 --- /dev/null +++ b/src/main/java/io/github/adrianvic/itemeconomy/commands/Utils.java @@ -0,0 +1,15 @@ +package io.github.adrianvic.itemeconomy.commands; + +import io.github.adrianvic.itemeconomy.Config; +import io.github.adrianvic.itemeconomy.Main; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.util.Locale; + +public class Utils { + public static Locale localeOrDefault(CommandSender sender) { + return (sender instanceof Player p) ? Locale.forLanguageTag(p.getLocale().replace('_', '-')) : Config.getServerLocale(); + } + +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 49262a7..1b2d06d 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,5 +1,7 @@ -item: "diamond" +item: "diamond" # MUST be a valid item. singular: "diamond" plural: "diamonds" -format: "{} $" -commands: "true" \ No newline at end of file +format: "&b{} $" # {} unfolds to amount and $ to singular or plural. +commands: "true" # Enables or disables plugin commands. +player: "&b{}" # {} unfolds to player name. +localization: "default" # can be "en" and "pt" too, if set to anything else uses system locale. \ No newline at end of file diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties new file mode 100644 index 0000000..8dde12e --- /dev/null +++ b/src/main/resources/messages.properties @@ -0,0 +1,10 @@ +enabling=enabling +balance-successful=balance-successful +balance-other-successful=balance-other-successful +must-be-player-to-issue-command=must-be-player-to-issue-command +pay-successful=pay-successful +pay-received=pay-received +pay-could-not-realize-transaction=pay-could-not-realize-transaction +pay-could-not-find-target=pay-could-not-find-target +pay-not-enough-money=pay-not-enough-money +pay-invalid-amount=pay-invalid-amount \ No newline at end of file diff --git a/src/main/resources/messages_en.properties b/src/main/resources/messages_en.properties new file mode 100644 index 0000000..06b8422 --- /dev/null +++ b/src/main/resources/messages_en.properties @@ -0,0 +1,10 @@ +enabling=Starting %s version %s with locale '%s'. +balance-successful=You have %s. +balance-other-successful=%s has %s. +must-be-player-to-issue-command=You must be a player to issue this command. +pay-successful=Transaction of %s to %s was successfully realized. +pay-received=You received %s from %s. +pay-could-not-realize-transaction=Could not realize transaction: %s +pay-could-not-find-target=Could not find target player. +pay-not-enough-money=You don't have enough money. +pay-invalid-amount=The amount you tried to pay is not valid. \ No newline at end of file diff --git a/src/main/resources/messages_pt.properties b/src/main/resources/messages_pt.properties new file mode 100644 index 0000000..8b624b1 --- /dev/null +++ b/src/main/resources/messages_pt.properties @@ -0,0 +1,10 @@ +enabling=Iniciando %s verso %s com localizao para %s. +balance-successful=Voc tem %s. +balance-other-successful=%s possui %s. +must-be-player-to-issue-command=Voc precisa ser um jogador para executar esse comando. +pay-successful=Transao de %s para %s realizada com sucesso. +pay-received=Voc recebeu %s de %s. +pay-could-not-realize-transaction=No foi possvel realizar a transao: %s +pay-could-not-find-target=No foi possvel encontrar o jogador-alvo. +pay-not-enough-money=Voc no tem dinheiro suficiente. +pay-invalid-amount=A quantidade que voc tentou enviar invlida. \ No newline at end of file From 90b2a117b46a7b0cb27787e36eb77c6a9d6088fb Mon Sep 17 00:00:00 2001 From: Tenkuma <85490958+adrianvic@users.noreply.github.com> Date: Sun, 4 Jan 2026 00:21:24 -0300 Subject: [PATCH 07/12] Cleaned up README.md Configuration section now links to config file from GH tree. --- README.md | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 23e865b..1448468 100644 --- a/README.md +++ b/README.md @@ -3,32 +3,25 @@ image

-ItemEconomy II is a fork of [ItemEconomy](https://modrinth.com/plugin/itemeconomy), keeping it updated to later versions of Minecraft and adding new features. +**ItemEconomy II** is a fork of [ItemEconomy](https://modrinth.com/plugin/itemeconomy), keeping it updated to later versions of Minecraft and adding new features. This PaperMC plugin integrates with VaultUnlocked to provide a unique, item-based economy system for your Minecraft server. Instead of relying solely on virtual balances, players use in-game items as physical currency, adding a layer of immersion and realism to your economy. -Features: -- **Item-Based Currency:** Set any Minecraft item as your server's currency (default: diamonds). +ItemEconomy is as powerful as you need and as simple as you want, with every feature being optional. + +## Features +- **Item-Based Currency:** Set any Minecraft item as your server's currency (diamonds by default). - **VaultUnlocked Integration:** Fully compatible with VaultUnlocked, enabling seamless interaction with other economy-based plugins. - **Simple logic:** Just checks if the user has the item/how many when queried. - **Customizable Formatting:** Define how your currency is displayed, including singular and plural forms. - **Ender Chest support:** Items on Ender Chests are counted in the user balance. - **Built-int optional balance and pay commands** with support for permissions. +- **Translation support** with per-user language and per-language currency name. -## Configuration Example: -```yaml -item: diamond # Define the item to be used as currency. -singular: diamond # Singular form of the currency. -plural: diamonds # Plural form of the currency. -format: "{} $" # {} will be replaced with the amount and $ either with singular or plural -ender_chest: balance # Either none or balance -commands: true # Disabling this will disable /balance and /pay -``` - -This configuration will use diamonds as the currency, displayed as {amount} {name}, e.g., "5 diamonds" or "1 diamond". - -## Usage: +## Configuration +An updated example configuration file is available [here](https://github.com/adrianvic/ItemEconomy/blob/main/src/main/resources/config.yml). +## Usage - Players can earn, trade, and store the configured item as physical currency. -- Integrates seamlessly with Vault-compatible plugins for shops, auctions, and more. +- Once they spend the currency, that amount of the item will be subtracted from their inventory. - Administrators can customize the item and formatting to match their server's theme. From 7e3edff269ce3e256735bec907b09ebe390d1788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A9=E3=82=AF=E3=83=9E?= <85490958+adrianvic@users.noreply.github.com> Date: Tue, 19 May 2026 19:26:12 -0300 Subject: [PATCH 08/12] Update README.md to include commands Closes #1 --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 1448468..0af72de 100644 --- a/README.md +++ b/README.md @@ -25,3 +25,13 @@ An updated example configuration file is available [here](https://github.com/adr - Players can earn, trade, and store the configured item as physical currency. - Once they spend the currency, that amount of the item will be subtracted from their inventory. - Administrators can customize the item and formatting to match their server's theme. + +## Commands +
+
/balance
+
Prints player balance, permission is `iteco.balance` but is allowed by default. Requires permission `iteco.balance.others` to specify other user.
+
/pay
+
Transfers money from your account to another player's, permission is `iteco.pay` but is allowed by default.
+
/itecoreload
+
Reloads the plugin configuration, requires permission `iteco.reload`.
+
From f65c3ddc97e32fcaaf109accaad59c11f273f940 Mon Sep 17 00:00:00 2001 From: Adrian Victor Date: Tue, 19 May 2026 19:41:07 -0300 Subject: [PATCH 09/12] Fix bug where Main.addItems would try to add 0 items to Ender Chest. Bumped version to `1.2.1`. --- .../io/github/adrianvic/itemeconomy/Main.java | 18 +++++++++++++++--- src/main/resources/plugin.yml | 2 +- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/github/adrianvic/itemeconomy/Main.java b/src/main/java/io/github/adrianvic/itemeconomy/Main.java index bb524d2..3b999ee 100644 --- a/src/main/java/io/github/adrianvic/itemeconomy/Main.java +++ b/src/main/java/io/github/adrianvic/itemeconomy/Main.java @@ -122,12 +122,24 @@ public class Main extends JavaPlugin { } public static void addItems(Player player, Material type, int amount) { - HashMap invOverflow = getInventory(player, InventoryID.INVENTORY).addItem(new ItemStack(type, amount)); - HashMap echestOverflow = getInventory(player, InventoryID.ENDER_CHEST).addItem(new ItemStack(type, invOverflow.values() + if (amount <= 0) return; + + HashMap invOverflow = + getInventory(player, InventoryID.INVENTORY) + .addItem(new ItemStack(type, amount)); + + int overflowAmount = invOverflow.values() .stream() .mapToInt(ItemStack::getAmount) - .sum())); + .sum(); + if (overflowAmount <= 0) { + return; + } + + HashMap echestOverflow = + getInventory(player, InventoryID.ENDER_CHEST) + .addItem(new ItemStack(type, overflowAmount)); for (ItemStack overflow : echestOverflow.values()) { player.getWorld().dropItemNaturally(player.getLocation(), overflow); diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index e78d2d1..02fae9e 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,6 +1,6 @@ name: ItemEconomy main: io.github.adrianvic.itemeconomy.Main -version: 1.2 +version: 1.2.1 depend: [Vault] api-version: '1.21' commands: From 1259cd874ec50a378e7d196a27c924bf819a45df Mon Sep 17 00:00:00 2001 From: Adrian Victor Date: Tue, 19 May 2026 19:48:01 -0300 Subject: [PATCH 10/12] Add messages to reload command --- src/main/java/io/github/adrianvic/itemeconomy/Messages.java | 6 +++++- .../io/github/adrianvic/itemeconomy/commands/Reload.java | 4 ++++ src/main/resources/messages.properties | 5 ++++- src/main/resources/messages_en.properties | 5 ++++- src/main/resources/messages_pt.properties | 5 ++++- 5 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/github/adrianvic/itemeconomy/Messages.java b/src/main/java/io/github/adrianvic/itemeconomy/Messages.java index d9ee83c..33102ce 100644 --- a/src/main/java/io/github/adrianvic/itemeconomy/Messages.java +++ b/src/main/java/io/github/adrianvic/itemeconomy/Messages.java @@ -17,7 +17,11 @@ public enum Messages { PAY_COULD_NOT_REALIZE_TRANSACTION("pay-could-not-realize-transaction"), PAY_COULD_NOT_FIND_TARGET("pay-could-not-find-target"), PAY_NOT_ENOUGH_MONEY("pay-not-enough-money"), - PAY_INVALID_AMOUNT("pay-invalid-amount"); + PAY_INVALID_AMOUNT("pay-invalid-amount"), + RELOADING("reloading"), + RELOAD_ERROR("reload-error"), + RELOAD_FINISHED("reload-finished"); + private final String path; Messages(String path) { this.path = path; } diff --git a/src/main/java/io/github/adrianvic/itemeconomy/commands/Reload.java b/src/main/java/io/github/adrianvic/itemeconomy/commands/Reload.java index 804e6ed..4e5ff26 100644 --- a/src/main/java/io/github/adrianvic/itemeconomy/commands/Reload.java +++ b/src/main/java/io/github/adrianvic/itemeconomy/commands/Reload.java @@ -2,6 +2,7 @@ package io.github.adrianvic.itemeconomy.commands; import io.github.adrianvic.itemeconomy.Config; import io.github.adrianvic.itemeconomy.Main; +import io.github.adrianvic.itemeconomy.Messages; import io.github.adrianvic.itemeconomy.UnrealConfig; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -13,9 +14,12 @@ public class Reload implements CommandExecutor { @Override public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String @NotNull [] strings) { try { + commandSender.sendMessage("[ECONOMY] %s".formatted(Messages.RELOADING)); Config.loadConfig(new UnrealConfig(Main.getInstance(), Main.getInstance().getDataFolder(), "config.yml")); + commandSender.sendMessage("[ECONOMY] %s".formatted(Messages.RELOAD_FINISHED)); return true; } catch (Exception e) { + commandSender.sendMessage("[ECONOMY] %s".formatted(Messages.RELOAD_ERROR)); return false; } } diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index 8dde12e..77e17f5 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -7,4 +7,7 @@ pay-received=pay-received pay-could-not-realize-transaction=pay-could-not-realize-transaction pay-could-not-find-target=pay-could-not-find-target pay-not-enough-money=pay-not-enough-money -pay-invalid-amount=pay-invalid-amount \ No newline at end of file +pay-invalid-amount=pay-invalid-amount +reloading=reloading +reload-error=reload-error +reload-finished=reload-finished \ No newline at end of file diff --git a/src/main/resources/messages_en.properties b/src/main/resources/messages_en.properties index 06b8422..ee946e3 100644 --- a/src/main/resources/messages_en.properties +++ b/src/main/resources/messages_en.properties @@ -7,4 +7,7 @@ pay-received=You received %s from %s. pay-could-not-realize-transaction=Could not realize transaction: %s pay-could-not-find-target=Could not find target player. pay-not-enough-money=You don't have enough money. -pay-invalid-amount=The amount you tried to pay is not valid. \ No newline at end of file +pay-invalid-amount=The amount you tried to pay is not valid. +reloading=Reloading... +reload-error=Reload complete. +reload-finished=An error occurred while reloading the config, please check your logs. \ No newline at end of file diff --git a/src/main/resources/messages_pt.properties b/src/main/resources/messages_pt.properties index 8b624b1..be1edbc 100644 --- a/src/main/resources/messages_pt.properties +++ b/src/main/resources/messages_pt.properties @@ -7,4 +7,7 @@ pay-received=Voc pay-could-not-realize-transaction=No foi possvel realizar a transao: %s pay-could-not-find-target=No foi possvel encontrar o jogador-alvo. pay-not-enough-money=Voc no tem dinheiro suficiente. -pay-invalid-amount=A quantidade que voc tentou enviar invlida. \ No newline at end of file +pay-invalid-amount=A quantidade que voc tentou enviar invlida. +reloading=Recarregando... +reload-error=Carregamento completo. +reload-finished=Ocorreu um erro ao recarregar, por favor, verifique seu registro. \ No newline at end of file From 97f16f98c739803c7992820eae7fce03262401fb Mon Sep 17 00:00:00 2001 From: Adrian Victor Date: Tue, 19 May 2026 20:31:01 -0300 Subject: [PATCH 11/12] Fix messages in reload command --- .gitignore | 1 + build.gradle.kts | 2 +- .../github/adrianvic/itemeconomy/commands/Reload.java | 10 +++++++--- src/main/resources/messages_en.properties | 4 ++-- src/main/resources/messages_pt.properties | 4 ++-- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 9ede845..4c59a71 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ build/ out/ .idea/ libs/ +run/ \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index bbc19a2..35e0edf 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -106,4 +106,4 @@ tasks.withType { tasks.runServer { minecraftVersion("1.21") -} +} \ No newline at end of file diff --git a/src/main/java/io/github/adrianvic/itemeconomy/commands/Reload.java b/src/main/java/io/github/adrianvic/itemeconomy/commands/Reload.java index 4e5ff26..b0d8514 100644 --- a/src/main/java/io/github/adrianvic/itemeconomy/commands/Reload.java +++ b/src/main/java/io/github/adrianvic/itemeconomy/commands/Reload.java @@ -9,17 +9,21 @@ import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; +import java.util.Locale; + public class Reload implements CommandExecutor { @Override public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String @NotNull [] strings) { + Locale locale = Utils.localeOrDefault(commandSender); try { - commandSender.sendMessage("[ECONOMY] %s".formatted(Messages.RELOADING)); + commandSender.sendMessage("[ECONOMY] %s".formatted(Messages.RELOADING.get(locale))); Config.loadConfig(new UnrealConfig(Main.getInstance(), Main.getInstance().getDataFolder(), "config.yml")); - commandSender.sendMessage("[ECONOMY] %s".formatted(Messages.RELOAD_FINISHED)); + commandSender.sendMessage("[ECONOMY] %s".formatted(Messages.RELOAD_FINISHED.get(locale))); return true; } catch (Exception e) { - commandSender.sendMessage("[ECONOMY] %s".formatted(Messages.RELOAD_ERROR)); + commandSender.sendMessage("[ECONOMY] %s".formatted(Messages.RELOAD_ERROR.get(locale))); + e.printStackTrace(); return false; } } diff --git a/src/main/resources/messages_en.properties b/src/main/resources/messages_en.properties index ee946e3..95f9873 100644 --- a/src/main/resources/messages_en.properties +++ b/src/main/resources/messages_en.properties @@ -9,5 +9,5 @@ pay-could-not-find-target=Could not find target player. pay-not-enough-money=You don't have enough money. pay-invalid-amount=The amount you tried to pay is not valid. reloading=Reloading... -reload-error=Reload complete. -reload-finished=An error occurred while reloading the config, please check your logs. \ No newline at end of file +reload-error=An error occurred while reloading the config, please check your logs. +reload-finished=Reload complete. \ No newline at end of file diff --git a/src/main/resources/messages_pt.properties b/src/main/resources/messages_pt.properties index be1edbc..e11dc4c 100644 --- a/src/main/resources/messages_pt.properties +++ b/src/main/resources/messages_pt.properties @@ -9,5 +9,5 @@ pay-could-not-find-target=N pay-not-enough-money=Voc no tem dinheiro suficiente. pay-invalid-amount=A quantidade que voc tentou enviar invlida. reloading=Recarregando... -reload-error=Carregamento completo. -reload-finished=Ocorreu um erro ao recarregar, por favor, verifique seu registro. \ No newline at end of file +reload-error=Ocorreu um erro ao recarregar, por favor, verifique seu registro. +reload-finished=Carregamento completo. \ No newline at end of file From 81f6f24affff20070faa4404c1ec26536ac054b4 Mon Sep 17 00:00:00 2001 From: Adrian Victor Date: Tue, 19 May 2026 20:32:44 -0300 Subject: [PATCH 12/12] Bump to 1.3.1 --- src/main/resources/plugin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 02fae9e..75cefe8 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,6 +1,6 @@ name: ItemEconomy main: io.github.adrianvic.itemeconomy.Main -version: 1.2.1 +version: 1.3.1 depend: [Vault] api-version: '1.21' commands: