package net.knarcraft.blacksmith.config; import net.citizensnpcs.api.util.DataKey; import net.citizensnpcs.api.util.YamlStorage; import net.knarcraft.blacksmith.BlacksmithPlugin; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.enchantments.Enchantment; import java.io.File; import java.util.HashMap; import java.util.Map; 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<Material, Double> materialBasePrices = new HashMap<>(); private final Map<Material, Double> materialPricePerDurabilityPoints = new HashMap<>(); private final Map<Enchantment, Double> enchantmentCosts = new HashMap<>(); private final Map<NPCSetting, Object> defaultNPCSettings = new HashMap<>(); private final Map<GlobalSetting, Object> globalSettings = new HashMap<>(); private final YamlStorage defaultConfig; /** * Instantiates a new "Settings" * * @param plugin <p>A reference to the blacksmith plugin</p> */ 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(); } /** * Gets the current value of the default NPC settings * * @return <p>The current value of the default NPC settings</p> */ public Map<NPCSetting, Object> getDefaultNPCSettings() { return new HashMap<>(this.defaultNPCSettings); } /** * Gets whether to use natural cost for cost calculation * * <p>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.</p> * * @return <p>Whether to use natural cost</p> */ public boolean getUseNaturalCost() { return asBoolean(GlobalSetting.NATURAL_COST); } /** * Gets the base price for the given material * * @param material <p>The material to get the base price for</p> * @return <p>The base price for the material</p> */ 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 <p>The material to get the durability point price for</p> * @return <p>The durability point price for the material</p> */ 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 <p>The enchantment to get the cost for</p> * @return <p>The cost of each enchantment level</p> */ 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 * * <p>This will throw an exception if used for a non-boolean value</p> * * @param setting <p>The setting to get the value of</p> * @return <p>The value of the given setting as a boolean</p> */ public boolean asBoolean(GlobalSetting setting) { Object value = getValue(setting); if (value instanceof String) { return Boolean.parseBoolean((String) value); } else { return (Boolean) value; } } /** * Gets the given value as a double * * <p>This will throw an exception if used for a non-double setting</p> * * @param setting <p>The setting to get the value of</p> * @return <p>The value of the given setting as a double</p> */ public double asDouble(GlobalSetting setting) { Object value = getValue(setting); if (value instanceof String) { return Double.parseDouble((String) value); } else if (value instanceof Integer) { return (Integer) value; } else { return (Double) value; } } /** * Gets the value of a setting, using the default if not set * * @param setting <p>The setting to get the value of</p> * @return <p>The current value</p> */ 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 <p>The root node of all global settings</p> */ 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<String, String> 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 <p>The root data key containing sub-keys</p> * @return <p>Any sub-keys found that aren't the default</p> */ private Map<String, String> getRelevantKeys(DataKey rootKey) { Map<String, String> relevant = new HashMap<>(); for (DataKey dataKey : rootKey.getSubKeys()) { String keyName = dataKey.name(); //Skip the default value if (keyName.equals("default")) { continue; } String normalizedName = keyName.toUpperCase().replace("-", "_"); relevant.put(keyName, normalizedName); } return relevant; } /** * Loads all default NPC settings * * @param root <p>The root node of all default NPC settings</p> */ 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())); } } } }