diff --git a/src/main/java/net/knarcraft/blacksmith/BlacksmithPlugin.java b/src/main/java/net/knarcraft/blacksmith/BlacksmithPlugin.java index f0454bb..5ebdf3b 100644 --- a/src/main/java/net/knarcraft/blacksmith/BlacksmithPlugin.java +++ b/src/main/java/net/knarcraft/blacksmith/BlacksmithPlugin.java @@ -1,33 +1,20 @@ package net.knarcraft.blacksmith; import net.citizensnpcs.api.CitizensAPI; -import net.citizensnpcs.api.util.DataKey; -import net.knarcraft.blacksmith.config.Setting; -import net.knarcraft.blacksmith.config.Settings; -import net.milkbowl.vault.economy.Economy; -import org.bukkit.ChatColor; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.Damageable; -import org.bukkit.plugin.RegisteredServiceProvider; +import net.knarcraft.blacksmith.command.BlackSmithCommand; +import net.knarcraft.blacksmith.config.GlobalSettings; +import org.bukkit.command.PluginCommand; import org.bukkit.plugin.java.JavaPlugin; -import org.jetbrains.annotations.NotNull; import java.util.logging.Level; -import static net.knarcraft.blacksmith.util.Sanitizer.sanitizeItemName; - /** * Blacksmith's main class */ public class BlacksmithPlugin extends JavaPlugin { private static BlacksmithPlugin instance; - private Settings config; - private Economy economy; + private GlobalSettings config; /** * Gets an instance of the Blacksmith plugin @@ -43,14 +30,19 @@ public class BlacksmithPlugin extends JavaPlugin { * * @return

Settings for the blacksmith plugin

*/ - public Settings getSettings() { + public GlobalSettings getSettings() { return config; } + /** + * Reloads the configuration file from disk + */ + public void reload() { + config.load(); + } + @Override public void onDisable() { - // config.save(); - getLogger().log(Level.INFO, " v" + getDescription().getVersion() + " disabled."); } @@ -59,11 +51,11 @@ public class BlacksmithPlugin extends JavaPlugin { instance = this; //Load settings - config = new Settings(this); + config = new GlobalSettings(this); config.load(); getLogger().log(Level.INFO, "Setting Up Vault now...."); - boolean canLoad = setupVault(); + boolean canLoad = EconomyManager.setUp(getServer().getServicesManager(), getLogger()); if (!canLoad) { getLogger().log(Level.SEVERE, "Vault Integration Failed...."); getServer().getPluginManager().disablePlugin(this); @@ -73,200 +65,13 @@ public class BlacksmithPlugin extends JavaPlugin { CitizensAPI.getTraitFactory().registerTrait( net.citizensnpcs.api.trait.TraitInfo.create(BlacksmithTrait.class).withName("blacksmith")); + //Register the blacksmith main-command + PluginCommand blacksmithCommand = this.getCommand("blacksmith"); + if (blacksmithCommand != null) { + blacksmithCommand.setExecutor(new BlackSmithCommand()); + } + getLogger().log(Level.INFO, " v" + getDescription().getVersion() + " enabled."); } - /** - * Sets up Vault for economy - * - * @return

True if Vault was successfully set up

- */ - private boolean setupVault() { - // Setup Vault - RegisteredServiceProvider economyProvider = getServer().getServicesManager().getRegistration( - Economy.class); - if (economyProvider != null) { - economy = economyProvider.getProvider(); - return true; - } else { - // Disable if no economy plugin was found - getServer().getLogger().log(Level.SEVERE, "Failed to load an economy plugin. Disabling..."); - return false; - } - } - - @Override - public boolean onCommand(final CommandSender sender, final @NotNull Command command, final @NotNull String label, - final String[] args) { - //Handle the reload command - config.load(); - sender.sendMessage(ChatColor.GREEN + "Blacksmith config reloaded!"); - return true; - } - - /** - * Gets whether the given item is a type of tool - * - * @param item

The item to check if is tool or not

- * @return

True if the given item is a type of tool

- */ - public boolean isTool(ItemStack item) { - return switch (item.getType()) { - case WOODEN_PICKAXE, WOODEN_SHOVEL, WOODEN_HOE, WOODEN_SWORD, WOODEN_AXE, STONE_PICKAXE, STONE_SHOVEL, - STONE_HOE, STONE_SWORD, STONE_AXE, GOLDEN_PICKAXE, GOLDEN_SHOVEL, GOLDEN_HOE, GOLDEN_SWORD, - GOLDEN_AXE, IRON_PICKAXE, IRON_SHOVEL, IRON_HOE, IRON_SWORD, IRON_AXE, DIAMOND_PICKAXE, - DIAMOND_SHOVEL, DIAMOND_HOE, DIAMOND_SWORD, DIAMOND_AXE, NETHERITE_SWORD, NETHERITE_SHOVEL, - NETHERITE_PICKAXE, NETHERITE_AXE, NETHERITE_HOE, BOW, CROSSBOW, FLINT_AND_STEEL, FISHING_ROD, - SHEARS, TRIDENT, SHIELD -> true; - default -> false; - }; - } - - /** - * Gets whether the given item is a type of armor - * - * @param item

The item to check if is armor or not

- * @return

True if the given item is a type of armor

- */ - public static boolean isArmor(ItemStack item) { - return switch (item.getType()) { - case LEATHER_HELMET, LEATHER_CHESTPLATE, LEATHER_LEGGINGS, LEATHER_BOOTS, CHAINMAIL_HELMET, - CHAINMAIL_CHESTPLATE, CHAINMAIL_LEGGINGS, CHAINMAIL_BOOTS, GOLDEN_HELMET, GOLDEN_CHESTPLATE, - GOLDEN_LEGGINGS, GOLDEN_BOOTS, IRON_HELMET, IRON_CHESTPLATE, IRON_LEGGINGS, IRON_BOOTS, - DIAMOND_HELMET, DIAMOND_CHESTPLATE, DIAMOND_LEGGINGS, DIAMOND_BOOTS, TURTLE_HELMET, ELYTRA, - NETHERITE_HELMET, NETHERITE_CHESTPLATE, NETHERITE_LEGGINGS, NETHERITE_BOOTS -> true; - default -> false; - }; - } - - /** - * Gets whether the given player can pay for re-forging their held item - * - * @param player

The player holding an item

- * @return

Whether the player can pay for the re-forge

- */ - public boolean canPay(Player player) { - return economy.getBalance(player) - getHeldItemCost(player) >= 0; - } - - /** - * Gets the human-readable cost of the given player's held item - * - * @param player

The player holding an item

- * @return

The formatted cost

- */ - public String formatCost(Player player) { - double cost = getHeldItemCost(player); - return economy.format(cost); - } - - /** - * Withdraws the re-forge cost from the given player - * - *

The cost is automatically calculated from the item in the player's main hand.

- * - * @param player

The player to withdraw from

- */ - public void withdraw(Player player) { - economy.withdrawPlayer(player, getHeldItemCost(player)); - } - - /** - * Gets the current durability of the given item - * - * @param itemStack

The item to get the durability of

- * @return

The durability of the item

- */ - public static short getDurability(ItemStack itemStack) { - Damageable damageable = (Damageable) itemStack.getItemMeta(); - int maxDurability = itemStack.getType().getMaxDurability(); - if (damageable != null) { - return (short) (maxDurability - damageable.getDamage()); - } else { - return (short) maxDurability; - } - } - - /** - * Gets the damage done to the given item - * - * @param itemStack

The damage done to the item

- * @return

The damage done to the item

- */ - public static short getDamage(ItemStack itemStack) { - Damageable damageable = (Damageable) itemStack.getItemMeta(); - if (damageable != null) { - return (short) damageable.getDamage(); - } else { - return 0; - } - } - - /** - * Gets the cost of repairing the given item - * - * @param item

The item to be repaired

- * @return

The cost of the repair

- */ - private double getCost(ItemStack item) { - DataKey root = config.getConfig().getKey(""); - String itemName = sanitizeItemName(item.getType().name()); - double price; - if (root.keyExists("base-prices." + itemName)) { - price = root.getDouble("base-prices." + itemName); - } else { - price = Setting.BASE_PRICE.asDouble(); - } - - // Adjust price based on durability and enchantments - double pricePerDurabilityPoint; - if (root.keyExists("price-per-durability-point." + itemName)) { - pricePerDurabilityPoint = root.getDouble("price-per-durability-point." + itemName); - } else { - pricePerDurabilityPoint = Setting.PRICE_PER_DURABILITY_POINT.asDouble(); - } - if (config.getNaturalCost()) { - //Cost increases with damage - price += ((double) getDamage(item)) * pricePerDurabilityPoint; - } else { - //Cost decreases with damage - price += ((double) getDurability(item)) * pricePerDurabilityPoint; - } - - //Add the enchantment modifier for each enchantment on the item - price += getEnchantmentCost(item, root); - return price; - } - - /** - * Gets the cost resulting from all enchantments on the given item - * - * @param item

The item to calculate enchantment cost for

- * @param root

The data key containing the enchantment-modifiers option

- * @return

The resulting enchantment cost

- */ - private double getEnchantmentCost(ItemStack item, DataKey root) { - double enchantmentModifier = Setting.ENCHANTMENT_MODIFIER.asDouble(); - double price = 0; - for (Enchantment enchantment : item.getEnchantments().keySet()) { - String enchantmentKey = "enchantment-modifiers." + sanitizeItemName(enchantment.getKey().toString()); - if (root.keyExists(enchantmentKey)) { - price += root.getDouble(enchantmentKey) * item.getEnchantmentLevel(enchantment); - } else { - price += enchantmentModifier * item.getEnchantmentLevel(enchantment); - } - } - return price; - } - - /** - * Gets the cost of the item in the given player's main hand - * - * @param player

The player to calculate the cost for

- * @return

The calculated cost

- */ - private double getHeldItemCost(Player player) { - return getCost(player.getInventory().getItemInMainHand()); - } - } diff --git a/src/main/java/net/knarcraft/blacksmith/BlacksmithTrait.java b/src/main/java/net/knarcraft/blacksmith/BlacksmithTrait.java index 5dbf99c..2adac65 100644 --- a/src/main/java/net/knarcraft/blacksmith/BlacksmithTrait.java +++ b/src/main/java/net/knarcraft/blacksmith/BlacksmithTrait.java @@ -4,10 +4,10 @@ import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.api.trait.Trait; import net.citizensnpcs.api.util.DataKey; -import net.knarcraft.blacksmith.config.Settings; -import net.knarcraft.blacksmith.util.Sanitizer; +import net.knarcraft.blacksmith.config.NPCSettings; import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.enchantments.EnchantmentTarget; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; @@ -17,9 +17,9 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.block.Action; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.Damageable; import org.bukkit.util.Vector; -import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; import java.util.List; @@ -27,18 +27,14 @@ import java.util.Map; import java.util.Objects; import java.util.UUID; -import static net.knarcraft.blacksmith.util.Sanitizer.sanitizedToItemName; - /** * The class representing the Blacksmith NPC trait */ public class BlacksmithTrait extends Trait { - private final BlacksmithPlugin plugin; - private final List reforgeAbleItems = new ArrayList<>(); private final Map coolDowns = new HashMap<>(); private ReforgeSession session; - private final Settings config; + private final NPCSettings config; private long _sessionStart = System.currentTimeMillis(); /** @@ -46,8 +42,9 @@ public class BlacksmithTrait extends Trait { */ public BlacksmithTrait() { super("blacksmith"); - plugin = (BlacksmithPlugin) Bukkit.getServer().getPluginManager().getPlugin("Blacksmith"); - this.config = BlacksmithPlugin.getInstance().getSettings(); + //This should crash if the blacksmith plugin hasn't been properly registered + Bukkit.getServer().getPluginManager().getPlugin("Blacksmith"); + this.config = new NPCSettings(BlacksmithPlugin.getInstance().getSettings()); } /** @@ -67,26 +64,23 @@ public class BlacksmithTrait extends Trait { this.session = null; } + /** + * Loads all config values stored in citizens' config file for this NPC + * + * @param key

The data key used for the config root

+ */ @Override public void load(DataKey key) { - for (DataKey sub : key.getRelative("reforge-able-items").getIntegerSubKeys()) { - Material material = Material.getMaterial(sanitizedToItemName(sub.getString(""))); - if (material != null) { - reforgeAbleItems.add(material); - } - } config.loadVariables(key); } + /** + * Saves all config values for this NPC + * + * @param key

The data key used for the config root

+ */ @Override public void save(DataKey key) { - //Save all items the blacksmith knows how to reforge - for (int i = 0; i < reforgeAbleItems.size(); i++) { - key.getRelative("reforge-able-items").setString(String.valueOf(i), Sanitizer.sanitizeItemName( - reforgeAbleItems.get(i).name())); - } - - //Save all other config values config.saveVariables(key); } @@ -105,7 +99,7 @@ public class BlacksmithTrait extends Trait { //Block armor equip if interacting with a blacksmith ItemStack usedItem = event.getPlayer().getInventory().getItem(event.getHand()); - if (usedItem != null && BlacksmithPlugin.isArmor(usedItem)) { + if (usedItem != null && isArmor(usedItem)) { event.setUseItemInHand(Event.Result.DENY); event.getPlayer().updateInventory(); } @@ -199,9 +193,9 @@ public class BlacksmithTrait extends Trait { */ private void startSession(Player player) { ItemStack hand = player.getInventory().getItemInMainHand(); - //If not a tool, not armor, and not set in reforgeAbleItems, refuse to repair - if ((!plugin.isTool(hand) && !BlacksmithPlugin.isArmor(hand)) || - (!reforgeAbleItems.isEmpty() && !reforgeAbleItems.contains(hand.getType()))) { + //Refuse if not repairable, or if reforge-able items is set, but doesn't include the held item + List reforgeAbleItems = config.getReforgeAbleItems(); + if (!isRepairable(hand) || (!reforgeAbleItems.isEmpty() && !reforgeAbleItems.contains(hand.getType()))) { player.sendMessage(config.getInvalidItemMessage()); return; } @@ -211,7 +205,7 @@ public class BlacksmithTrait extends Trait { session = new ReforgeSession(this, player, npc, config); //Tell the player the cost of repairing the item - String cost = plugin.formatCost(player); + String cost = EconomyManager.formatCost(player); String itemName = hand.getType().name().toLowerCase().replace('_', ' '); player.sendMessage(config.getCostMessage().replace("", cost).replace("", itemName)); } @@ -224,7 +218,7 @@ public class BlacksmithTrait extends Trait { */ private void reforge(NPC npc, Player player) { player.sendMessage(config.getStartReforgeMessage()); - plugin.withdraw(player); + EconomyManager.withdraw(player); session.beginReforge(); ItemStack heldItem = player.getInventory().getItemInMainHand(); @@ -266,4 +260,33 @@ public class BlacksmithTrait extends Trait { return target; } + /** + * Gets whether the given item is repairable + * + * @param item

The item to check

+ * @return

True if the item is repairable

+ */ + private static boolean isRepairable(ItemStack item) { + return item.getItemMeta() instanceof Damageable; + } + + /** + * Gets whether the given item is a type of armor + * + * @param item

The item to check if is armor or not

+ * @return

True if the given item is a type of armor

+ */ + public static boolean isArmor(ItemStack item) { + return EnchantmentTarget.WEARABLE.includes(item); + //TODO: Remove this commented-out code if the above line works + /*return switch (item.getType()) { + case LEATHER_HELMET, LEATHER_CHESTPLATE, LEATHER_LEGGINGS, LEATHER_BOOTS, CHAINMAIL_HELMET, + CHAINMAIL_CHESTPLATE, CHAINMAIL_LEGGINGS, CHAINMAIL_BOOTS, GOLDEN_HELMET, GOLDEN_CHESTPLATE, + GOLDEN_LEGGINGS, GOLDEN_BOOTS, IRON_HELMET, IRON_CHESTPLATE, IRON_LEGGINGS, IRON_BOOTS, + DIAMOND_HELMET, DIAMOND_CHESTPLATE, DIAMOND_LEGGINGS, DIAMOND_BOOTS, TURTLE_HELMET, ELYTRA, + NETHERITE_HELMET, NETHERITE_CHESTPLATE, NETHERITE_LEGGINGS, NETHERITE_BOOTS -> true; + default -> false; + };*/ + } + } diff --git a/src/main/java/net/knarcraft/blacksmith/EconomyManager.java b/src/main/java/net/knarcraft/blacksmith/EconomyManager.java new file mode 100644 index 0000000..35c5a70 --- /dev/null +++ b/src/main/java/net/knarcraft/blacksmith/EconomyManager.java @@ -0,0 +1,174 @@ +package net.knarcraft.blacksmith; + +import net.knarcraft.blacksmith.config.GlobalSettings; +import net.milkbowl.vault.economy.Economy; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.Damageable; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.plugin.ServicesManager; + +import java.util.logging.Level; +import java.util.logging.Logger; + +public class EconomyManager { + + private static Economy economy; + + private EconomyManager() { + + } + + /** + * Sets up Vault economy support + * + * @param servicesManager

The services manager to use for finding a Vault provider

+ * @param logger

The logger to use for logging

+ * @return

True if Vault was successfully set up

+ */ + public static boolean setUp(ServicesManager servicesManager, Logger logger) { + //If already set up, there is nothing to do + if (economy != null) { + return true; + } + return setupVault(servicesManager, logger); + } + + /** + * Gets whether the given player can pay for re-forging their held item + * + * @param player

The player holding an item

+ * @return

Whether the player can pay for the re-forge

+ */ + public static boolean canPay(Player player) { + return economy.getBalance(player) - getHeldItemCost(player) >= 0; + } + + /** + * Gets the human-readable cost of the given player's held item + * + * @param player

The player holding an item

+ * @return

The formatted cost

+ */ + public static String formatCost(Player player) { + double cost = getHeldItemCost(player); + return economy.format(cost); + } + + /** + * Withdraws the re-forge cost from the given player + * + *

The cost is automatically calculated from the item in the player's main hand.

+ * + * @param player

The player to withdraw from

+ */ + public static void withdraw(Player player) { + economy.withdrawPlayer(player, getHeldItemCost(player)); + } + + /** + * Gets the current durability of the given item + * + * @param itemStack

The item to get the durability of

+ * @return

The durability of the item

+ */ + public static short getDurability(ItemStack itemStack) { + Damageable damageable = (Damageable) itemStack.getItemMeta(); + int maxDurability = itemStack.getType().getMaxDurability(); + if (damageable != null) { + return (short) (maxDurability - damageable.getDamage()); + } else { + return (short) maxDurability; + } + } + + /** + * Gets the damage done to the given item + * + * @param itemStack

The damage done to the item

+ * @return

The damage done to the item

+ */ + public static short getDamage(ItemStack itemStack) { + Damageable damageable = (Damageable) itemStack.getItemMeta(); + if (damageable != null) { + return (short) damageable.getDamage(); + } else { + return 0; + } + } + + /** + * Gets the cost of the item in the given player's main hand + * + * @param player

The player to calculate the cost for

+ * @return

The calculated cost

+ */ + private static double getHeldItemCost(Player player) { + return getCost(player.getInventory().getItemInMainHand()); + } + + /** + * Gets the cost of repairing the given item + * + * @param item

The item to be repaired

+ * @return

The cost of the repair

+ */ + private static double getCost(ItemStack item) { + GlobalSettings globalSettings = BlacksmithPlugin.getInstance().getSettings(); + Material material = item.getType(); + //Calculate the base price + double price = globalSettings.getBasePrice(material); + + // Adjust price based on durability + double pricePerDurabilityPoint = globalSettings.getPricePerDurabilityPoint(material); + if (globalSettings.getUseNaturalCost()) { + //Cost increases with damage + price += ((double) getDamage(item)) * pricePerDurabilityPoint; + } else { + //Cost decreases with damage + price += ((double) getDurability(item)) * pricePerDurabilityPoint; + } + + //Increase price for any enchantments + price += getEnchantmentCost(item); + return price; + } + + /** + * Gets the cost resulting from all enchantments on the given item + * + * @param item

The item to calculate enchantment cost for

+ * @return

The resulting enchantment cost

+ */ + private static double getEnchantmentCost(ItemStack item) { + GlobalSettings settings = BlacksmithPlugin.getInstance().getSettings(); + double price = 0; + for (Enchantment enchantment : item.getEnchantments().keySet()) { + price += settings.getEnchantmentModifier(enchantment) * item.getEnchantmentLevel(enchantment); + } + return price; + } + + /** + * Sets up Vault for economy + * + * @param servicesManager

The services manager to use for finding a Vault provider

+ * @param logger

The logger to use for logging

+ * @return

True if Vault was successfully set up

+ */ + private static boolean setupVault(ServicesManager servicesManager, Logger logger) { + // Setup Vault + RegisteredServiceProvider economyProvider = servicesManager.getRegistration(Economy.class); + if (economyProvider != null) { + economy = economyProvider.getProvider(); + return true; + } else { + // Disable if no economy plugin was found + logger.log(Level.SEVERE, "Failed to load an economy plugin. Disabling..."); + return false; + } + } + +} diff --git a/src/main/java/net/knarcraft/blacksmith/ReforgeSession.java b/src/main/java/net/knarcraft/blacksmith/ReforgeSession.java index 8eb4ad5..668d46f 100644 --- a/src/main/java/net/knarcraft/blacksmith/ReforgeSession.java +++ b/src/main/java/net/knarcraft/blacksmith/ReforgeSession.java @@ -1,7 +1,7 @@ package net.knarcraft.blacksmith; import net.citizensnpcs.api.npc.NPC; -import net.knarcraft.blacksmith.config.Settings; +import net.knarcraft.blacksmith.config.NPCSettings; import org.bukkit.NamespacedKey; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.LivingEntity; @@ -25,7 +25,7 @@ public class ReforgeSession implements Runnable { private final NPC npc; private final ItemStack itemToReforge; private int taskId; - private final Settings config; + private final NPCSettings config; private static final String[] enchantments = new String[Enchantment.values().length]; /** @@ -36,7 +36,7 @@ public class ReforgeSession implements Runnable { * @param npc

The Blacksmith NPC involved in the session

* @param config

The config to use for the session

*/ - ReforgeSession(BlacksmithTrait blacksmithTrait, Player player, NPC npc, Settings config) { + ReforgeSession(BlacksmithTrait blacksmithTrait, Player player, NPC npc, NPCSettings config) { this.blacksmithTrait = blacksmithTrait; this.player = player; this.npc = npc; @@ -88,7 +88,7 @@ public class ReforgeSession implements Runnable { } } // Damage the item - short reforgeDurability = BlacksmithPlugin.getDurability(itemToReforge); + short reforgeDurability = EconomyManager.getDurability(itemToReforge); short durability = (short) (reforgeDurability + reforgeDurability * random.nextInt(8)); short maxDurability = itemToReforge.getType().getMaxDurability(); if (durability <= 0) { @@ -151,7 +151,7 @@ public class ReforgeSession implements Runnable { return true; } // The player is unable to pay - if (!BlacksmithPlugin.getInstance().canPay(player)) { + if (!EconomyManager.canPay(player)) { player.sendMessage(config.getInsufficientFundsMessage()); return true; } diff --git a/src/main/java/net/knarcraft/blacksmith/command/BlackSmithCommand.java b/src/main/java/net/knarcraft/blacksmith/command/BlackSmithCommand.java new file mode 100644 index 0000000..8a4729f --- /dev/null +++ b/src/main/java/net/knarcraft/blacksmith/command/BlackSmithCommand.java @@ -0,0 +1,23 @@ +package net.knarcraft.blacksmith.command; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; + +public class BlackSmithCommand implements CommandExecutor { + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, + @NotNull String[] args) { + //TODO: This command should have one config sub-command which changes the default config values, and all + // setting names which can be changed for each NPC. + if (args.length > 0) { + if (args[0].equalsIgnoreCase("reload")) { + return new ReloadCommand().onCommand(sender, command, label, args); + } + } + return false; + } + +} diff --git a/src/main/java/net/knarcraft/blacksmith/command/ReloadCommand.java b/src/main/java/net/knarcraft/blacksmith/command/ReloadCommand.java new file mode 100644 index 0000000..4f6613a --- /dev/null +++ b/src/main/java/net/knarcraft/blacksmith/command/ReloadCommand.java @@ -0,0 +1,29 @@ +package net.knarcraft.blacksmith.command; + +import net.knarcraft.blacksmith.BlacksmithPlugin; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabExecutor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class ReloadCommand implements TabExecutor { + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + BlacksmithPlugin.getInstance().reload(); + sender.sendMessage(ChatColor.GREEN + "Blacksmith config reloaded!"); + return true; + } + + @Nullable + @Override + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + return new ArrayList<>(); + } + +} diff --git a/src/main/java/net/knarcraft/blacksmith/config/GlobalSetting.java b/src/main/java/net/knarcraft/blacksmith/config/GlobalSetting.java new file mode 100644 index 0000000..4405ee3 --- /dev/null +++ b/src/main/java/net/knarcraft/blacksmith/config/GlobalSetting.java @@ -0,0 +1,79 @@ +package net.knarcraft.blacksmith.config; + +import java.util.Arrays; + +public enum GlobalSetting { + + /** + * The base price for repairing, regardless of durability + * + *

This allows specifying a price for each item, by setting base-price.item_name.

+ */ + BASE_PRICE("global.base-price.default", 10.0), + + /** + * The base price for each durability point + * + *

If natural cost, this is the cost each missing durability point will add to the cost. If not natural cost, + * this is the cost each present durability point will add to the cost. This allows specifying a price per + * durability point value for each item, by setting price-per-durability-point.item_name

+ */ + PRICE_PER_DURABILITY_POINT("global.price-per-durability-point.default", 0.005), + + /** + * The price increase for each level of each present enchantment + * + *

This can be specified for each possible enchantment by setting enchantment-modifiers.enchantment_name

+ */ + ENCHANTMENT_MODIFIER("global.enchantment-cost.default", 5), + + /** + * Whether the cost should increase for damage taken, as opposed to increase for durability present + */ + NATURAL_COST("global.natural-cost", true); + + private final String path; + private final String parent; + private final Object value; + + /** + * Instantiates a new setting + * + * @param path

The full config path for this setting

+ * @param value

The default value of this setting

+ */ + GlobalSetting(String path, Object value) { + this.path = path; + this.value = value; + String[] pathParts = path.split("\\."); + this.parent = String.join(".", Arrays.copyOfRange(pathParts, 0, pathParts.length - 1)); + } + + /** + * Gets the full config path for this setting + * + * @return

The full config path for this setting

+ */ + public String getPath() { + return path; + } + + /** + * Gets the parent item of the defined path + * + * @return

The parent node

+ */ + public String getParent() { + return parent; + } + + /** + * Gets the value of this setting + * + * @return

The value of this setting

+ */ + Object getDefaultValue() { + return value; + } + +} diff --git a/src/main/java/net/knarcraft/blacksmith/config/GlobalSettings.java b/src/main/java/net/knarcraft/blacksmith/config/GlobalSettings.java new file mode 100644 index 0000000..a049379 --- /dev/null +++ b/src/main/java/net/knarcraft/blacksmith/config/GlobalSettings.java @@ -0,0 +1,263 @@ +package net.knarcraft.blacksmith.config; + +import net.citizensnpcs.api.util.DataKey; +import net.citizensnpcs.api.util.YamlStorage; +import net.knarcraft.blacksmith.BlacksmithPlugin; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.enchantments.Enchantment; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +/** + * A class which keeps track of all default NPC settings and all global settings + */ +public class GlobalSettings { + + private final Map materialBasePrices = new HashMap<>(); + private final Map materialPricePerDurabilityPoints = new HashMap<>(); + private final Map enchantmentModifiers = new HashMap<>(); + + private final Map defaultNPCSettings = new HashMap<>(); + private final Map globalSettings = new HashMap<>(); + + private final YamlStorage defaultConfig; + + /** + * Instantiates a new "Settings" + * + * @param plugin

A reference to the blacksmith plugin

+ */ + public GlobalSettings(BlacksmithPlugin plugin) { + defaultConfig = new YamlStorage(new File(plugin.getDataFolder() + File.separator + "config.yml"), + "Blacksmith Configuration\nWarning: The values under defaults are the values set for a blacksmith" + + "upon creation. To change any values for existing NPCs, edit the citizens NPC file."); + } + + /** + * Loads all configuration values from the config file + */ + public void load() { + //Load the config from disk + defaultConfig.load(); + DataKey root = defaultConfig.getKey(""); + + //Just in case, clear existing values + defaultNPCSettings.clear(); + globalSettings.clear(); + materialBasePrices.clear(); + materialPricePerDurabilityPoints.clear(); + enchantmentModifiers.clear(); + + //Load/Save NPC default settings + loadDefaultNPCSettings(root); + + //Load/Save global settings + loadGlobalSettings(root); + + //Save any modified values to disk + defaultConfig.save(); + } + + /** + * Gets the current value of the default NPC settings + * + * @return

The current value of the default NPC settings

+ */ + public Map getDefaultNPCSettings() { + return new HashMap<>(this.defaultNPCSettings); + } + + /** + * Gets whether to use natural cost for cost calculation + * + *

Natural cost makes it more costly the more damage is dealt to an item. The alternative is the legacy behavior + * where the amount of durability points remaining increases the cost.

+ * + * @return

Whether to use natural cost

+ */ + public boolean getUseNaturalCost() { + return asBoolean(GlobalSetting.NATURAL_COST); + } + + /** + * Gets the base price for the given material + * + * @param material

The material to get the base price for

+ * @return

The base price for the material

+ */ + public double getBasePrice(Material material) { + if (materialBasePrices.containsKey(material) && materialBasePrices.get(material) != null) { + return materialBasePrices.get(material); + } else { + return asDouble(GlobalSetting.BASE_PRICE); + } + } + + /** + * Gets the price per durability point for the given material + * + * @param material

The material to get the durability point price for

+ * @return

The durability point price for the material

+ */ + public double getPricePerDurabilityPoint(Material material) { + if (materialPricePerDurabilityPoints.containsKey(material) && + materialPricePerDurabilityPoints.get(material) != null) { + return materialPricePerDurabilityPoints.get(material); + } else { + return asDouble(GlobalSetting.PRICE_PER_DURABILITY_POINT); + } + } + + /** + * Gets the cost to be added for each level of the given enchantment + * + * @param enchantment

The enchantment to get the cost for

+ * @return

The cost of each enchantment level

+ */ + public double getEnchantmentModifier(Enchantment enchantment) { + if (enchantmentModifiers.containsKey(enchantment) && enchantmentModifiers.get(enchantment) != null) { + return enchantmentModifiers.get(enchantment); + } else { + return asDouble(GlobalSetting.ENCHANTMENT_MODIFIER); + } + } + + /** + * Gets the given value as a boolean + * + *

This will throw an exception if used for a non-boolean value

+ * + * @param setting

The setting to get the value of

+ * @return

The value of the given setting as a boolean

+ */ + public boolean asBoolean(GlobalSetting setting) { + Object value = getValue(setting); + if (value instanceof String) { + return Boolean.parseBoolean((String) value); + } else { + return (Boolean) value; + } + } + + /** + * 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(GlobalSetting setting) { + Object value = getValue(setting); + if (value instanceof String) { + return Double.parseDouble((String) value); + } else if (value instanceof Integer) { + return (Integer) value; + } else { + return (Double) value; + } + } + + /** + * Gets the value of a setting, using the default if not set + * + * @param setting

The setting to get the value of

+ * @return

The current value

+ */ + private Object getValue(GlobalSetting setting) { + Object value = globalSettings.get(setting); + //If not set in config.yml, use the default value from the enum + if (value == null) { + value = setting.getDefaultValue(); + } + return value; + } + + /** + * Loads all global settings + * + * @param root

The root node of all global settings

+ */ + private void loadGlobalSettings(DataKey root) { + for (GlobalSetting globalSetting : GlobalSetting.values()) { + if (!root.keyExists(globalSetting.getPath())) { + //If the setting does not exist in the config file, add it + root.setRaw(globalSetting.getPath(), globalSetting.getDefaultValue()); + } else { + //Set the setting to the value found in the path + globalSettings.put(globalSetting, root.getRaw(globalSetting.getPath())); + } + } + + //Load all base prices + DataKey basePriceNode = root.getRelative(GlobalSetting.BASE_PRICE.getParent()); + Map relevantKeys = getRelevantKeys(basePriceNode); + for (String key : relevantKeys.keySet()) { + Material material = Material.matchMaterial(relevantKeys.get(key)); + if (material != null) { + materialBasePrices.put(material, basePriceNode.getDouble(key)); + } + } + + //Load all per-durability-point prices + DataKey basePerDurabilityPriceNode = root.getRelative(GlobalSetting.PRICE_PER_DURABILITY_POINT.getParent()); + relevantKeys = getRelevantKeys(basePerDurabilityPriceNode); + for (String key : relevantKeys.keySet()) { + Material material = Material.matchMaterial(relevantKeys.get(key)); + if (material != null) { + materialPricePerDurabilityPoints.put(material, basePerDurabilityPriceNode.getDouble(key)); + } + } + + //Load all enchantment prices + DataKey enchantmentModifiersNode = root.getRelative(GlobalSetting.ENCHANTMENT_MODIFIER.getParent()); + relevantKeys = getRelevantKeys(basePerDurabilityPriceNode); + for (String key : relevantKeys.keySet()) { + Enchantment enchantment = Enchantment.getByKey(NamespacedKey.minecraft(relevantKeys.get(key))); + if (enchantment != null) { + enchantmentModifiers.put(enchantment, enchantmentModifiersNode.getDouble(key)); + } + } + } + + /** + * Gets a map between relevant keys and their normalized name + * + * @param rootKey

The root data key containing sub-keys

+ * @return

Any sub-keys found that aren't the default

+ */ + private Map getRelevantKeys(DataKey rootKey) { + Map relevant = new HashMap<>(); + for (DataKey dataKey : rootKey.getSubKeys()) { + String keyName = dataKey.name(); + //Skip the default value + if (keyName.equals("default")) { + continue; + } + String normalizedName = keyName.toUpperCase().replace("-", "_"); + relevant.put(keyName, normalizedName); + } + return relevant; + } + + /** + * Loads all default NPC settings + * + * @param root

The root node of all default NPC settings

+ */ + private void loadDefaultNPCSettings(DataKey root) { + for (NPCSetting setting : NPCSetting.values()) { + if (!root.keyExists(setting.getPath())) { + //If the setting does not exist in the config file, add it + root.setRaw(setting.getPath(), setting.getDefaultValue()); + } else { + //Set the setting to the value found in the path + defaultNPCSettings.put(setting, root.getRaw(setting.getPath())); + } + } + } + +} diff --git a/src/main/java/net/knarcraft/blacksmith/config/Setting.java b/src/main/java/net/knarcraft/blacksmith/config/NPCSetting.java similarity index 59% rename from src/main/java/net/knarcraft/blacksmith/config/Setting.java rename to src/main/java/net/knarcraft/blacksmith/config/NPCSetting.java index ebffae2..0a63011 100644 --- a/src/main/java/net/knarcraft/blacksmith/config/Setting.java +++ b/src/main/java/net/knarcraft/blacksmith/config/NPCSetting.java @@ -5,10 +5,22 @@ import java.util.Arrays; /** * An enum representing all of Blacksmith's settings */ -public enum Setting { +public enum NPCSetting { - BASE_PRICE("base-prices.default", 10.0), - PRICE_PER_DURABILITY_POINT("price-per-durability-point.default", 1.0), + DROP_ITEM("defaults.drop-item", true), + DISABLE_COOL_DOWN("defaults.disable-cool-down", false), + DISABLE_DELAY("defaults.disable-delay", false), + FAIL_CHANCE("defaults.percent-chance-to-fail-reforge", 10), + EXTRA_ENCHANTMENT_CHANCE("defaults.percent-chance-for-extra-enchantment", 5), + MAX_ENCHANTMENTS("defaults.maximum-enchantments", 3), + MAX_REFORGE_DELAY("defaults.delays-in-seconds.maximum", 30), + MIN_REFORGE_DELAY("defaults.delays-in-seconds.minimum", 5), + REFORGE_COOL_DOWN("defaults.delays-in-seconds.reforge-cool-down", 60), + REFORGE_ABLE_ITEMS("defaults.reforge-able-items", new String[]{}), + + /*----------- + | Messages | + -----------*/ BUSY_WITH_PLAYER_MESSAGE("defaults.messages.busy-with-player", "§cI'm busy at the moment. Come back later!"), BUSY_WITH_REFORGE_MESSAGE("defaults.messages.busy-with-reforge", "§cI'm working on it. Be patient!"), COOL_DOWN_UNEXPIRED_MESSAGE( @@ -17,11 +29,6 @@ public enum Setting { COST_MESSAGE( "defaults.messages.cost", "§eIt will cost §a §eto reforge that §a§e! Click again to reforge!"), - DROP_ITEM("defaults.drop-item", true), - DISABLE_COOL_DOWN("defaults.disable-cool-down", false), - DISABLE_DELAY("defaults.disable-delay", false), - ENCHANTMENT_MODIFIER("enchantment-modifiers.default", 5), - FAIL_CHANCE("defaults.percent-chance-to-fail-reforge", 10), FAIL_MESSAGE("defaults.messages.fail-reforge", "§cWhoops! Didn't mean to do that! Maybe next time?"), INSUFFICIENT_FUNDS_MESSAGE( "defaults.messages.insufficient-funds", @@ -30,18 +37,12 @@ public enum Setting { ITEM_UNEXPECTEDLY_CHANGED_MESSAGE( "defaults.messages.item-changed-during-reforge", "§cThat's not the item you wanted to reforge before!"), - EXTRA_ENCHANTMENT_CHANCE("defaults.percent-chance-for-extra-enchantment", 5), - MAX_ENCHANTMENTS("defaults.maximum-enchantments", 3), - MAX_REFORGE_DELAY("defaults.delays-in-seconds.maximum", 30), - MIN_REFORGE_DELAY("defaults.delays-in-seconds.minimum", 5), - REFORGE_COOL_DOWN("defaults.delays-in-seconds.reforge-cool-down", 60), START_REFORGE_MESSAGE("defaults.messages.start-reforge", "§eOk, let's see what I can do..."), - SUCCESS_MESSAGE("defaults.messages.successful-reforge", "There you go! All better!"), - NATURAL_COST("defaults.natural-cost", true); + SUCCESS_MESSAGE("defaults.messages.successful-reforge", "There you go! All better!"); private final String path; private final String childPath; - private Object value; + private final Object value; /** * Instantiates a new setting @@ -49,7 +50,7 @@ public enum Setting { * @param path

The full config path for this setting

* @param value

The default value of this setting

*/ - Setting(String path, Object value) { + NPCSetting(String path, Object value) { this.path = path; this.value = value; String[] pathParts = path.split("\\."); @@ -74,78 +75,13 @@ public enum Setting { return childPath; } - /** - * Gets this setting as a boolean - * - *

This will throw an exception if used for a non-boolean value

- * - * @return

This setting as a boolean

- */ - public boolean asBoolean() { - if (value instanceof String) { - return Boolean.parseBoolean((String) value); - } else { - return (Boolean) value; - } - } - - /** - * Gets this setting as a double - * - *

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

- * - * @return

This setting as a double

- */ - public double asDouble() { - if (value instanceof String) { - return Double.parseDouble((String) value); - } else if (value instanceof Integer) { - return (Integer) value; - } else { - return (Double) value; - } - } - - /** - * Gets this setting as an integer - * - *

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

- * - * @return

This setting as an integer

- */ - public int asInt() { - if (value instanceof String) { - return Integer.parseInt((String) value); - } else { - return (Integer) value; - } - } - - /** - * Gets this setting as a string - * - * @return

This setting as a string

- */ - public String asString() { - return value.toString(); - } - /** * Gets the value of this setting * * @return

The value of this setting

*/ - Object get() { + Object getDefaultValue() { return value; } - /** - * Sets the value of this setting - * - * @param value

The new value of this setting

- */ - void set(Object value) { - this.value = value; - } - } diff --git a/src/main/java/net/knarcraft/blacksmith/config/NPCSettings.java b/src/main/java/net/knarcraft/blacksmith/config/NPCSettings.java new file mode 100644 index 0000000..66f461f --- /dev/null +++ b/src/main/java/net/knarcraft/blacksmith/config/NPCSettings.java @@ -0,0 +1,322 @@ +package net.knarcraft.blacksmith.config; + +import net.citizensnpcs.api.util.DataKey; +import org.bukkit.Material; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * A class which keeps track of all Blacksmith settings/config values for one NPC + */ +public class NPCSettings { + + private final List reforgeAbleItems = new ArrayList<>(); + private final Map currentValues = new HashMap<>(); + private final GlobalSettings globalSettings; + + /** + * Instantiates a new "Settings" object + */ + public NPCSettings(GlobalSettings globalSettings) { + this.globalSettings = globalSettings; + } + + /** + * Loads variables from the given data key + * + * @param key

The data key to load variables from

+ */ + public void loadVariables(DataKey key) { + for (NPCSetting setting : NPCSetting.values()) { + if (key.keyExists(setting.getChildPath())) { + currentValues.put(setting, key.getRaw(setting.getChildPath())); + } + } + //Updates the list of reforge-able items/materials + updateReforgeAbleItems(); + } + + /** + * Saves variables to the given data key + * + * @param key

The data key to save variables to

+ */ + public void saveVariables(DataKey key) { + for (NPCSetting setting : NPCSetting.values()) { + key.setRaw(setting.getChildPath(), currentValues.get(setting)); + } + } + + /** + * Gets the message to display when the blacksmith is busy with another player + * + * @return

The busy with player message

+ */ + public String getBusyWithPlayerMessage() { + return asString(NPCSetting.BUSY_WITH_PLAYER_MESSAGE); + } + + /** + * Gets the message to display when the blacksmith is busy with reforging an item + * + * @return

The busy reforging message

+ */ + public String getBusyReforgingMessage() { + return asString(NPCSetting.BUSY_WITH_REFORGE_MESSAGE); + } + + /** + * Gets the message to use for displaying an item's cost + * + * @return

The message to use for displaying item cost

+ */ + public String getCostMessage() { + return asString(NPCSetting.COST_MESSAGE); + } + + /** + * Gets the message to display when a blacksmith has been given an invalid item + * + * @return

The invalid item message

+ */ + public String getInvalidItemMessage() { + return asString(NPCSetting.INVALID_ITEM_MESSAGE); + } + + /** + * Gets the message to display when a blacksmith starts reforging an item + * + * @return

The start reforge message

+ */ + public String getStartReforgeMessage() { + return asString(NPCSetting.START_REFORGE_MESSAGE); + } + + /** + * Gets the message to display when a blacksmith has successfully repaired an item + * + * @return

The reforge success message

+ */ + public String getSuccessMessage() { + return asString(NPCSetting.SUCCESS_MESSAGE); + } + + /** + * Gets the message to display when a blacksmith has failed to repair an item + * + * @return

The reforge fail message

+ */ + public String getFailMessage() { + return asString(NPCSetting.FAIL_MESSAGE); + } + + /** + * Gets the message to display when a player cannot afford re-forging an item + * + * @return

The insufficient funds message

+ */ + public String getInsufficientFundsMessage() { + return asString(NPCSetting.INSUFFICIENT_FUNDS_MESSAGE); + } + + /** + * Gets the message to display when a blacksmith is still affected by a cool-down + * + * @return

The cool down unexpired message

+ */ + public String getCoolDownUnexpiredMessage() { + return asString(NPCSetting.COOL_DOWN_UNEXPIRED_MESSAGE); + } + + /** + * Gets the message to display when a player has changed the item they're trying to reforge + * + * @return

The item changed message

+ */ + public String getItemChangedMessage() { + return asString(NPCSetting.ITEM_UNEXPECTEDLY_CHANGED_MESSAGE); + } + + /** + * Gets all items reforge-able by this NPC + * + *

If this is not empty, only the items specified can be repaired by this NPC.

+ * + * @return

All items reforge-able by this NPC

+ */ + public List getReforgeAbleItems() { + return new ArrayList<>(reforgeAbleItems); + } + + /** + * Gets the minimum delay used to wait for a re-forge to finish. + * + * @return

The minimum reforge delay

+ */ + public int getMinReforgeDelay() { + return asInt(NPCSetting.MIN_REFORGE_DELAY); + } + + /** + * Gets the maximum delay used to wait for a re-forge to finish + * + * @return

The maximum reforge delay

+ */ + public int getMaxReforgeDelay() { + return asInt(NPCSetting.MAX_REFORGE_DELAY); + } + + /** + * Gets the cool-down between each reforge + * + * @return

The reforge cool-down

+ */ + public int getReforgeCoolDown() { + return asInt(NPCSetting.REFORGE_COOL_DOWN); + } + + /** + * Gets the chance to fail a re-forge + * + * @return

The fail chance

+ */ + public int getFailChance() { + return asInt(NPCSetting.FAIL_CHANCE); + } + + /** + * Gets the chance for adding an extra enchantment to an item + * + * @return

The extra enchantment chance

+ */ + public int getExtraEnchantmentChance() { + return asInt(NPCSetting.EXTRA_ENCHANTMENT_CHANCE); + } + + /** + * Gets the max number of enchantment to add to an item + * + * @return

The maximum enchantments

+ */ + public int getMaxEnchantments() { + return asInt(NPCSetting.MAX_ENCHANTMENTS); + } + + /** + * Gets whether an item should be dropped on the ground instead of being given to the player + * + * @return

Whether to drop reforged items on the ground

+ */ + public boolean getDropItem() { + return asBoolean(NPCSetting.DROP_ITEM); + } + + /** + * Gets whether to disable the reforge-cool-down + * + * @return

Whether to disable the reforge-cool-down

+ */ + public boolean getDisableCoolDown() { + return asBoolean(NPCSetting.DISABLE_COOL_DOWN); + } + + /** + * Gets whether to disable the delay between starting reforging and the re-forge finishing + * + * @return

Whether to disable the reforge delay

+ */ + public boolean getDisableDelay() { + return asBoolean(NPCSetting.DISABLE_DELAY); + } + + /** + * Gets the given value as a boolean + * + *

This will throw an exception if used for a non-boolean value

+ * + * @param setting

The setting to get the value of

+ * @return

The value of the given setting as a boolean

+ */ + private boolean asBoolean(NPCSetting setting) { + Object value = getValue(setting); + if (value instanceof String) { + return Boolean.parseBoolean((String) value); + } else { + return (Boolean) value; + } + } + + /** + * Gets the given value as an integer + * + *

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

+ * + * @param setting

The setting to get the value of

+ * @return

The value of the given setting as an integer

+ */ + private int asInt(NPCSetting setting) { + Object value = getValue(setting); + if (value instanceof String) { + return Integer.parseInt((String) value); + } else { + return (Integer) value; + } + } + + /** + * Gets the string value of the given setting + * + * @param setting

The setting to get the value of

+ * @return

The value of the given setting as a string

+ */ + private String asString(NPCSetting setting) { + return getValue(setting).toString(); + } + + /** + * Gets the value of a setting, using the default if not set + * + * @param setting

The setting to get the value of

+ * @return

The current value

+ */ + private Object getValue(NPCSetting setting) { + Object value = currentValues.get(setting); + //If not set, use the default value from the config.yml file + if (value == null) { + Map defaultNPCSettings = globalSettings.getDefaultNPCSettings(); + if (defaultNPCSettings.containsKey(setting)) { + value = defaultNPCSettings.get(setting); + } + } + //If not set in config.yml, use the default value from the enum + if (value == null) { + value = setting.getDefaultValue(); + } + return value; + } + + /** + * Updates the reforge-able items according to the current value of the setting + */ + private void updateReforgeAbleItems() { + this.reforgeAbleItems.clear(); + List reforgeAbleItems = (List) currentValues.get(NPCSetting.REFORGE_ABLE_ITEMS); + if (reforgeAbleItems == null) { + return; + } + + for (Object item : reforgeAbleItems) { + if (item == null) { + continue; + } + Material material = Material.matchMaterial(String.valueOf(item)); + if (material != null) { + this.reforgeAbleItems.add(material); + } + } + } + +} \ No newline at end of file diff --git a/src/main/java/net/knarcraft/blacksmith/config/Settings.java b/src/main/java/net/knarcraft/blacksmith/config/Settings.java deleted file mode 100644 index 9c195d5..0000000 --- a/src/main/java/net/knarcraft/blacksmith/config/Settings.java +++ /dev/null @@ -1,357 +0,0 @@ -package net.knarcraft.blacksmith.config; - -import net.citizensnpcs.api.util.DataKey; -import net.citizensnpcs.api.util.YamlStorage; -import net.knarcraft.blacksmith.BlacksmithPlugin; - -import java.io.File; - -/** - * A class which keeps track of all Blacksmith settings/config values - */ -public class Settings { - - private String busyWithPlayerMessage = Setting.BUSY_WITH_PLAYER_MESSAGE.asString(); - private String busyReforgingMessage = Setting.BUSY_WITH_REFORGE_MESSAGE.asString(); - private String costMessage = Setting.COST_MESSAGE.asString(); - private String invalidItemMessage = Setting.INVALID_ITEM_MESSAGE.asString(); - private String startReforgeMessage = Setting.START_REFORGE_MESSAGE.asString(); - private String successMessage = Setting.SUCCESS_MESSAGE.asString(); - private String failMessage = Setting.FAIL_MESSAGE.asString(); - private String insufficientFundsMessage = Setting.INSUFFICIENT_FUNDS_MESSAGE.asString(); - private String coolDownUnexpiredMessage = Setting.COOL_DOWN_UNEXPIRED_MESSAGE.asString(); - private String itemChangedMessage = Setting.ITEM_UNEXPECTEDLY_CHANGED_MESSAGE.asString(); - private int minReforgeDelay = Setting.MIN_REFORGE_DELAY.asInt(); - private int maxReforgeDelay = Setting.MAX_REFORGE_DELAY.asInt(); - private int reforgeCoolDown = Setting.REFORGE_COOL_DOWN.asInt(); - private int failChance = Setting.FAIL_CHANCE.asInt(); - private int extraEnchantmentChance = Setting.EXTRA_ENCHANTMENT_CHANCE.asInt(); - private int maxEnchantments = Setting.MAX_ENCHANTMENTS.asInt(); - private boolean dropItem = Setting.DROP_ITEM.asBoolean(); - private boolean disableCoolDown = Setting.DISABLE_COOL_DOWN.asBoolean(); - private boolean disableDelay = Setting.DISABLE_DELAY.asBoolean(); - private boolean naturalCost = Setting.NATURAL_COST.asBoolean(); - private final YamlStorage config; - - /** - * Instantiates a new "Settings" - * - * @param plugin

A reference to the blacksmith plugin

- */ - public Settings(BlacksmithPlugin plugin) { - config = new YamlStorage(new File(plugin.getDataFolder() + File.separator + "config.yml"), - "Blacksmith Configuration\nWarning: The values under defaults are the values set for a blacksmith" + - "upon creation. To change any values for existing NPCs, edit the citizens NPC file."); - } - - /** - * Loads all configuration values from the config file - */ - public void load() { - //Load the config from disk - config.load(); - DataKey root = config.getKey(""); - for (Setting setting : Setting.values()) { - if (!root.keyExists(setting.getPath())) { - //If the setting does not exist in the config file, add it - root.setRaw(setting.getPath(), setting.get()); - } else { - //Set the setting to the value found in the path - setting.set(root.getRaw(setting.getPath())); - } - } - //Save any modified values to disk - config.save(); - } - - /** - * Gets the configuration used for saving/loading from disk - * - * @return

The configuration

- */ - public YamlStorage getConfig() { - return config; - } - - /** - * Loads variables from the given data key - * - * @param key

The data key to load variables from

- */ - public void loadVariables(DataKey key) { - // Override defaults if they exist - if (key.keyExists(Setting.BUSY_WITH_PLAYER_MESSAGE.getChildPath())) { - busyWithPlayerMessage = key.getString(Setting.BUSY_WITH_PLAYER_MESSAGE.getChildPath()); - } - if (key.keyExists(Setting.BUSY_WITH_REFORGE_MESSAGE.getChildPath())) { - busyReforgingMessage = key.getString(Setting.BUSY_WITH_REFORGE_MESSAGE.getChildPath()); - } - if (key.keyExists(Setting.COST_MESSAGE.getChildPath())) { - costMessage = key.getString(Setting.COST_MESSAGE.getChildPath()); - } - if (key.keyExists(Setting.INVALID_ITEM_MESSAGE.getChildPath())) { - invalidItemMessage = key.getString(Setting.INVALID_ITEM_MESSAGE.getChildPath()); - } - if (key.keyExists(Setting.START_REFORGE_MESSAGE.getChildPath())) { - startReforgeMessage = key.getString(Setting.START_REFORGE_MESSAGE.getChildPath()); - } - if (key.keyExists(Setting.SUCCESS_MESSAGE.getChildPath())) { - successMessage = key.getString(Setting.SUCCESS_MESSAGE.getChildPath()); - } - if (key.keyExists(Setting.FAIL_MESSAGE.getChildPath())) { - failMessage = key.getString(Setting.FAIL_MESSAGE.getChildPath()); - } - if (key.keyExists(Setting.INSUFFICIENT_FUNDS_MESSAGE.getChildPath())) { - insufficientFundsMessage = key.getString(Setting.INSUFFICIENT_FUNDS_MESSAGE.getChildPath()); - } - if (key.keyExists(Setting.COOL_DOWN_UNEXPIRED_MESSAGE.getChildPath())) { - coolDownUnexpiredMessage = key.getString(Setting.COOL_DOWN_UNEXPIRED_MESSAGE.getChildPath()); - } - if (key.keyExists(Setting.ITEM_UNEXPECTEDLY_CHANGED_MESSAGE.getChildPath())) { - itemChangedMessage = key.getString(Setting.ITEM_UNEXPECTEDLY_CHANGED_MESSAGE.getChildPath()); - } - if (key.keyExists(Setting.MIN_REFORGE_DELAY.getChildPath())) { - minReforgeDelay = key.getInt(Setting.MIN_REFORGE_DELAY.getChildPath()); - } - if (key.keyExists(Setting.MAX_REFORGE_DELAY.getChildPath())) { - maxReforgeDelay = key.getInt(Setting.MAX_REFORGE_DELAY.getChildPath()); - } - if (key.keyExists(Setting.REFORGE_COOL_DOWN.getChildPath())) { - reforgeCoolDown = key.getInt(Setting.REFORGE_COOL_DOWN.getChildPath()); - } - if (key.keyExists(Setting.FAIL_CHANCE.getChildPath())) { - failChance = key.getInt(Setting.FAIL_CHANCE.getChildPath()); - } - if (key.keyExists(Setting.MAX_ENCHANTMENTS.getChildPath())) { - maxEnchantments = key.getInt(Setting.MAX_ENCHANTMENTS.getChildPath()); - } - if (key.keyExists(Setting.EXTRA_ENCHANTMENT_CHANCE.getChildPath())) { - extraEnchantmentChance = key.getInt(Setting.EXTRA_ENCHANTMENT_CHANCE.getChildPath()); - } - if (key.keyExists(Setting.DROP_ITEM.getChildPath())) { - dropItem = key.getBoolean(Setting.DROP_ITEM.getChildPath()); - } - if (key.keyExists(Setting.DISABLE_COOL_DOWN.getChildPath())) { - disableCoolDown = key.getBoolean(Setting.DISABLE_COOL_DOWN.getChildPath()); - } - if (key.keyExists(Setting.DISABLE_DELAY.getChildPath())) { - disableDelay = key.getBoolean(Setting.DISABLE_DELAY.getChildPath()); - } - if (key.keyExists(Setting.NATURAL_COST.getChildPath())) { - naturalCost = key.getBoolean(Setting.NATURAL_COST.getChildPath()); - } - } - - /** - * Saves variables to the given data key - * - * @param key

The data key to save variables to

- */ - public void saveVariables(DataKey key) { - //This saves variables to the specific NPC. - key.setString(Setting.BUSY_WITH_PLAYER_MESSAGE.getChildPath(), getBusyWithPlayerMessage()); - key.setString(Setting.BUSY_WITH_REFORGE_MESSAGE.getChildPath(), getBusyReforgingMessage()); - key.setString(Setting.COST_MESSAGE.getChildPath(), getCostMessage()); - key.setString(Setting.INVALID_ITEM_MESSAGE.getChildPath(), getInvalidItemMessage()); - key.setString(Setting.START_REFORGE_MESSAGE.getChildPath(), getStartReforgeMessage()); - key.setString(Setting.SUCCESS_MESSAGE.getChildPath(), getSuccessMessage()); - key.setString(Setting.FAIL_MESSAGE.getChildPath(), getFailMessage()); - key.setString(Setting.INSUFFICIENT_FUNDS_MESSAGE.getChildPath(), getInsufficientFundsMessage()); - key.setString(Setting.COOL_DOWN_UNEXPIRED_MESSAGE.getChildPath(), getCoolDownUnexpiredMessage()); - key.setString(Setting.ITEM_UNEXPECTEDLY_CHANGED_MESSAGE.getChildPath(), getItemChangedMessage()); - key.setInt(Setting.MIN_REFORGE_DELAY.getChildPath(), getMinReforgeDelay()); - key.setInt(Setting.MAX_REFORGE_DELAY.getChildPath(), getMaxReforgeDelay()); - key.setInt(Setting.REFORGE_COOL_DOWN.getChildPath(), getReforgeCoolDown()); - key.setInt(Setting.FAIL_CHANCE.getChildPath(), getFailChance()); - key.setInt(Setting.EXTRA_ENCHANTMENT_CHANCE.getChildPath(), getExtraEnchantmentChance()); - key.setInt(Setting.MAX_ENCHANTMENTS.getChildPath(), getMaxEnchantments()); - key.setBoolean(Setting.DROP_ITEM.getChildPath(), getDropItem()); - key.setBoolean(Setting.DISABLE_DELAY.getChildPath(), getDisableDelay()); - key.setBoolean(Setting.DISABLE_COOL_DOWN.getChildPath(), getDisableCoolDown()); - key.setBoolean(Setting.DISABLE_COOL_DOWN.getChildPath(), getDisableCoolDown()); - key.setBoolean(Setting.NATURAL_COST.getChildPath(), getNaturalCost()); - } - - /** - * Gets the message to display when the blacksmith is busy with another player - * - * @return

The busy with player message

- */ - public String getBusyWithPlayerMessage() { - return busyWithPlayerMessage; - } - - /** - * Gets the message to display when the blacksmith is busy with reforging an item - * - * @return

The busy reforging message

- */ - public String getBusyReforgingMessage() { - return busyReforgingMessage; - } - - /** - * Gets the message to use for displaying an item's cost - * - * @return

The message to use for displaying item cost

- */ - public String getCostMessage() { - return costMessage; - } - - /** - * Gets the message to display when a blacksmith has been given an invalid item - * - * @return

The invalid item message

- */ - public String getInvalidItemMessage() { - return invalidItemMessage; - } - - /** - * Gets the message to display when a blacksmith starts reforging an item - * - * @return

The start reforge message

- */ - public String getStartReforgeMessage() { - return startReforgeMessage; - } - - /** - * Gets the message to display when a blacksmith has successfully repaired an item - * - * @return

The reforge success message

- */ - public String getSuccessMessage() { - return successMessage; - } - - /** - * Gets the message to display when a blacksmith has failed to repair an item - * - * @return

The reforge fail message

- */ - public String getFailMessage() { - return failMessage; - } - - /** - * Gets the message to display when a player cannot afford re-forging an item - * - * @return

The insufficient funds message

- */ - public String getInsufficientFundsMessage() { - return insufficientFundsMessage; - } - - /** - * Gets the message to display when a blacksmith is still affected by a cool-down - * - * @return

The cool down unexpired message

- */ - public String getCoolDownUnexpiredMessage() { - return coolDownUnexpiredMessage; - } - - /** - * Gets the message to display when a player has changed the item they're trying to reforge - * - * @return

The item changed message

- */ - public String getItemChangedMessage() { - return itemChangedMessage; - } - - /** - * Gets the minimum delay used to wait for a re-forge to finish. - * - * @return

The minimum reforge delay

- */ - public int getMinReforgeDelay() { - return minReforgeDelay; - } - - /** - * Gets the maximum delay used to wait for a re-forge to finish - * - * @return

The maximum reforge delay

- */ - public int getMaxReforgeDelay() { - return maxReforgeDelay; - } - - /** - * Gets the cool-down between each reforge - * - * @return

The reforge cool-down

- */ - public int getReforgeCoolDown() { - return reforgeCoolDown; - } - - /** - * Gets the chance to fail a re-forge - * - * @return

The fail chance

- */ - public int getFailChance() { - return failChance; - } - - /** - * Gets the chance for adding an extra enchantment to an item - * - * @return

The extra enchantment chance

- */ - public int getExtraEnchantmentChance() { - return extraEnchantmentChance; - } - - /** - * Gets the max number of enchantment to add to an item - * - * @return

The maximum enchantments

- */ - public int getMaxEnchantments() { - return maxEnchantments; - } - - /** - * Gets whether an item should be dropped on the ground instead of being given to the player - * - * @return

Whether to drop reforged items on the ground

- */ - public boolean getDropItem() { - return dropItem; - } - - /** - * Gets whether to disable the reforge-cool-down - * - * @return

Whether to disable the reforge-cool-down

- */ - public boolean getDisableCoolDown() { - return disableCoolDown; - } - - /** - * Gets whether to disable the delay between starting reforging and the re-forge finishing - * - * @return

Whether to disable the reforge delay

- */ - public boolean getDisableDelay() { - return disableDelay; - } - - /** - * Gets whether to use a natural cost calculation - * - *

The natural cost makes repairs more expensive the more damaged an item is, rather than the opposite.

- * - * @return

Whether to use a natural cost calculation

- */ - public boolean getNaturalCost() { - return naturalCost; - } - -} \ No newline at end of file diff --git a/src/main/java/net/knarcraft/blacksmith/util/Sanitizer.java b/src/main/java/net/knarcraft/blacksmith/util/Sanitizer.java deleted file mode 100644 index 3386ff4..0000000 --- a/src/main/java/net/knarcraft/blacksmith/util/Sanitizer.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.knarcraft.blacksmith.util; - -public final class Sanitizer { - - private Sanitizer() { - - } - - /** - * Sanitizes an item name to the format used by this plugin - * - * @param itemName

The item name to sanitize

- * @return

The sanitized name

- */ - public static String sanitizeItemName(String itemName) { - return itemName.toLowerCase().replace('_', '-'); - } - - /** - * Converts a sanitized item name to the original name - * - * @param itemName

The item name to convert

- * @return

The un-sanitized name

- */ - public static String sanitizedToItemName(String itemName) { - return itemName.toUpperCase().replace('-', '_'); - } - -} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..87faeb9 --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,86 @@ +# Blacksmith Configuration + +# The settings which apply to all Blacksmith NPCs +global: + # The minimum price of each cost + base-price: + # You can add, for example "diamond-sword: 15.3" to change the base cost for a specific item + default: 10.0 + + # The additional cost for each durability point missing (natural cost) or present (not natural cost) + price-per-durability-point: + # You can add, for example "diamond-sword: 0.09" to change the base cost for a specific item + default: 0.005 + + # The additional cost for each enchantment level present on an item + enchantment-cost: + # You can add, for example "arrow-infinite: 0.09" to change the enchantment cost for a specific enchantment + default: 5 + + # Natural cost makes re-forging more expensive the more damaged the item is. Disabling this will enable the legacy + # blacksmith behavior instead + natural-cost: true + +# The settings which are set to any new NPC. To change any of these settings for an existing NPC, you must change the +# Citizens NPC file +defaults: + # Whether the item will drop a re-forged item on the ground, instead of putting it into the user's inventory + drop-item: true + + # The items a blacksmith is able to reforge. Setting this only allows the NPC to repair the listed items + reforge-able-items: [ ] + + # Whether to disable the cool-down period between each re-forge + disable-cool-down: false + + # Whether to disable the re-forge delay, making re-forging complete instantly + disable-delay: false + + # The chance to fail a re-forge, which only repairs the item a tiny bit or not at all (0-100) + percent-chance-to-fail-reforge: 10 + + # The chance that an enchantment will be added to the re-forged item (0-100) + percent-chance-for-extra-enchantment: 5 + + # The maximum number of enchantments the blacksmith will try to add + maximum-enchantments: 3 + + # All settable delays + delays-in-seconds: + maximum: 30 # The maximum time for a re-forge to finish + + minimum: 5 # The minimum time for a re-forge to finish + + reforge-cool-down: 60 # The cool-down period between each re-forge + + # All messages used by the NPC + messages: + # The message to display when another player is using the blacksmith + busy-with-player: "§cI'm busy at the moment. Come back later!" + + # The message to display when the blacksmith is working on the re-forge + busy-with-reforge: "§cI'm working on it. Be patient!" + + # The message to display when the blacksmith is still on a cool-down from the previous re-forging + cool-down-not-expired: "§cYou've already had your chance! Give me a break!" + + # The message to display when informing a player about the re-forge cost + cost: "§eIt will cost §a §eto reforge that §a§e! Click again to reforge!" + + # The message to display when the blacksmith fails to re-forge an item + fail-reforge: "§cWhoops! Didn't mean to do that! Maybe next time?" + + # The message to display when a player cannot pay for the re-forge + insufficient-funds: "§cYou don't have enough money to reforge that item!" + + # The message to display when holding an item the blacksmith is unable to re-forge + invalid-item: "§cI'm sorry, but I don't know how to reforge that!" + + # The message to display when presenting a different item than the one just evaluated + item-changed-during-reforge: "§cThat's not the item you wanted to reforge before!" + + # The message to display once the blacksmith starts re-forging + start-reforge: "§eOk, let's see what I can do..." + + # The message to display once the re-forge has successfully finished + successful-reforge: "There you go! All better!" \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 36b8563..a54b3d0 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -4,15 +4,14 @@ authors: [ EpicKnarvik97, aPunch, jrbudda, HurricanKai ] version: 1.18.1 main: net.knarcraft.blacksmith.BlacksmithPlugin depend: [ Citizens, Vault ] -softdepend: [ HyperConomy ] api-version: 1.18 commands: - blacksmithreload: - permission: blacksmith.reload + blacksmith: + permission: blacksmith.admin description: reloads the config file for Blacksmith permissions: - blacksmith.reload: - description: Allows the player to run the /reload command + blacksmith.admin: + description: Allows blacksmith configuration default: op \ No newline at end of file