diff --git a/src/main/java/net/knarcraft/blacksmith/BlacksmithPlugin.java b/src/main/java/net/knarcraft/blacksmith/BlacksmithPlugin.java index 9cb62ce..1dc7cf3 100644 --- a/src/main/java/net/knarcraft/blacksmith/BlacksmithPlugin.java +++ b/src/main/java/net/knarcraft/blacksmith/BlacksmithPlugin.java @@ -1,8 +1,10 @@ package net.knarcraft.blacksmith; import net.citizensnpcs.api.CitizensAPI; -import net.knarcraft.blacksmith.command.BlackSmithCommand; -import net.knarcraft.blacksmith.command.BlackSmithTabCompleter; +import net.knarcraft.blacksmith.command.BlackSmithConfigCommand; +import net.knarcraft.blacksmith.command.BlackSmithConfigTabCompleter; +import net.knarcraft.blacksmith.command.BlackSmithEditCommand; +import net.knarcraft.blacksmith.command.BlackSmithEditTabCompleter; import net.knarcraft.blacksmith.config.GlobalSettings; import net.knarcraft.blacksmith.listener.NPCClickListener; import net.knarcraft.blacksmith.listener.PlayerListener; @@ -57,6 +59,7 @@ public class BlacksmithPlugin extends JavaPlugin { public void onEnable() { instance = this; + //Copy default config to disk FileConfiguration fileConfiguration = this.getConfig(); this.saveDefaultConfig(); fileConfiguration.options().copyDefaults(true); @@ -65,29 +68,65 @@ public class BlacksmithPlugin extends JavaPlugin { config = new GlobalSettings(this); config.load(); + //Set up Vault integration + if (!setUpVault()) { + return; + } + + //Register the blacksmith trait with Citizens + CitizensAPI.getTraitFactory().registerTrait( + net.citizensnpcs.api.trait.TraitInfo.create(BlacksmithTrait.class).withName("blacksmith")); + + //Register all commands + registerCommands(); + //Register all listeners + registerListeners(); + + getLogger().log(Level.INFO, " v" + getDescription().getVersion() + " enabled."); + } + + /** + * Tries to set up Vault + * + * @return

True if Vault setup/integration succeeded

+ */ + private boolean setUpVault() { getLogger().log(Level.INFO, "Setting Up Vault now...."); boolean canLoad = EconomyManager.setUp(getServer().getServicesManager(), getLogger()); if (!canLoad) { getLogger().log(Level.SEVERE, "Vault Integration Failed...."); getServer().getPluginManager().disablePlugin(this); - return; - } - //Register the blacksmith trait with Citizens - 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()); - blacksmithCommand.setTabCompleter(new BlackSmithTabCompleter()); + return false; } + return true; + } + /** + * Registers all listeners used by this plugin + */ + private void registerListeners() { PluginManager pluginManager = getServer().getPluginManager(); pluginManager.registerEvents(new PlayerListener(), this); pluginManager.registerEvents(new NPCClickListener(), this); + } - getLogger().log(Level.INFO, " v" + getDescription().getVersion() + " enabled."); + /** + * Registers all commands used by this plugin + */ + private void registerCommands() { + //Register the blacksmith NPC edit main-command + PluginCommand blacksmithCommand = this.getCommand("blacksmith"); + if (blacksmithCommand != null) { + blacksmithCommand.setExecutor(new BlackSmithEditCommand()); + blacksmithCommand.setTabCompleter(new BlackSmithEditTabCompleter()); + } + + //Register the global config edit command + PluginCommand blacksmithConfigCommand = this.getCommand("blacksmithConfig"); + if (blacksmithConfigCommand != null) { + blacksmithConfigCommand.setExecutor(new BlackSmithConfigCommand()); + blacksmithConfigCommand.setTabCompleter(new BlackSmithConfigTabCompleter()); + } } } diff --git a/src/main/java/net/knarcraft/blacksmith/command/BlackSmithCommand.java b/src/main/java/net/knarcraft/blacksmith/command/BlackSmithCommand.java deleted file mode 100644 index 3bee842..0000000 --- a/src/main/java/net/knarcraft/blacksmith/command/BlackSmithCommand.java +++ /dev/null @@ -1,36 +0,0 @@ -package net.knarcraft.blacksmith.command; - -import net.md_5.bungee.api.ChatColor; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.jetbrains.annotations.NotNull; - -/** - * The main command used for everything blacksmith related - */ -public class BlackSmithCommand implements CommandExecutor { - - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, - @NotNull String[] args) { - if (!sender.hasPermission("blacksmith.admin")) { - sender.sendMessage(ChatColor.DARK_RED + "You don't have the necessary permission for using this command."); - return true; - } - - //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); - } else if (args[0].equalsIgnoreCase("config")) { - //TODO: Allow changing any global/default setting + reloading here - } else { - return new NPCSettingCommand().onCommand(sender, command, label, args); - } - } - return false; - } - -} diff --git a/src/main/java/net/knarcraft/blacksmith/command/BlackSmithConfigCommand.java b/src/main/java/net/knarcraft/blacksmith/command/BlackSmithConfigCommand.java new file mode 100644 index 0000000..4a907b4 --- /dev/null +++ b/src/main/java/net/knarcraft/blacksmith/command/BlackSmithConfigCommand.java @@ -0,0 +1,85 @@ +package net.knarcraft.blacksmith.command; + +import net.knarcraft.blacksmith.BlacksmithPlugin; +import net.knarcraft.blacksmith.config.GlobalSetting; +import net.knarcraft.blacksmith.config.GlobalSettings; +import net.knarcraft.blacksmith.config.NPCSetting; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.enchantments.Enchantment; +import org.jetbrains.annotations.NotNull; + +/** + * The command used for changing global configuration options + */ +public class BlackSmithConfigCommand implements CommandExecutor { + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, + @NotNull String[] args) { + if (args.length > 0) { + String commandName = args[0]; + if (commandName.equalsIgnoreCase("reload")) { + return new ReloadCommand().onCommand(sender, command, label, args); + } + GlobalSettings settings = BlacksmithPlugin.getInstance().getSettings(); + + //Changing reforge-able items' default isn't recommended + if (commandName.equalsIgnoreCase(NPCSetting.REFORGE_ABLE_ITEMS.getCommandName())) { + sender.sendMessage(ChatColor.DARK_RED + "Changing reforge-able items globally will make every new " + + "blacksmith unable to re-forge anything not in the list, unless it's changed for the " + + "individual NPC. If you really want to change this, change it manually."); + return false; + } + + if (isSpecialCase(settings, commandName, args)) { + return true; + } + + for (GlobalSetting globalSetting : GlobalSetting.values()) { + if (commandName.equalsIgnoreCase(globalSetting.getCommandName())) { + settings.changeValue(globalSetting, args[1]); + return true; + } + } + for (NPCSetting npcSetting : NPCSetting.values()) { + if (commandName.equalsIgnoreCase(npcSetting.getCommandName())) { + settings.changeValue(npcSetting, args[1]); + } + } + } + return false; + } + + /** + * Gets whether the command could be processed as one of the three special cases + * + * @param settings

The settings to modify

+ * @param commandName

The sub-command the player specified

+ * @param args

All arguments given

+ * @return

True if already handled as a special case

+ */ + private boolean isSpecialCase(GlobalSettings settings, String commandName, String[] args) { + if (commandName.equalsIgnoreCase(GlobalSetting.BASE_PRICE.getCommandName())) { + settings.setBasePrice(Material.matchMaterial(args[1]), Double.parseDouble(args[2])); + return true; + } + + if (commandName.equalsIgnoreCase(GlobalSetting.PRICE_PER_DURABILITY_POINT.getCommandName())) { + settings.setPricePerDurabilityPoint(Material.matchMaterial(args[1]), Double.parseDouble(args[2])); + return true; + } + + if (commandName.equalsIgnoreCase(GlobalSetting.ENCHANTMENT_COST.getCommandName())) { + settings.setEnchantmentCost(Enchantment.getByKey(NamespacedKey.minecraft(args[1])), Double.parseDouble(args[2])); + return true; + } + + return false; + } + +} diff --git a/src/main/java/net/knarcraft/blacksmith/command/BlackSmithConfigTabCompleter.java b/src/main/java/net/knarcraft/blacksmith/command/BlackSmithConfigTabCompleter.java new file mode 100644 index 0000000..d11b1ff --- /dev/null +++ b/src/main/java/net/knarcraft/blacksmith/command/BlackSmithConfigTabCompleter.java @@ -0,0 +1,64 @@ +package net.knarcraft.blacksmith.command; + +import net.knarcraft.blacksmith.config.GlobalSetting; +import net.knarcraft.blacksmith.config.NPCSetting; +import net.knarcraft.blacksmith.util.TabCompleteValuesHelper; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * The tab completer for the command used for changing global configuration options + */ +public class BlackSmithConfigTabCompleter implements TabCompleter { + + @Nullable + @Override + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, + @NotNull String[] args) { + if (args.length == 1) { + if (!sender.hasPermission("blacksmith.admin")) { + return new ArrayList<>(); + } + + List availableCommands = new ArrayList<>(); + availableCommands.add("reload"); + for (NPCSetting setting : NPCSetting.values()) { + availableCommands.add(setting.getCommandName()); + } + for (GlobalSetting globalSetting : GlobalSetting.values()) { + availableCommands.add(globalSetting.getCommandName()); + } + return availableCommands; + } else if (args.length == 2) { + return tabCompleteCommandValues(args[0]); + } + return null; + } + + /** + * Tab completes the values available for the given command + * + * @param commandName

The name of the used command

+ * @return

Some valid options for the command's argument

+ */ + private List tabCompleteCommandValues(String commandName) { + for (GlobalSetting globalSetting : GlobalSetting.values()) { + if (globalSetting.getCommandName().equalsIgnoreCase(commandName)) { + return TabCompleteValuesHelper.getTabCompletions(globalSetting.getValueType()); + } + } + for (NPCSetting npcSetting : NPCSetting.values()) { + if (npcSetting.getCommandName().equalsIgnoreCase(commandName)) { + return TabCompleteValuesHelper.getTabCompletions(npcSetting.getValueType()); + } + } + return null; + } + +} diff --git a/src/main/java/net/knarcraft/blacksmith/command/BlackSmithEditCommand.java b/src/main/java/net/knarcraft/blacksmith/command/BlackSmithEditCommand.java new file mode 100644 index 0000000..5a5be5d --- /dev/null +++ b/src/main/java/net/knarcraft/blacksmith/command/BlackSmithEditCommand.java @@ -0,0 +1,70 @@ +package net.knarcraft.blacksmith.command; + +import net.citizensnpcs.api.CitizensAPI; +import net.citizensnpcs.api.npc.NPC; +import net.knarcraft.blacksmith.config.NPCSetting; +import net.knarcraft.blacksmith.trait.BlacksmithTrait; +import net.knarcraft.blacksmith.util.TypeValidationHelper; +import net.md_5.bungee.api.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; + +/** + * The main command used for blacksmith editing + */ +public class BlackSmithEditCommand implements CommandExecutor { + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, + @NotNull String[] args) { + NPC npc = CitizensAPI.getDefaultNPCSelector().getSelected(sender); + if (npc == null || !npc.hasTrait(BlacksmithTrait.class)) { + sender.sendMessage(ChatColor.DARK_RED + "You must select an NPC before running this command"); + return true; + } + + BlacksmithTrait blacksmithTrait = npc.getTrait(BlacksmithTrait.class); + + for (NPCSetting npcSetting : NPCSetting.values()) { + String commandName = npcSetting.getCommandName(); + if (commandName.equalsIgnoreCase(args[0])) { + String newValue = args.length < 2 ? null : args[1]; + return changeNPCSetting(blacksmithTrait, npcSetting, newValue, sender); + } + } + return false; + } + + /** + * Changes the given NPC setting, or displays the current value if a new value isn't specified + * + * @param blacksmithTrait

The blacksmith trait belonging to the selected NPC

+ * @param npcSetting

The NPC setting to change

+ * @param newValue

The value to change the setting to

+ * @param sender

The command sender to notify about results

+ * @return

True if everything went successfully

+ */ + private boolean changeNPCSetting(BlacksmithTrait blacksmithTrait, NPCSetting npcSetting, String newValue, + CommandSender sender) { + if (newValue == null) { + //Display the current value of the setting + sender.sendMessage(ChatColor.GREEN + "Current value of " + npcSetting.getCommandName() + ": " + + ChatColor.GOLD + blacksmithTrait.getSettings().getRawValue(npcSetting)); + return true; + } else { + boolean isValidType = TypeValidationHelper.isValid(npcSetting.getValueType(), newValue, sender); + if (isValidType) { + //Change the setting + blacksmithTrait.getSettings().changeSetting(npcSetting, + ChatColor.translateAlternateColorCodes('&', newValue)); + sender.sendMessage(ChatColor.GREEN + npcSetting.getNodeName() + " set to " + ChatColor.GOLD + newValue); + return true; + } else { + return false; + } + } + } + +} diff --git a/src/main/java/net/knarcraft/blacksmith/command/BlackSmithEditTabCompleter.java b/src/main/java/net/knarcraft/blacksmith/command/BlackSmithEditTabCompleter.java new file mode 100644 index 0000000..7bb9464 --- /dev/null +++ b/src/main/java/net/knarcraft/blacksmith/command/BlackSmithEditTabCompleter.java @@ -0,0 +1,57 @@ +package net.knarcraft.blacksmith.command; + +import net.knarcraft.blacksmith.config.NPCSetting; +import net.knarcraft.blacksmith.util.TabCompleteValuesHelper; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * The tab completer for the blacksmith editing command + */ +public class BlackSmithEditTabCompleter implements TabCompleter { + + @Nullable + @Override + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, + @NotNull String[] args) { + List npcSettings = new ArrayList<>(); + for (NPCSetting setting : NPCSetting.values()) { + npcSettings.add(setting.getCommandName()); + } + + if (args.length == 1) { + if (!sender.hasPermission("blacksmith.edit")) { + return new ArrayList<>(); + } + return npcSettings; + } else { + if (npcSettings.contains(args[0]) && args.length <= 2) { + return tabCompleteCommandValues(args[0]); + } else { + return new ArrayList<>(); + } + } + } + + /** + * Tab completes the values available for the given command + * + * @param commandName

The name of the used command

+ * @return

Some valid options for the command's argument

+ */ + private List tabCompleteCommandValues(String commandName) { + for (NPCSetting npcSetting : NPCSetting.values()) { + if (npcSetting.getCommandName().equalsIgnoreCase(commandName)) { + return TabCompleteValuesHelper.getTabCompletions(npcSetting.getValueType()); + } + } + return null; + } + +} diff --git a/src/main/java/net/knarcraft/blacksmith/command/BlackSmithTabCompleter.java b/src/main/java/net/knarcraft/blacksmith/command/BlackSmithTabCompleter.java deleted file mode 100644 index 9fac692..0000000 --- a/src/main/java/net/knarcraft/blacksmith/command/BlackSmithTabCompleter.java +++ /dev/null @@ -1,44 +0,0 @@ -package net.knarcraft.blacksmith.command; - -import net.knarcraft.blacksmith.config.NPCSetting; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.command.TabCompleter; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; - -/** - * The tab completer for the main blacksmith command - */ -public class BlackSmithTabCompleter implements TabCompleter { - - @Nullable - @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, - @NotNull String[] args) { - List npcSettings = new ArrayList<>(); - for (NPCSetting setting : NPCSetting.values()) { - npcSettings.add(setting.getCommandName()); - } - - if (args.length == 1) { - if (!sender.hasPermission("blacksmith.admin")) { - return new ArrayList<>(); - } - - List availableCommands = new ArrayList<>(npcSettings); - availableCommands.add("reload"); - return availableCommands; - } else { - if (npcSettings.contains(args[0])) { - return new NPCSettingTabCompleter().onTabComplete(sender, command, label, args); - } else { - return new ArrayList<>(); - } - } - } - -} diff --git a/src/main/java/net/knarcraft/blacksmith/command/NPCSettingCommand.java b/src/main/java/net/knarcraft/blacksmith/command/NPCSettingCommand.java deleted file mode 100644 index af1cab6..0000000 --- a/src/main/java/net/knarcraft/blacksmith/command/NPCSettingCommand.java +++ /dev/null @@ -1,44 +0,0 @@ -package net.knarcraft.blacksmith.command; - -import net.citizensnpcs.api.CitizensAPI; -import net.citizensnpcs.api.npc.NPC; -import net.knarcraft.blacksmith.config.NPCSetting; -import net.knarcraft.blacksmith.trait.BlacksmithTrait; -import net.md_5.bungee.api.ChatColor; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.jetbrains.annotations.NotNull; - -/** - * A class to perform everything related to changing a blacksmith's options - */ -public class NPCSettingCommand implements CommandExecutor { - - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - NPC npc = CitizensAPI.getDefaultNPCSelector().getSelected(sender); - if (npc == null || !npc.hasTrait(BlacksmithTrait.class)) { - sender.sendMessage(ChatColor.DARK_RED + "You must select an NPC before running this command"); - return true; - } - BlacksmithTrait blacksmithTrait = npc.getTrait(BlacksmithTrait.class); - - for (NPCSetting npcSetting : NPCSetting.values()) { - String commandName = npcSetting.getCommandName(); - if (commandName.equalsIgnoreCase(args[0])) { - if (args.length < 2) { - sender.sendMessage(ChatColor.GREEN + "Current value of " + commandName + ": " + - ChatColor.GOLD + blacksmithTrait.getSettings().getRawValue(npcSetting)); - } else { - blacksmithTrait.getSettings().changeSetting(npcSetting, - ChatColor.translateAlternateColorCodes('&', args[1])); - sender.sendMessage(ChatColor.GREEN + npcSetting.getNodeName() + " set to " + ChatColor.GOLD + args[1]); - } - return true; - } - } - return false; - } - -} diff --git a/src/main/java/net/knarcraft/blacksmith/command/NPCSettingTabCompleter.java b/src/main/java/net/knarcraft/blacksmith/command/NPCSettingTabCompleter.java deleted file mode 100644 index be1f0cb..0000000 --- a/src/main/java/net/knarcraft/blacksmith/command/NPCSettingTabCompleter.java +++ /dev/null @@ -1,24 +0,0 @@ -package net.knarcraft.blacksmith.command; - -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.command.TabCompleter; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -/** - * The tab completer for the NPC setting command - */ -public class NPCSettingTabCompleter implements TabCompleter { - - @Nullable - @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, - @NotNull String[] args) { - //TODO: Add tab completions based on each setting's type - return null; - } - -} diff --git a/src/main/java/net/knarcraft/blacksmith/config/GlobalSetting.java b/src/main/java/net/knarcraft/blacksmith/config/GlobalSetting.java index 82fd8d8..a388a0c 100644 --- a/src/main/java/net/knarcraft/blacksmith/config/GlobalSetting.java +++ b/src/main/java/net/knarcraft/blacksmith/config/GlobalSetting.java @@ -9,7 +9,7 @@ public enum GlobalSetting { * *

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

*/ - BASE_PRICE("global.base-price.default", 10.0), + BASE_PRICE("global.base-price.default", SettingValueType.POSITIVE_DOUBLE, 10.0, "basePrice"), /** * The base price for each durability point @@ -18,33 +18,39 @@ public enum GlobalSetting { * 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), + PRICE_PER_DURABILITY_POINT("global.price-per-durability-point.default", SettingValueType.POSITIVE_DOUBLE, 0.005, "pricePerDurabilityPoint"), /** * The price increase for each level of each present enchantment * *

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

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

The full config path for this setting

- * @param value

The default value of this setting

+ * @param path

The full config path for this setting

+ * @param valueType

The type of value used by this setting

+ * @param value

The default value of this setting

+ * @param commandName

The name of the command used to change this setting

*/ - GlobalSetting(String path, Object value) { + GlobalSetting(String path, SettingValueType valueType, Object value, String commandName) { this.path = path; this.value = value; + this.commandName = commandName; + this.valueType = valueType; String[] pathParts = path.split("\\."); this.parent = String.join(".", Arrays.copyOfRange(pathParts, 0, pathParts.length - 1)); } @@ -72,8 +78,26 @@ public enum GlobalSetting { * * @return

The value of this setting

*/ - Object getDefaultValue() { + public Object getDefaultValue() { return value; } + /** + * The name of the command used to change this setting + * + * @return

The name of this setting's command

+ */ + public String getCommandName() { + return commandName; + } + + /** + * Gets the value type for this setting + * + * @return

The value type for this setting

+ */ + public SettingValueType getValueType() { + return this.valueType; + } + } diff --git a/src/main/java/net/knarcraft/blacksmith/config/GlobalSettings.java b/src/main/java/net/knarcraft/blacksmith/config/GlobalSettings.java index 89c2119..f67f3e8 100644 --- a/src/main/java/net/knarcraft/blacksmith/config/GlobalSettings.java +++ b/src/main/java/net/knarcraft/blacksmith/config/GlobalSettings.java @@ -3,6 +3,7 @@ package net.knarcraft.blacksmith.config; import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.api.util.YamlStorage; import net.knarcraft.blacksmith.BlacksmithPlugin; +import net.knarcraft.blacksmith.util.ConfigHelper; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.enchantments.Enchantment; @@ -33,8 +34,8 @@ public class GlobalSettings { */ 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."); + "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."); } /** @@ -62,6 +63,82 @@ public class GlobalSettings { defaultConfig.save(); } + /** + * Changes the value of the given setting + * + * @param globalSetting

The global setting to change

+ * @param newValue

The new value of the setting

+ */ + public void changeValue(GlobalSetting globalSetting, Object newValue) { + globalSettings.put(globalSetting, newValue); + save(); + } + + /** + * Changes the value of the given setting + * + * @param npcSetting

The default NPC setting to change

+ * @param newValue

The new value for the setting

+ */ + public void changeValue(NPCSetting npcSetting, Object newValue) { + defaultNPCSettings.put(npcSetting, newValue); + save(); + } + + /** + * Sets the enchantment cost for the given enchantment + * + * @param enchantment

The enchantment to set the enchantment cost for

+ * @param newEnchantmentCost

The new enchantment cost

+ */ + public void setEnchantmentCost(Enchantment enchantment, double newEnchantmentCost) { + if (newEnchantmentCost < 0) { + throw new IllegalArgumentException("Enchantment cost cannot be negative!"); + } + if (enchantment == null) { + globalSettings.put(GlobalSetting.ENCHANTMENT_COST, newEnchantmentCost); + } else { + enchantmentCosts.put(enchantment, newEnchantmentCost); + } + save(); + } + + /** + * Sets the price per durability point for the given material + * + * @param material

The material to set the price per durability point price for

+ * @param newPrice

The new price per durability point price

+ */ + public void setPricePerDurabilityPoint(Material material, double newPrice) { + if (newPrice < 0) { + throw new IllegalArgumentException("Price per durability point cannot be negative!"); + } + if (material == null) { + globalSettings.put(GlobalSetting.PRICE_PER_DURABILITY_POINT, newPrice); + } else { + materialPricePerDurabilityPoints.put(material, newPrice); + } + save(); + } + + /** + * Sets the base price for the given material + * + * @param material

The material to set the base price for

+ * @param newBasePrice

The new base price

+ */ + public void setBasePrice(Material material, double newBasePrice) { + if (newBasePrice < 0) { + throw new IllegalArgumentException("Base price cannot be negative!"); + } + if (material == null) { + globalSettings.put(GlobalSetting.BASE_PRICE, newBasePrice); + } else { + materialBasePrices.put(material, newBasePrice); + } + save(); + } + /** * Gets the current value of the default NPC settings * @@ -135,12 +212,7 @@ public class GlobalSettings { * @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; - } + return ConfigHelper.asBoolean(getValue(setting)); } /** @@ -152,14 +224,7 @@ public class GlobalSettings { * @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; - } + return ConfigHelper.asDouble(getValue(setting)); } /** @@ -256,6 +321,16 @@ public class GlobalSettings { return relevant; } + /** + * Converts a normalized material name to the format used in the config file + * + * @param normalizedName

The normalized name to un-normalize

+ * @return

The un-normalized name

+ */ + private String unNormalizeName(String normalizedName) { + return normalizedName.toLowerCase().replace("_", "-"); + } + /** * Loads all default NPC settings * @@ -273,4 +348,41 @@ public class GlobalSettings { } } + /** + * Saves all current settings to the config file + */ + private void save() { + DataKey root = defaultConfig.getKey(""); + //Save all default NPC settings + for (NPCSetting setting : NPCSetting.values()) { + root.setRaw(setting.getPath(), defaultNPCSettings.get(setting)); + } + + //Save all normal global settings + for (GlobalSetting globalSetting : GlobalSetting.values()) { + root.setRaw(globalSetting.getPath(), globalSettings.get(globalSetting)); + } + + //Save all base prices + DataKey basePriceNode = root.getRelative(GlobalSetting.BASE_PRICE.getParent()); + for (Material material : materialBasePrices.keySet()) { + basePriceNode.setRaw(unNormalizeName(material.name()), materialBasePrices.get(material)); + } + + //Save all per-durability-point prices + DataKey basePerDurabilityPriceNode = root.getRelative(GlobalSetting.PRICE_PER_DURABILITY_POINT.getParent()); + for (Material material : materialPricePerDurabilityPoints.keySet()) { + basePerDurabilityPriceNode.setRaw(unNormalizeName(material.name()), materialPricePerDurabilityPoints.get(material)); + } + + //Load all enchantment prices + DataKey enchantmentCostNode = root.getRelative(GlobalSetting.ENCHANTMENT_COST.getParent()); + for (Enchantment enchantment : enchantmentCosts.keySet()) { + enchantmentCostNode.setRaw(unNormalizeName(enchantment.getKey().toString()), enchantmentCosts.get(enchantment)); + } + + //Perform the actual save to disk + defaultConfig.save(); + } + } diff --git a/src/main/java/net/knarcraft/blacksmith/config/NPCSetting.java b/src/main/java/net/knarcraft/blacksmith/config/NPCSetting.java index 44ac759..19b22b3 100644 --- a/src/main/java/net/knarcraft/blacksmith/config/NPCSetting.java +++ b/src/main/java/net/knarcraft/blacksmith/config/NPCSetting.java @@ -7,58 +7,62 @@ import java.util.Arrays; */ public enum NPCSetting { - DROP_ITEM("defaults.drop-item", true, "dropItem"), - DISABLE_COOL_DOWN("defaults.disable-cool-down", false, "disableCoolDown"), - DISABLE_DELAY("defaults.disable-delay", false, "disableDelay"), - FAIL_CHANCE("defaults.percent-chance-to-fail-reforge", 10, "failReforgeChance"), - EXTRA_ENCHANTMENT_CHANCE("defaults.percent-chance-for-extra-enchantment", 5, + DROP_ITEM("defaults.drop-item", SettingValueType.BOOLEAN, true, "dropItem"), + DISABLE_COOL_DOWN("defaults.disable-cool-down", SettingValueType.BOOLEAN, false, "disableCoolDown"), + DISABLE_DELAY("defaults.disable-delay", SettingValueType.BOOLEAN, false, "disableDelay"), + FAIL_CHANCE("defaults.percent-chance-to-fail-reforge", SettingValueType.PERCENTAGE, 10, "failReforgeChance"), + EXTRA_ENCHANTMENT_CHANCE("defaults.percent-chance-for-extra-enchantment", SettingValueType.PERCENTAGE, 5, "extraEnchantmentChance"), - MAX_ENCHANTMENTS("defaults.maximum-enchantments", 3, "maxEnchantments"), - MAX_REFORGE_DELAY("defaults.delays-in-seconds.maximum", 30, "maxReforgeDelay"), - MIN_REFORGE_DELAY("defaults.delays-in-seconds.minimum", 5, "minReforgeDelay"), - REFORGE_COOL_DOWN("defaults.delays-in-seconds.reforge-cool-down", 60, "reforgeCoolDown"), - REFORGE_ABLE_ITEMS("defaults.reforge-able-items", new String[]{}, "reforgeAbleItems"), + MAX_ENCHANTMENTS("defaults.maximum-enchantments", SettingValueType.POSITIVE_INTEGER, 3, "maxEnchantments"), + MAX_REFORGE_DELAY("defaults.delays-in-seconds.maximum", SettingValueType.POSITIVE_INTEGER, 30, "maxReforgeDelay"), + MIN_REFORGE_DELAY("defaults.delays-in-seconds.minimum", SettingValueType.POSITIVE_INTEGER, 5, "minReforgeDelay"), + REFORGE_COOL_DOWN("defaults.delays-in-seconds.reforge-cool-down", SettingValueType.POSITIVE_INTEGER, 60, "reforgeCoolDown"), + REFORGE_ABLE_ITEMS("defaults.reforge-able-items", SettingValueType.STRING_LIST, new String[]{}, "reforgeAbleItems"), /*----------- | Messages | -----------*/ - BUSY_WITH_PLAYER_MESSAGE("defaults.messages.busy-with-player", + BUSY_WITH_PLAYER_MESSAGE("defaults.messages.busy-with-player", SettingValueType.STRING, "§cI'm busy at the moment. Come back later!", "busyPlayerMessage"), - BUSY_WITH_REFORGE_MESSAGE("defaults.messages.busy-with-reforge", "§cI'm working on it. Be patient!", + BUSY_WITH_REFORGE_MESSAGE("defaults.messages.busy-with-reforge", SettingValueType.STRING, "§cI'm working on it. Be patient!", "busyReforgeMessage"), - COOL_DOWN_UNEXPIRED_MESSAGE("defaults.messages.cool-down-not-expired", + COOL_DOWN_UNEXPIRED_MESSAGE("defaults.messages.cool-down-not-expired", SettingValueType.STRING, "§cYou've already had your chance! Give me a break!", "coolDownUnexpiredMessage"), COST_MESSAGE( - "defaults.messages.cost", + "defaults.messages.cost", SettingValueType.STRING, "§eIt will cost §a §eto reforge that §a§e! Click again to reforge!", "costMessage"), - FAIL_MESSAGE("defaults.messages.fail-reforge", "§cWhoops! Didn't mean to do that! Maybe next time?", + FAIL_MESSAGE("defaults.messages.fail-reforge", SettingValueType.STRING, "§cWhoops! Didn't mean to do that! Maybe next time?", "failReforgeMessage"), - INSUFFICIENT_FUNDS_MESSAGE("defaults.messages.insufficient-funds", + INSUFFICIENT_FUNDS_MESSAGE("defaults.messages.insufficient-funds", SettingValueType.STRING, "§cYou don't have enough money to reforge that item!", "insufficientFundsMessage"), - INVALID_ITEM_MESSAGE("defaults.messages.invalid-item", "§cI'm sorry, but I don't know how to reforge that!", - "invalidItemMessage"), - ITEM_UNEXPECTEDLY_CHANGED_MESSAGE("defaults.messages.item-changed-during-reforge", + INVALID_ITEM_MESSAGE("defaults.messages.invalid-item", SettingValueType.STRING, + "§cI'm sorry, but I don't know how to reforge that!", "invalidItemMessage"), + ITEM_UNEXPECTEDLY_CHANGED_MESSAGE("defaults.messages.item-changed-during-reforge", SettingValueType.STRING, "§cThat's not the item you wanted to reforge before!", "itemChangedMessage"), - START_REFORGE_MESSAGE("defaults.messages.start-reforge", "§eOk, let's see what I can do...", - "startReforgeMessage"), - SUCCESS_MESSAGE("defaults.messages.successful-reforge", "There you go! All better!", "successMessage"); + START_REFORGE_MESSAGE("defaults.messages.start-reforge", SettingValueType.STRING, + "§eOk, let's see what I can do...", "startReforgeMessage"), + SUCCESS_MESSAGE("defaults.messages.successful-reforge", SettingValueType.STRING, + "There you go! All better!", "successMessage"); private final String path; private final String childPath; private final Object value; private final String commandName; private final String nodeName; + private final SettingValueType valueType; /** * Instantiates a new setting * * @param path

The full config path for this setting

+ * @param valueType

The type of value used by this setting

* @param value

The default value of this setting

* @param commandName

The name of the command used to change this setting

*/ - NPCSetting(String path, Object value, String commandName) { + NPCSetting(String path, SettingValueType valueType, Object value, String commandName) { this.path = path; this.value = value; + this.valueType = valueType; String[] pathParts = path.split("\\."); this.childPath = String.join(".", Arrays.copyOfRange(pathParts, 1, pathParts.length)); this.commandName = commandName; @@ -114,4 +118,13 @@ public enum NPCSetting { return nodeName; } + /** + * Gets the value type for this setting + * + * @return

The value type for this setting

+ */ + public SettingValueType getValueType() { + return this.valueType; + } + } diff --git a/src/main/java/net/knarcraft/blacksmith/config/NPCSettings.java b/src/main/java/net/knarcraft/blacksmith/config/NPCSettings.java index 4209bec..54f047c 100644 --- a/src/main/java/net/knarcraft/blacksmith/config/NPCSettings.java +++ b/src/main/java/net/knarcraft/blacksmith/config/NPCSettings.java @@ -3,6 +3,7 @@ package net.knarcraft.blacksmith.config; import net.citizensnpcs.api.util.DataKey; import net.knarcraft.blacksmith.BlacksmithPlugin; import net.knarcraft.blacksmith.trait.BlacksmithTrait; +import net.knarcraft.blacksmith.util.ConfigHelper; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -61,6 +62,9 @@ public class NPCSettings { * @param newValue

The new value of the setting

*/ public void changeSetting(NPCSetting setting, Object newValue) { + if (setting == NPCSetting.REFORGE_ABLE_ITEMS) { + newValue = replaceReforgeAblePlaceholders(newValue); + } currentValues.put(setting, newValue); } @@ -265,12 +269,7 @@ public class NPCSettings { * @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; - } + return ConfigHelper.asBoolean(getValue(setting)); } /** @@ -282,12 +281,7 @@ public class NPCSettings { * @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; - } + return ConfigHelper.asInt(getValue(setting)); } /** @@ -322,6 +316,31 @@ public class NPCSettings { return value; } + /** + * Replaces placeholders in the given reforge-able value + * + * @param value

The value specified by a user

+ * @return

The value with placeholders replaced

+ */ + private Object replaceReforgeAblePlaceholders(Object value) { + if (value instanceof String string) { + String[] list = string.split(","); + List replaced = new ArrayList<>(list.length); + for (String item : list) { + replaced.add(SmithPreset.replacePlaceholder(item)); + } + return String.join(",", replaced); + } else if (value instanceof String[] stringList) { + List replaced = new ArrayList<>(stringList.length); + for (String item : stringList) { + replaced.add(SmithPreset.replacePlaceholder(item)); + } + return replaced.toArray(); + } else { + throw new IllegalArgumentException("Unexpected object type encountered!"); + } + } + /** * Updates the reforge-able items according to the current value of the setting */ diff --git a/src/main/java/net/knarcraft/blacksmith/config/SettingValueType.java b/src/main/java/net/knarcraft/blacksmith/config/SettingValueType.java new file mode 100644 index 0000000..d9b9937 --- /dev/null +++ b/src/main/java/net/knarcraft/blacksmith/config/SettingValueType.java @@ -0,0 +1,38 @@ +package net.knarcraft.blacksmith.config; + +/** + * A representation of all value types used by settings + */ +public enum SettingValueType { + + /** + * A double value which cannot be negative + */ + POSITIVE_DOUBLE, + + /** + * Any string (used for messages), except empty + */ + STRING, + + /** + * An integer value which cannot be negative + */ + POSITIVE_INTEGER, + + /** + * A percentage integer value (0-100 only) + */ + PERCENTAGE, + + /** + * A boolean value + */ + BOOLEAN, + + /** + * A string list (used for reforge-able items) + */ + STRING_LIST + +} diff --git a/src/main/java/net/knarcraft/blacksmith/config/SmithPreset.java b/src/main/java/net/knarcraft/blacksmith/config/SmithPreset.java new file mode 100644 index 0000000..6a34833 --- /dev/null +++ b/src/main/java/net/knarcraft/blacksmith/config/SmithPreset.java @@ -0,0 +1,158 @@ +package net.knarcraft.blacksmith.config; + +import org.bukkit.Material; + +import java.util.ArrayList; +import java.util.List; + +/** + * A representation of the presets for different kinds of smiths + */ +public enum SmithPreset { + + /** + * A blacksmith capable of re-forging all swords + */ + SWORD_SMITH, + + /** + * A blacksmith capable of re-forging all weapons (including shields) + */ + WEAPON_SMITH, + + /** + * A blacksmith capable of re-forging all armor + */ + ARMOR_SMITH, + + /** + * A blacksmith capable of re-forging all tools (hoe, axe, shovel, pickaxe, flint and steel, shears, fishing rod) + */ + TOOL_SMITH, + + /** + * A blacksmith capable of re-forging all ranged weapons (bow, crossbow, trident) + */ + RANGED_SMITH; + + /** + * Replaces the given string if it's a smith type placeholder + * + * @param possiblePlaceholder

The string that might be a placeholder

+ * @return

The string, possibly with the placeholder replaced

+ */ + public static String replacePlaceholder(String possiblePlaceholder) { + for (SmithPreset smithPreset : SmithPreset.values()) { + if (possiblePlaceholder.equalsIgnoreCase("preset:" + smithPreset.name())) { + return String.join(",", smithPreset.getMaterialNames()); + } + } + return possiblePlaceholder; + } + + /** + * Gets all materials included in this preset + * + * @return

All materials in this preset

+ */ + public List getMaterials() { + return switch (this) { + case SWORD_SMITH -> getSwords(); + case WEAPON_SMITH -> getWeapons(); + case ARMOR_SMITH -> getArmor(); + case TOOL_SMITH -> getTools(); + case RANGED_SMITH -> getRanged(); + }; + } + + /** + * Gets all ranged weapon materials + * + * @return

All ranged weapon materials

+ */ + private List getRanged() { + List ranged = new ArrayList<>(); + ranged.add(Material.TRIDENT); + ranged.add(Material.BOW); + ranged.add(Material.CROSSBOW); + return ranged; + } + + /** + * Gets all tool materials + * + * @return

All tool materials

+ */ + private List getTools() { + List tools = new ArrayList<>(); + tools.addAll(getMaterialsEndingWith("_HOE")); + tools.addAll(getMaterialsEndingWith("_SHOVEL")); + tools.addAll(getMaterialsEndingWith("_AXE")); + tools.addAll(getMaterialsEndingWith("_PICKAXE")); + tools.add(Material.FLINT_AND_STEEL); + tools.add(Material.FISHING_ROD); + tools.add(Material.SHEARS); + return tools; + } + + /** + * Gets all weapon materials + * + * @return

All weapon materials

+ */ + private List getWeapons() { + List weapons = new ArrayList<>(getSwords()); + weapons.addAll(getRanged()); + weapons.add(Material.SHIELD); + return weapons; + } + + /** + * Gets all sword materials + * + * @return

All sword materials

+ */ + private List getSwords() { + return getMaterialsEndingWith("_SWORD"); + } + + private List getArmor() { + List armor = new ArrayList<>(); + armor.addAll(getMaterialsEndingWith("HELMET")); + armor.addAll(getMaterialsEndingWith("CHESTPLATE")); + armor.addAll(getMaterialsEndingWith("LEGGINGS")); + armor.addAll(getMaterialsEndingWith("BOOTS")); + armor.add(Material.ELYTRA); + return armor; + } + + /** + * Gets all materials ending with the given string + * + * @param end

The string to look for

+ * @return

The resulting materials

+ */ + private List getMaterialsEndingWith(String end) { + List swords = new ArrayList<>(); + for (Material material : Material.values()) { + if (!material.name().startsWith("LEGACY") && material.name().endsWith(end)) { + swords.add(material); + } + } + return swords; + } + + /** + * Gets material names of all materials re-forge-able by this smith + * + * @return

All material names for this smith

+ */ + private List getMaterialNames() { + List items = new ArrayList<>(); + for (Material material : this.getMaterials()) { + items.add(material.name().toLowerCase().replace("_", "-")); + } + return items; + } + +} diff --git a/src/main/java/net/knarcraft/blacksmith/listener/PlayerListener.java b/src/main/java/net/knarcraft/blacksmith/listener/PlayerListener.java index fd0845c..bfc300e 100644 --- a/src/main/java/net/knarcraft/blacksmith/listener/PlayerListener.java +++ b/src/main/java/net/knarcraft/blacksmith/listener/PlayerListener.java @@ -2,6 +2,7 @@ package net.knarcraft.blacksmith.listener; import net.citizensnpcs.api.CitizensAPI; import net.knarcraft.blacksmith.trait.BlacksmithTrait; +import org.bukkit.Material; import org.bukkit.enchantments.EnchantmentTarget; import org.bukkit.entity.Entity; import org.bukkit.event.Event; @@ -48,16 +49,7 @@ public class PlayerListener implements Listener { * @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; - };*/ + return EnchantmentTarget.WEARABLE.includes(item) || item.getType() == Material.ELYTRA; } /** diff --git a/src/main/java/net/knarcraft/blacksmith/trait/ReforgeSession.java b/src/main/java/net/knarcraft/blacksmith/trait/ReforgeSession.java index fcdc05e..ace17bc 100644 --- a/src/main/java/net/knarcraft/blacksmith/trait/ReforgeSession.java +++ b/src/main/java/net/knarcraft/blacksmith/trait/ReforgeSession.java @@ -68,13 +68,14 @@ public class ReforgeSession implements Runnable { //Give the item back to the player if (!config.getDisableDelay()) { - //If the player isn't online, drop the item to prevent it from disappearing - if (config.getDropItem() || !player.isOnline()) { + //If the player isn't online, or the player cannot fit the item, drop the item to prevent it from disappearing + if (config.getDropItem() || !player.isOnline() || player.getInventory().firstEmpty() == -1) { player.getWorld().dropItemNaturally(npc.getEntity().getLocation(), itemToReforge); } else { player.getInventory().addItem(itemToReforge); } } else { + //It can be assumed as this happens instantly, that the player still has the item's previous slot selected player.getInventory().setItemInMainHand(itemToReforge); } diff --git a/src/main/java/net/knarcraft/blacksmith/util/ConfigHelper.java b/src/main/java/net/knarcraft/blacksmith/util/ConfigHelper.java new file mode 100644 index 0000000..e303630 --- /dev/null +++ b/src/main/java/net/knarcraft/blacksmith/util/ConfigHelper.java @@ -0,0 +1,62 @@ +package net.knarcraft.blacksmith.util; + +/** + * A helper class for getting an object value as the correct type + */ +public final class ConfigHelper { + + private ConfigHelper() { + + } + + /** + * Gets the given value as a double + * + *

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

+ * + * @param value

The object value to get

+ * @return

The value of the given object as a double

+ */ + public static double asDouble(Object value) { + if (value instanceof String) { + return Double.parseDouble((String) value); + } else if (value instanceof Integer) { + return (Integer) value; + } else { + return (Double) value; + } + } + + /** + * Gets the given value as a boolean + * + *

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

+ * + * @param value

The object value to get

+ * @return

The value of the given object as a boolean

+ */ + public static boolean asBoolean(Object value) { + 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 value

The object value to get

+ * @return

The value of the given object as an integer

+ */ + public static int asInt(Object value) { + if (value instanceof String) { + return Integer.parseInt((String) value); + } else { + return (Integer) value; + } + } + +} diff --git a/src/main/java/net/knarcraft/blacksmith/util/TabCompleteValuesHelper.java b/src/main/java/net/knarcraft/blacksmith/util/TabCompleteValuesHelper.java new file mode 100644 index 0000000..572cd7c --- /dev/null +++ b/src/main/java/net/knarcraft/blacksmith/util/TabCompleteValuesHelper.java @@ -0,0 +1,121 @@ +package net.knarcraft.blacksmith.util; + +import net.knarcraft.blacksmith.config.SettingValueType; + +import java.util.ArrayList; +import java.util.List; + +/** + * A helper class for getting valid values for tab-completion + */ +public final class TabCompleteValuesHelper { + + private TabCompleteValuesHelper() { + + } + + /** + * Gets tab-completion values for the given value type + * + * @param valueType

The value type to get possible values for

+ * @return

The values to show the user

+ */ + public static List getTabCompletions(SettingValueType valueType) { + return switch (valueType) { + case POSITIVE_INTEGER -> getPositiveIntegers(); + case BOOLEAN -> getBooleans(); + case POSITIVE_DOUBLE -> getPositiveDoubles(); + case STRING -> getStrings(); + case PERCENTAGE -> getPercentages(); + case STRING_LIST -> getReforgeAbleMaterials(); + }; + } + + /** + * Gets some example possible values for reforge-able materials + * + * @return

Some example possible values for reforge-able materials

+ */ + private static List getReforgeAbleMaterials() { + List stringLists = new ArrayList<>(); + stringLists.add("preset:sword-smith"); + stringLists.add("preset:weapon-smith"); + stringLists.add("preset:armor-smith"); + stringLists.add("preset:tool-smith"); + stringLists.add("preset:ranged-smith"); + stringLists.add("bow,crossbow,elytra"); + return stringLists; + } + + /** + * Gets some example string values + * + * @return

Some example string values

+ */ + private static List getStrings() { + List strings = new ArrayList<>(1); + strings.add("&aExample message. Use & for color tags."); + return strings; + } + + /** + * Gets some example percentage values + * + * @return

Some example percentage values

+ */ + private static List getPercentages() { + List percentages = new ArrayList<>(6); + percentages.add("0"); + percentages.add("10"); + percentages.add("25"); + percentages.add("45"); + percentages.add("75"); + percentages.add("100"); + return percentages; + } + + /** + * Gets some possible positive doubles + * + * @return

Some possible positive doubles

+ */ + private static List getPositiveDoubles() { + List positiveDoubles = new ArrayList<>(4); + positiveDoubles.add("0.0"); + positiveDoubles.add("0.0001"); + positiveDoubles.add("5.0"); + positiveDoubles.add("7.34"); + positiveDoubles.add("5674.34534"); + return positiveDoubles; + } + + /** + * Gets some example positive integers + * + * @return

Some example positive integers

+ */ + private static List getPositiveIntegers() { + List positiveIntegers = new ArrayList<>(6); + positiveIntegers.add("0"); + positiveIntegers.add("5"); + positiveIntegers.add("10"); + positiveIntegers.add("25"); + positiveIntegers.add("50"); + positiveIntegers.add("100"); + positiveIntegers.add("4565"); + return positiveIntegers; + } + + /** + * Gets the possible boolean values + * + * @return

The possible boolean values

+ */ + private static List getBooleans() { + List booleans = new ArrayList<>(2); + booleans.add("True"); + booleans.add("False"); + return booleans; + } + +} diff --git a/src/main/java/net/knarcraft/blacksmith/util/TypeValidationHelper.java b/src/main/java/net/knarcraft/blacksmith/util/TypeValidationHelper.java new file mode 100644 index 0000000..769778c --- /dev/null +++ b/src/main/java/net/knarcraft/blacksmith/util/TypeValidationHelper.java @@ -0,0 +1,125 @@ +package net.knarcraft.blacksmith.util; + +import net.knarcraft.blacksmith.config.SettingValueType; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; + +/** + * A helper class for validating a value's type + */ +public final class TypeValidationHelper { + + private TypeValidationHelper() { + + } + + /** + * Gets whether the given value is valid for the given value type + * + * @param valueType

The value type required

+ * @param value

The value given

+ * @param sender

The command sender to use for printing error messages

+ * @return

True if the value is valid

+ */ + public static boolean isValid(SettingValueType valueType, Object value, CommandSender sender) { + try { + return switch (valueType) { + case POSITIVE_DOUBLE -> isPositiveDouble(value, sender); + case STRING -> isNonEmptyString(value, sender); + case POSITIVE_INTEGER -> isPositiveInteger(value, sender); + case PERCENTAGE -> isPercentage(value, sender); + case BOOLEAN -> true; + case STRING_LIST -> isStringList(value, sender); + }; + } catch (ClassCastException exception) { + //This error signifies that an object is not a string, and of the wrong class + return false; + } + } + + /** + * Checks whether the given value is a string list + * + * @param value

The value to check

+ * @param sender

The command sender to use for printing error messages

+ * @return

True if the value is a string list

+ */ + private static boolean isStringList(Object value, CommandSender sender) { + boolean isStringList = value instanceof String[] || value instanceof String; + if (!isStringList && sender != null) { + sender.sendMessage(ChatColor.DARK_RED + "A string list is required!"); + } + return isStringList; + } + + /** + * Checks whether the given value is a valid percentage + * + * @param value

The value to check

+ * @param sender

The command sender to use for printing error messages

+ * @return

True if the value is a percentage

+ */ + private static boolean isPercentage(Object value, CommandSender sender) { + try { + int intValue = ConfigHelper.asInt(value); + return intValue > 0 && intValue <= 100; + } catch (NumberFormatException | NullPointerException exception) { + if (sender != null) { + sender.sendMessage(ChatColor.DARK_RED + "You specified a value which isn't between 0 and 100!"); + } + return false; + } + } + + /** + * Checks whether the given value is a non-empty string + * + * @param value

The value to check

+ * @param sender

The command sender to use for printing error messages

+ * @return

True if the value is a non-empty string

+ */ + private static boolean isNonEmptyString(Object value, CommandSender sender) { + boolean isString = value instanceof String string && !string.strip().isEmpty(); + if (!isString && sender != null) { + sender.sendMessage(ChatColor.DARK_RED + "A non-empty string is required!"); + } + return isString; + } + + /** + * Checks whether the given value is a positive double + * + * @param value

The value to check

+ * @param sender

The command sender to use for printing error messages

+ * @return

True if the value is a positive double

+ */ + private static boolean isPositiveDouble(Object value, CommandSender sender) { + try { + return ConfigHelper.asDouble(value) > 0.0; + } catch (NumberFormatException | NullPointerException exception) { + if (sender != null) { + sender.sendMessage(ChatColor.DARK_RED + "You specified a value which isn't a positive double!"); + } + return false; + } + } + + /** + * Checks whether the given value is a positive integer + * + * @param value

The value to check

+ * @param sender

The command sender to use for printing error messages

+ * @return

True if the value is a positive integer

+ */ + private static boolean isPositiveInteger(Object value, CommandSender sender) { + try { + return ConfigHelper.asInt(value) > 0; + } catch (NumberFormatException | NullPointerException exception) { + if (sender != null) { + sender.sendMessage(ChatColor.DARK_RED + "You specified a value which isn't a positive integer!"); + } + return false; + } + } + +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 91b1228..ac72b0a 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -9,9 +9,19 @@ api-version: 1.18 commands: blacksmith: + permission: blacksmith.edit + usage: /