From 0919b4c4db066cac7e78d8456fbcbf6b67dc0ff8 Mon Sep 17 00:00:00 2001 From: EpicKnarvik97 Date: Wed, 17 Dec 2025 14:25:14 +0100 Subject: [PATCH] Attempts to start proper implementation of the new action cost --- pom.xml | 2 +- .../blacksmith/BlacksmithPlugin.java | 4 + .../scrapper/GlobalScrapperSettings.java | 67 +++-- .../config/scrapper/ScrapperSetting.java | 18 +- .../blacksmith/container/ActionCost.java | 46 ++-- .../blacksmith/manager/EconomyManager.java | 50 ++-- .../blacksmith/property/CostModifyAction.java | 43 +++ .../blacksmith/trait/CustomTrait.java | 5 +- .../blacksmith/trait/SalvageSession.java | 2 - .../blacksmith/trait/ScrapperTrait.java | 22 +- .../blacksmith/util/ConfigCommandHelper.java | 9 +- .../knarcraft/blacksmith/util/CostHelper.java | 259 +++++++----------- src/main/resources/config.yml | 6 + 13 files changed, 269 insertions(+), 264 deletions(-) create mode 100644 src/main/java/net/knarcraft/blacksmith/property/CostModifyAction.java diff --git a/pom.xml b/pom.xml index a72be81..32567e2 100644 --- a/pom.xml +++ b/pom.xml @@ -83,7 +83,7 @@ net.knarcraft knarlib - 1.2.18 + 1.2.19 compile diff --git a/src/main/java/net/knarcraft/blacksmith/BlacksmithPlugin.java b/src/main/java/net/knarcraft/blacksmith/BlacksmithPlugin.java index 623bb60..ffaba46 100644 --- a/src/main/java/net/knarcraft/blacksmith/BlacksmithPlugin.java +++ b/src/main/java/net/knarcraft/blacksmith/BlacksmithPlugin.java @@ -15,6 +15,7 @@ import net.knarcraft.blacksmith.command.scrapper.ScrapperEditCommand; import net.knarcraft.blacksmith.command.scrapper.ScrapperEditTabCompleter; import net.knarcraft.blacksmith.config.blacksmith.GlobalBlacksmithSettings; import net.knarcraft.blacksmith.config.scrapper.GlobalScrapperSettings; +import net.knarcraft.blacksmith.container.ActionCost; import net.knarcraft.blacksmith.formatting.Translatable; import net.knarcraft.blacksmith.listener.NPCClickListener; import net.knarcraft.blacksmith.listener.PlayerListener; @@ -31,6 +32,7 @@ import net.knarcraft.knarlib.util.ConfigHelper; import net.knarcraft.knarlib.util.UpdateChecker; import org.bukkit.Bukkit; import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.serialization.ConfigurationSerialization; import org.bukkit.event.Event; import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.PluginManager; @@ -124,6 +126,8 @@ public class BlacksmithPlugin extends ConfigCommentPlugin { instance = this; ConfigHelper.saveDefaults(this); + ConfigurationSerialization.registerClass(ActionCost.class); + //Migrate from an earlier configuration file syntax if necessary if (getConfig().getString("scrapper.defaults.dropItem") == null) { net.knarcraft.knarlib.util.ConfigHelper.migrateConfig(this); diff --git a/src/main/java/net/knarcraft/blacksmith/config/scrapper/GlobalScrapperSettings.java b/src/main/java/net/knarcraft/blacksmith/config/scrapper/GlobalScrapperSettings.java index d52a8f2..0c2b069 100644 --- a/src/main/java/net/knarcraft/blacksmith/config/scrapper/GlobalScrapperSettings.java +++ b/src/main/java/net/knarcraft/blacksmith/config/scrapper/GlobalScrapperSettings.java @@ -3,6 +3,7 @@ package net.knarcraft.blacksmith.config.scrapper; import net.knarcraft.blacksmith.BlacksmithPlugin; import net.knarcraft.blacksmith.config.SettingValueType; import net.knarcraft.blacksmith.config.Settings; +import net.knarcraft.blacksmith.container.ActionCost; import net.knarcraft.blacksmith.util.ConfigHelper; import net.knarcraft.blacksmith.util.ItemHelper; import org.bukkit.Material; @@ -113,18 +114,6 @@ public class GlobalScrapperSettings implements Settings { return ConfigHelper.asBoolean(getValue(setting)); } - /** - * Gets the given value as a double - * - *

This will throw an exception if used for a non-double setting

- * - * @param setting

The setting to get the value of

- * @return

The value of the given setting as a double

- */ - public double asDouble(@NotNull ScrapperSetting setting) { - return ConfigHelper.asDouble(getValue(setting)); - } - /** * Gets the value of a setting, using the default if not set * @@ -190,8 +179,9 @@ public class GlobalScrapperSettings implements Settings { * * @return

The cost of using a scrapper to salvage an item

*/ - public double getSalvageCost() { - return asDouble(ScrapperSetting.SALVAGE_COST); + @NotNull + public ActionCost getSalvageCost() { + return getCost(ScrapperSetting.SALVAGE_COST, "salvage"); } /** @@ -199,8 +189,9 @@ public class GlobalScrapperSettings implements Settings { * * @return

The cost of using a scrapper to remove armor trim

*/ - public double getArmorTrimSalvageCost() { - return asDouble(ScrapperSetting.ARMOR_TRIM_SALVAGE_COST); + @NotNull + public ActionCost getArmorTrimSalvageCost() { + return getCost(ScrapperSetting.ARMOR_TRIM_SALVAGE_COST, "armor trim salvage"); } /** @@ -208,8 +199,19 @@ public class GlobalScrapperSettings implements Settings { * * @return

The cost of using a scrapper to remove netherite from an item

*/ - public double getNetheriteSalvageCost() { - return asDouble(ScrapperSetting.NETHERITE_SALVAGE_COST); + @NotNull + public ActionCost getNetheriteSalvageCost() { + return getCost(ScrapperSetting.NETHERITE_SALVAGE_COST, "netherite salvage"); + } + + /** + * Gets the cost of using a scrapper to split an enchanted book + * + * @return

The cost of using a scrapper to split an enchanted book

+ */ + @NotNull + public ActionCost getEnchantedBookSalvageCost() { + return getCost(ScrapperSetting.ENCHANTED_BOOK_SALVAGE_COST, "enchanted book salvage"); } /** @@ -230,6 +232,15 @@ public class GlobalScrapperSettings implements Settings { return asString(ScrapperSetting.SALVAGE_COOLDOWN_INCREASE); } + /** + * Gets whether the enchanted book salvage price should be multiplied with the number of enchantments + * + * @return

Whether the enchanted book salvage price should be multiplied with the number of enchantments

+ */ + public boolean multiplyEnchantedBokSalvagePrice() { + return asBoolean(ScrapperSetting.MULTIPLY_ENCHANTED_BOOK_SALVAGE_COST); + } + /** * Gets trash salvage for the given material * @@ -304,4 +315,24 @@ public class GlobalScrapperSettings implements Settings { return getValue(setting).toString(); } + /** + * Gets the action cost from the given scrapper setting + * + * @param setting

The setting to get cost from

+ * @param costType

Cost identifier for error message

+ * @return

The cost of the action

+ */ + @NotNull + private ActionCost getCost(@NotNull ScrapperSetting setting, @NotNull String costType) { + Object value = getValue(setting); + if (value instanceof ActionCost actionCost) { + return actionCost; + } else if (value instanceof Double number) { + return new ActionCost(number); + } else { + BlacksmithPlugin.error("Unable to load " + costType + " cost! Cost set to free!"); + return new ActionCost(); + } + } + } diff --git a/src/main/java/net/knarcraft/blacksmith/config/scrapper/ScrapperSetting.java b/src/main/java/net/knarcraft/blacksmith/config/scrapper/ScrapperSetting.java index 3f1d849..70865b0 100644 --- a/src/main/java/net/knarcraft/blacksmith/config/scrapper/ScrapperSetting.java +++ b/src/main/java/net/knarcraft/blacksmith/config/scrapper/ScrapperSetting.java @@ -276,21 +276,33 @@ public enum ScrapperSetting implements Setting { /** * The setting for the salvage cost */ - SALVAGE_COST("salvagePrice", SettingValueType.POSITIVE_DOUBLE, 0, + SALVAGE_COST("salvagePrice", SettingValueType.ADVANCED_COST, 0, "The cost of using a scrapper to salvage an item", false, false), /** * The setting for the armor trim salvage cost */ - ARMOR_TRIM_SALVAGE_COST("armorTrimSalvagePrice", SettingValueType.POSITIVE_DOUBLE, 5, + ARMOR_TRIM_SALVAGE_COST("armorTrimSalvagePrice", SettingValueType.ADVANCED_COST, 5, "The cost of using the scrapper to remove armor trim", false, false), /** * The setting for the netherite salvage cost */ - NETHERITE_SALVAGE_COST("netheriteSalvagePrice", SettingValueType.POSITIVE_DOUBLE, 15, + NETHERITE_SALVAGE_COST("netheriteSalvagePrice", SettingValueType.ADVANCED_COST, 15, "The cost of using the scrapper to remove netherite from an item", false, false), + /** + * The setting for the enchanted book salvage cost + */ + ENCHANTED_BOOK_SALVAGE_COST("enchantedBookSalvagePrice", SettingValueType.ADVANCED_COST, 15, + "The cost of using the scrapper to split an enchanted book", false, false), + + /** + * The setting for whether to multiply enchanted book salvage cost + */ + MULTIPLY_ENCHANTED_BOOK_SALVAGE_COST("multiplyEnchantedBookSalvageCost", SettingValueType.BOOLEAN, false, + "Whether to multiply the enchanted book salvage cost with the number of enchantments", false, false), + /** * The mathematical formula for increasing salvage cost */ diff --git a/src/main/java/net/knarcraft/blacksmith/container/ActionCost.java b/src/main/java/net/knarcraft/blacksmith/container/ActionCost.java index 3d72942..3f352f9 100644 --- a/src/main/java/net/knarcraft/blacksmith/container/ActionCost.java +++ b/src/main/java/net/knarcraft/blacksmith/container/ActionCost.java @@ -4,11 +4,9 @@ import net.knarcraft.blacksmith.BlacksmithPlugin; import net.knarcraft.blacksmith.manager.EconomyManager; import net.md_5.bungee.api.ChatColor; import org.bukkit.NamespacedKey; -import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.serialization.ConfigurationSerializable; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,6 +28,22 @@ import java.util.Set; public record ActionCost(double monetaryCost, int expCost, @Nullable ItemStack itemCost, @NotNull Set requiredPermissions) implements ConfigurationSerializable { + /** + * Instantiates a new empty action cost + */ + public ActionCost() { + this(0, 0, null, Set.of()); + } + + /** + * Instantiates a new action cost with the specified monetary cost + * + * @param monetaryCost

The monetary cost to set

+ */ + public ActionCost(double monetaryCost) { + this(monetaryCost, 0, null, Set.of()); + } + /** * Changes the monetary cost of this action * @@ -71,13 +85,13 @@ public record ActionCost(double monetaryCost, int expCost, @Nullable ItemStack i } /** - * Displays this action cost as a string + * Gets this action cost's costs as a string * * @param player

The player to calculate the cost for

* @return

The string representation of this action cost

*/ @NotNull - public String displayCost(@NotNull Player player) { + public String getCostString(@NotNull Player player) { StringBuilder builder = new StringBuilder(); if (monetaryCost > 0) { builder.append(EconomyManager.format(monetaryCost)).append(", ").append("\n"); @@ -174,7 +188,6 @@ public record ActionCost(double monetaryCost, int expCost, @Nullable ItemStack i return new HashMap<>(); } - PlayerInventory playerInventory = player.getInventory(); ItemMeta targetMeta = this.itemCost.getItemMeta(); String displayName = null; List lore = null; @@ -184,9 +197,7 @@ public record ActionCost(double monetaryCost, int expCost, @Nullable ItemStack i } Map output = new HashMap<>(); - HashMap itemsOfType = playerInventory.all(this.itemCost.getType()); - - for (Map.Entry entry : itemsOfType.entrySet()) { + for (Map.Entry entry : player.getInventory().all(this.itemCost.getType()).entrySet()) { if (targetMeta != null) { // Only consider item if the name and lore is the same ItemMeta meta = entry.getValue().getItemMeta(); @@ -214,14 +225,13 @@ public record ActionCost(double monetaryCost, int expCost, @Nullable ItemStack i int clearedAmount = 0; for (Map.Entry entry : getValidItems(player).entrySet()) { - int inventory = entry.getKey(); int amount = entry.getValue(); if (amount <= this.itemCost.getAmount() - clearedAmount) { clearedAmount += amount; player.getInventory().clear(entry.getKey()); } else { clearedAmount = this.itemCost.getAmount(); - ItemStack item = player.getInventory().getItem(inventory); + ItemStack item = player.getInventory().getItem(entry.getKey()); if (item != null) { item.setAmount(amount - clearedAmount); } else { @@ -236,22 +246,6 @@ public record ActionCost(double monetaryCost, int expCost, @Nullable ItemStack i } } - /** - * Loads an action cost from a configuration section - * - * @param configurationSection

The configuration section to load from

- * @param key

The key of the cost to load

- * @return

The loaded cost

- */ - private static ActionCost loadActionCost(@NotNull ConfigurationSection configurationSection, @NotNull String key) { - double cost = configurationSection.getDouble(key, Double.MIN_VALUE); - if (cost != Double.MIN_VALUE) { - return new ActionCost(cost, 0, null, Set.of()); - } else { - return (ActionCost) configurationSection.get(key); - } - } - /** * Deserializes an action cost * diff --git a/src/main/java/net/knarcraft/blacksmith/manager/EconomyManager.java b/src/main/java/net/knarcraft/blacksmith/manager/EconomyManager.java index 9e137ee..5b8d03c 100644 --- a/src/main/java/net/knarcraft/blacksmith/manager/EconomyManager.java +++ b/src/main/java/net/knarcraft/blacksmith/manager/EconomyManager.java @@ -3,8 +3,10 @@ package net.knarcraft.blacksmith.manager; import net.knarcraft.blacksmith.BlacksmithPlugin; import net.knarcraft.blacksmith.config.blacksmith.GlobalBlacksmithSettings; import net.knarcraft.blacksmith.config.scrapper.GlobalScrapperSettings; +import net.knarcraft.blacksmith.container.ActionCost; import net.knarcraft.blacksmith.property.SalvageMethod; import net.knarcraft.blacksmith.util.ItemHelper; +import net.knarcraft.blacksmith.util.SalvageHelper; import net.knarcraft.knarlib.formatting.StringReplacer; import net.milkbowl.vault.economy.Economy; import net.objecthunter.exp4j.Expression; @@ -60,9 +62,9 @@ public class EconomyManager { * @param item

The item to be salvaged

* @return

Whether the player cannot pay for the salvage

*/ - public static boolean cannotPayForSalvage(@NotNull Player player, @NotNull SalvageMethod salvageMethod, @NotNull ItemStack item) { - // TODO: Account for advanced cost options - return economy.getBalance(player) - getSalvageCost(salvageMethod, item, player) < 0; + public static boolean cannotPayForSalvage(@NotNull Player player, @NotNull SalvageMethod salvageMethod, + @NotNull ItemStack item) { + return !getSalvageCost(salvageMethod, item, player).canPay(player); } /** @@ -88,7 +90,7 @@ public class EconomyManager { @NotNull public static String formatSalvageCost(@NotNull SalvageMethod salvageMethod, @NotNull ItemStack item, @NotNull Player player) { - return economy.format(getSalvageCost(salvageMethod, item, player)); + return getSalvageCost(salvageMethod, item, player).getCostString(player); } /** @@ -120,10 +122,11 @@ public class EconomyManager { * @param item

The item to be salvaged

* @return

The salvage cost

*/ - private static double getSalvageCost(@NotNull SalvageMethod salvageMethod, @NotNull ItemStack item, - @NotNull Player player) { + @NotNull + private static ActionCost getSalvageCost(@NotNull SalvageMethod salvageMethod, @NotNull ItemStack item, + @NotNull Player player) { GlobalScrapperSettings settings = BlacksmithPlugin.getInstance().getGlobalScrapperSettings(); - double baseCost = switch (salvageMethod) { + ActionCost cost = switch (salvageMethod) { case SALVAGE, EXTENDED_SALVAGE -> settings.getSalvageCost(); case NETHERITE -> settings.getNetheriteSalvageCost(); case ARMOR_TRIM -> settings.getArmorTrimSalvageCost(); @@ -131,11 +134,12 @@ public class EconomyManager { }; StringReplacer replacer = new StringReplacer(settings.getSalvageCostIncrease()); - replacer.add("{cost}", String.valueOf(baseCost)); + replacer.add("{cost}", String.valueOf(cost.monetaryCost())); replacer.add("{timesUsed}", String.valueOf(PlayerUsageManager.getUsages(player, System.currentTimeMillis() - 3600000))); Expression expression = new ExpressionBuilder(replacer.replace()).build(); - return Math.max(expression.evaluate(), baseCost); + cost.changeMonetaryCost(Math.max(cost.monetaryCost(), expression.evaluate())); + return cost; } /** @@ -158,10 +162,13 @@ public class EconomyManager { * @param player

The player to withdraw from

* @param salvageMethod

The salvage method to withdraw for

*/ - public static void withdrawScrapper(@NotNull Player player, @NotNull SalvageMethod salvageMethod) { - double cost = getSalvageCost(salvageMethod, player.getInventory().getItemInMainHand(), player); - if (cost > 0) { - economy.withdrawPlayer(player, cost); + public static boolean withdrawScrapper(@NotNull Player player, @NotNull SalvageMethod salvageMethod) { + ActionCost cost = getSalvageCost(salvageMethod, player.getInventory().getItemInMainHand(), player); + if (cost.canPay(player)) { + cost.takePayment(player); + return true; + } else { + return false; } } @@ -243,16 +250,15 @@ public class EconomyManager { * @param item

The enchanted book to calculate cost for

* @return

The cost of scrapping the enchanted book

*/ - private static double getEnchantedBookSalvageCost(@NotNull ItemStack item) { - // TODO: Properly implement this - /*GlobalScrapperSettings settings = BlacksmithPlugin.getInstance().getGlobalScrapperSettings(); - - double cost = settings.getEnchantedBookSalvageCost(); - if (settings.multiplyEnchantedBookSalvageCost()) { - cost *= SalvageHelper.getEnchantmentCount(item) - 1; + @NotNull + private static ActionCost getEnchantedBookSalvageCost(@NotNull ItemStack item) { + GlobalScrapperSettings settings = BlacksmithPlugin.getInstance().getGlobalScrapperSettings(); + + ActionCost cost = settings.getEnchantedBookSalvageCost(); + if (settings.multiplyEnchantedBokSalvagePrice()) { + cost.changeMonetaryCost(cost.monetaryCost() * Math.max(SalvageHelper.getEnchantmentCount(item) - 1, 1)); } - return SalvageHelper.getEnchantmentCount(item) * cost;*/ - return 1000000; + return cost; } /** diff --git a/src/main/java/net/knarcraft/blacksmith/property/CostModifyAction.java b/src/main/java/net/knarcraft/blacksmith/property/CostModifyAction.java new file mode 100644 index 0000000..00434b8 --- /dev/null +++ b/src/main/java/net/knarcraft/blacksmith/property/CostModifyAction.java @@ -0,0 +1,43 @@ +package net.knarcraft.blacksmith.property; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * An action for modifying cost + */ +public enum CostModifyAction { + + /** + * Adds some cost to the existing cost, effectively modifying the total cost + */ + ADD, + + /** + * Clears the cost completely + */ + CLEAR, + + /** + * Sets the cost to the new cost, clearing any other existing costs + */ + SET, + ; + + /** + * Gets the action specified by the given string + * + * @param input

The input string to parse

+ * @return

The action, or null if not matched

+ */ + @Nullable + public static CostModifyAction fromString(@NotNull String input) { + for (CostModifyAction action : CostModifyAction.values()) { + if (input.toUpperCase().equals(action.name())) { + return action; + } + } + return null; + } + +} diff --git a/src/main/java/net/knarcraft/blacksmith/trait/CustomTrait.java b/src/main/java/net/knarcraft/blacksmith/trait/CustomTrait.java index 3e1a3bb..8dcf4d4 100644 --- a/src/main/java/net/knarcraft/blacksmith/trait/CustomTrait.java +++ b/src/main/java/net/knarcraft/blacksmith/trait/CustomTrait.java @@ -187,7 +187,10 @@ public abstract class CustomTrait extends Trait { if (isBlacksmith) { EconomyManager.withdrawBlacksmith(player); } else if (this.session instanceof SalvageSession salvageSession) { - EconomyManager.withdrawScrapper(player, salvageSession.salvageMethod); + if (!EconomyManager.withdrawScrapper(player, salvageSession.salvageMethod)) { + return; + } + } PlayerInventory playerInventory = player.getInventory(); ItemStack heldItem = player.getInventory().getItemInMainHand(); diff --git a/src/main/java/net/knarcraft/blacksmith/trait/SalvageSession.java b/src/main/java/net/knarcraft/blacksmith/trait/SalvageSession.java index 39bbca1..c580824 100644 --- a/src/main/java/net/knarcraft/blacksmith/trait/SalvageSession.java +++ b/src/main/java/net/knarcraft/blacksmith/trait/SalvageSession.java @@ -73,8 +73,6 @@ public class SalvageSession extends Session implements Runnable { return true; } - // TODO: Check item cost. If - if (EconomyManager.cannotPayForSalvage(this.player, this.salvageMethod, this.itemToSalvage)) { NPCFormatter.sendNPCMessage(this.npc, this.player, this.config.getInsufficientFundsMessage()); return true; diff --git a/src/main/java/net/knarcraft/blacksmith/trait/ScrapperTrait.java b/src/main/java/net/knarcraft/blacksmith/trait/ScrapperTrait.java index a4482cf..4c16dd9 100644 --- a/src/main/java/net/knarcraft/blacksmith/trait/ScrapperTrait.java +++ b/src/main/java/net/knarcraft/blacksmith/trait/ScrapperTrait.java @@ -4,7 +4,6 @@ import net.citizensnpcs.api.util.DataKey; import net.knarcraft.blacksmith.BlacksmithPlugin; import net.knarcraft.blacksmith.config.SmithPreset; import net.knarcraft.blacksmith.config.SmithPresetFilter; -import net.knarcraft.blacksmith.config.scrapper.GlobalScrapperSettings; import net.knarcraft.blacksmith.config.scrapper.ScrapperNPCSettings; import net.knarcraft.blacksmith.config.scrapper.ScrapperSetting; import net.knarcraft.blacksmith.container.RecipeResult; @@ -312,31 +311,12 @@ public class ScrapperTrait extends CustomTrait { } else if (salvageMethod == SalvageMethod.NETHERITE) { NPCFormatter.sendNPCMessage(this.npc, player, replacer.replace(getSettings().getNetheriteCostMessage())); } else if (salvageMethod == SalvageMethod.ENCHANTED_BOOK) { - StringReplacer replacer2 = new StringReplacer(); - replacer2.add("{cost}", getEnchantedBookCost()); - NPCFormatter.sendNPCMessage(this.npc, player, replacer2.replace(getSettings().getEnchantedBookCostMessage())); + NPCFormatter.sendNPCMessage(this.npc, player, replacer.replace(getSettings().getEnchantedBookCostMessage())); } else { BlacksmithPlugin.error("Unrecognized salvage method " + salvageMethod); } } - private String getEnchantedBookCost() { - // TODO: If both an item and money is required, print both requirements - // TODO: If only money is required, print the money requirement - // TODO: If an item requirement is set, print the item requirement - - GlobalScrapperSettings scrapperSettings = BlacksmithPlugin.getInstance().getGlobalScrapperSettings(); - /*String moneyCost = EconomyManager.format(scrapperSettings.getEnchantedBookSalvageCost()); - //ItemStack itemCost = scrapperSettings. - if (scrapperSettings.requireMoneyAndItemForEnchantedBookSalvage()) { - // TODO: Print both with a + between them (if item has a special name, use that instead of the material name) - - } else { - // TODO: If the item is not null, print it, otherwise print the monetary cost - }*/ - return ""; - } - @Override protected boolean showExactTime() { return BlacksmithPlugin.getInstance().getGlobalScrapperSettings().showExactTime(); diff --git a/src/main/java/net/knarcraft/blacksmith/util/ConfigCommandHelper.java b/src/main/java/net/knarcraft/blacksmith/util/ConfigCommandHelper.java index b242301..03ce11e 100644 --- a/src/main/java/net/knarcraft/blacksmith/util/ConfigCommandHelper.java +++ b/src/main/java/net/knarcraft/blacksmith/util/ConfigCommandHelper.java @@ -26,19 +26,20 @@ public final class ConfigCommandHelper { /** * Changes the value of the setting defined in the user's input * - * @param args

The arguments given by the user

+ * @param arguments

The arguments given by the user

* @param detectedSetting

The setting recognized from the input, if any

* @param settings

The global settings object to get settings from

* @param sender

The command sender to display any output to

*/ - public static void changeValue(@NotNull String[] args, + public static void changeValue(@NotNull String[] arguments, @NotNull K detectedSetting, @NotNull Settings settings, @NotNull CommandSender sender) { - String newValue = args[1]; + // TODO: Account for action cost + String newValue = arguments[1]; //This makes sure all arguments are treated as a sentence if (detectedSetting.getValueType() == SettingValueType.STRING) { - newValue = String.join(" ", Arrays.asList(args).subList(1, args.length)); + newValue = String.join(" ", Arrays.asList(arguments).subList(1, arguments.length)); } settings.changeValue(detectedSetting, newValue); getValueChangedMessage(detectedSetting.getCommandName(), newValue).success(sender); diff --git a/src/main/java/net/knarcraft/blacksmith/util/CostHelper.java b/src/main/java/net/knarcraft/blacksmith/util/CostHelper.java index e4fc8f1..596ac81 100644 --- a/src/main/java/net/knarcraft/blacksmith/util/CostHelper.java +++ b/src/main/java/net/knarcraft/blacksmith/util/CostHelper.java @@ -2,33 +2,26 @@ package net.knarcraft.blacksmith.util; import net.knarcraft.blacksmith.container.ActionCost; import net.knarcraft.blacksmith.formatting.Translatable; +import net.knarcraft.blacksmith.property.CostModifyAction; import net.knarcraft.blacksmith.property.CostType; import net.knarcraft.knarlib.formatting.FormatBuilder; -import org.bukkit.Bukkit; +import net.knarcraft.knarlib.util.TabCompletionHelper; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; -import org.bukkit.permissions.Permission; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; -import java.util.StringJoiner; /** * A helper class for setting action costs */ public final class CostHelper { - private static List plugins; - private static Map> permissions; - private CostHelper() { } @@ -38,10 +31,10 @@ public final class CostHelper { * * @param commandSender

The command sender to notify of any problems

* @param costString

The string to parse into a cost

- * @return

The parsed cost

- * @throws IllegalArgumentException

If the specified cost is invalid

+ * @return

The parsed cost, or null if not a valid number

*/ - public static double parseSimpleCost(@NotNull CommandSender commandSender, + @Nullable + public static Double parseSimpleCost(@NotNull CommandSender commandSender, @NotNull String costString) throws IllegalArgumentException { try { double cost = Double.parseDouble(costString); @@ -51,7 +44,7 @@ public final class CostHelper { return cost; } catch (NumberFormatException exception) { new FormatBuilder(Translatable.DOUBLE_COST_REQUIRED).error(commandSender); - throw new IllegalArgumentException("Invalid cost given"); + return null; } } @@ -62,23 +55,19 @@ public final class CostHelper { * @return

The available tab-complete options

*/ public static @Nullable List tabCompleteCost(@NotNull String[] arguments) { - if (plugins == null) { - loadAvailablePermissions(); - } - if (arguments.length == 1) { return List.of("simple", "advanced"); } else if (arguments.length == 2) { if (arguments[0].equalsIgnoreCase("simple")) { - return List.of(""); + return List.of(); } else { - return List.of("add", "set", "clear"); + return TabCompletionHelper.filterMatchingStartsWith(TabCompletionHelper.getEnumList(CostModifyAction.class), arguments[1]); } } else if (arguments.length == 3) { if (arguments[0].equalsIgnoreCase("simple")) { - return List.of(""); + return List.of(); } else { - return List.of("economy", "item", "exp", "permission"); + return TabCompletionHelper.filterMatchingStartsWith(TabCompletionHelper.getEnumList(CostType.class), arguments[2]); } } else if (arguments.length == 4) { CostType costType = CostType.parse(arguments[2]); @@ -86,7 +75,7 @@ public final class CostHelper { return null; } return switch (costType) { - case PERMISSION -> tabCompletePermission(arguments[3]); + case PERMISSION -> TabCompletionHelper.tabCompletePermission(arguments[3]); case ECONOMY -> List.of("0.5", "1", "10"); case EXP -> List.of("1, 5, 10"); case ITEM -> List.of(); @@ -98,86 +87,123 @@ public final class CostHelper { /** * Modifies the cost of an action * - * @param arguments

The arguments given by a player

- * @param oldCost

The previous cost of the action

- * @param player

The player attempting to alter the action cost

+ * @param costAction

The action to perform on the cost

+ * @param costTypeName

The name of the cost to modify, or null if clearing costs

+ * @param costValue

The value of the new cost, or null if clearing costs

+ * @param oldCost

The previous cost of the action

+ * @param player

The player attempting to alter the action cost

* @return

The modified action cost, or null if something went wrong

*/ @Nullable - public static ActionCost modifyActionCost(@NotNull String[] arguments, @NotNull ActionCost oldCost, + public static ActionCost modifyActionCost(@NotNull String costAction, @Nullable String costTypeName, + @Nullable String costValue, @NotNull ActionCost oldCost, @NotNull Player player) { CostType costType; - if (arguments.length > 2) { - costType = CostType.parse(arguments[2]); + if (costTypeName != null) { + costType = CostType.parse(costTypeName); } else { costType = null; } - switch (arguments[1].toLowerCase()) { - case "add": - if (costType == null) { - player.sendMessage("Invalid cost type specified!"); - return null; - } - return parseCost(costType, Arrays.copyOfRange(arguments, 2, arguments.length), oldCost, player); - case "clear": - // Clears one or all fields of a cost - if (costType == null) { - return new ActionCost(0, 0, null, Set.of()); - } else { - return switch (costType) { - case EXP -> oldCost.changeExpCost(0); - case ITEM -> oldCost.changeItemCost(null); - case ECONOMY -> oldCost.changeMonetaryCost(0); - case PERMISSION -> oldCost.changePermissionCost(Set.of()); - }; - } - case "set": - if (costType == null) { - player.sendMessage("Invalid cost type specified!"); - return null; - } - return parseCost(costType, Arrays.copyOfRange(arguments, 2, arguments.length), - new ActionCost(0, 0, null, Set.of()), player); - default: - return null; + CostModifyAction action = CostModifyAction.fromString(costAction); + if (action == null) { + return null; + } + + if (action != CostModifyAction.CLEAR && (costType == null || costValue == null)) { + player.sendMessage("Invalid cost type or value specified!"); + return null; + } + + return switch (action) { + case CLEAR -> clearActionCost(costType, oldCost); + case ADD -> addActionCost(costType, costValue, oldCost, player); + case SET -> setActionCost(costType, costValue, player); + }; + } + + /** + * Sets the cost to the specified value + * + * @param costType

The type of cost to set

+ * @param costValue

The value of the new cost

+ * @param player

The player to alert if the cost cannot be properly set

+ * @return

The new action cost

+ */ + public static ActionCost setActionCost(@NotNull CostType costType, @NotNull String costValue, + @NotNull Player player) { + return parseCost(costType, costValue, new ActionCost(), player); + } + + /** + * Modifies a value for the specified action cost + * + * @param costType

The type of cost to modify

+ * @param costValue

The new value of the cost

+ * @param oldCost

The cost to modify

+ * @param player

The player to alert if the cost cannot be properly set

+ * @return

The new action cost

+ */ + public static ActionCost addActionCost(@NotNull CostType costType, @NotNull String costValue, + @NotNull ActionCost oldCost, @NotNull Player player) { + return parseCost(costType, costValue, oldCost, player); + } + + /** + * Clears an action cost + * + * @param costType

The type of action cost to clear, or null if clearing all action costs

+ * @param oldCost

The old cost to modify, or null if clearing all action costs

+ * @return

The modified cost

+ */ + public static ActionCost clearActionCost(@Nullable CostType costType, @Nullable ActionCost oldCost) { + // Clears one or all fields of a cost + if (costType == null || oldCost == null) { + return new ActionCost(); + } else { + return switch (costType) { + case EXP -> oldCost.changeExpCost(0); + case ITEM -> oldCost.changeItemCost(null); + case ECONOMY -> oldCost.changeMonetaryCost(0); + case PERMISSION -> oldCost.changePermissionCost(Set.of()); + }; } } /** * Parses an advanced action cost * - * @param costType

The type of cost to parse

- * @param arguments

The arguments given by the player

- * @param oldCost

The old cost to modify

- * @param player

The player changing the value

+ * @param costType

The type of cost to parse

+ * @param value

The value to parse

+ * @param oldCost

The old cost to modify

+ * @param player

The player changing the value

* @return

The new action cost, or null if the process failed.

*/ @Nullable - private static ActionCost parseCost(@NotNull CostType costType, @NotNull String[] arguments, @NotNull ActionCost oldCost, + private static ActionCost parseCost(@NotNull CostType costType, @NotNull String value, @NotNull ActionCost oldCost, @NotNull Player player) { switch (costType) { case ECONOMY: - double economyCost = Double.parseDouble(arguments[0]); + double economyCost = Double.parseDouble(value); if (economyCost < 0) { - player.sendMessage("Cost cannot be negative!"); + new FormatBuilder("Cost cannot be negative!").error(player); return null; } return oldCost.changeMonetaryCost(economyCost); case ITEM: ItemStack itemCost = player.getInventory().getItemInMainHand(); if (itemCost.getType().isAir()) { - player.sendMessage("You have no item in your main hand"); + new FormatBuilder("You have no item in your main hand").error(player); return null; } return oldCost.changeItemCost(itemCost); case PERMISSION: - Set permissionSet = new HashSet<>(Arrays.asList(arguments[0].split(","))); + Set permissionSet = new HashSet<>(Arrays.asList(value.split(","))); return oldCost.changePermissionCost(permissionSet); case EXP: - int expCost = Integer.parseInt(arguments[0]); + int expCost = Integer.parseInt(value); if (expCost < 0) { - player.sendMessage("Exp cost cannot be negative!"); + new FormatBuilder("Exp cost cannot be negative!").error(player); return null; } return oldCost.changeExpCost(expCost); @@ -186,103 +212,4 @@ public final class CostHelper { } } - /** - * Gets the tab complete value for the permission typed - * - * @param typedNode

The full permission node typed by the player

- * @return

All known valid auto-complete options

- */ - private static @NotNull List tabCompletePermission(@NotNull String typedNode) { - StringBuilder permissionListString = new StringBuilder(); - if (typedNode.contains(",")) { - String[] permissionList = typedNode.split(","); - for (int i = 0; i < permissionList.length - 1; i++) { - permissionListString.append(permissionList[i]); - permissionListString.append(","); - } - typedNode = permissionList[permissionList.length - 1]; - } - String permissionPrefix = permissionListString.toString(); - List output; - if (typedNode.contains(".")) { - List matchingPermissions = permissions.get(typedNode.substring(0, typedNode.lastIndexOf("."))); - if (matchingPermissions == null) { - if (permissionPrefix.isEmpty()) { - output = new ArrayList<>(); - } else { - List onlyPrefix = new ArrayList<>(); - onlyPrefix.add(permissionPrefix); - output = onlyPrefix; - } - } else { - //Filter by the typed text - output = filterMatching(matchingPermissions, typedNode); - } - } else { - output = plugins; - } - - //Add previous permissions in the comma-separated lists as a prefix - if (permissionPrefix.isEmpty()) { - return output; - } else { - List prefixed = new ArrayList<>(output.size()); - for (String matchingCompletion : output) { - prefixed.add(permissionPrefix + matchingCompletion); - } - return prefixed; - } - } - - /** - * Find completable strings which match the text typed by the command's sender - * - * @param values

The values to filter

- * @param typedText

The text the player has started typing

- * @return

The given string values which start with the player's typed text

- */ - private static @NotNull List filterMatching(@NotNull List values, @NotNull String typedText) { - List configValues = new ArrayList<>(); - for (String value : values) { - if (value.toLowerCase().startsWith(typedText.toLowerCase())) { - configValues.add(value); - } - } - return configValues; - } - - /** - * Loads all permissions available from bukkit plugins - */ - private static void loadAvailablePermissions() { - plugins = new ArrayList<>(); - permissions = new HashMap<>(); - - for (Permission permission : Bukkit.getPluginManager().getPermissions()) { - loadPermission(permission.getName()); - } - } - - /** - * Loads a given permission into the proper lists and maps - * - * @param permissionName

The permission to load

- */ - private static void loadPermission(@NotNull String permissionName) { - String[] permissionParts = permissionName.split("\\."); - if (permissionParts.length == 1 && !plugins.contains(permissionParts[0])) { - plugins.add(permissionParts[0]); - } else if (permissionParts.length > 1) { - StringJoiner pathJoiner = new StringJoiner("."); - for (int j = 0; j < permissionParts.length - 1; j++) { - pathJoiner.add(permissionParts[j]); - } - String path = pathJoiner.toString(); - List permissionList = permissions.computeIfAbsent(path, k -> new ArrayList<>()); - permissionList.add(permissionName); - - loadPermission(path); - } - } - } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index b35b87e..648b7bb 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -142,6 +142,9 @@ scrapper: # The cost of using the scrapper to remove netherite from an item netheriteSalvagePrice: 15 + # The cost of splitting an enchanted book into several books + enchantedBookSalvagePrice: 15 + # The mathematical formula for salvage cost increase when continually used within the same hour. This is necessary # for some servers where items can be easily farmed. Set to {cost} to disable behavior. salvageCostIncrease: "{cost}*{timesUsed}" @@ -149,6 +152,9 @@ scrapper: # The mathematical formula for salvage cooldown increase when continually used within the same hour. This is # necessary for some servers where items can be easily farmed. Set to {cooldown} to disable behavior. salvageCooldownIncrease: "{cooldown}*{timesUsed}" + + # Whether to multiply the enchanted book salvage price with the number of enchantments on the book + multiplyEnchantedBookSalvageCost: false # The settings which are set to any new scrapper NPC. To change any of these settings for an existing NPC, you must # change the Citizens NPC file, or use the /scrapper command