Splits the blacksmith command into two commands, and much more

This commit is contained in:
Kristian Knarvik 2022-08-19 19:08:54 +02:00
parent 755db8c497
commit e1191dad7d
21 changed files with 1077 additions and 235 deletions

View File

@ -1,8 +1,10 @@
package net.knarcraft.blacksmith; package net.knarcraft.blacksmith;
import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.CitizensAPI;
import net.knarcraft.blacksmith.command.BlackSmithCommand; import net.knarcraft.blacksmith.command.BlackSmithConfigCommand;
import net.knarcraft.blacksmith.command.BlackSmithTabCompleter; 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.config.GlobalSettings;
import net.knarcraft.blacksmith.listener.NPCClickListener; import net.knarcraft.blacksmith.listener.NPCClickListener;
import net.knarcraft.blacksmith.listener.PlayerListener; import net.knarcraft.blacksmith.listener.PlayerListener;
@ -57,6 +59,7 @@ public class BlacksmithPlugin extends JavaPlugin {
public void onEnable() { public void onEnable() {
instance = this; instance = this;
//Copy default config to disk
FileConfiguration fileConfiguration = this.getConfig(); FileConfiguration fileConfiguration = this.getConfig();
this.saveDefaultConfig(); this.saveDefaultConfig();
fileConfiguration.options().copyDefaults(true); fileConfiguration.options().copyDefaults(true);
@ -65,29 +68,65 @@ public class BlacksmithPlugin extends JavaPlugin {
config = new GlobalSettings(this); config = new GlobalSettings(this);
config.load(); 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 <p>True if Vault setup/integration succeeded</p>
*/
private boolean setUpVault() {
getLogger().log(Level.INFO, "Setting Up Vault now...."); getLogger().log(Level.INFO, "Setting Up Vault now....");
boolean canLoad = EconomyManager.setUp(getServer().getServicesManager(), getLogger()); boolean canLoad = EconomyManager.setUp(getServer().getServicesManager(), getLogger());
if (!canLoad) { if (!canLoad) {
getLogger().log(Level.SEVERE, "Vault Integration Failed...."); getLogger().log(Level.SEVERE, "Vault Integration Failed....");
getServer().getPluginManager().disablePlugin(this); getServer().getPluginManager().disablePlugin(this);
return; return false;
} }
//Register the blacksmith trait with Citizens return true;
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());
} }
/**
* Registers all listeners used by this plugin
*/
private void registerListeners() {
PluginManager pluginManager = getServer().getPluginManager(); PluginManager pluginManager = getServer().getPluginManager();
pluginManager.registerEvents(new PlayerListener(), this); pluginManager.registerEvents(new PlayerListener(), this);
pluginManager.registerEvents(new NPCClickListener(), 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());
}
} }
} }

View File

@ -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;
}
}

View File

@ -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 <p>The settings to modify</p>
* @param commandName <p>The sub-command the player specified</p>
* @param args <p>All arguments given</p>
* @return <p>True if already handled as a special case</p>
*/
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;
}
}

View File

@ -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<String> 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<String> 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 <p>The name of the used command</p>
* @return <p>Some valid options for the command's argument</p>
*/
private List<String> 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;
}
}

View File

@ -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 <p>The blacksmith trait belonging to the selected NPC</p>
* @param npcSetting <p>The NPC setting to change</p>
* @param newValue <p>The value to change the setting to</p>
* @param sender <p>The command sender to notify about results</p>
* @return <p>True if everything went successfully</p>
*/
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;
}
}
}
}

View File

@ -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<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
@NotNull String[] args) {
List<String> 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 <p>The name of the used command</p>
* @return <p>Some valid options for the command's argument</p>
*/
private List<String> tabCompleteCommandValues(String commandName) {
for (NPCSetting npcSetting : NPCSetting.values()) {
if (npcSetting.getCommandName().equalsIgnoreCase(commandName)) {
return TabCompleteValuesHelper.getTabCompletions(npcSetting.getValueType());
}
}
return null;
}
}

View File

@ -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<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
@NotNull String[] args) {
List<String> 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<String> 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<>();
}
}
}
}

View File

@ -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;
}
}

View File

@ -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<String> 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;
}
}

View File

@ -9,7 +9,7 @@ public enum GlobalSetting {
* *
* <p>This allows specifying a price for each item, by setting base-price.item_name.</p> * <p>This allows specifying a price for each item, by setting base-price.item_name.</p>
*/ */
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 * 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 * 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</p> * durability point value for each item, by setting price-per-durability-point.item_name</p>
*/ */
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 * The price increase for each level of each present enchantment
* *
* <p>This can be specified for each possible enchantment by setting enchantment-cost.enchantment_name</p> * <p>This can be specified for each possible enchantment by setting enchantment-cost.enchantment_name</p>
*/ */
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 * 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 path;
private final String parent; private final String parent;
private final String commandName;
private final Object value; private final Object value;
private final SettingValueType valueType;
/** /**
* Instantiates a new setting * Instantiates a new setting
* *
* @param path <p>The full config path for this setting</p> * @param path <p>The full config path for this setting</p>
* @param valueType <p>The type of value used by this setting</p>
* @param value <p>The default value of this setting</p> * @param value <p>The default value of this setting</p>
* @param commandName <p>The name of the command used to change this setting</p>
*/ */
GlobalSetting(String path, Object value) { GlobalSetting(String path, SettingValueType valueType, Object value, String commandName) {
this.path = path; this.path = path;
this.value = value; this.value = value;
this.commandName = commandName;
this.valueType = valueType;
String[] pathParts = path.split("\\."); String[] pathParts = path.split("\\.");
this.parent = String.join(".", Arrays.copyOfRange(pathParts, 0, pathParts.length - 1)); this.parent = String.join(".", Arrays.copyOfRange(pathParts, 0, pathParts.length - 1));
} }
@ -72,8 +78,26 @@ public enum GlobalSetting {
* *
* @return <p>The value of this setting</p> * @return <p>The value of this setting</p>
*/ */
Object getDefaultValue() { public Object getDefaultValue() {
return value; return value;
} }
/**
* The name of the command used to change this setting
*
* @return <p>The name of this setting's command</p>
*/
public String getCommandName() {
return commandName;
}
/**
* Gets the value type for this setting
*
* @return <p>The value type for this setting</p>
*/
public SettingValueType getValueType() {
return this.valueType;
}
} }

View File

@ -3,6 +3,7 @@ package net.knarcraft.blacksmith.config;
import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.api.util.YamlStorage; import net.citizensnpcs.api.util.YamlStorage;
import net.knarcraft.blacksmith.BlacksmithPlugin; import net.knarcraft.blacksmith.BlacksmithPlugin;
import net.knarcraft.blacksmith.util.ConfigHelper;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
@ -33,8 +34,8 @@ public class GlobalSettings {
*/ */
public GlobalSettings(BlacksmithPlugin plugin) { public GlobalSettings(BlacksmithPlugin plugin) {
defaultConfig = new YamlStorage(new File(plugin.getDataFolder() + File.separator + "config.yml"), 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" + "Blacksmith Configuration\nWarning: The values under defaults are the values set for a " +
"upon creation. To change any values for existing NPCs, edit the citizens NPC file."); "blacksmith upon creation. To change any values for existing NPCs, edit the citizens NPC file.");
} }
/** /**
@ -62,6 +63,82 @@ public class GlobalSettings {
defaultConfig.save(); defaultConfig.save();
} }
/**
* Changes the value of the given setting
*
* @param globalSetting <p>The global setting to change</p>
* @param newValue <p>The new value of the setting</p>
*/
public void changeValue(GlobalSetting globalSetting, Object newValue) {
globalSettings.put(globalSetting, newValue);
save();
}
/**
* Changes the value of the given setting
*
* @param npcSetting <p>The default NPC setting to change</p>
* @param newValue <p>The new value for the setting</p>
*/
public void changeValue(NPCSetting npcSetting, Object newValue) {
defaultNPCSettings.put(npcSetting, newValue);
save();
}
/**
* Sets the enchantment cost for the given enchantment
*
* @param enchantment <p>The enchantment to set the enchantment cost for</p>
* @param newEnchantmentCost <p>The new enchantment cost</p>
*/
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 <p>The material to set the price per durability point price for</p>
* @param newPrice <p>The new price per durability point price</p>
*/
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 <p>The material to set the base price for</p>
* @param newBasePrice <p>The new base price</p>
*/
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 * Gets the current value of the default NPC settings
* *
@ -135,12 +212,7 @@ public class GlobalSettings {
* @return <p>The value of the given setting as a boolean</p> * @return <p>The value of the given setting as a boolean</p>
*/ */
public boolean asBoolean(GlobalSetting setting) { public boolean asBoolean(GlobalSetting setting) {
Object value = getValue(setting); return ConfigHelper.asBoolean(getValue(setting));
if (value instanceof String) {
return Boolean.parseBoolean((String) value);
} else {
return (Boolean) value;
}
} }
/** /**
@ -152,14 +224,7 @@ public class GlobalSettings {
* @return <p>The value of the given setting as a double</p> * @return <p>The value of the given setting as a double</p>
*/ */
public double asDouble(GlobalSetting setting) { public double asDouble(GlobalSetting setting) {
Object value = getValue(setting); return ConfigHelper.asDouble(getValue(setting));
if (value instanceof String) {
return Double.parseDouble((String) value);
} else if (value instanceof Integer) {
return (Integer) value;
} else {
return (Double) value;
}
} }
/** /**
@ -256,6 +321,16 @@ public class GlobalSettings {
return relevant; return relevant;
} }
/**
* Converts a normalized material name to the format used in the config file
*
* @param normalizedName <p>The normalized name to un-normalize</p>
* @return <p>The un-normalized name</p>
*/
private String unNormalizeName(String normalizedName) {
return normalizedName.toLowerCase().replace("_", "-");
}
/** /**
* Loads all default NPC settings * 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();
}
} }

View File

@ -7,58 +7,62 @@ import java.util.Arrays;
*/ */
public enum NPCSetting { public enum NPCSetting {
DROP_ITEM("defaults.drop-item", true, "dropItem"), DROP_ITEM("defaults.drop-item", SettingValueType.BOOLEAN, true, "dropItem"),
DISABLE_COOL_DOWN("defaults.disable-cool-down", false, "disableCoolDown"), DISABLE_COOL_DOWN("defaults.disable-cool-down", SettingValueType.BOOLEAN, false, "disableCoolDown"),
DISABLE_DELAY("defaults.disable-delay", false, "disableDelay"), DISABLE_DELAY("defaults.disable-delay", SettingValueType.BOOLEAN, false, "disableDelay"),
FAIL_CHANCE("defaults.percent-chance-to-fail-reforge", 10, "failReforgeChance"), FAIL_CHANCE("defaults.percent-chance-to-fail-reforge", SettingValueType.PERCENTAGE, 10, "failReforgeChance"),
EXTRA_ENCHANTMENT_CHANCE("defaults.percent-chance-for-extra-enchantment", 5, EXTRA_ENCHANTMENT_CHANCE("defaults.percent-chance-for-extra-enchantment", SettingValueType.PERCENTAGE, 5,
"extraEnchantmentChance"), "extraEnchantmentChance"),
MAX_ENCHANTMENTS("defaults.maximum-enchantments", 3, "maxEnchantments"), MAX_ENCHANTMENTS("defaults.maximum-enchantments", SettingValueType.POSITIVE_INTEGER, 3, "maxEnchantments"),
MAX_REFORGE_DELAY("defaults.delays-in-seconds.maximum", 30, "maxReforgeDelay"), MAX_REFORGE_DELAY("defaults.delays-in-seconds.maximum", SettingValueType.POSITIVE_INTEGER, 30, "maxReforgeDelay"),
MIN_REFORGE_DELAY("defaults.delays-in-seconds.minimum", 5, "minReforgeDelay"), MIN_REFORGE_DELAY("defaults.delays-in-seconds.minimum", SettingValueType.POSITIVE_INTEGER, 5, "minReforgeDelay"),
REFORGE_COOL_DOWN("defaults.delays-in-seconds.reforge-cool-down", 60, "reforgeCoolDown"), REFORGE_COOL_DOWN("defaults.delays-in-seconds.reforge-cool-down", SettingValueType.POSITIVE_INTEGER, 60, "reforgeCoolDown"),
REFORGE_ABLE_ITEMS("defaults.reforge-able-items", new String[]{}, "reforgeAbleItems"), REFORGE_ABLE_ITEMS("defaults.reforge-able-items", SettingValueType.STRING_LIST, new String[]{}, "reforgeAbleItems"),
/*----------- /*-----------
| Messages | | 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"), "§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"), "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"), "§cYou've already had your chance! Give me a break!", "coolDownUnexpiredMessage"),
COST_MESSAGE( COST_MESSAGE(
"defaults.messages.cost", "defaults.messages.cost", SettingValueType.STRING,
"§eIt will cost §a<price> §eto reforge that §a<item>§e! Click again to reforge!", "costMessage"), "§eIt will cost §a<price> §eto reforge that §a<item>§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"), "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"), "§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!", INVALID_ITEM_MESSAGE("defaults.messages.invalid-item", SettingValueType.STRING,
"invalidItemMessage"), "§cI'm sorry, but I don't know how to reforge that!", "invalidItemMessage"),
ITEM_UNEXPECTEDLY_CHANGED_MESSAGE("defaults.messages.item-changed-during-reforge", ITEM_UNEXPECTEDLY_CHANGED_MESSAGE("defaults.messages.item-changed-during-reforge", SettingValueType.STRING,
"§cThat's not the item you wanted to reforge before!", "itemChangedMessage"), "§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...", START_REFORGE_MESSAGE("defaults.messages.start-reforge", SettingValueType.STRING,
"startReforgeMessage"), "§eOk, let's see what I can do...", "startReforgeMessage"),
SUCCESS_MESSAGE("defaults.messages.successful-reforge", "There you go! All better!", "successMessage"); SUCCESS_MESSAGE("defaults.messages.successful-reforge", SettingValueType.STRING,
"There you go! All better!", "successMessage");
private final String path; private final String path;
private final String childPath; private final String childPath;
private final Object value; private final Object value;
private final String commandName; private final String commandName;
private final String nodeName; private final String nodeName;
private final SettingValueType valueType;
/** /**
* Instantiates a new setting * Instantiates a new setting
* *
* @param path <p>The full config path for this setting</p> * @param path <p>The full config path for this setting</p>
* @param valueType <p>The type of value used by this setting</p>
* @param value <p>The default value of this setting</p> * @param value <p>The default value of this setting</p>
* @param commandName <p>The name of the command used to change this setting</p> * @param commandName <p>The name of the command used to change this setting</p>
*/ */
NPCSetting(String path, Object value, String commandName) { NPCSetting(String path, SettingValueType valueType, Object value, String commandName) {
this.path = path; this.path = path;
this.value = value; this.value = value;
this.valueType = valueType;
String[] pathParts = path.split("\\."); String[] pathParts = path.split("\\.");
this.childPath = String.join(".", Arrays.copyOfRange(pathParts, 1, pathParts.length)); this.childPath = String.join(".", Arrays.copyOfRange(pathParts, 1, pathParts.length));
this.commandName = commandName; this.commandName = commandName;
@ -114,4 +118,13 @@ public enum NPCSetting {
return nodeName; return nodeName;
} }
/**
* Gets the value type for this setting
*
* @return <p>The value type for this setting</p>
*/
public SettingValueType getValueType() {
return this.valueType;
}
} }

View File

@ -3,6 +3,7 @@ package net.knarcraft.blacksmith.config;
import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.api.util.DataKey;
import net.knarcraft.blacksmith.BlacksmithPlugin; import net.knarcraft.blacksmith.BlacksmithPlugin;
import net.knarcraft.blacksmith.trait.BlacksmithTrait; import net.knarcraft.blacksmith.trait.BlacksmithTrait;
import net.knarcraft.blacksmith.util.ConfigHelper;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@ -61,6 +62,9 @@ public class NPCSettings {
* @param newValue <p>The new value of the setting</p> * @param newValue <p>The new value of the setting</p>
*/ */
public void changeSetting(NPCSetting setting, Object newValue) { public void changeSetting(NPCSetting setting, Object newValue) {
if (setting == NPCSetting.REFORGE_ABLE_ITEMS) {
newValue = replaceReforgeAblePlaceholders(newValue);
}
currentValues.put(setting, newValue); currentValues.put(setting, newValue);
} }
@ -265,12 +269,7 @@ public class NPCSettings {
* @return <p>The value of the given setting as a boolean</p> * @return <p>The value of the given setting as a boolean</p>
*/ */
private boolean asBoolean(NPCSetting setting) { private boolean asBoolean(NPCSetting setting) {
Object value = getValue(setting); return ConfigHelper.asBoolean(getValue(setting));
if (value instanceof String) {
return Boolean.parseBoolean((String) value);
} else {
return (Boolean) value;
}
} }
/** /**
@ -282,12 +281,7 @@ public class NPCSettings {
* @return <p>The value of the given setting as an integer</p> * @return <p>The value of the given setting as an integer</p>
*/ */
private int asInt(NPCSetting setting) { private int asInt(NPCSetting setting) {
Object value = getValue(setting); return ConfigHelper.asInt(getValue(setting));
if (value instanceof String) {
return Integer.parseInt((String) value);
} else {
return (Integer) value;
}
} }
/** /**
@ -322,6 +316,31 @@ public class NPCSettings {
return value; return value;
} }
/**
* Replaces placeholders in the given reforge-able value
*
* @param value <p>The value specified by a user</p>
* @return <p>The value with placeholders replaced</p>
*/
private Object replaceReforgeAblePlaceholders(Object value) {
if (value instanceof String string) {
String[] list = string.split(",");
List<String> 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<String> 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 * Updates the reforge-able items according to the current value of the setting
*/ */

View File

@ -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
}

View File

@ -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 <p>The string that might be a placeholder</p>
* @return <p>The string, possibly with the placeholder replaced</p>
*/
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 <p>All materials in this preset</p>
*/
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();
};
}
/**
* Gets all ranged weapon materials
*
* @return <p>All ranged weapon materials</p>
*/
private List<Material> getRanged() {
List<Material> ranged = new ArrayList<>();
ranged.add(Material.TRIDENT);
ranged.add(Material.BOW);
ranged.add(Material.CROSSBOW);
return ranged;
}
/**
* Gets all tool materials
*
* @return <p>All tool materials</p>
*/
private List<Material> getTools() {
List<Material> 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 <p>All weapon materials</p>
*/
private List<Material> getWeapons() {
List<Material> weapons = new ArrayList<>(getSwords());
weapons.addAll(getRanged());
weapons.add(Material.SHIELD);
return weapons;
}
/**
* Gets all sword materials
*
* @return <p>All sword materials</p>
*/
private List<Material> getSwords() {
return getMaterialsEndingWith("_SWORD");
}
private List<Material> getArmor() {
List<Material> 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 <p>The string to look for</p>
* @return <p>The resulting materials</p>
*/
private List<Material> getMaterialsEndingWith(String end) {
List<Material> 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 <p>All material names for this smith</p>
*/
private List<String> getMaterialNames() {
List<String> items = new ArrayList<>();
for (Material material : this.getMaterials()) {
items.add(material.name().toLowerCase().replace("_", "-"));
}
return items;
}
}

View File

@ -2,6 +2,7 @@ package net.knarcraft.blacksmith.listener;
import net.citizensnpcs.api.CitizensAPI; import net.citizensnpcs.api.CitizensAPI;
import net.knarcraft.blacksmith.trait.BlacksmithTrait; import net.knarcraft.blacksmith.trait.BlacksmithTrait;
import org.bukkit.Material;
import org.bukkit.enchantments.EnchantmentTarget; import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.event.Event; import org.bukkit.event.Event;
@ -48,16 +49,7 @@ public class PlayerListener implements Listener {
* @return <p>True if the given item is a type of armor</p> * @return <p>True if the given item is a type of armor</p>
*/ */
public static boolean isArmor(ItemStack item) { public static boolean isArmor(ItemStack item) {
return EnchantmentTarget.WEARABLE.includes(item); return EnchantmentTarget.WEARABLE.includes(item) || item.getType() == Material.ELYTRA;
//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;
};*/
} }
/** /**

View File

@ -68,13 +68,14 @@ public class ReforgeSession implements Runnable {
//Give the item back to the player //Give the item back to the player
if (!config.getDisableDelay()) { if (!config.getDisableDelay()) {
//If the player isn't online, drop the item to prevent it from disappearing //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()) { if (config.getDropItem() || !player.isOnline() || player.getInventory().firstEmpty() == -1) {
player.getWorld().dropItemNaturally(npc.getEntity().getLocation(), itemToReforge); player.getWorld().dropItemNaturally(npc.getEntity().getLocation(), itemToReforge);
} else { } else {
player.getInventory().addItem(itemToReforge); player.getInventory().addItem(itemToReforge);
} }
} else { } else {
//It can be assumed as this happens instantly, that the player still has the item's previous slot selected
player.getInventory().setItemInMainHand(itemToReforge); player.getInventory().setItemInMainHand(itemToReforge);
} }

View File

@ -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
*
* <p>This will throw an exception if used for a non-double setting</p>
*
* @param value <p>The object value to get</p>
* @return <p>The value of the given object as a double</p>
*/
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
*
* <p>This will throw an exception if used for a non-boolean value</p>
*
* @param value <p>The object value to get</p>
* @return <p>The value of the given object as a boolean</p>
*/
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
*
* <p>This will throw an exception if used for a non-integer setting</p>
*
* @param value <p>The object value to get</p>
* @return <p>The value of the given object as an integer</p>
*/
public static int asInt(Object value) {
if (value instanceof String) {
return Integer.parseInt((String) value);
} else {
return (Integer) value;
}
}
}

View File

@ -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 <p>The value type to get possible values for</p>
* @return <p>The values to show the user</p>
*/
public static List<String> 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 <p>Some example possible values for reforge-able materials</p>
*/
private static List<String> getReforgeAbleMaterials() {
List<String> 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 <p>Some example string values</p>
*/
private static List<String> getStrings() {
List<String> strings = new ArrayList<>(1);
strings.add("&aExample message. Use & for color tags.");
return strings;
}
/**
* Gets some example percentage values
*
* @return <p>Some example percentage values</p>
*/
private static List<String> getPercentages() {
List<String> 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 <p>Some possible positive doubles</p>
*/
private static List<String> getPositiveDoubles() {
List<String> 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 <p>Some example positive integers</p>
*/
private static List<String> getPositiveIntegers() {
List<String> 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 <p>The possible boolean values</p>
*/
private static List<String> getBooleans() {
List<String> booleans = new ArrayList<>(2);
booleans.add("True");
booleans.add("False");
return booleans;
}
}

View File

@ -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 <p>The value type required</p>
* @param value <p>The value given</p>
* @param sender <p>The command sender to use for printing error messages</p>
* @return <p>True if the value is valid</p>
*/
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 <p>The value to check</p>
* @param sender <p>The command sender to use for printing error messages</p>
* @return <p>True if the value is a string list</p>
*/
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 <p>The value to check</p>
* @param sender <p>The command sender to use for printing error messages</p>
* @return <p>True if the value is a percentage</p>
*/
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 <p>The value to check</p>
* @param sender <p>The command sender to use for printing error messages</p>
* @return <p>True if the value is a non-empty string</p>
*/
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 <p>The value to check</p>
* @param sender <p>The command sender to use for printing error messages</p>
* @return <p>True if the value is a positive double</p>
*/
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 <p>The value to check</p>
* @param sender <p>The command sender to use for printing error messages</p>
* @return <p>True if the value is a positive integer</p>
*/
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;
}
}
}

View File

@ -9,9 +9,19 @@ api-version: 1.18
commands: commands:
blacksmith: blacksmith:
permission: blacksmith.edit
usage: /<command> <option> [new value]
description: Used for configuring the selected blacksmith NPC
blacksmithconfig:
permission: blacksmith.admin permission: blacksmith.admin
description: Used for configuring a blacksmith or the plugin usage: /<command> <option/reload> [new value]
description: Used for configuring default blacksmith settings, or global settings
permissions: permissions:
blacksmith.admin: blacksmith.admin:
description: Allows blacksmith configuration description: Allows overall blacksmith configuration
default: op
children:
blacksmith.edit: true
blacksmith.edit:
description: Allows changing settings for the selected blacksmith NPC
default: op default: op