|
@@ -0,0 +1,368 @@
|
|
|
+package com.gmail.nossr50.config.treasure;
|
|
|
+
|
|
|
+import com.gmail.nossr50.config.ConfigLoader;
|
|
|
+import com.gmail.nossr50.datatypes.treasure.*;
|
|
|
+import com.gmail.nossr50.mcMMO;
|
|
|
+import com.gmail.nossr50.util.EnchantmentUtils;
|
|
|
+import org.bukkit.ChatColor;
|
|
|
+import org.bukkit.Material;
|
|
|
+import org.bukkit.configuration.ConfigurationSection;
|
|
|
+import org.bukkit.enchantments.Enchantment;
|
|
|
+import org.bukkit.entity.EntityType;
|
|
|
+import org.bukkit.inventory.ItemStack;
|
|
|
+import org.bukkit.inventory.meta.ItemMeta;
|
|
|
+import org.bukkit.inventory.meta.PotionMeta;
|
|
|
+import org.bukkit.potion.PotionData;
|
|
|
+import org.bukkit.potion.PotionType;
|
|
|
+import org.jetbrains.annotations.NotNull;
|
|
|
+
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+public class FishingTreasureConfig extends ConfigLoader {
|
|
|
+
|
|
|
+ public static final String FILENAME = "fishing_treasures.yml";
|
|
|
+ private static FishingTreasureConfig instance;
|
|
|
+
|
|
|
+ public @NotNull HashMap<Rarity, List<FishingTreasure>> fishingRewards = new HashMap<>();
|
|
|
+ public @NotNull HashMap<Rarity, List<EnchantmentTreasure>> fishingEnchantments = new HashMap<>();
|
|
|
+ public @NotNull HashMap<EntityType, List<ShakeTreasure>> shakeMap = new HashMap<>();
|
|
|
+
|
|
|
+ private FishingTreasureConfig() {
|
|
|
+ super(FILENAME);
|
|
|
+ loadKeys();
|
|
|
+ validate();
|
|
|
+ }
|
|
|
+
|
|
|
+ public static FishingTreasureConfig getInstance() {
|
|
|
+ if (instance == null) {
|
|
|
+ instance = new FishingTreasureConfig();
|
|
|
+ }
|
|
|
+
|
|
|
+ return instance;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected boolean validateKeys() {
|
|
|
+ // Validate all the settings!
|
|
|
+ List<String> reason = new ArrayList<>();
|
|
|
+ for (String tier : config.getConfigurationSection("Enchantment_Drop_Rates").getKeys(false)) {
|
|
|
+ double totalEnchantDropRate = 0;
|
|
|
+ double totalItemDropRate = 0;
|
|
|
+
|
|
|
+ for (Rarity rarity : Rarity.values()) {
|
|
|
+ double enchantDropRate = config.getDouble("Enchantment_Drop_Rates." + tier + "." + rarity.toString());
|
|
|
+ double itemDropRate = config.getDouble("Item_Drop_Rates." + tier + "." + rarity.toString());
|
|
|
+
|
|
|
+ if ((enchantDropRate < 0.0 || enchantDropRate > 100.0)) {
|
|
|
+ reason.add("The enchant drop rate for " + tier + " items that are " + rarity.toString() + "should be between 0.0 and 100.0!");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (itemDropRate < 0.0 || itemDropRate > 100.0) {
|
|
|
+ reason.add("The item drop rate for " + tier + " items that are " + rarity.toString() + "should be between 0.0 and 100.0!");
|
|
|
+ }
|
|
|
+
|
|
|
+ totalEnchantDropRate += enchantDropRate;
|
|
|
+ totalItemDropRate += itemDropRate;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (totalEnchantDropRate < 0 || totalEnchantDropRate > 100.0) {
|
|
|
+ reason.add("The total enchant drop rate for " + tier + " should be between 0.0 and 100.0!");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (totalItemDropRate < 0 || totalItemDropRate > 100.0) {
|
|
|
+ reason.add("The total item drop rate for " + tier + " should be between 0.0 and 100.0!");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return noErrorsInConfig(reason);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void loadKeys() {
|
|
|
+ if (config.getConfigurationSection("Treasures") != null) {
|
|
|
+ backup();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ loadTreasures("Fishing");
|
|
|
+ loadEnchantments();
|
|
|
+
|
|
|
+ for (EntityType entity : EntityType.values()) {
|
|
|
+ if (entity.isAlive()) {
|
|
|
+ loadTreasures("Shake." + entity.toString());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void loadTreasures(String type) {
|
|
|
+ boolean isFishing = type.equals("Fishing");
|
|
|
+ boolean isShake = type.contains("Shake");
|
|
|
+
|
|
|
+ ConfigurationSection treasureSection = config.getConfigurationSection(type);
|
|
|
+
|
|
|
+ if (treasureSection == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Initialize fishing HashMap
|
|
|
+ for (Rarity rarity : Rarity.values()) {
|
|
|
+ if (!fishingRewards.containsKey(rarity)) {
|
|
|
+ fishingRewards.put(rarity, (new ArrayList<>()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (String treasureName : treasureSection.getKeys(false)) {
|
|
|
+ // Validate all the things!
|
|
|
+ List<String> reason = new ArrayList<>();
|
|
|
+
|
|
|
+ String[] treasureInfo = treasureName.split("[|]");
|
|
|
+ String materialName = treasureInfo[0];
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Material, Amount, and Data
|
|
|
+ */
|
|
|
+ Material material;
|
|
|
+
|
|
|
+ if (materialName.contains("INVENTORY")) {
|
|
|
+ // Use magic material BEDROCK to know that we're grabbing something from the inventory and not a normal treasure
|
|
|
+ if (!shakeMap.containsKey(EntityType.PLAYER))
|
|
|
+ shakeMap.put(EntityType.PLAYER, new ArrayList<>());
|
|
|
+ shakeMap.get(EntityType.PLAYER).add(new ShakeTreasure(new ItemStack(Material.BEDROCK, 1, (byte) 0), 1, getInventoryStealDropChance(), getInventoryStealDropLevel()));
|
|
|
+ continue;
|
|
|
+ } else {
|
|
|
+ material = Material.matchMaterial(materialName);
|
|
|
+ }
|
|
|
+
|
|
|
+ int amount = config.getInt(type + "." + treasureName + ".Amount");
|
|
|
+ short data = (treasureInfo.length == 2) ? Short.parseShort(treasureInfo[1]) : (short) config.getInt(type + "." + treasureName + ".Data");
|
|
|
+
|
|
|
+ if (material == null) {
|
|
|
+ reason.add("Invalid material: " + materialName);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (amount <= 0) {
|
|
|
+ amount = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (material != null && material.isBlock() && (data > 127 || data < -128)) {
|
|
|
+ reason.add("Data of " + treasureName + " is invalid! " + data);
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * XP, Drop Chance, and Drop Level
|
|
|
+ */
|
|
|
+
|
|
|
+ int xp = config.getInt(type + "." + treasureName + ".XP");
|
|
|
+ double dropChance = config.getDouble(type + "." + treasureName + ".Drop_Chance");
|
|
|
+ int dropLevel = config.getInt(type + "." + treasureName + ".Drop_Level");
|
|
|
+
|
|
|
+ if (xp < 0) {
|
|
|
+ reason.add(treasureName + " has an invalid XP value: " + xp);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dropChance < 0.0D) {
|
|
|
+ reason.add(treasureName + " has an invalid Drop_Chance: " + dropChance);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dropLevel < 0) {
|
|
|
+ reason.add(treasureName + " has an invalid Drop_Level: " + dropLevel);
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Specific Types
|
|
|
+ */
|
|
|
+ Rarity rarity = null;
|
|
|
+
|
|
|
+ if (isFishing) {
|
|
|
+ rarity = Rarity.getRarity(config.getString(type + "." + treasureName + ".Rarity"));
|
|
|
+
|
|
|
+ if (rarity == null) {
|
|
|
+ reason.add("Invalid Rarity for item: " + treasureName);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Itemstack
|
|
|
+ */
|
|
|
+ ItemStack item = null;
|
|
|
+
|
|
|
+
|
|
|
+ String customName = null;
|
|
|
+
|
|
|
+ if(hasCustomName(type, treasureName)) {
|
|
|
+ customName = config.getString(type + "." + treasureName + ".Custom_Name");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (materialName.contains("POTION")) {
|
|
|
+ Material mat = Material.matchMaterial(materialName);
|
|
|
+ if (mat == null) {
|
|
|
+ reason.add("Potion format for Treasures.yml has changed");
|
|
|
+ } else {
|
|
|
+ item = new ItemStack(mat, amount, data);
|
|
|
+ PotionMeta itemMeta = (PotionMeta) item.getItemMeta();
|
|
|
+
|
|
|
+ PotionType potionType = null;
|
|
|
+ try {
|
|
|
+ potionType = PotionType.valueOf(config.getString(type + "." + treasureName + ".PotionData.PotionType", "WATER"));
|
|
|
+ } catch (IllegalArgumentException ex) {
|
|
|
+ reason.add("Invalid Potion_Type: " + config.getString(type + "." + treasureName + ".PotionData.PotionType", "WATER"));
|
|
|
+ }
|
|
|
+ boolean extended = config.getBoolean(type + "." + treasureName + ".PotionData.Extended", false);
|
|
|
+ boolean upgraded = config.getBoolean(type + "." + treasureName + ".PotionData.Upgraded", false);
|
|
|
+ itemMeta.setBasePotionData(new PotionData(potionType, extended, upgraded));
|
|
|
+
|
|
|
+ if (customName != null) {
|
|
|
+ itemMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', customName));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (config.contains(type + "." + treasureName + ".Lore")) {
|
|
|
+ List<String> lore = new ArrayList<>();
|
|
|
+ for (String s : config.getStringList(type + "." + treasureName + ".Lore")) {
|
|
|
+ lore.add(ChatColor.translateAlternateColorCodes('&', s));
|
|
|
+ }
|
|
|
+ itemMeta.setLore(lore);
|
|
|
+ }
|
|
|
+ item.setItemMeta(itemMeta);
|
|
|
+ }
|
|
|
+ } else if (material != null) {
|
|
|
+ if(material == Material.ENCHANTED_BOOK) {
|
|
|
+ //If any whitelisted enchants exist we use whitelist-based matching
|
|
|
+ item = new ItemStack(material, 1);
|
|
|
+ ItemMeta itemMeta = item.getItemMeta();
|
|
|
+
|
|
|
+ List<String> allowedEnchantsList = config.getStringList(type + "." + treasureName + ".Enchantments_Whitelist");
|
|
|
+ List<String> disallowedEnchantsList = config.getStringList(type + "." + treasureName + ".Enchantments_Blacklist");
|
|
|
+
|
|
|
+ Set<Enchantment> blackListedEnchants = new HashSet<>();
|
|
|
+ Set<Enchantment> whiteListedEnchants = new HashSet<>();
|
|
|
+
|
|
|
+ matchAndFillSet(disallowedEnchantsList, blackListedEnchants);
|
|
|
+ matchAndFillSet(allowedEnchantsList, whiteListedEnchants);
|
|
|
+
|
|
|
+ if (customName != null && itemMeta != null) {
|
|
|
+ itemMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', customName));
|
|
|
+ item.setItemMeta(itemMeta);
|
|
|
+ }
|
|
|
+
|
|
|
+ FishingTreasureBook fishingTreasureBook = new FishingTreasureBook(item, xp, blackListedEnchants, whiteListedEnchants);
|
|
|
+ //TODO: Add book support for shake
|
|
|
+ continue; //The code in this whole file is a disaster, ignore this hacky solution :P
|
|
|
+ } else {
|
|
|
+ item = new ItemStack(material, amount, data);
|
|
|
+
|
|
|
+ if (customName != null) {
|
|
|
+ ItemMeta itemMeta = item.getItemMeta();
|
|
|
+ itemMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', customName));
|
|
|
+ item.setItemMeta(itemMeta);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (config.contains(type + "." + treasureName + ".Lore")) {
|
|
|
+ ItemMeta itemMeta = item.getItemMeta();
|
|
|
+ List<String> lore = new ArrayList<>();
|
|
|
+ for (String s : config.getStringList(type + "." + treasureName + ".Lore")) {
|
|
|
+ lore.add(ChatColor.translateAlternateColorCodes('&', s));
|
|
|
+ }
|
|
|
+ itemMeta.setLore(lore);
|
|
|
+ item.setItemMeta(itemMeta);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (noErrorsInConfig(reason)) {
|
|
|
+ if (isFishing) {
|
|
|
+ fishingRewards.get(rarity).add(new FishingTreasure(item, xp));
|
|
|
+ } else if (isShake) {
|
|
|
+ ShakeTreasure shakeTreasure = new ShakeTreasure(item, xp, dropChance, dropLevel);
|
|
|
+
|
|
|
+ EntityType entityType = EntityType.valueOf(type.substring(6));
|
|
|
+ if (!shakeMap.containsKey(entityType))
|
|
|
+ shakeMap.put(entityType, new ArrayList<>());
|
|
|
+ shakeMap.get(entityType).add(shakeTreasure);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean hasCustomName(@NotNull String type, @NotNull String treasureName) {
|
|
|
+ return config.contains(type + "." + treasureName + ".Custom_Name");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Matches enchantments on a list (user provided string) to known enchantments in the Spigot API
|
|
|
+ * Any matches are added to the passed set
|
|
|
+ * @param enchantListStr the users string list of enchantments
|
|
|
+ * @param permissiveList the permissive list of enchantments
|
|
|
+ */
|
|
|
+ private void matchAndFillSet(List<String> enchantListStr, Set<Enchantment> permissiveList) {
|
|
|
+ if(enchantListStr.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ for(String str : enchantListStr) {
|
|
|
+ boolean foundMatch = false;
|
|
|
+ for(Enchantment enchantment : Enchantment.values()) {
|
|
|
+ if(enchantment.getKey().getKey().equalsIgnoreCase(str)) {
|
|
|
+ permissiveList.add(enchantment);
|
|
|
+ foundMatch = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!foundMatch) {
|
|
|
+ mcMMO.p.getLogger().info("[Fishing Treasure Init] Could not find any enchantments which matched the user defined enchantment named: "+str);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void loadEnchantments() {
|
|
|
+ for (Rarity rarity : Rarity.values()) {
|
|
|
+ if (!fishingEnchantments.containsKey(rarity)) {
|
|
|
+ fishingEnchantments.put(rarity, (new ArrayList<>()));
|
|
|
+ }
|
|
|
+
|
|
|
+ ConfigurationSection enchantmentSection = config.getConfigurationSection("Enchantments_Rarity." + rarity.toString());
|
|
|
+
|
|
|
+ if (enchantmentSection == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (String enchantmentName : enchantmentSection.getKeys(false)) {
|
|
|
+ int level = config.getInt("Enchantments_Rarity." + rarity.toString() + "." + enchantmentName);
|
|
|
+ Enchantment enchantment = EnchantmentUtils.getByName(enchantmentName);
|
|
|
+
|
|
|
+ if (enchantment == null) {
|
|
|
+ plugin.getLogger().warning("Skipping invalid enchantment in " + FILENAME + ": " + enchantmentName);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ fishingEnchantments.get(rarity).add(new EnchantmentTreasure(enchantment, level));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean getInventoryStealEnabled() {
|
|
|
+ return config.contains("Shake.PLAYER.INVENTORY");
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean getInventoryStealStacks() {
|
|
|
+ return config.getBoolean("Shake.PLAYER.INVENTORY.Whole_Stacks");
|
|
|
+ }
|
|
|
+
|
|
|
+ public double getInventoryStealDropChance() {
|
|
|
+ return config.getDouble("Shake.PLAYER.INVENTORY.Drop_Chance");
|
|
|
+ }
|
|
|
+
|
|
|
+ public int getInventoryStealDropLevel() {
|
|
|
+ return config.getInt("Shake.PLAYER.INVENTORY.Drop_Level");
|
|
|
+ }
|
|
|
+
|
|
|
+ public double getItemDropRate(int tier, Rarity rarity) {
|
|
|
+ return config.getDouble("Item_Drop_Rates.Tier_" + tier + "." + rarity.toString());
|
|
|
+ }
|
|
|
+
|
|
|
+ public double getEnchantmentDropRate(int tier, Rarity rarity) {
|
|
|
+ return config.getDouble("Enchantment_Drop_Rates.Tier_" + tier + "." + rarity.toString());
|
|
|
+ }
|
|
|
+}
|