package net.knarcraft.blacksmith.config; import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.api.util.YamlStorage; import net.knarcraft.blacksmith.BlacksmithPlugin; import net.knarcraft.blacksmith.util.ConfigHelper; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.enchantments.Enchantment; import java.io.File; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; /** * A class which keeps track of all default NPC settings and all global settings */ public class GlobalSettings { private final Map materialBasePrices = new HashMap<>(); private final Map materialPricePerDurabilityPoints = new HashMap<>(); private final Map enchantmentCosts = new HashMap<>(); private final Map defaultNPCSettings = new HashMap<>(); private final Map globalSettings = new HashMap<>(); private final YamlStorage defaultConfig; /** * Instantiates a new "Settings" * * @param plugin

A reference to the blacksmith plugin

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

The global setting to change

* @param newValue

The new value of the setting

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

The default NPC setting to change

* @param newValue

The new value for the setting

*/ public void changeValue(NPCSetting npcSetting, Object newValue) { defaultNPCSettings.put(npcSetting, newValue); save(); } /** * Gets the current raw value of the given global setting * * @param globalSetting

The setting to get

* @return

The current raw setting value

*/ public Object getRawValue(GlobalSetting globalSetting) { return globalSettings.get(globalSetting); } /** * Gets the current raw value of the given default NPC setting * * @param npcSetting

The setting to get

* @return

The current raw setting value

*/ public Object getRawValue(NPCSetting npcSetting) { return defaultNPCSettings.get(npcSetting); } /** * Sets the enchantment cost for the given enchantment * * @param enchantment

The enchantment to set the enchantment cost for

* @param newEnchantmentCost

The new enchantment cost

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

The material to set the price per durability point price for

* @param newPrice

The new price per durability point price

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

The material to set the base price for

* @param newBasePrice

The new base price

*/ public void setBasePrice(Material material, double newBasePrice) { if (newBasePrice < 0) { throw new IllegalArgumentException("Base price cannot be negative!"); } if (material == null) { globalSettings.put(GlobalSetting.BASE_PRICE, newBasePrice); } else { materialBasePrices.put(material, newBasePrice); } save(); } /** * Gets the current value of the default NPC settings * * @return

The current value of the default NPC settings

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

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

* * @return

Whether to use natural cost

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

The material to get the base price for

* @return

The base price for the material

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

The material to get the durability point price for

* @return

The durability point price for the material

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

The enchantment to get the cost for

* @return

The cost of each enchantment level

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

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

* * @param setting

The setting to get the value of

* @return

The value of the given setting as a boolean

*/ public boolean asBoolean(GlobalSetting setting) { return ConfigHelper.asBoolean(getValue(setting)); } /** * Gets the given value as a double * *

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

* * @param setting

The setting to get the value of

* @return

The value of the given setting as a double

*/ public double asDouble(GlobalSetting setting) { return ConfigHelper.asDouble(getValue(setting)); } /** * Gets the value of a setting, using the default if not set * * @param setting

The setting to get the value of

* @return

The current value

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

The root node of all global settings

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

The root data key containing sub-keys

* @return

Any sub-keys found that aren't the default

*/ private Map getRelevantKeys(DataKey rootKey) { Map relevant = new HashMap<>(); for (DataKey dataKey : rootKey.getSubKeys()) { String keyName = dataKey.name(); //Skip the default value if (keyName.equals("default")) { continue; } String normalizedName = keyName.toUpperCase().replace("-", "_"); relevant.put(keyName, normalizedName); } return relevant; } /** * Converts a normalized material name to the format used in the config file * * @param normalizedName

The normalized name to un-normalize

* @return

The un-normalized name

*/ private String unNormalizeName(String normalizedName) { return normalizedName.toLowerCase().replace("_", "-"); } /** * Loads all default NPC settings * * @param root

The root node of all default NPC settings

*/ private void loadDefaultNPCSettings(DataKey root) { for (NPCSetting setting : NPCSetting.values()) { if (!root.keyExists(setting.getPath())) { //If the setting does not exist in the config file, add it root.setRaw(setting.getPath(), setting.getDefaultValue()); } else { //Set the setting to the value found in the path defaultNPCSettings.put(setting, root.getRaw(setting.getPath())); } } } /** * 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(); } }