Adds a preset command which can be used to see available presets Adds preset filters which can be used to specify item sub-categories within a preset Removes SWORD_SMITH and RANGED_SMITH, as those are replaced by the RANGED and SWORD filters Adds a list of usable filters for each preset
This commit is contained in:
		@@ -5,6 +5,8 @@ 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.command.PresetCommand;
 | 
			
		||||
import net.knarcraft.blacksmith.command.PresetTabCompleter;
 | 
			
		||||
import net.knarcraft.blacksmith.config.GlobalSettings;
 | 
			
		||||
import net.knarcraft.blacksmith.formatting.Translator;
 | 
			
		||||
import net.knarcraft.blacksmith.listener.NPCClickListener;
 | 
			
		||||
@@ -88,10 +90,6 @@ public class BlacksmithPlugin extends JavaPlugin {
 | 
			
		||||
        registerListeners();
 | 
			
		||||
 | 
			
		||||
        getLogger().log(Level.INFO, " v" + getDescription().getVersion() + " enabled.");
 | 
			
		||||
        //TODO: Improve un-setting of values for a given NPC: While setting values works fine, a bit more care should
 | 
			
		||||
        // be performed regarding removing a custom value. Basically, using null for strings and -1 for numbers should
 | 
			
		||||
        // unset a value for an NPC. Unsetting a value would make the NPC use the default value set in the config file
 | 
			
		||||
        // instead
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -136,6 +134,12 @@ public class BlacksmithPlugin extends JavaPlugin {
 | 
			
		||||
            blacksmithConfigCommand.setExecutor(new BlackSmithConfigCommand());
 | 
			
		||||
            blacksmithConfigCommand.setTabCompleter(new BlackSmithConfigTabCompleter());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        PluginCommand presetCommand = this.getCommand("preset");
 | 
			
		||||
        if (presetCommand != null) {
 | 
			
		||||
            presetCommand.setExecutor(new PresetCommand());
 | 
			
		||||
            presetCommand.setTabCompleter(new PresetTabCompleter());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@ import net.knarcraft.blacksmith.config.NPCSetting;
 | 
			
		||||
import net.knarcraft.blacksmith.config.SettingValueType;
 | 
			
		||||
import net.knarcraft.blacksmith.formatting.ItemType;
 | 
			
		||||
import net.knarcraft.blacksmith.formatting.TranslatableMessage;
 | 
			
		||||
import net.knarcraft.blacksmith.formatting.Translator;
 | 
			
		||||
import net.knarcraft.blacksmith.util.InputParsingHelper;
 | 
			
		||||
import net.knarcraft.blacksmith.util.TypeValidationHelper;
 | 
			
		||||
import net.md_5.bungee.api.ChatColor;
 | 
			
		||||
@@ -44,8 +43,7 @@ public class BlackSmithConfigCommand implements CommandExecutor {
 | 
			
		||||
 | 
			
		||||
        //Changing reforge-able items' default isn't recommended
 | 
			
		||||
        if (commandName.equalsIgnoreCase(NPCSetting.REFORGE_ABLE_ITEMS.getCommandName())) {
 | 
			
		||||
            displayErrorMessage(sender,
 | 
			
		||||
                    Translator.getTranslatedMessage(TranslatableMessage.DEFAULT_REFORGE_ABLE_ITEMS_UNCHANGEABLE));
 | 
			
		||||
            displayErrorMessage(sender, TranslatableMessage.DEFAULT_REFORGE_ABLE_ITEMS_UNCHANGEABLE);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@ import net.knarcraft.blacksmith.config.NPCSetting;
 | 
			
		||||
import net.knarcraft.blacksmith.config.SettingValueType;
 | 
			
		||||
import net.knarcraft.blacksmith.formatting.StringFormatter;
 | 
			
		||||
import net.knarcraft.blacksmith.formatting.TranslatableMessage;
 | 
			
		||||
import net.knarcraft.blacksmith.formatting.Translator;
 | 
			
		||||
import net.knarcraft.blacksmith.trait.BlacksmithTrait;
 | 
			
		||||
import net.knarcraft.blacksmith.util.TypeValidationHelper;
 | 
			
		||||
import net.md_5.bungee.api.ChatColor;
 | 
			
		||||
@@ -30,8 +29,7 @@ public class BlackSmithEditCommand implements CommandExecutor {
 | 
			
		||||
                             @NotNull String[] args) {
 | 
			
		||||
        NPC npc = CitizensAPI.getDefaultNPCSelector().getSelected(sender);
 | 
			
		||||
        if (npc == null || !npc.hasTrait(BlacksmithTrait.class)) {
 | 
			
		||||
            StringFormatter.displayErrorMessage(sender,
 | 
			
		||||
                    Translator.getTranslatedMessage(TranslatableMessage.NO_NPC_SELECTED));
 | 
			
		||||
            StringFormatter.displayErrorMessage(sender, TranslatableMessage.NO_NPC_SELECTED);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,65 @@
 | 
			
		||||
package net.knarcraft.blacksmith.command;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.blacksmith.config.SmithPreset;
 | 
			
		||||
import net.knarcraft.blacksmith.config.SmithPresetFilter;
 | 
			
		||||
import net.knarcraft.blacksmith.formatting.StringFormatter;
 | 
			
		||||
import net.knarcraft.blacksmith.formatting.TranslatableMessage;
 | 
			
		||||
import net.knarcraft.blacksmith.formatting.Translator;
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
import org.bukkit.command.Command;
 | 
			
		||||
import org.bukkit.command.CommandExecutor;
 | 
			
		||||
import org.bukkit.command.CommandSender;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static net.knarcraft.blacksmith.formatting.StringFormatter.displayErrorMessage;
 | 
			
		||||
import static net.knarcraft.blacksmith.formatting.StringFormatter.displaySuccessMessage;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The command for displaying which materials are contained in a preset
 | 
			
		||||
 */
 | 
			
		||||
public class PresetCommand implements CommandExecutor {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
 | 
			
		||||
                             @NotNull String[] args) {
 | 
			
		||||
        if (args.length < 1) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        String presetName = args[0].toUpperCase().replace('-', '_');
 | 
			
		||||
        List<Material> includedMaterials;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            //Display the preset with the filter applied
 | 
			
		||||
            if (presetName.contains(":")) {
 | 
			
		||||
                String[] parts = presetName.split(":");
 | 
			
		||||
                SmithPreset smithPreset = SmithPreset.valueOf(parts[0]);
 | 
			
		||||
                SmithPresetFilter filter = SmithPresetFilter.valueOf(parts[1]);
 | 
			
		||||
 | 
			
		||||
                if (!smithPreset.supportsFilter(filter)) {
 | 
			
		||||
                    displayErrorMessage(sender, TranslatableMessage.INVALID_FILTER_FOR_PRESET);
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
                includedMaterials = smithPreset.getFilteredMaterials(filter);
 | 
			
		||||
            } else {
 | 
			
		||||
                includedMaterials = SmithPreset.valueOf(presetName).getMaterials();
 | 
			
		||||
            }
 | 
			
		||||
        } catch (IllegalArgumentException exception) {
 | 
			
		||||
            displayErrorMessage(sender, TranslatableMessage.INVALID_PRESET_OR_FILTER);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Convert materials to strings before output
 | 
			
		||||
        List<String> materialNames = new ArrayList<>();
 | 
			
		||||
        for (Material material : includedMaterials) {
 | 
			
		||||
            materialNames.add(material.name());
 | 
			
		||||
        }
 | 
			
		||||
        displaySuccessMessage(sender, StringFormatter.replacePlaceholder(Translator.getTranslatedMessage(
 | 
			
		||||
                TranslatableMessage.PRESET_MATERIALS), "{materials}", String.join(", ", materialNames)));
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,60 @@
 | 
			
		||||
package net.knarcraft.blacksmith.command;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.blacksmith.config.SmithPreset;
 | 
			
		||||
import net.knarcraft.blacksmith.config.SmithPresetFilter;
 | 
			
		||||
import net.knarcraft.blacksmith.util.TabCompletionHelper;
 | 
			
		||||
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 preset command
 | 
			
		||||
 */
 | 
			
		||||
public class PresetTabCompleter implements TabCompleter {
 | 
			
		||||
 | 
			
		||||
    @Nullable
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
 | 
			
		||||
                                      @NotNull String[] args) {
 | 
			
		||||
        //Only one argument is expected
 | 
			
		||||
        if (args.length > 1) {
 | 
			
		||||
            return new ArrayList<>();
 | 
			
		||||
        }
 | 
			
		||||
        //If no preset has been fully matched, tab-complete for presets.
 | 
			
		||||
        //If a preset has been fully matched, tab-complete for applicable filters
 | 
			
		||||
 | 
			
		||||
        String input = args[0].toUpperCase().replace('-', '_');
 | 
			
		||||
 | 
			
		||||
        List<String> completions = new ArrayList<>();
 | 
			
		||||
        String filterString = "";
 | 
			
		||||
 | 
			
		||||
        if (input.contains(":")) {
 | 
			
		||||
            String[] parts = input.split(":");
 | 
			
		||||
            input = parts[0];
 | 
			
		||||
            filterString = parts.length > 1 ? parts[1] : "";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Add tab-completions for all supported filters
 | 
			
		||||
        try {
 | 
			
		||||
            List<SmithPresetFilter> filters = SmithPreset.valueOf(input).getSupportedFilters();
 | 
			
		||||
            for (SmithPresetFilter filter : filters) {
 | 
			
		||||
                if (filterString.isEmpty() || filter.name().contains(filterString)) {
 | 
			
		||||
                    completions.add(input + ":" + filter.name());
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } catch (IllegalArgumentException ignored) {
 | 
			
		||||
            /* An illegal argument exception here simply means that the user has typed an unrecognized smith preset.
 | 
			
		||||
               This can be safely ignored, as it simply means no filter tab-completions are necessary. */
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Adds all default completions
 | 
			
		||||
        completions.addAll(TabCompletionHelper.filterMatchingContains(SmithPreset.getPresetNames(), input));
 | 
			
		||||
        return completions;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -2,7 +2,6 @@ package net.knarcraft.blacksmith.command;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.blacksmith.BlacksmithPlugin;
 | 
			
		||||
import net.knarcraft.blacksmith.formatting.TranslatableMessage;
 | 
			
		||||
import net.knarcraft.blacksmith.formatting.Translator;
 | 
			
		||||
import org.bukkit.command.Command;
 | 
			
		||||
import org.bukkit.command.CommandSender;
 | 
			
		||||
import org.bukkit.command.TabExecutor;
 | 
			
		||||
@@ -23,7 +22,7 @@ public class ReloadCommand implements TabExecutor {
 | 
			
		||||
    public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
 | 
			
		||||
                             @NotNull String[] args) {
 | 
			
		||||
        BlacksmithPlugin.getInstance().reload();
 | 
			
		||||
        displaySuccessMessage(sender, Translator.getTranslatedMessage(TranslatableMessage.PLUGIN_RELOADED));
 | 
			
		||||
        displaySuccessMessage(sender, TranslatableMessage.PLUGIN_RELOADED);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,43 +5,126 @@ package net.knarcraft.blacksmith.config;
 | 
			
		||||
 */
 | 
			
		||||
public enum NPCSetting {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The setting for whether the NPC should drop an item to the ground when finished
 | 
			
		||||
     *
 | 
			
		||||
     * <p>If set to false, the item will be directly put in the player's inventory instead</p>
 | 
			
		||||
     */
 | 
			
		||||
    DROP_ITEM("dropItem", SettingValueType.BOOLEAN, true, "dropItem"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The setting for whether the cool-down period between reforging sessions should be disabled
 | 
			
		||||
     */
 | 
			
		||||
    DISABLE_COOL_DOWN("disableCoolDown", SettingValueType.BOOLEAN, false, "disableCoolDown"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The setting for whether the delay it takes for an item to be repaired should be disabled
 | 
			
		||||
     */
 | 
			
		||||
    DISABLE_DELAY("disableDelay", SettingValueType.BOOLEAN, false, "disableDelay"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The setting for the chance of a reforging to fail
 | 
			
		||||
     */
 | 
			
		||||
    FAIL_CHANCE("failReforgeChance", SettingValueType.PERCENTAGE, 10, "failReforgeChance"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The setting for the chance of an additional enchantment being added
 | 
			
		||||
     */
 | 
			
		||||
    EXTRA_ENCHANTMENT_CHANCE("extraEnchantmentChance", SettingValueType.PERCENTAGE, 5,
 | 
			
		||||
            "extraEnchantmentChance"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The setting for the maximum amount of enchantments that can be added to an item
 | 
			
		||||
     */
 | 
			
		||||
    MAX_ENCHANTMENTS("maxEnchantments", SettingValueType.POSITIVE_INTEGER, 3, "maxEnchantments"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The maximum amount of seconds a player may need to wait for the reforging to finish
 | 
			
		||||
     */
 | 
			
		||||
    MAX_REFORGE_DELAY("delaysInSeconds.maximum", SettingValueType.POSITIVE_INTEGER, 30, "maxReforgeDelay"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The minimum amount of seconds a player may need to wait for the reforging to finish
 | 
			
		||||
     */
 | 
			
		||||
    MIN_REFORGE_DELAY("delaysInSeconds.minimum", SettingValueType.POSITIVE_INTEGER, 5, "minReforgeDelay"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The setting for number of seconds a player has to wait between each usage of the blacksmith
 | 
			
		||||
     */
 | 
			
		||||
    REFORGE_COOL_DOWN("delaysInSeconds.reforgeCoolDown", SettingValueType.POSITIVE_INTEGER, 60, "reforgeCoolDown"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The setting for which items the blacksmith is able to reforge
 | 
			
		||||
     */
 | 
			
		||||
    REFORGE_ABLE_ITEMS("reforgeAbleItems", SettingValueType.STRING_LIST, new String[]{}, "reforgeAbleItems"),
 | 
			
		||||
 | 
			
		||||
    /*-----------
 | 
			
		||||
     | Messages |
 | 
			
		||||
     -----------*/
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The message displayed when the blacksmith is busy with another player
 | 
			
		||||
     */
 | 
			
		||||
    BUSY_WITH_PLAYER_MESSAGE("messages.busyPlayerMessage", SettingValueType.STRING,
 | 
			
		||||
            "&cI'm busy at the moment. Come back later!", "busyPlayerMessage"),
 | 
			
		||||
    //TODO: Add placeholder for remaining time?
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The message displayed when the blacksmith is already reforging something for the player
 | 
			
		||||
     */
 | 
			
		||||
    BUSY_WITH_REFORGE_MESSAGE("messages.busyReforgeMessage", SettingValueType.STRING,
 | 
			
		||||
            "&cI'm working on it. Be patient!", "busyReforgeMessage"),
 | 
			
		||||
    //TODO: Add placeholder for remaining time?
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The message displayed if the player has to wait for the cool-down to expire
 | 
			
		||||
     */
 | 
			
		||||
    COOL_DOWN_UNEXPIRED_MESSAGE("messages.coolDownUnexpiredMessage", SettingValueType.STRING,
 | 
			
		||||
            "&cYou've already had your chance! Give me a break!", "coolDownUnexpiredMessage"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The message displayed when displaying the cost of reforging the held item to the player
 | 
			
		||||
     */
 | 
			
		||||
    COST_MESSAGE("messages.costMessage", SettingValueType.STRING,
 | 
			
		||||
            "&eIt will cost &a<price> &eto reforge that &a<item>&e! Click again to reforge!", "costMessage"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The message displayed if the blacksmith fails reforging an item
 | 
			
		||||
     */
 | 
			
		||||
    FAIL_MESSAGE("messages.failReforgeMessage", SettingValueType.STRING,
 | 
			
		||||
            "&cWhoops! Didn't mean to do that! Maybe next time?", "failReforgeMessage"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The message displayed if a player is unable to pay the blacksmith
 | 
			
		||||
     */
 | 
			
		||||
    INSUFFICIENT_FUNDS_MESSAGE("messages.insufficientFundsMessage", SettingValueType.STRING,
 | 
			
		||||
            "&cYou don't have enough money to reforge that item!", "insufficientFundsMessage"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The message displayed if the blacksmith encounters an item they cannot reforge
 | 
			
		||||
     */
 | 
			
		||||
    INVALID_ITEM_MESSAGE("messages.invalidItemMessage", SettingValueType.STRING,
 | 
			
		||||
            "&cI'm sorry, but I don't know how to reforge that!", "invalidItemMessage"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The message displayed if a player presents a different item after seeing the price to reforge an item
 | 
			
		||||
     */
 | 
			
		||||
    ITEM_UNEXPECTEDLY_CHANGED_MESSAGE("messages.itemChangedMessage", SettingValueType.STRING,
 | 
			
		||||
            "&cThat's not the item you wanted to reforge before!", "itemChangedMessage"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The message displayed when the blacksmith starts reforging an item
 | 
			
		||||
     */
 | 
			
		||||
    START_REFORGE_MESSAGE("messages.startReforgeMessage", SettingValueType.STRING,
 | 
			
		||||
            "&eOk, let's see what I can do...", "startReforgeMessage"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The message displayed when the blacksmith successfully finishes reforging an item
 | 
			
		||||
     */
 | 
			
		||||
    SUCCESS_MESSAGE("messages.successMessage", SettingValueType.STRING,
 | 
			
		||||
            "There you go! All better!", "successMessage"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The message displayed when trying to reforge an item with full durability
 | 
			
		||||
     */
 | 
			
		||||
    NOT_DAMAGED_MESSAGE("messages.notDamagedMessage", SettingValueType.STRING,
 | 
			
		||||
            "&cThat item is not in need of repair", "notDamagedMessage");
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,39 +1,77 @@
 | 
			
		||||
package net.knarcraft.blacksmith.config;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.blacksmith.BlacksmithPlugin;
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.logging.Level;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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,
 | 
			
		||||
    WEAPON_SMITH(new SmithPresetFilter[]{SmithPresetFilter.BOW, SmithPresetFilter.SWORD, SmithPresetFilter.RANGED}),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A blacksmith capable of re-forging all armor
 | 
			
		||||
     */
 | 
			
		||||
    ARMOR_SMITH,
 | 
			
		||||
    ARMOR_SMITH(new SmithPresetFilter[]{SmithPresetFilter.LEATHER, SmithPresetFilter.IRON, SmithPresetFilter.CHAINMAIL,
 | 
			
		||||
            SmithPresetFilter.GOLD, SmithPresetFilter.DIAMOND, SmithPresetFilter.NETHERITE}),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A blacksmith capable of re-forging all tools (hoe, axe, shovel, pickaxe, flint and steel, shears, fishing rod)
 | 
			
		||||
     */
 | 
			
		||||
    TOOL_SMITH,
 | 
			
		||||
    TOOL_SMITH(new SmithPresetFilter[]{SmithPresetFilter.WOOD, SmithPresetFilter.STONE, SmithPresetFilter.IRON,
 | 
			
		||||
            SmithPresetFilter.GOLD, SmithPresetFilter.DIAMOND, SmithPresetFilter.NETHERITE, SmithPresetFilter.PICKAXE,
 | 
			
		||||
            SmithPresetFilter.AXE, SmithPresetFilter.HOE, SmithPresetFilter.SHOVEL, SmithPresetFilter.MISC});
 | 
			
		||||
 | 
			
		||||
    private final SmithPresetFilter[] filters;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A blacksmith capable of re-forging all ranged weapons (bow, crossbow, trident)
 | 
			
		||||
     * Instantiates a new smith preset
 | 
			
		||||
     *
 | 
			
		||||
     * @param filters <p>The filters applicable to this preset</p>
 | 
			
		||||
     */
 | 
			
		||||
    RANGED_SMITH;
 | 
			
		||||
    SmithPreset(SmithPresetFilter[] filters) {
 | 
			
		||||
        this.filters = filters;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether this preset supports the given filter
 | 
			
		||||
     *
 | 
			
		||||
     * @param filter <p>The filter to check</p>
 | 
			
		||||
     * @return <p>True if the filter is supported</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean supportsFilter(SmithPresetFilter filter) {
 | 
			
		||||
        return List.of(filters).contains(filter);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets all filters supported by this preset
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>The filters supported by this preset</p>
 | 
			
		||||
     */
 | 
			
		||||
    public List<SmithPresetFilter> getSupportedFilters() {
 | 
			
		||||
        return List.of(filters);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the names of all available smith presets
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>All available smith presets</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static List<String> getPresetNames() {
 | 
			
		||||
        List<String> presetNames = new ArrayList<>();
 | 
			
		||||
        for (SmithPreset preset : SmithPreset.values()) {
 | 
			
		||||
            presetNames.add(preset.name());
 | 
			
		||||
        }
 | 
			
		||||
        return presetNames;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Replaces the given string if it's a smith type preset
 | 
			
		||||
@@ -42,13 +80,47 @@ public enum SmithPreset {
 | 
			
		||||
     * @return <p>The string, possibly with the preset replaced</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static String replacePreset(String possiblePreset) {
 | 
			
		||||
        for (SmithPreset smithPreset : SmithPreset.values()) {
 | 
			
		||||
            if (possiblePreset.replace('-', '_').equalsIgnoreCase("preset:" +
 | 
			
		||||
                    smithPreset.name())) {
 | 
			
		||||
                return String.join(",", smithPreset.getMaterialNames());
 | 
			
		||||
            }
 | 
			
		||||
        String upperCasedPreset = possiblePreset.replace('-', '_').toUpperCase();
 | 
			
		||||
        if (!upperCasedPreset.startsWith("PRESET:")) {
 | 
			
		||||
            return possiblePreset;
 | 
			
		||||
        }
 | 
			
		||||
        return possiblePreset;
 | 
			
		||||
 | 
			
		||||
        //Parse the input
 | 
			
		||||
        SmithPresetFilter filter = null;
 | 
			
		||||
        SmithPreset preset;
 | 
			
		||||
        try {
 | 
			
		||||
            String[] parts = upperCasedPreset.split(":");
 | 
			
		||||
 | 
			
		||||
            if (parts.length > 2) {
 | 
			
		||||
                filter = SmithPresetFilter.valueOf(parts[2]);
 | 
			
		||||
            }
 | 
			
		||||
            preset = SmithPreset.valueOf(parts[1]);
 | 
			
		||||
        } catch (IllegalArgumentException exception) {
 | 
			
		||||
            /* This case means that either the preset or the filter given is invalid, and thus the preset string should
 | 
			
		||||
               be ignored to prevent any problems. */
 | 
			
		||||
            BlacksmithPlugin.getInstance().getLogger().log(Level.WARNING, String.format("The smith preset %s is " +
 | 
			
		||||
                    "invalid, and will be ignored. Please fix it!", possiblePreset));
 | 
			
		||||
            return "";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //Return the list of materials included in the preset
 | 
			
		||||
        if (filter != null) {
 | 
			
		||||
            return String.join(",", preset.getMaterialNames(filter));
 | 
			
		||||
        } else {
 | 
			
		||||
            return String.join(",", preset.getMaterialNames());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the materials included in this preset, filtered using the given filter
 | 
			
		||||
     *
 | 
			
		||||
     * @param filter <p>The filter to use for filtering</p>
 | 
			
		||||
     * @return <p>The materials included in this preset, filtered using the given filter</p>
 | 
			
		||||
     */
 | 
			
		||||
    public List<Material> getFilteredMaterials(SmithPresetFilter filter) {
 | 
			
		||||
        List<Material> materials = new ArrayList<>(this.getMaterials());
 | 
			
		||||
        materials.removeIf((item) -> !filter.isIncluded(item));
 | 
			
		||||
        return materials;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -58,11 +130,9 @@ public enum SmithPreset {
 | 
			
		||||
     */
 | 
			
		||||
    public List<Material> getMaterials() {
 | 
			
		||||
        return switch (this) {
 | 
			
		||||
            case SWORD_SMITH -> getSwords();
 | 
			
		||||
            case WEAPON_SMITH -> getWeapons();
 | 
			
		||||
            case ARMOR_SMITH -> getArmor();
 | 
			
		||||
            case TOOL_SMITH -> getTools();
 | 
			
		||||
            case RANGED_SMITH -> getRanged();
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -149,8 +219,28 @@ public enum SmithPreset {
 | 
			
		||||
     * @return <p>All material names for this smith</p>
 | 
			
		||||
     */
 | 
			
		||||
    private List<String> getMaterialNames() {
 | 
			
		||||
        return getNames(this.getMaterials());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets material names of all materials reforge-able by this smith
 | 
			
		||||
     *
 | 
			
		||||
     * @param filter <p>The filter used for filtering materials</p>
 | 
			
		||||
     * @return <p>All material names for this smith</p>
 | 
			
		||||
     */
 | 
			
		||||
    private List<String> getMaterialNames(SmithPresetFilter filter) {
 | 
			
		||||
        return getNames(this.getFilteredMaterials(filter));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a list of material names from the given materials
 | 
			
		||||
     *
 | 
			
		||||
     * @param materials <p>The materials to get the names of</p>
 | 
			
		||||
     * @return <p>The names of the materials</p>
 | 
			
		||||
     */
 | 
			
		||||
    private List<String> getNames(List<Material> materials) {
 | 
			
		||||
        List<String> items = new ArrayList<>();
 | 
			
		||||
        for (Material material : this.getMaterials()) {
 | 
			
		||||
        for (Material material : materials) {
 | 
			
		||||
            items.add(material.name().toLowerCase().replace("_", "-"));
 | 
			
		||||
        }
 | 
			
		||||
        return items;
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,147 @@
 | 
			
		||||
package net.knarcraft.blacksmith.config;
 | 
			
		||||
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A representation of all available filters for smith presets
 | 
			
		||||
 */
 | 
			
		||||
public enum SmithPresetFilter {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filters to only include items made of wood
 | 
			
		||||
     */
 | 
			
		||||
    WOOD(true, "WOODEN_"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filters to only include items made of iron
 | 
			
		||||
     */
 | 
			
		||||
    IRON(true, "IRON_"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filters to only include items made of leather
 | 
			
		||||
     */
 | 
			
		||||
    LEATHER(true, "LEATHER_"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filters to only include items made of chainmail
 | 
			
		||||
     */
 | 
			
		||||
    CHAINMAIL(true, "CHAINMAIL_"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filters to only include items made of gold
 | 
			
		||||
     */
 | 
			
		||||
    GOLD(true, "GOLDEN_"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filters to only include items made of diamond
 | 
			
		||||
     */
 | 
			
		||||
    DIAMOND(true, "DIAMOND"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filters to only include items made of netherite
 | 
			
		||||
     */
 | 
			
		||||
    NETHERITE(true, "NETHERITE_"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filters to only include items made of stone
 | 
			
		||||
     */
 | 
			
		||||
    STONE(true, "STONE_"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filters to only include bows
 | 
			
		||||
     */
 | 
			
		||||
    BOW(false, "BOW"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filters to only include pickaxes
 | 
			
		||||
     */
 | 
			
		||||
    PICKAXE(false, "_PICKAXE"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filters to only include hoes
 | 
			
		||||
     */
 | 
			
		||||
    HOE(false, "_HOE"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filters to only include shovels
 | 
			
		||||
     */
 | 
			
		||||
    SHOVEL(false, "_SHOVEL"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filters to only include axes
 | 
			
		||||
     */
 | 
			
		||||
    AXE(false, "_AXE"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filters to only include swords
 | 
			
		||||
     */
 | 
			
		||||
    SWORD(false, "_SWORD"),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filters to only include ranged weapons (bows and trident)
 | 
			
		||||
     */
 | 
			
		||||
    RANGED(false, null),
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Filters to only include miscellaneous tools (fishing rod, flint and steel, shears)
 | 
			
		||||
     */
 | 
			
		||||
    MISC(false, null);
 | 
			
		||||
 | 
			
		||||
    private final boolean searchStart;
 | 
			
		||||
    private final String identifier;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instantiates a new smith preset filter
 | 
			
		||||
     *
 | 
			
		||||
     * @param searchStart <p>Whether to search the start of a string for the identifier</p>
 | 
			
		||||
     * @param identifier  <p>The string any material matching this filter contains</p>
 | 
			
		||||
     */
 | 
			
		||||
    SmithPresetFilter(boolean searchStart, String identifier) {
 | 
			
		||||
        this.searchStart = searchStart;
 | 
			
		||||
        this.identifier = identifier;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets whether the given material is included in this filter
 | 
			
		||||
     *
 | 
			
		||||
     * @param material <p>The material to check</p>
 | 
			
		||||
     * @return <p>True if the material is included in this filter</p>
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isIncluded(Material material) {
 | 
			
		||||
        if (isSpecialCase()) {
 | 
			
		||||
            return isIncludedSpecialCase(material);
 | 
			
		||||
        }
 | 
			
		||||
        if (this.searchStart) {
 | 
			
		||||
            return material.name().startsWith(this.identifier);
 | 
			
		||||
        } else {
 | 
			
		||||
            return material.name().endsWith(this.identifier);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks if this filter is a special case which doesn't work with normal rules
 | 
			
		||||
     *
 | 
			
		||||
     * @return <p>True if this filter is a special case</p>
 | 
			
		||||
     */
 | 
			
		||||
    private boolean isSpecialCase() {
 | 
			
		||||
        return this == RANGED || this == MISC;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Uses a special-case check to see if the given material is part of this filter
 | 
			
		||||
     *
 | 
			
		||||
     * @param material <p>The material to check</p>
 | 
			
		||||
     * @return <p>True if the material is part of this filter</p>
 | 
			
		||||
     */
 | 
			
		||||
    private boolean isIncludedSpecialCase(Material material) {
 | 
			
		||||
        if (this == RANGED) {
 | 
			
		||||
            return material.name().endsWith(BOW.identifier) || material == Material.TRIDENT;
 | 
			
		||||
        } else if (this == MISC) {
 | 
			
		||||
            return material == Material.SHEARS || material == Material.FLINT_AND_STEEL ||
 | 
			
		||||
                    material == Material.FISHING_ROD;
 | 
			
		||||
        } else {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -32,6 +32,16 @@ public final class StringFormatter {
 | 
			
		||||
                translateColors(message));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Displays a message signifying a successful action
 | 
			
		||||
     *
 | 
			
		||||
     * @param sender  <p>The command sender to display the message to</p>
 | 
			
		||||
     * @param message <p>The translatable message to display</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void displaySuccessMessage(CommandSender sender, TranslatableMessage message) {
 | 
			
		||||
        sender.sendMessage(ChatColor.GREEN + getFormattedMessage(Translator.getTranslatedMessage(message)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Displays a message signifying a successful action
 | 
			
		||||
     *
 | 
			
		||||
@@ -46,10 +56,10 @@ public final class StringFormatter {
 | 
			
		||||
     * Displays a message signifying an unsuccessful action
 | 
			
		||||
     *
 | 
			
		||||
     * @param sender  <p>The command sender to display the message to</p>
 | 
			
		||||
     * @param message <p>The raw message to display</p>
 | 
			
		||||
     * @param message <p>The translatable message to display</p>
 | 
			
		||||
     */
 | 
			
		||||
    public static void displayErrorMessage(CommandSender sender, String message) {
 | 
			
		||||
        sender.sendMessage(ChatColor.DARK_RED + getFormattedMessage(message));
 | 
			
		||||
    public static void displayErrorMessage(CommandSender sender, TranslatableMessage message) {
 | 
			
		||||
        sender.sendMessage(ChatColor.DARK_RED + getFormattedMessage(Translator.getTranslatedMessage(message)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,10 @@ public enum TranslatableMessage {
 | 
			
		||||
    INPUT_POSITIVE_DOUBLE_REQUIRED,
 | 
			
		||||
    INPUT_POSITIVE_INTEGER_REQUIRED,
 | 
			
		||||
    PERMISSION_DENIED,
 | 
			
		||||
    PLUGIN_RELOADED;
 | 
			
		||||
    PLUGIN_RELOADED,
 | 
			
		||||
    INVALID_FILTER_FOR_PRESET,
 | 
			
		||||
    INVALID_PRESET_OR_FILTER,
 | 
			
		||||
    PRESET_MATERIALS;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the message to display when displaying the raw value of messages
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@ package net.knarcraft.blacksmith.listener;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.blacksmith.formatting.StringFormatter;
 | 
			
		||||
import net.knarcraft.blacksmith.formatting.TranslatableMessage;
 | 
			
		||||
import net.knarcraft.blacksmith.formatting.Translator;
 | 
			
		||||
import net.knarcraft.blacksmith.trait.BlacksmithTrait;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.event.EventHandler;
 | 
			
		||||
@@ -26,8 +25,7 @@ public class NPCClickListener implements Listener {
 | 
			
		||||
 | 
			
		||||
        //Permission check
 | 
			
		||||
        if (!player.hasPermission("blacksmith.use")) {
 | 
			
		||||
            StringFormatter.displayErrorMessage(player,
 | 
			
		||||
                    Translator.getTranslatedMessage(TranslatableMessage.PERMISSION_DENIED));
 | 
			
		||||
            StringFormatter.displayErrorMessage(player, TranslatableMessage.PERMISSION_DENIED);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@ package net.knarcraft.blacksmith.util;
 | 
			
		||||
 | 
			
		||||
import net.knarcraft.blacksmith.config.SettingValueType;
 | 
			
		||||
import net.knarcraft.blacksmith.formatting.TranslatableMessage;
 | 
			
		||||
import net.knarcraft.blacksmith.formatting.Translator;
 | 
			
		||||
import org.bukkit.command.CommandSender;
 | 
			
		||||
 | 
			
		||||
import static net.knarcraft.blacksmith.formatting.StringFormatter.displayErrorMessage;
 | 
			
		||||
@@ -51,7 +50,7 @@ public final class TypeValidationHelper {
 | 
			
		||||
    private static boolean isStringList(Object value, CommandSender sender) {
 | 
			
		||||
        boolean isStringList = value instanceof String[] || value instanceof String;
 | 
			
		||||
        if (!isStringList && sender != null) {
 | 
			
		||||
            displayErrorMessage(sender, Translator.getTranslatedMessage(TranslatableMessage.INPUT_STRING_LIST_REQUIRED));
 | 
			
		||||
            displayErrorMessage(sender, TranslatableMessage.INPUT_STRING_LIST_REQUIRED);
 | 
			
		||||
        }
 | 
			
		||||
        return isStringList;
 | 
			
		||||
    }
 | 
			
		||||
@@ -69,7 +68,7 @@ public final class TypeValidationHelper {
 | 
			
		||||
            return intValue > 0 && intValue <= 100;
 | 
			
		||||
        } catch (NumberFormatException | NullPointerException exception) {
 | 
			
		||||
            if (sender != null) {
 | 
			
		||||
                displayErrorMessage(sender, Translator.getTranslatedMessage(TranslatableMessage.INPUT_PERCENTAGE_REQUIRED));
 | 
			
		||||
                displayErrorMessage(sender, TranslatableMessage.INPUT_PERCENTAGE_REQUIRED);
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
@@ -85,7 +84,7 @@ public final class TypeValidationHelper {
 | 
			
		||||
    private static boolean isNonEmptyString(Object value, CommandSender sender) {
 | 
			
		||||
        boolean isString = value instanceof String string && !string.strip().isEmpty();
 | 
			
		||||
        if (!isString && sender != null) {
 | 
			
		||||
            displayErrorMessage(sender, Translator.getTranslatedMessage(TranslatableMessage.INPUT_STRING_REQUIRED));
 | 
			
		||||
            displayErrorMessage(sender, TranslatableMessage.INPUT_STRING_REQUIRED);
 | 
			
		||||
        }
 | 
			
		||||
        return isString;
 | 
			
		||||
    }
 | 
			
		||||
@@ -102,8 +101,7 @@ public final class TypeValidationHelper {
 | 
			
		||||
            return ConfigHelper.asDouble(value) > 0.0;
 | 
			
		||||
        } catch (NumberFormatException | NullPointerException exception) {
 | 
			
		||||
            if (sender != null) {
 | 
			
		||||
                displayErrorMessage(sender,
 | 
			
		||||
                        Translator.getTranslatedMessage(TranslatableMessage.INPUT_POSITIVE_DOUBLE_REQUIRED));
 | 
			
		||||
                displayErrorMessage(sender, TranslatableMessage.INPUT_POSITIVE_DOUBLE_REQUIRED);
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
@@ -121,8 +119,7 @@ public final class TypeValidationHelper {
 | 
			
		||||
            return ConfigHelper.asInt(value) > 0;
 | 
			
		||||
        } catch (NumberFormatException | NullPointerException exception) {
 | 
			
		||||
            if (sender != null) {
 | 
			
		||||
                displayErrorMessage(sender,
 | 
			
		||||
                        Translator.getTranslatedMessage(TranslatableMessage.INPUT_POSITIVE_INTEGER_REQUIRED));
 | 
			
		||||
                displayErrorMessage(sender, TranslatableMessage.INPUT_POSITIVE_INTEGER_REQUIRED);
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,10 @@ commands:
 | 
			
		||||
    permission: blacksmith.admin
 | 
			
		||||
    usage: /<command> <option/reload> [new value]
 | 
			
		||||
    description: Used for configuring default blacksmith settings, or global settings
 | 
			
		||||
  preset:
 | 
			
		||||
    permission: blacksmith.preset
 | 
			
		||||
    usage: /<command> <preset>[:filter]
 | 
			
		||||
    description: Used to display which materials are part of a given preset. If a filter, such as diamond is used, the result of applying the filter is shown.
 | 
			
		||||
permissions:
 | 
			
		||||
  blacksmith.admin:
 | 
			
		||||
    description: Allows overall blacksmith configuration
 | 
			
		||||
@@ -23,9 +27,13 @@ permissions:
 | 
			
		||||
    children:
 | 
			
		||||
      blacksmith.edit: true
 | 
			
		||||
      blacksmith.use: true
 | 
			
		||||
      blacksmith.preset: true
 | 
			
		||||
  blacksmith.edit:
 | 
			
		||||
    description: Allows changing settings for the selected blacksmith NPC
 | 
			
		||||
    default: op
 | 
			
		||||
  blacksmith.use:
 | 
			
		||||
    description: Allows the player to repair items using blacksmiths
 | 
			
		||||
    default: true
 | 
			
		||||
    default: true
 | 
			
		||||
  blacksmith.preset:
 | 
			
		||||
    description: Allows the player to use the /preset command
 | 
			
		||||
    default: op
 | 
			
		||||
@@ -14,4 +14,7 @@ en:
 | 
			
		||||
  INPUT_POSITIVE_DOUBLE_REQUIRED: "You specified a value which isn't a positive double!"
 | 
			
		||||
  INPUT_POSITIVE_INTEGER_REQUIRED: "You specified a value which isn't a positive integer!"
 | 
			
		||||
  PERMISSION_DENIED: "You lack the necessary permission"
 | 
			
		||||
  PLUGIN_RELOADED: "Blacksmith config reloaded!"
 | 
			
		||||
  PLUGIN_RELOADED: "Blacksmith config reloaded!"
 | 
			
		||||
  INVALID_FILTER_FOR_PRESET: "The specified filter is not valid for that preset"
 | 
			
		||||
  INVALID_PRESET_OR_FILTER: "You specified an invalid preset or an invalid filter"
 | 
			
		||||
  PRESET_MATERIALS: "Materials in preset: {materials}"
 | 
			
		||||
		Reference in New Issue
	
	Block a user