From aae18ce853788c9dd738809645d33de0f4b9968a Mon Sep 17 00:00:00 2001 From: Silent <46107752+TheSilentPro@users.noreply.github.com> Date: Thu, 15 Oct 2026 22:02:08 +0200 Subject: [PATCH 1/8] feat(paper): add item economy configuration --- .../paper/economy/ItemEconomyConfig.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 headdb-platforms/headdb-paper/src/main/java/io/github/silentdevelopment/headdb/paper/economy/ItemEconomyConfig.java diff --git a/headdb-platforms/headdb-paper/src/main/java/io/github/silentdevelopment/headdb/paper/economy/ItemEconomyConfig.java b/headdb-platforms/headdb-paper/src/main/java/io/github/silentdevelopment/headdb/paper/economy/ItemEconomyConfig.java new file mode 100644 index 0000000..21cb80f --- /dev/null +++ b/headdb-platforms/headdb-paper/src/main/java/io/github/silentdevelopment/headdb/paper/economy/ItemEconomyConfig.java @@ -0,0 +1,36 @@ +package io.github.silentdevelopment.headdb.paper.economy; + +import org.jetbrains.annotations.NotNull; + +import java.util.Locale; +import java.util.Objects; + +public record ItemEconomyConfig( + @NotNull String match, + @NotNull String material, + @NotNull String singular, + @NotNull String plural +) { + + public ItemEconomyConfig { + Objects.requireNonNull(match, "match"); + Objects.requireNonNull(material, "material"); + Objects.requireNonNull(singular, "singular"); + Objects.requireNonNull(plural, "plural"); + + match = match.trim().toLowerCase(Locale.ROOT); + material = material.trim(); + singular = singular.trim(); + plural = plural.trim(); + } + + public @NotNull String singularOr(@NotNull String fallback) { + Objects.requireNonNull(fallback, "fallback"); + return singular.isBlank() ? fallback : singular; + } + + public @NotNull String pluralOr(@NotNull String fallback) { + Objects.requireNonNull(fallback, "fallback"); + return plural.isBlank() ? fallback : plural; + } +} From eee3099c4245a7b819863cfc186215a743bda830 Mon Sep 17 00:00:00 2001 From: Silent <46107752+TheSilentPro@users.noreply.github.com> Date: Thu, 15 Oct 2026 22:02:11 +0200 Subject: [PATCH 2/8] feat(paper): add material item economy provider --- .../paper/economy/ItemEconomyProvider.java | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 headdb-platforms/headdb-paper/src/main/java/io/github/silentdevelopment/headdb/paper/economy/ItemEconomyProvider.java diff --git a/headdb-platforms/headdb-paper/src/main/java/io/github/silentdevelopment/headdb/paper/economy/ItemEconomyProvider.java b/headdb-platforms/headdb-paper/src/main/java/io/github/silentdevelopment/headdb/paper/economy/ItemEconomyProvider.java new file mode 100644 index 0000000..5804176 --- /dev/null +++ b/headdb-platforms/headdb-paper/src/main/java/io/github/silentdevelopment/headdb/paper/economy/ItemEconomyProvider.java @@ -0,0 +1,131 @@ +package io.github.silentdevelopment.headdb.paper.economy; + +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Locale; +import java.util.Objects; + +public final class ItemEconomyProvider implements EconomyProvider { + + public static final String MATCH_MATERIAL = "material"; + + private final Material material; + private final String singular; + private final String plural; + + public ItemEconomyProvider(@NotNull Material material, @NotNull String singular, @NotNull String plural) { + this.material = Objects.requireNonNull(material, "material"); + this.singular = Objects.requireNonNull(singular, "singular"); + this.plural = Objects.requireNonNull(plural, "plural"); + } + + @Override + public boolean available() { + return true; + } + + @Override + public @NotNull String format(double amount) { + Long units = wholeUnits(amount); + if (units == null) { + return String.format(Locale.ROOT, "%.2f %s", amount, plural); + } + + return units + " " + (units == 1L ? singular : plural); + } + + @Override + public @NotNull EconomyWithdrawal withdraw(@NotNull Player player, double amount) { + Objects.requireNonNull(player, "player"); + + Long required = wholeUnits(amount); + if (required == null) { + return new EconomyWithdrawal(false, "Item economy requires whole-number prices."); + } + + if (required <= 0L) { + return new EconomyWithdrawal(true, ""); + } + + PlayerInventory inventory = player.getInventory(); + ItemStack[] updated = withdrawStorage(inventory.getStorageContents(), material, required); + if (updated == null) { + return new EconomyWithdrawal(false, "Insufficient item currency."); + } + + inventory.setStorageContents(updated); + return new EconomyWithdrawal(true, ""); + } + + static boolean isWholeAmount(double amount) { + return wholeUnits(amount) != null; + } + + static @Nullable ItemStack[] withdrawStorage(@NotNull ItemStack[] storage, @NotNull Material material, long required) { + Objects.requireNonNull(storage, "storage"); + Objects.requireNonNull(material, "material"); + + if (required < 0L) { + throw new IllegalArgumentException("Required amount cannot be negative."); + } + + long available = 0L; + for (ItemStack item : storage) { + if (item == null || item.getType() != material) { + continue; + } + + available += item.getAmount(); + if (available >= required) { + break; + } + } + + if (available < required) { + return null; + } + + ItemStack[] updated = new ItemStack[storage.length]; + for (int index = 0; index < storage.length; index++) { + ItemStack item = storage[index]; + updated[index] = item == null ? null : item.clone(); + } + + long remaining = required; + for (int index = 0; index < updated.length && remaining > 0L; index++) { + ItemStack item = updated[index]; + if (item == null || item.getType() != material) { + continue; + } + + int remove = (int) Math.min(remaining, item.getAmount()); + int left = item.getAmount() - remove; + remaining -= remove; + + if (left <= 0) { + updated[index] = null; + } else { + item.setAmount(left); + } + } + + return updated; + } + + private static @Nullable Long wholeUnits(double amount) { + if (!Double.isFinite(amount) || amount < 0.0D || amount != Math.rint(amount)) { + return null; + } + + if (amount > Long.MAX_VALUE) { + return null; + } + + return (long) amount; + } +} From ad2c7cca87d80a6a33ceac0ee2e9cdcf20bc0d22 Mon Sep 17 00:00:00 2001 From: Silent <46107752+TheSilentPro@users.noreply.github.com> Date: Thu, 15 Oct 2026 22:02:13 +0200 Subject: [PATCH 3/8] test(paper): cover item economy withdrawal --- .../economy/ItemEconomyProviderTest.java | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 headdb-platforms/headdb-paper/src/test/java/io/github/silentdevelopment/headdb/paper/economy/ItemEconomyProviderTest.java diff --git a/headdb-platforms/headdb-paper/src/test/java/io/github/silentdevelopment/headdb/paper/economy/ItemEconomyProviderTest.java b/headdb-platforms/headdb-paper/src/test/java/io/github/silentdevelopment/headdb/paper/economy/ItemEconomyProviderTest.java new file mode 100644 index 0000000..a432a29 --- /dev/null +++ b/headdb-platforms/headdb-paper/src/test/java/io/github/silentdevelopment/headdb/paper/economy/ItemEconomyProviderTest.java @@ -0,0 +1,62 @@ +package io.github.silentdevelopment.headdb.paper.economy; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ItemEconomyProviderTest { + + @Test + void formatsSingularAndPluralAmounts() { + ItemEconomyProvider provider = new ItemEconomyProvider(Material.DIAMOND, "Diamond", "Diamonds"); + + assertEquals("1 Diamond", provider.format(1.0D)); + assertEquals("2 Diamonds", provider.format(2.0D)); + } + + @Test + void validatesWholeAmounts() { + assertTrue(ItemEconomyProvider.isWholeAmount(0.0D)); + assertTrue(ItemEconomyProvider.isWholeAmount(12.0D)); + assertFalse(ItemEconomyProvider.isWholeAmount(2.5D)); + assertFalse(ItemEconomyProvider.isWholeAmount(Double.NaN)); + } + + @Test + void withdrawsAcrossMultipleStacksWithoutTouchingOtherItems() { + ItemStack[] storage = { + new ItemStack(Material.DIAMOND, 1), + new ItemStack(Material.STONE, 32), + new ItemStack(Material.DIAMOND, 4) + }; + + ItemStack[] updated = ItemEconomyProvider.withdrawStorage(storage, Material.DIAMOND, 3); + + assertEquals(1, storage[0].getAmount()); + assertEquals(4, storage[2].getAmount()); + assertNull(updated[0]); + assertEquals(Material.STONE, updated[1].getType()); + assertEquals(32, updated[1].getAmount()); + assertEquals(Material.DIAMOND, updated[2].getType()); + assertEquals(2, updated[2].getAmount()); + } + + @Test + void insufficientCurrencyDoesNotProduceModifiedStorage() { + ItemStack[] storage = { + new ItemStack(Material.DIAMOND, 2), + new ItemStack(Material.EMERALD, 5) + }; + + ItemStack[] updated = ItemEconomyProvider.withdrawStorage(storage, Material.DIAMOND, 3); + + assertNull(updated); + assertEquals(2, storage[0].getAmount()); + assertEquals(5, storage[1].getAmount()); + } +} From f93adf8f9a5ecf89d2c71d43b29cf4a685647901 Mon Sep 17 00:00:00 2001 From: Silent <46107752+TheSilentPro@users.noreply.github.com> Date: Thu, 15 Oct 2026 22:03:00 +0200 Subject: [PATCH 4/8] feat(paper): load item economy settings --- .../headdb/paper/economy/EconomyConfig.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/headdb-platforms/headdb-paper/src/main/java/io/github/silentdevelopment/headdb/paper/economy/EconomyConfig.java b/headdb-platforms/headdb-paper/src/main/java/io/github/silentdevelopment/headdb/paper/economy/EconomyConfig.java index 512eff3..cec3a3f 100644 --- a/headdb-platforms/headdb-paper/src/main/java/io/github/silentdevelopment/headdb/paper/economy/EconomyConfig.java +++ b/headdb-platforms/headdb-paper/src/main/java/io/github/silentdevelopment/headdb/paper/economy/EconomyConfig.java @@ -18,6 +18,7 @@ public record EconomyConfig( boolean enabled, @NotNull String provider, + @NotNull ItemEconomyConfig item, double anyHeadPrice, @NotNull Map categoryPrices, @NotNull Map customCategoryPrices, @@ -27,6 +28,7 @@ public record EconomyConfig( public EconomyConfig { Objects.requireNonNull(provider, "provider"); + Objects.requireNonNull(item, "item"); Objects.requireNonNull(categoryPrices, "categoryPrices"); Objects.requireNonNull(customCategoryPrices, "customCategoryPrices"); Objects.requireNonNull(headPrices, "headPrices"); @@ -55,6 +57,12 @@ public record EconomyConfig( return new EconomyConfig( yaml.getBoolean("enabled", false), yaml.getString("provider", "vault"), + new ItemEconomyConfig( + yaml.getString("item.match", ItemEconomyProvider.MATCH_MATERIAL), + yaml.getString("item.material", "DIAMOND"), + yaml.getString("item.singular", ""), + yaml.getString("item.plural", "") + ), yaml.getDouble("prices.any-head", 0.0D), prices(yaml.getConfigurationSection("prices.categories")), prices(yaml.getConfigurationSection("prices.custom-categories")), @@ -144,10 +152,19 @@ private static void copyDefault(@NotNull Path file) { private static @NotNull String defaultConfig() { return "enabled: false\n" + + "# Supported providers: vault, item\n" + "provider: vault\n" + "\n" + + "item:\n" + + " # Item economy currently supports material-only matching.\n" + + " match: material\n" + + " material: DIAMOND\n" + + " singular: Diamond\n" + + " plural: Diamonds\n" + + "\n" + "prices:\n" + " # Fallback price for every head. Set to 0 to make heads free.\n" + + " # Item economy prices must be whole numbers.\n" + " any-head: 0.0\n" + "\n" + " # Price for player heads. If omitted, any-head is used.\n" From c79b634ba7be05daaca7c3f5d6f01d956028420c Mon Sep 17 00:00:00 2001 From: Silent <46107752+TheSilentPro@users.noreply.github.com> Date: Thu, 15 Oct 2026 22:03:02 +0200 Subject: [PATCH 5/8] feat(paper): select and validate item economy provider --- .../headdb/paper/economy/EconomyService.java | 109 ++++++++++++++++-- 1 file changed, 101 insertions(+), 8 deletions(-) diff --git a/headdb-platforms/headdb-paper/src/main/java/io/github/silentdevelopment/headdb/paper/economy/EconomyService.java b/headdb-platforms/headdb-paper/src/main/java/io/github/silentdevelopment/headdb/paper/economy/EconomyService.java index 043e7fb..b6bdf6d 100644 --- a/headdb-platforms/headdb-paper/src/main/java/io/github/silentdevelopment/headdb/paper/economy/EconomyService.java +++ b/headdb-platforms/headdb-paper/src/main/java/io/github/silentdevelopment/headdb/paper/economy/EconomyService.java @@ -3,6 +3,7 @@ import io.github.silentdevelopment.headdb.model.Head; import io.github.silentdevelopment.headdb.paper.HeadDBPlugin; import net.milkbowl.vault.economy.Economy; +import org.bukkit.Material; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; import org.bukkit.plugin.RegisteredServiceProvider; @@ -36,25 +37,113 @@ private EconomyService(@NotNull HeadDBPlugin plugin, @NotNull EconomyConfig conf return new EconomyService(plugin, config, new DisabledEconomyProvider()); } - if (!config.provider().equalsIgnoreCase("vault")) { - plugin.getSLF4JLogger().warn("Unsupported economy provider '{}'. Economy integration is disabled.", config.provider()); - return new EconomyService(plugin, config, new DisabledEconomyProvider()); - } + return switch (config.provider()) { + case "vault" -> createVault(plugin, config); + case "item" -> createItem(plugin, config); + default -> { + plugin.getSLF4JLogger().warn("Unsupported economy provider '{}'. Economy integration is disabled.", config.provider()); + yield new EconomyService(plugin, config, new DisabledEconomyProvider()); + } + }; + } + private static @NotNull EconomyService createVault(@NotNull HeadDBPlugin plugin, @NotNull EconomyConfig config) { if (plugin.getServer().getPluginManager().getPlugin("Vault") == null) { - plugin.getSLF4JLogger().warn("Economy is enabled but Vault is not loaded."); + plugin.getSLF4JLogger().warn("Economy is enabled with provider 'vault' but Vault is not loaded."); return new EconomyService(plugin, config, new DisabledEconomyProvider()); } RegisteredServiceProvider registration = plugin.getServer().getServicesManager().getRegistration(Economy.class); if (registration == null || registration.getProvider() == null) { - plugin.getSLF4JLogger().warn("Economy is enabled but Vault did not provide an Economy service."); + plugin.getSLF4JLogger().warn("Economy is enabled with provider 'vault' but Vault did not provide an Economy service."); return new EconomyService(plugin, config, new DisabledEconomyProvider()); } return new EconomyService(plugin, config, new VaultEconomyProvider(registration.getProvider())); } + private static @NotNull EconomyService createItem(@NotNull HeadDBPlugin plugin, @NotNull EconomyConfig config) { + ItemEconomyConfig itemConfig = config.item(); + + if (!itemConfig.match().equals(ItemEconomyProvider.MATCH_MATERIAL)) { + plugin.getSLF4JLogger().warn( + "Unsupported item economy match mode '{}'. Only 'material' is supported. Economy integration is disabled.", + itemConfig.match() + ); + return new EconomyService(plugin, config, new DisabledEconomyProvider()); + } + + Material material = Material.matchMaterial(itemConfig.material()); + if (material == null || material.isAir() || !material.isItem()) { + plugin.getSLF4JLogger().warn( + "Invalid item economy material '{}'. Economy integration is disabled.", + itemConfig.material() + ); + return new EconomyService(plugin, config, new DisabledEconomyProvider()); + } + + if (!wholeItemPrices(config)) { + plugin.getSLF4JLogger().warn( + "Item economy requires whole-number prices. Economy integration is disabled until fractional prices are removed." + ); + return new EconomyService(plugin, config, new DisabledEconomyProvider()); + } + + String fallbackName = displayName(material); + String singular = itemConfig.singularOr(fallbackName); + String plural = itemConfig.pluralOr(singular + "s"); + return new EconomyService(plugin, config, new ItemEconomyProvider(material, singular, plural)); + } + + private static boolean wholeItemPrices(@NotNull EconomyConfig config) { + if (!ItemEconomyProvider.isWholeAmount(config.anyHeadPrice())) { + return false; + } + + if (config.playerHeadPrice() != null && !ItemEconomyProvider.isWholeAmount(config.playerHeadPrice())) { + return false; + } + + for (double price : config.categoryPrices().values()) { + if (!ItemEconomyProvider.isWholeAmount(price)) { + return false; + } + } + + for (double price : config.customCategoryPrices().values()) { + if (!ItemEconomyProvider.isWholeAmount(price)) { + return false; + } + } + + for (double price : config.headPrices().values()) { + if (!ItemEconomyProvider.isWholeAmount(price)) { + return false; + } + } + + return true; + } + + private static @NotNull String displayName(@NotNull Material material) { + String[] parts = material.name().toLowerCase(Locale.ROOT).split("_"); + StringBuilder result = new StringBuilder(); + + for (String part : parts) { + if (part.isBlank()) { + continue; + } + + if (!result.isEmpty()) { + result.append(' '); + } + + result.append(Character.toUpperCase(part.charAt(0))).append(part.substring(1)); + } + + return result.toString(); + } + public boolean enabled() { return config.enabled() && provider.available(); } @@ -137,8 +226,12 @@ public void setCustomCategoryPrice(@NotNull String categoryId, double price) { } private void setPrice(@NotNull String path, double price) { - if (price < 0.0D) { - throw new IllegalArgumentException("Price cannot be negative."); + if (!Double.isFinite(price) || price < 0.0D) { + throw new IllegalArgumentException("Price must be a finite non-negative number."); + } + + if (config.provider().equals("item") && !ItemEconomyProvider.isWholeAmount(price)) { + throw new IllegalArgumentException("Item economy prices must be whole numbers."); } Path file = plugin.getDataFolder().toPath().resolve("economy.yml"); From 7b0739241da27311fd576f3c4c74742576d74aea Mon Sep 17 00:00:00 2001 From: Silent <46107752+TheSilentPro@users.noreply.github.com> Date: Thu, 15 Oct 2026 22:03:05 +0200 Subject: [PATCH 6/8] docs(paper): configure item economy provider --- .../headdb-paper/src/main/resources/economy.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/headdb-platforms/headdb-paper/src/main/resources/economy.yml b/headdb-platforms/headdb-paper/src/main/resources/economy.yml index dfb2e94..b1b46dd 100644 --- a/headdb-platforms/headdb-paper/src/main/resources/economy.yml +++ b/headdb-platforms/headdb-paper/src/main/resources/economy.yml @@ -1,8 +1,17 @@ enabled: false +# Supported providers: vault, item provider: vault +item: + # Item economy currently supports material-only matching. + match: material + material: DIAMOND + singular: Diamond + plural: Diamonds + prices: # Fallback price for every head. Set to 0 to make heads free. + # Item economy prices must be whole numbers. any-head: 0.0 # Price for player heads. If omitted, any-head is used. From 6aa2c50b0596ad2a6cb05260a3a66e7cf0d0eacb Mon Sep 17 00:00:00 2001 From: Silent <46107752+TheSilentPro@users.noreply.github.com> Date: Thu, 15 Oct 2026 22:06:36 +0200 Subject: [PATCH 7/8] refactor(paper): isolate item withdrawal planning --- .../paper/economy/ItemEconomyProvider.java | 65 +++++++++++++------ 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/headdb-platforms/headdb-paper/src/main/java/io/github/silentdevelopment/headdb/paper/economy/ItemEconomyProvider.java b/headdb-platforms/headdb-paper/src/main/java/io/github/silentdevelopment/headdb/paper/economy/ItemEconomyProvider.java index 5804176..073225f 100644 --- a/headdb-platforms/headdb-paper/src/main/java/io/github/silentdevelopment/headdb/paper/economy/ItemEconomyProvider.java +++ b/headdb-platforms/headdb-paper/src/main/java/io/github/silentdevelopment/headdb/paper/economy/ItemEconomyProvider.java @@ -74,19 +74,16 @@ static boolean isWholeAmount(double amount) { throw new IllegalArgumentException("Required amount cannot be negative."); } - long available = 0L; - for (ItemStack item : storage) { - if (item == null || item.getType() != material) { - continue; - } - - available += item.getAmount(); - if (available >= required) { - break; + int[] matchingAmounts = new int[storage.length]; + for (int index = 0; index < storage.length; index++) { + ItemStack item = storage[index]; + if (item != null && item.getType() == material) { + matchingAmounts[index] = item.getAmount(); } } - if (available < required) { + int[] remainingAmounts = withdrawAmounts(matchingAmounts, required); + if (remainingAmounts == null) { return null; } @@ -94,29 +91,57 @@ static boolean isWholeAmount(double amount) { for (int index = 0; index < storage.length; index++) { ItemStack item = storage[index]; updated[index] = item == null ? null : item.clone(); - } - long remaining = required; - for (int index = 0; index < updated.length && remaining > 0L; index++) { - ItemStack item = updated[index]; if (item == null || item.getType() != material) { continue; } - int remove = (int) Math.min(remaining, item.getAmount()); - int left = item.getAmount() - remove; - remaining -= remove; - - if (left <= 0) { + int remaining = remainingAmounts[index]; + if (remaining <= 0) { updated[index] = null; } else { - item.setAmount(left); + updated[index].setAmount(remaining); } } return updated; } + static @Nullable int[] withdrawAmounts(@NotNull int[] amounts, long required) { + Objects.requireNonNull(amounts, "amounts"); + + if (required < 0L) { + throw new IllegalArgumentException("Required amount cannot be negative."); + } + + long available = 0L; + for (int amount : amounts) { + if (amount < 0) { + throw new IllegalArgumentException("Stack amount cannot be negative."); + } + + available += amount; + if (available >= required) { + break; + } + } + + if (available < required) { + return null; + } + + int[] updated = amounts.clone(); + long remaining = required; + + for (int index = 0; index < updated.length && remaining > 0L; index++) { + int remove = (int) Math.min(remaining, updated[index]); + updated[index] -= remove; + remaining -= remove; + } + + return updated; + } + private static @Nullable Long wholeUnits(double amount) { if (!Double.isFinite(amount) || amount < 0.0D || amount != Math.rint(amount)) { return null; From 21931a631d37d776f047969161a3e4a3b83c588a Mon Sep 17 00:00:00 2001 From: Silent <46107752+TheSilentPro@users.noreply.github.com> Date: Thu, 15 Oct 2026 22:06:39 +0200 Subject: [PATCH 8/8] test(paper): avoid live Paper registries in item economy tests --- .../economy/ItemEconomyProviderTest.java | 37 ++++++------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/headdb-platforms/headdb-paper/src/test/java/io/github/silentdevelopment/headdb/paper/economy/ItemEconomyProviderTest.java b/headdb-platforms/headdb-paper/src/test/java/io/github/silentdevelopment/headdb/paper/economy/ItemEconomyProviderTest.java index a432a29..7490e97 100644 --- a/headdb-platforms/headdb-paper/src/test/java/io/github/silentdevelopment/headdb/paper/economy/ItemEconomyProviderTest.java +++ b/headdb-platforms/headdb-paper/src/test/java/io/github/silentdevelopment/headdb/paper/economy/ItemEconomyProviderTest.java @@ -1,9 +1,9 @@ package io.github.silentdevelopment.headdb.paper.economy; import org.bukkit.Material; -import org.bukkit.inventory.ItemStack; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; @@ -28,35 +28,22 @@ void validatesWholeAmounts() { } @Test - void withdrawsAcrossMultipleStacksWithoutTouchingOtherItems() { - ItemStack[] storage = { - new ItemStack(Material.DIAMOND, 1), - new ItemStack(Material.STONE, 32), - new ItemStack(Material.DIAMOND, 4) - }; - - ItemStack[] updated = ItemEconomyProvider.withdrawStorage(storage, Material.DIAMOND, 3); - - assertEquals(1, storage[0].getAmount()); - assertEquals(4, storage[2].getAmount()); - assertNull(updated[0]); - assertEquals(Material.STONE, updated[1].getType()); - assertEquals(32, updated[1].getAmount()); - assertEquals(Material.DIAMOND, updated[2].getType()); - assertEquals(2, updated[2].getAmount()); + void withdrawsAcrossMultipleStacks() { + int[] amounts = {1, 0, 4}; + + int[] updated = ItemEconomyProvider.withdrawAmounts(amounts, 3); + + assertArrayEquals(new int[]{0, 0, 2}, updated); + assertArrayEquals(new int[]{1, 0, 4}, amounts); } @Test - void insufficientCurrencyDoesNotProduceModifiedStorage() { - ItemStack[] storage = { - new ItemStack(Material.DIAMOND, 2), - new ItemStack(Material.EMERALD, 5) - }; + void insufficientCurrencyDoesNotProduceModifiedAmounts() { + int[] amounts = {2, 0, 0}; - ItemStack[] updated = ItemEconomyProvider.withdrawStorage(storage, Material.DIAMOND, 3); + int[] updated = ItemEconomyProvider.withdrawAmounts(amounts, 3); assertNull(updated); - assertEquals(2, storage[0].getAmount()); - assertEquals(5, storage[1].getAmount()); + assertArrayEquals(new int[]{2, 0, 0}, amounts); } }