From 78558107b33a1575b18d795ba8cd409d9197c91e Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 2 May 2024 06:28:20 -0700 Subject: [PATCH] WIP 1.20.6 support --- Changelog.txt | 7 + pom.xml | 33 +- .../nossr50/commands/skills/MacesCommand.java | 56 +++ .../nossr50/config/LegacyConfigLoader.java | 17 +- .../config/skills/alchemy/PotionConfig.java | 211 ++++++--- .../treasure/FishingTreasureConfig.java | 43 +- .../config/treasure/TreasureConfig.java | 35 +- .../database/FlatFileDataProcessor.java | 82 +--- .../database/FlatFileDatabaseManager.java | 24 +- .../nossr50/database/SQLDatabaseManager.java | 52 +- .../database/flatfile/FlatFileDataUtil.java | 84 +--- .../nossr50/datatypes/player/McMMOPlayer.java | 8 + .../datatypes/skills/PrimarySkillType.java | 1 + .../datatypes/skills/SubSkillType.java | 3 + .../datatypes/skills/SuperAbilityType.java | 32 +- .../nossr50/datatypes/skills/ToolType.java | 5 +- .../skills/alchemy/AlchemyPotion.java | 211 ++++----- .../datatypes/skills/alchemy/PotionStage.java | 27 +- .../skills/subskills/acrobatics/Roll.java | 3 +- .../nossr50/listeners/EntityListener.java | 2 +- src/main/java/com/gmail/nossr50/mcMMO.java | 38 +- .../nossr50/metadata/ItemMetadataService.java | 7 +- .../skills/alchemy/AlchemyManager.java | 4 +- .../skills/alchemy/AlchemyPotionBrewer.java | 14 +- .../skills/archery/ArcheryManager.java | 7 +- .../skills/fishing/FishingManager.java | 6 +- .../nossr50/skills/maces/MacesManager.java | 21 + .../nossr50/skills/taming/TamingManager.java | 2 +- .../gmail/nossr50/util/AttributeMapper.java | 45 ++ .../gmail/nossr50/util/EnchantmentMapper.java | 149 ++++++ .../gmail/nossr50/util/EnchantmentUtils.java | 61 +-- .../com/gmail/nossr50/util/ItemUtils.java | 40 +- .../gmail/nossr50/util/MaterialMapStore.java | 17 + .../com/gmail/nossr50/util/Permissions.java | 8 + .../nossr50/util/PotionCompatibilityType.java | 6 + .../nossr50/util/PotionEffectMapper.java | 142 ++++++ .../com/gmail/nossr50/util/PotionUtil.java | 447 ++++++++++++++++++ .../commands/CommandRegistrationManager.java | 9 +- .../util/compat/CompatibilityManager.java | 3 +- .../nossr50/util/skills/CombatUtils.java | 36 ++ .../gmail/nossr50/util/skills/SkillTools.java | 1 + .../gmail/nossr50/util/skills/SkillUtils.java | 25 +- src/main/resources/experience.yml | 20 +- .../resources/locale/locale_en_US.properties | 7 +- src/main/resources/plugin.yml | 3 + src/main/resources/skillranks.yml | 24 + .../com/gmail/nossr50/MMOTestEnvironment.java | 61 ++- .../skills/alchemy/PotionConfigTest.java | 69 +++ .../database/FlatFileDatabaseManagerTest.java | 345 ++++++-------- .../gmail/nossr50/util/PotionUtilTest.java | 51 ++ src/test/resources/healthydb.users | 6 +- 51 files changed, 1874 insertions(+), 736 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/commands/skills/MacesCommand.java create mode 100644 src/main/java/com/gmail/nossr50/skills/maces/MacesManager.java create mode 100644 src/main/java/com/gmail/nossr50/util/AttributeMapper.java create mode 100644 src/main/java/com/gmail/nossr50/util/EnchantmentMapper.java create mode 100644 src/main/java/com/gmail/nossr50/util/PotionCompatibilityType.java create mode 100644 src/main/java/com/gmail/nossr50/util/PotionEffectMapper.java create mode 100644 src/main/java/com/gmail/nossr50/util/PotionUtil.java create mode 100644 src/test/java/com/gmail/nossr50/config/skills/alchemy/PotionConfigTest.java create mode 100644 src/test/java/com/gmail/nossr50/util/PotionUtilTest.java diff --git a/Changelog.txt b/Changelog.txt index 698739102..eb01a4712 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,6 +1,13 @@ Version 2.2.007 + Compatibility with the 1.20.5 MC Update + Alchemy now has more warning/errors that will print out to help debug Fixed bug where Green Thumb did not replant if seed was in the off hand + NOTES: + I did my best to keep mcMMO compatible with older versions of Minecraft for this update. + This update to MC was quite large, with breaking changes to a lot of code relating to Alchemy, and some other things. + I expect there to be bugs, please report them on GitHub or Discord, but preferably GitHub. + I will be working on fixing these bugs as they come in, so please be patient. Version 2.2.006 Added new config custom_item_support.yml Added support for hex color codes in the locale file, uses the format &#RRGGBB (see notes) diff --git a/pom.xml b/pom.xml index 9bdddf369..136deebdf 100644 --- a/pom.xml +++ b/pom.xml @@ -254,8 +254,11 @@ devmart-other https://nexuslite.gcnt.net/repos/other/ - - + + + papermc + https://repo.papermc.io/repository/maven-public/ + @@ -361,7 +364,7 @@ org.spigotmc spigot-api - 1.20.4-R0.1-SNAPSHOT + 1.20.5-R0.1-SNAPSHOT provided @@ -435,5 +438,29 @@ 0.3.1 compile + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/com/gmail/nossr50/commands/skills/MacesCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/MacesCommand.java new file mode 100644 index 000000000..757c8dcf1 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/commands/skills/MacesCommand.java @@ -0,0 +1,56 @@ +//package com.gmail.nossr50.commands.skills; +// +//import com.gmail.nossr50.datatypes.player.McMMOPlayer; +//import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +//import com.gmail.nossr50.util.player.UserManager; +//import com.gmail.nossr50.util.skills.CombatUtils; +//import com.gmail.nossr50.util.skills.SkillUtils; +//import com.gmail.nossr50.util.text.TextComponentFactory; +//import net.kyori.adventure.text.Component; +//import org.bukkit.ChatColor; +//import org.bukkit.entity.Player; +// +//import java.util.ArrayList; +//import java.util.List; +// +//import static com.gmail.nossr50.datatypes.skills.SubSkillType.MACES_MACES_LIMIT_BREAK; +// +//public class MacesCommand extends SkillCommand { +// +// public MacesCommand() { +// super(PrimarySkillType.MACES); +// } +// +// @Override +// protected void dataCalculations(Player player, float skillValue) {} +// +// @Override +// protected void permissionsCheck(Player player) {} +// +// @Override +// protected List statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) { +// List messages = new ArrayList<>(); +// McMMOPlayer mmoPlayer = UserManager.getPlayer(player); +// if (mmoPlayer == null) { +// return messages; +// } +// +// if(SkillUtils.canUseSubskill(player, MACES_MACES_LIMIT_BREAK)) { +// messages.add(getStatMessage(MACES_MACES_LIMIT_BREAK, +// String.valueOf(CombatUtils.getLimitBreakDamageAgainstQuality(player, MACES_MACES_LIMIT_BREAK, 1000)))); +// } +// +// messages.add(ChatColor.GRAY + "The Maces skill is a work in progress and is still being developed," + +// " feedback would be appreciated in the mcMMO discord server."); +// return messages; +// } +// +// @Override +// protected List getTextComponents(Player player) { +// List textComponents = new ArrayList<>(); +// +// TextComponentFactory.getSubSkillTextComponents(player, textComponents, PrimarySkillType.MACES); +// +// return textComponents; +// } +//} diff --git a/src/main/java/com/gmail/nossr50/config/LegacyConfigLoader.java b/src/main/java/com/gmail/nossr50/config/LegacyConfigLoader.java index 6a917b3fd..c9d808e01 100644 --- a/src/main/java/com/gmail/nossr50/config/LegacyConfigLoader.java +++ b/src/main/java/com/gmail/nossr50/config/LegacyConfigLoader.java @@ -4,31 +4,40 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.LogUtils; import org.bukkit.configuration.file.YamlConfiguration; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.VisibleForTesting; import java.io.File; import java.util.List; @Deprecated public abstract class LegacyConfigLoader { - protected final File configFile; + protected final @NotNull File configFile; protected final @NotNull File dataFolder; - protected String fileName; + protected @NotNull String fileName; protected YamlConfiguration config; - public LegacyConfigLoader(String relativePath, String fileName, @NotNull File dataFolder) { + public LegacyConfigLoader(@NotNull String relativePath, @NotNull String fileName, @NotNull File dataFolder) { this.fileName = fileName; this.dataFolder = dataFolder; configFile = new File(dataFolder, relativePath + File.separator + fileName); loadFile(); } - public LegacyConfigLoader(String fileName, @NotNull File dataFolder) { + public LegacyConfigLoader(@NotNull String fileName, @NotNull File dataFolder) { this.fileName = fileName; this.dataFolder = dataFolder; configFile = new File(dataFolder, fileName); loadFile(); } + @VisibleForTesting + public LegacyConfigLoader(@NotNull File file) { + this.fileName = file.getName(); + this.dataFolder = file.getParentFile(); + configFile = new File(dataFolder, fileName); + loadFile(); + } + @Deprecated public LegacyConfigLoader(String relativePath, String fileName) { this.fileName = fileName; diff --git a/src/main/java/com/gmail/nossr50/config/skills/alchemy/PotionConfig.java b/src/main/java/com/gmail/nossr50/config/skills/alchemy/PotionConfig.java index 3b21589c6..37b992dad 100644 --- a/src/main/java/com/gmail/nossr50/config/skills/alchemy/PotionConfig.java +++ b/src/main/java/com/gmail/nossr50/config/skills/alchemy/PotionConfig.java @@ -2,22 +2,30 @@ package com.gmail.nossr50.config.skills.alchemy; import com.gmail.nossr50.config.LegacyConfigLoader; import com.gmail.nossr50.datatypes.skills.alchemy.AlchemyPotion; +import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.LogUtils; +import com.gmail.nossr50.util.ItemUtils; +import com.gmail.nossr50.util.PotionUtil; import org.bukkit.ChatColor; import org.bukkit.Color; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.inventory.ItemStack; -import org.bukkit.potion.*; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.potion.PotionType; +import org.jetbrains.annotations.VisibleForTesting; +import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import static com.gmail.nossr50.util.PotionUtil.*; + public class PotionConfig extends LegacyConfigLoader { - private static PotionConfig instance; private final List concoctionsIngredientsTierOne = new ArrayList<>(); private final List concoctionsIngredientsTierTwo = new ArrayList<>(); @@ -28,30 +36,34 @@ public class PotionConfig extends LegacyConfigLoader { private final List concoctionsIngredientsTierSeven = new ArrayList<>(); private final List concoctionsIngredientsTierEight = new ArrayList<>(); - private final Map potionMap = new HashMap<>(); + /** + * Map of potion names to AlchemyPotion objects. + */ + private final Map loadedPotions = new HashMap<>(); - private PotionConfig() { + public PotionConfig() { super("potions.yml"); - loadKeys(); } - public static PotionConfig getInstance() { - if (instance == null) { - instance = new PotionConfig(); - } - - return instance; + @VisibleForTesting + PotionConfig(File file) { + super(file); } @Override protected void loadKeys() { + } + + public void loadPotions() { loadConcoctions(); loadPotionMap(); } - private void loadConcoctions() { - ConfigurationSection concoctionSection = config.getConfigurationSection("Concoctions"); + @VisibleForTesting + void loadConcoctions() { + final ConfigurationSection concoctionSection = config.getConfigurationSection("Concoctions"); + // Load the ingredients for each tier loadConcoctionsTier(concoctionsIngredientsTierOne, concoctionSection.getStringList("Tier_One_Ingredients")); loadConcoctionsTier(concoctionsIngredientsTierTwo, concoctionSection.getStringList("Tier_Two_Ingredients")); loadConcoctionsTier(concoctionsIngredientsTierThree, concoctionSection.getStringList("Tier_Three_Ingredients")); @@ -71,7 +83,7 @@ public class PotionConfig extends LegacyConfigLoader { } private void loadConcoctionsTier(List ingredientList, List ingredientStrings) { - if (ingredientStrings != null && ingredientStrings.size() > 0) { + if (ingredientStrings != null && !ingredientStrings.isEmpty()) { for (String ingredientString : ingredientStrings) { ItemStack ingredient = loadIngredient(ingredientString); @@ -85,23 +97,24 @@ public class PotionConfig extends LegacyConfigLoader { /** * Find the Potions configuration section and load all defined potions. */ - private void loadPotionMap() { + int loadPotionMap() { ConfigurationSection potionSection = config.getConfigurationSection("Potions"); - int pass = 0; - int fail = 0; + int potionsLoaded = 0; + int failures = 0; for (String potionName : potionSection.getKeys(false)) { AlchemyPotion potion = loadPotion(potionSection.getConfigurationSection(potionName)); if (potion != null) { - potionMap.put(potionName, potion); - pass++; + loadedPotions.put(potionName, potion); + potionsLoaded++; } else { - fail++; + failures++; } } - LogUtils.debug(mcMMO.p.getLogger(), "Loaded " + pass + " Alchemy potions, skipped " + fail + "."); + mcMMO.p.getLogger().info("Loaded " + potionsLoaded + " Alchemy potions, skipped " + failures + "."); + return potionsLoaded; } /** @@ -114,37 +127,88 @@ public class PotionConfig extends LegacyConfigLoader { */ private AlchemyPotion loadPotion(ConfigurationSection potion_section) { try { + final String key = potion_section.getName(); + final String displayName = potion_section.getString("Name") != null + ? LocaleLoader.addColors(potion_section.getString("Name")) + : null; + final ConfigurationSection potionData = potion_section.getConfigurationSection("PotionData"); + boolean extended = false; + boolean upgraded = false; - String name = potion_section.getString("Name"); - if (name != null) { - name = ChatColor.translateAlternateColorCodes('&', name); + if (potionData != null) { + extended = potionData.getBoolean("Extended", false); + upgraded = potionData.getBoolean("Upgraded", false); } - PotionData data; - if (!potion_section.contains("PotionData")) { // Backwards config compatability - short dataValue = Short.parseShort(potion_section.getName()); - Potion potion = Potion.fromDamage(dataValue); - data = new PotionData(potion.getType(), potion.hasExtendedDuration(), potion.getLevel() == 2); + Material material; + final String materialString = potion_section.getString("Material", null); + if (materialString != null) { + material = ItemUtils.exhaustiveMaterialLookup(materialString); + if (material == null) { + mcMMO.p.getLogger().warning("PotionConfig: Failed to parse material for potion " + key + ": " + materialString); + mcMMO.p.getLogger().warning("PotionConfig: Defaulting to POTION"); + material = Material.POTION; + } } else { - ConfigurationSection potionData = potion_section.getConfigurationSection("PotionData"); - data = new PotionData(PotionType.valueOf(potionData.getString("PotionType", "WATER")), potionData.getBoolean("Extended", false), potionData.getBoolean("Upgraded", false)); + mcMMO.p.getLogger().warning("PotionConfig: Missing Material config entry for potion " + key + "," + + " from configuration section: " + potion_section + ", defaulting to POTION"); + material = Material.POTION; } - Material material = Material.POTION; - String mat = potion_section.getString("Material", null); - if (mat != null) { - material = Material.valueOf(mat); + final ItemStack itemStack = new ItemStack(material, 1); + final PotionMeta potionMeta = (PotionMeta) itemStack.getItemMeta(); + + if (potionMeta == null) { + mcMMO.p.getLogger().severe("PotionConfig: Failed to get PotionMeta for " + displayName + ", from configuration section:" + + " " + potion_section); + return null; } + // extended and upgraded seem to be mutually exclusive + if (extended && upgraded) { + mcMMO.p.getLogger().warning("Potion " + key + " has both Extended and Upgraded set to true," + + " defaulting to Extended."); + upgraded = false; + } + String potionTypeStr = potionData.getString("PotionType", null); + if (potionTypeStr == null) { + mcMMO.p.getLogger().severe("PotionConfig: Missing PotionType for " + displayName + ", from configuration section:" + + " " + potion_section); + return null; + } + + PotionType potionType = matchPotionType(potionTypeStr, upgraded, extended); + if (potionType == null) { + // try matching to key + mcMMO.p.getLogger().warning("Failed to match potion type, trying to match with config key..."); + matchPotionType(key, upgraded, extended); + } + + if (potionType == null) { + mcMMO.p.getLogger().severe("PotionConfig: Failed to parse potion type for: " + potionTypeStr); + return null; + } + + // Set base potion type + // NOTE: extended/ignored are effectively ignored here on 1.20.5 and later + PotionUtil.setBasePotionType(potionMeta, potionType, extended, upgraded); + +// // Use the name of the potion to indicate upgrade status if not set in PotionData +// if(convertPotionConfigName(key).toUpperCase().contains("STRONG")) +// upgraded = true; +// +// if(convertPotionConfigName(key).toUpperCase().contains("LONG")) +// extended = true; + List lore = new ArrayList<>(); if (potion_section.contains("Lore")) { for (String line : potion_section.getStringList("Lore")) { lore.add(ChatColor.translateAlternateColorCodes('&', line)); } } + potionMeta.setLore(lore); - List effects = new ArrayList<>(); if (potion_section.contains("Effects")) { for (String effect : potion_section.getStringList("Effects")) { String[] parts = effect.split(" "); @@ -154,9 +218,9 @@ public class PotionConfig extends LegacyConfigLoader { int duration = parts.length > 2 ? Integer.parseInt(parts[2]) : 0; if (type != null) { - effects.add(new PotionEffect(type, duration, amplifier)); + potionMeta.addCustomEffect(new PotionEffect(type, duration, amplifier), true); } else { - mcMMO.p.getLogger().warning("Failed to parse effect for potion " + name + ": " + effect); + mcMMO.p.getLogger().severe("PotionConfig: Failed to parse effect for potion " + displayName + ": " + effect); } } } @@ -165,8 +229,9 @@ public class PotionConfig extends LegacyConfigLoader { if (potion_section.contains("Color")) { color = Color.fromRGB(potion_section.getInt("Color")); } else { - color = this.generateColor(effects); + color = this.generateColor(potionMeta.getCustomEffects()); } + potionMeta.setColor(color); Map children = new HashMap<>(); if (potion_section.contains("Children")) { @@ -175,14 +240,15 @@ public class PotionConfig extends LegacyConfigLoader { if (ingredient != null) { children.put(ingredient, potion_section.getConfigurationSection("Children").getString(child)); } else { - mcMMO.p.getLogger().warning("Failed to parse child for potion " + name + ": " + child); + mcMMO.p.getLogger().severe("PotionConfig: Failed to parse child for potion " + displayName + ": " + child); } } } - - return new AlchemyPotion(material, data, name, lore, effects, color, children); + // TODO: Might not need to .setItemMeta + itemStack.setItemMeta(potionMeta); + return new AlchemyPotion(itemStack, children); } catch (Exception e) { - mcMMO.p.getLogger().warning("Failed to load Alchemy potion: " + potion_section.getName()); + mcMMO.p.getLogger().warning("PotionConfig: Failed to load Alchemy potion: " + potion_section.getName()); return null; } } @@ -210,39 +276,52 @@ public class PotionConfig extends LegacyConfigLoader { return null; } + /** + * Get the ingredients for the given tier. + * @param tier Tier to get ingredients for. + * @return List of ingredients for the given tier. + */ public List getIngredients(int tier) { - switch (tier) { - case 8: - return concoctionsIngredientsTierEight; - case 7: - return concoctionsIngredientsTierSeven; - case 6: - return concoctionsIngredientsTierSix; - case 5: - return concoctionsIngredientsTierFive; - case 4: - return concoctionsIngredientsTierFour; - case 3: - return concoctionsIngredientsTierThree; - case 2: - return concoctionsIngredientsTierTwo; - case 1: - default: - return concoctionsIngredientsTierOne; - } + return switch (tier) { + case 8 -> concoctionsIngredientsTierEight; + case 7 -> concoctionsIngredientsTierSeven; + case 6 -> concoctionsIngredientsTierSix; + case 5 -> concoctionsIngredientsTierFive; + case 4 -> concoctionsIngredientsTierFour; + case 3 -> concoctionsIngredientsTierThree; + case 2 -> concoctionsIngredientsTierTwo; + default -> concoctionsIngredientsTierOne; + }; } + /** + * Check if the given ItemStack is a valid potion. + * @param item ItemStack to be checked. + * @return True if the given ItemStack is a valid potion, false otherwise. + */ public boolean isValidPotion(ItemStack item) { return getPotion(item) != null; } + /** + * Get the AlchemyPotion that corresponds to the given name. + * @param name Name of the potion to be checked. + * @return AlchemyPotion that corresponds to the given name. + */ public AlchemyPotion getPotion(String name) { - return potionMap.get(name); + return loadedPotions.get(name); } + /** + * Get the AlchemyPotion that corresponds to the given ItemStack. + * + * @param item ItemStack to be checked. + * + * @return AlchemyPotion that corresponds to the given ItemStack. + */ public AlchemyPotion getPotion(ItemStack item) { - for (AlchemyPotion potion : potionMap.values()) { - if (potion.isSimilar(item)) { + for (AlchemyPotion potion : loadedPotions.values()) { + if (potion.isSimilarPotion(item)) { return potion; } } diff --git a/src/main/java/com/gmail/nossr50/config/treasure/FishingTreasureConfig.java b/src/main/java/com/gmail/nossr50/config/treasure/FishingTreasureConfig.java index a02e0bd3f..5ffbb74da 100755 --- a/src/main/java/com/gmail/nossr50/config/treasure/FishingTreasureConfig.java +++ b/src/main/java/com/gmail/nossr50/config/treasure/FishingTreasureConfig.java @@ -5,6 +5,7 @@ import com.gmail.nossr50.datatypes.treasure.*; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.EnchantmentUtils; import com.gmail.nossr50.util.LogUtils; +import com.gmail.nossr50.util.PotionUtil; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; @@ -13,12 +14,13 @@ 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.*; +import static com.gmail.nossr50.util.PotionUtil.matchPotionType; + public class FishingTreasureConfig extends BukkitConfig { public static final String FILENAME = "fishing_treasures.yml"; @@ -204,30 +206,40 @@ public class FishingTreasureConfig extends BukkitConfig { } if (materialName.contains("POTION")) { + // Update for 1.20.5 + Material mat = Material.matchMaterial(materialName); if (mat == null) { reason.add("Potion format for " + FILENAME + " has changed"); + continue; } else { item = new ItemStack(mat, amount, data); - PotionMeta itemMeta = (PotionMeta) item.getItemMeta(); + PotionMeta potionMeta = (PotionMeta) item.getItemMeta(); - if (itemMeta == null) { - mcMMO.p.getLogger().severe("Item meta when adding potion to fishing treasure was null, contact the mcMMO devs!"); + if (potionMeta == null) { + mcMMO.p.getLogger().severe("FishingConfig: Item meta when adding potion to fishing treasure was null," + + " contact the mcMMO devs!"); + reason.add("FishingConfig: Item meta when adding potion to fishing treasure was null"); continue; } - 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")); - } + String potionTypeStr; + potionTypeStr = 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)); + final PotionType potionType = matchPotionType(potionTypeStr, extended, upgraded); + + if (potionType == null) { + reason.add("FishingConfig: Could not derive potion type from: " + potionTypeStr +", " + extended + ", " + upgraded); + continue; + } + + // Set the base potion type + // NOTE: Upgraded/Extended are ignored in 1.20.5 and later + PotionUtil.setBasePotionType(potionMeta, potionType, upgraded, extended); if (customName != null) { - itemMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', customName)); + potionMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', customName)); } if (config.contains(type + "." + treasureName + ".Lore")) { @@ -235,9 +247,9 @@ public class FishingTreasureConfig extends BukkitConfig { for (String s : config.getStringList(type + "." + treasureName + ".Lore")) { lore.add(ChatColor.translateAlternateColorCodes('&', s)); } - itemMeta.setLore(lore); + potionMeta.setLore(lore); } - item.setItemMeta(itemMeta); + item.setItemMeta(potionMeta); } } else if (material == Material.ENCHANTED_BOOK) { //If any whitelisted enchants exist we use whitelist-based matching @@ -355,7 +367,8 @@ public class FishingTreasureConfig extends BukkitConfig { Enchantment enchantment = EnchantmentUtils.getByName(enchantmentName); if (enchantment == null) { - mcMMO.p.getLogger().warning("Skipping invalid enchantment in " + FILENAME + ": " + enchantmentName); + mcMMO.p.getLogger().info("Skipping invalid enchantment in '" + FILENAME + "', named:" + + enchantmentName); continue; } diff --git a/src/main/java/com/gmail/nossr50/config/treasure/TreasureConfig.java b/src/main/java/com/gmail/nossr50/config/treasure/TreasureConfig.java index 97967a131..bed8ed059 100755 --- a/src/main/java/com/gmail/nossr50/config/treasure/TreasureConfig.java +++ b/src/main/java/com/gmail/nossr50/config/treasure/TreasureConfig.java @@ -6,6 +6,7 @@ import com.gmail.nossr50.datatypes.treasure.HylianTreasure; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.BlockUtils; import com.gmail.nossr50.util.LogUtils; +import com.gmail.nossr50.util.PotionUtil; import com.gmail.nossr50.util.text.StringUtils; import org.bukkit.ChatColor; import org.bukkit.Material; @@ -14,7 +15,6 @@ import org.bukkit.configuration.ConfigurationSection; 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 java.io.IOException; @@ -165,22 +165,33 @@ public class TreasureConfig extends BukkitConfig { Material mat = Material.matchMaterial(materialName); if (mat == null) { reason.add("Potion format for " + FILENAME + " has changed"); + continue; } 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")); + PotionMeta potionMeta = (PotionMeta) item.getItemMeta(); + if (potionMeta == null) { + mcMMO.p.getLogger().severe("Item meta when adding potion to treasure was null, contact the mcMMO devs!"); + reason.add("Item meta when adding potion to treasure was null, contact the mcMMO devs!"); + continue; } + + String potionTypeStr; + potionTypeStr = 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)); + PotionType potionType = PotionUtil.matchPotionType(potionTypeStr, extended, upgraded); + + if (potionType == null) { + reason.add("Could not derive potion type from: " + potionTypeStr +", " + extended + ", " + upgraded); + continue; + } + + // Set the base potion type + // NOTE: extended/upgraded are ignored in 1.20.5 and later + PotionUtil.setBasePotionType(potionMeta, potionType, extended, upgraded); if (config.contains(type + "." + treasureName + ".Custom_Name")) { - itemMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', config.getString(type + "." + treasureName + ".Custom_Name"))); + potionMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', config.getString(type + "." + treasureName + ".Custom_Name"))); } if (config.contains(type + "." + treasureName + ".Lore")) { @@ -188,9 +199,9 @@ public class TreasureConfig extends BukkitConfig { for (String s : config.getStringList(type + "." + treasureName + ".Lore")) { lore.add(ChatColor.translateAlternateColorCodes('&', s)); } - itemMeta.setLore(lore); + potionMeta.setLore(lore); } - item.setItemMeta(itemMeta); + item.setItemMeta(potionMeta); } } else if (material != null) { item = new ItemStack(material, amount, data); diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java index 6f8c397e3..36e6c784c 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java @@ -253,68 +253,26 @@ public class FlatFileDataProcessor { } public static @NotNull ExpectedType getExpectedValueType(int dataIndex) throws IndexOutOfBoundsException { - switch(dataIndex) { - case USERNAME_INDEX: - return ExpectedType.STRING; - case 2: //Assumption: Used to be for something, no longer used - case 3: //Assumption: Used to be for something, no longer used - case 23: //Assumption: Used to be used for something, no longer used - case 33: //Assumption: Used to be used for something, no longer used - case HEALTHBAR: - case LEGACY_LAST_LOGIN: - return ExpectedType.IGNORED; - case SKILLS_MINING: - case SKILLS_REPAIR: - case SKILLS_UNARMED: - case SKILLS_HERBALISM: - case SKILLS_EXCAVATION: - case SKILLS_ARCHERY: - case SKILLS_SWORDS: - case SKILLS_AXES: - case SKILLS_WOODCUTTING: - case SKILLS_ACROBATICS: - case SKILLS_TAMING: - case SKILLS_FISHING: - case SKILLS_ALCHEMY: - case SKILLS_CROSSBOWS: - case SKILLS_TRIDENTS: - case COOLDOWN_BERSERK: - case COOLDOWN_GIGA_DRILL_BREAKER: - case COOLDOWN_TREE_FELLER: - case COOLDOWN_GREEN_TERRA: - case COOLDOWN_SERRATED_STRIKES: - case COOLDOWN_SKULL_SPLITTER: - case COOLDOWN_SUPER_BREAKER: - case COOLDOWN_BLAST_MINING: - case SCOREBOARD_TIPS: - case COOLDOWN_CHIMAERA_WING: - case COOLDOWN_SUPER_SHOTGUN: - case COOLDOWN_TRIDENTS: - case COOLDOWN_ARCHERY: - return ExpectedType.INTEGER; - case EXP_MINING: - case EXP_WOODCUTTING: - case EXP_REPAIR: - case EXP_UNARMED: - case EXP_HERBALISM: - case EXP_EXCAVATION: - case EXP_ARCHERY: - case EXP_SWORDS: - case EXP_AXES: - case EXP_ACROBATICS: - case EXP_TAMING: - case EXP_FISHING: - case EXP_ALCHEMY: - case EXP_CROSSBOWS: - case EXP_TRIDENTS: - return ExpectedType.FLOAT; - case UUID_INDEX: - return ExpectedType.UUID; - case OVERHAUL_LAST_LOGIN: - return ExpectedType.LONG; - } - - throw new IndexOutOfBoundsException(); + return switch (dataIndex) { + case USERNAME_INDEX -> ExpectedType.STRING; //Assumption: Used to be for something, no longer used + //Assumption: Used to be for something, no longer used + //Assumption: Used to be used for something, no longer used + //Assumption: Used to be used for something, no longer used + case 2, 3, 23, 33, HEALTHBAR, LEGACY_LAST_LOGIN -> ExpectedType.IGNORED; + case SKILLS_MINING, SKILLS_REPAIR, SKILLS_UNARMED, SKILLS_HERBALISM, SKILLS_EXCAVATION, SKILLS_ARCHERY, + SKILLS_SWORDS, SKILLS_AXES, SKILLS_WOODCUTTING, SKILLS_ACROBATICS, SKILLS_TAMING, SKILLS_FISHING, + SKILLS_ALCHEMY, SKILLS_CROSSBOWS, SKILLS_TRIDENTS, SKILLS_MACES, COOLDOWN_BERSERK, + COOLDOWN_GIGA_DRILL_BREAKER, COOLDOWN_TREE_FELLER, COOLDOWN_GREEN_TERRA, COOLDOWN_SERRATED_STRIKES, + COOLDOWN_SKULL_SPLITTER, COOLDOWN_SUPER_BREAKER, COOLDOWN_BLAST_MINING, SCOREBOARD_TIPS, + COOLDOWN_CHIMAERA_WING, COOLDOWN_SUPER_SHOTGUN, COOLDOWN_TRIDENTS, COOLDOWN_ARCHERY, COOLDOWN_MACES -> + ExpectedType.INTEGER; + case EXP_MINING, EXP_WOODCUTTING, EXP_REPAIR, EXP_UNARMED, EXP_HERBALISM, EXP_EXCAVATION, EXP_ARCHERY, + EXP_SWORDS, EXP_AXES, EXP_ACROBATICS, EXP_TAMING, EXP_FISHING, EXP_ALCHEMY, EXP_CROSSBOWS, + EXP_TRIDENTS, EXP_MACES -> ExpectedType.FLOAT; + case UUID_INDEX -> ExpectedType.UUID; + case OVERHAUL_LAST_LOGIN -> ExpectedType.LONG; + default -> throw new IndexOutOfBoundsException(); + }; } public @NotNull List getFlatFileDataContainers() { diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index d4d2e51b6..cd11065da 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -87,8 +87,11 @@ public final class FlatFileDatabaseManager implements DatabaseManager { public static final int COOLDOWN_SUPER_SHOTGUN = 49; public static final int COOLDOWN_TRIDENTS = 50; public static final int COOLDOWN_ARCHERY = 51; + public static final int EXP_MACES = 52; + public static final int SKILLS_MACES = 53; + public static final int COOLDOWN_MACES = 54; //Update this everytime new data is added - public static final int DATA_ENTRY_COUNT = COOLDOWN_ARCHERY + 1; + public static final int DATA_ENTRY_COUNT = COOLDOWN_MACES + 1; FlatFileDatabaseManager(@NotNull File usersFile, @NotNull Logger logger, long purgeTime, int startingLevel, boolean testing) { this.usersFile = usersFile; @@ -478,6 +481,18 @@ public final class FlatFileDatabaseManager implements DatabaseManager { appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.CROSSBOWS))).append(":"); appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.TRIDENTS))).append(":"); appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.TRIDENTS))).append(":"); + // public static final int COOLDOWN_SUPER_SHOTGUN = 49; + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SUPER_SHOTGUN))).append(":"); + // public static final int COOLDOWN_TRIDENTS = 50; + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.TRIDENTS_SUPER_ABILITY))).append(":"); + // public static final int COOLDOWN_ARCHERY = 51; + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.EXPLOSIVE_SHOT))).append(":"); + // public static final int EXP_MACES = 52; + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.MACES))).append(":"); + // public static final int SKILLS_MACES = 53; + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.MACES))).append(":"); + // public static final int COOLDOWN_MACES = 54; + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.MACES_SUPER_ABILITY))).append(":"); appendable.append("\r\n"); } @@ -987,6 +1002,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { List alchemy = new ArrayList<>(); List crossbows = new ArrayList<>(); List tridents = new ArrayList<>(); + List maces = new ArrayList<>(); BufferedReader in = null; String playerName = null; @@ -1022,6 +1038,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { powerLevel += putStat(woodcutting, playerName, skills.get(PrimarySkillType.WOODCUTTING)); powerLevel += putStat(crossbows, playerName, skills.get(PrimarySkillType.CROSSBOWS)); powerLevel += putStat(tridents, playerName, skills.get(PrimarySkillType.TRIDENTS)); + powerLevel += putStat(maces, playerName, skills.get(PrimarySkillType.MACES)); putStat(powerLevels, playerName, powerLevel); } @@ -1059,6 +1076,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { alchemy.sort(c); crossbows.sort(c); tridents.sort(c); + maces.sort(c); powerLevels.sort(c); playerStatHash.put(PrimarySkillType.MINING, mining); @@ -1076,6 +1094,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { playerStatHash.put(PrimarySkillType.ALCHEMY, alchemy); playerStatHash.put(PrimarySkillType.CROSSBOWS, crossbows); playerStatHash.put(PrimarySkillType.TRIDENTS, tridents); + playerStatHash.put(PrimarySkillType.MACES, maces); return LeaderboardStatus.UPDATED; } @@ -1239,6 +1258,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.ALCHEMY, EXP_ALCHEMY, username); tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.CROSSBOWS, EXP_CROSSBOWS, username); tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.TRIDENTS, EXP_TRIDENTS, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.MACES, EXP_MACES, username); // Taming - Unused tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SUPER_BREAKER, COOLDOWN_SUPER_BREAKER, username); @@ -1254,6 +1274,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.BLAST_MINING, COOLDOWN_BLAST_MINING, username); tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SUPER_SHOTGUN, COOLDOWN_SUPER_SHOTGUN, username); tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.TRIDENTS_SUPER_ABILITY, COOLDOWN_TRIDENTS, username); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.MACES_SUPER_ABILITY, COOLDOWN_MACES, username); UUID uuid; try { @@ -1343,6 +1364,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.ALCHEMY, SKILLS_ALCHEMY, username); tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.CROSSBOWS, SKILLS_CROSSBOWS, username); tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.TRIDENTS, SKILLS_TRIDENTS, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.MACES, SKILLS_MACES, username); return skills; } diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index 892a43721..3525f7211 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -169,7 +169,7 @@ public final class SQLDatabaseManager implements DatabaseManager { + "taming = 0 AND mining = 0 AND woodcutting = 0 AND repair = 0 " + "AND unarmed = 0 AND herbalism = 0 AND excavation = 0 AND " + "archery = 0 AND swords = 0 AND axes = 0 AND acrobatics = 0 " - + "AND fishing = 0 AND alchemy = 0 AND crossbows = 0 AND tridents = 0;"); + + "AND fishing = 0 AND alchemy = 0 AND crossbows = 0 AND tridents = 0 AND maces = 0;"); statement.executeUpdate("DELETE FROM `" + tablePrefix + "experience` WHERE NOT EXISTS (SELECT * FROM `" + tablePrefix + "skills` `s` WHERE `" + tablePrefix + "experience`.`user_id` = `s`.`user_id`)"); statement.executeUpdate("DELETE FROM `" + tablePrefix + "huds` WHERE NOT EXISTS (SELECT * FROM `" + tablePrefix + "skills` `s` WHERE `" + tablePrefix + "huds`.`user_id` = `s`.`user_id`)"); @@ -291,7 +291,7 @@ public final class SQLDatabaseManager implements DatabaseManager { + " taming = ?, mining = ?, repair = ?, woodcutting = ?" + ", unarmed = ?, herbalism = ?, excavation = ?" + ", archery = ?, swords = ?, axes = ?, acrobatics = ?" - + ", fishing = ?, alchemy = ?, crossbows = ?, tridents = ?, total = ? WHERE user_id = ?"); + + ", fishing = ?, alchemy = ?, crossbows = ?, tridents = ?, maces = ?, total = ? WHERE user_id = ?"); statement.setInt(1, profile.getSkillLevel(PrimarySkillType.TAMING)); statement.setInt(2, profile.getSkillLevel(PrimarySkillType.MINING)); statement.setInt(3, profile.getSkillLevel(PrimarySkillType.REPAIR)); @@ -307,11 +307,12 @@ public final class SQLDatabaseManager implements DatabaseManager { statement.setInt(13, profile.getSkillLevel(PrimarySkillType.ALCHEMY)); statement.setInt(14, profile.getSkillLevel(PrimarySkillType.CROSSBOWS)); statement.setInt(15, profile.getSkillLevel(PrimarySkillType.TRIDENTS)); + statement.setInt(16, profile.getSkillLevel(PrimarySkillType.MACES)); int total = 0; for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) total += profile.getSkillLevel(primarySkillType); - statement.setInt(16, total); - statement.setInt(17, id); + statement.setInt(17, total); + statement.setInt(18, id); success &= (statement.executeUpdate() != 0); statement.close(); if (!success) { @@ -323,7 +324,7 @@ public final class SQLDatabaseManager implements DatabaseManager { + " taming = ?, mining = ?, repair = ?, woodcutting = ?" + ", unarmed = ?, herbalism = ?, excavation = ?" + ", archery = ?, swords = ?, axes = ?, acrobatics = ?" - + ", fishing = ?, alchemy = ?, crossbows = ?, tridents = ? WHERE user_id = ?"); + + ", fishing = ?, alchemy = ?, crossbows = ?, tridents = ?, maces = ? WHERE user_id = ?"); statement.setInt(1, profile.getSkillXpLevel(PrimarySkillType.TAMING)); statement.setInt(2, profile.getSkillXpLevel(PrimarySkillType.MINING)); statement.setInt(3, profile.getSkillXpLevel(PrimarySkillType.REPAIR)); @@ -339,7 +340,8 @@ public final class SQLDatabaseManager implements DatabaseManager { statement.setInt(13, profile.getSkillXpLevel(PrimarySkillType.ALCHEMY)); statement.setInt(14, profile.getSkillXpLevel(PrimarySkillType.CROSSBOWS)); statement.setInt(15, profile.getSkillXpLevel(PrimarySkillType.TRIDENTS)); - statement.setInt(16, id); + statement.setInt(16, profile.getSkillXpLevel(PrimarySkillType.MACES)); + statement.setInt(17, id); success &= (statement.executeUpdate() != 0); statement.close(); if (!success) { @@ -350,7 +352,8 @@ public final class SQLDatabaseManager implements DatabaseManager { statement = connection.prepareStatement("UPDATE " + tablePrefix + "cooldowns SET " + " mining = ?, woodcutting = ?, unarmed = ?" + ", herbalism = ?, excavation = ?, swords = ?" - + ", axes = ?, blast_mining = ?, chimaera_wing = ?, crossbows = ?, tridents = ? WHERE user_id = ?"); + + ", axes = ?, blast_mining = ?, chimaera_wing = ?, crossbows = ?" + + ", tridents = ?, maces = ? WHERE user_id = ?"); statement.setLong(1, profile.getAbilityDATS(SuperAbilityType.SUPER_BREAKER)); statement.setLong(2, profile.getAbilityDATS(SuperAbilityType.TREE_FELLER)); statement.setLong(3, profile.getAbilityDATS(SuperAbilityType.BERSERK)); @@ -362,7 +365,8 @@ public final class SQLDatabaseManager implements DatabaseManager { statement.setLong(9, profile.getUniqueData(UniqueDataType.CHIMAERA_WING_DATS)); statement.setLong(10, profile.getAbilityDATS(SuperAbilityType.SUPER_SHOTGUN)); statement.setLong(11, profile.getAbilityDATS(SuperAbilityType.TRIDENTS_SUPER_ABILITY)); - statement.setInt(12, id); + statement.setLong(12, profile.getAbilityDATS(SuperAbilityType.MACES_SUPER_ABILITY)); + statement.setInt(13, id); success = (statement.executeUpdate() != 0); statement.close(); if (!success) { @@ -648,9 +652,9 @@ public final class SQLDatabaseManager implements DatabaseManager { statement = connection.prepareStatement( "SELECT " + - "s.taming, s.mining, s.repair, s.woodcutting, s.unarmed, s.herbalism, s.excavation, s.archery, s.swords, s.axes, s.acrobatics, s.fishing, s.alchemy, s.crossbows, s.tridents, " + - "e.taming, e.mining, e.repair, e.woodcutting, e.unarmed, e.herbalism, e.excavation, e.archery, e.swords, e.axes, e.acrobatics, e.fishing, e.alchemy, e.crossbows, e.tridents, " + - "c.taming, c.mining, c.repair, c.woodcutting, c.unarmed, c.herbalism, c.excavation, c.archery, c.swords, c.axes, c.acrobatics, c.blast_mining, c.chimaera_wing, c.crossbows, c.tridents, " + + "s.taming, s.mining, s.repair, s.woodcutting, s.unarmed, s.herbalism, s.excavation, s.archery, s.swords, s.axes, s.acrobatics, s.fishing, s.alchemy, s.crossbows, s.tridents, s.maces, " + + "e.taming, e.mining, e.repair, e.woodcutting, e.unarmed, e.herbalism, e.excavation, e.archery, e.swords, e.axes, e.acrobatics, e.fishing, e.alchemy, e.crossbows, e.tridents, e.maces, " + + "c.taming, c.mining, c.repair, c.woodcutting, c.unarmed, c.herbalism, c.excavation, c.archery, c.swords, c.axes, c.acrobatics, c.blast_mining, c.chimaera_wing, c.crossbows, c.tridents, c.maces, " + "h.mobhealthbar, h.scoreboardtips, u.uuid, u.`user` " + "FROM " + tablePrefix + "users u " + "JOIN " + tablePrefix + "skills s ON (u.id = s.user_id) " @@ -922,6 +926,7 @@ public final class SQLDatabaseManager implements DatabaseManager { + "`chimaera_wing` int(32) unsigned NOT NULL DEFAULT '0'," + "`crossbows` int(32) unsigned NOT NULL DEFAULT '0'," + "`tridents` int(32) unsigned NOT NULL DEFAULT '0'," + + "`maces` int(32) unsigned NOT NULL DEFAULT '0'," + "PRIMARY KEY (`user_id`)) " + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); tryClose(createStatement); @@ -950,6 +955,7 @@ public final class SQLDatabaseManager implements DatabaseManager { + "`alchemy` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," + "`crossbows` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," + "`tridents` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," + + "`maces` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," + "`total` int(10) unsigned NOT NULL DEFAULT "+totalLevel+"," + "PRIMARY KEY (`user_id`)) " + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); @@ -1017,20 +1023,24 @@ public final class SQLDatabaseManager implements DatabaseManager { tryClose(connection); } - String skills = "skills"; - String crossbows = "crossbows"; - String tridents = "tridents"; - String experience = "experience"; - String cooldowns = "cooldowns"; + final String skills = "skills"; + final String crossbows = "crossbows"; + final String tridents = "tridents"; + final String maces = "maces"; + final String experience = "experience"; + final String cooldowns = "cooldowns"; updateStructure(skills, crossbows, String.valueOf(32)); updateStructure(skills, tridents, String.valueOf(32)); + updateStructure(skills, maces, String.valueOf(32)); updateStructure(experience, crossbows, String.valueOf(10)); updateStructure(experience, tridents, String.valueOf(10)); + updateStructure(experience, maces, String.valueOf(10)); updateStructure(cooldowns, crossbows, String.valueOf(10)); updateStructure(cooldowns, tridents, String.valueOf(10)); + updateStructure(cooldowns, maces, String.valueOf(10)); } private void updateStructure(String tableName, String columnName, String columnSize) { @@ -1213,15 +1223,14 @@ public final class SQLDatabaseManager implements DatabaseManager { Map skillsXp = new EnumMap<>(PrimarySkillType.class); // Skill & XP Map skillsDATS = new EnumMap<>(SuperAbilityType.class); // Ability & Cooldown Map uniqueData = new EnumMap<>(UniqueDataType.class); //Chimaera wing cooldown and other misc info - MobHealthbarType mobHealthbarType; UUID uuid; int scoreboardTipsShown; final int OFFSET_SKILLS = 0; // TODO update these numbers when the query // changes (a new skill is added) - final int OFFSET_XP = 15; - final int OFFSET_DATS = 28; - final int OFFSET_OTHER = 41; + final int OFFSET_XP = 16; + final int OFFSET_DATS = 29; + final int OFFSET_OTHER = 42; skills.put(PrimarySkillType.TAMING, result.getInt(OFFSET_SKILLS + 1)); skills.put(PrimarySkillType.MINING, result.getInt(OFFSET_SKILLS + 2)); @@ -1238,6 +1247,7 @@ public final class SQLDatabaseManager implements DatabaseManager { skills.put(PrimarySkillType.ALCHEMY, result.getInt(OFFSET_SKILLS + 13)); skills.put(PrimarySkillType.CROSSBOWS, result.getInt(OFFSET_SKILLS + 14)); skills.put(PrimarySkillType.TRIDENTS, result.getInt(OFFSET_SKILLS + 15)); + skills.put(PrimarySkillType.MACES, result.getInt(OFFSET_SKILLS + 16)); skillsXp.put(PrimarySkillType.TAMING, result.getFloat(OFFSET_XP + 1)); skillsXp.put(PrimarySkillType.MINING, result.getFloat(OFFSET_XP + 2)); @@ -1254,6 +1264,7 @@ public final class SQLDatabaseManager implements DatabaseManager { skillsXp.put(PrimarySkillType.ALCHEMY, result.getFloat(OFFSET_XP + 13)); skillsXp.put(PrimarySkillType.CROSSBOWS, result.getFloat(OFFSET_XP + 14)); skillsXp.put(PrimarySkillType.TRIDENTS, result.getFloat(OFFSET_XP + 15)); + skillsXp.put(PrimarySkillType.MACES, result.getFloat(OFFSET_XP + 16)); // Taming - Unused - result.getInt(OFFSET_DATS + 1) skillsDATS.put(SuperAbilityType.SUPER_BREAKER, result.getInt(OFFSET_DATS + 2)); @@ -1270,6 +1281,7 @@ public final class SQLDatabaseManager implements DatabaseManager { uniqueData.put(UniqueDataType.CHIMAERA_WING_DATS, result.getInt(OFFSET_DATS + 13)); skillsDATS.put(SuperAbilityType.SUPER_SHOTGUN, result.getInt(OFFSET_DATS + 14)); skillsDATS.put(SuperAbilityType.TRIDENTS_SUPER_ABILITY, result.getInt(OFFSET_DATS + 15)); + skillsDATS.put(SuperAbilityType.MACES_SUPER_ABILITY, result.getInt(OFFSET_DATS + 16)); try { scoreboardTipsShown = result.getInt(OFFSET_OTHER + 2); diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtil.java b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtil.java index 285c501fd..bc1c19cb6 100644 --- a/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtil.java +++ b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtil.java @@ -56,67 +56,29 @@ public class FlatFileDataUtil { * @return the "zero" initialized data corresponding to the index */ public static @NotNull String getZeroInitialisedData(int index, int startingLevel) throws IndexOutOfBoundsException { - switch(index) { - case USERNAME_INDEX: - return LEGACY_INVALID_OLD_USERNAME; //We'll keep using this value for legacy compatibility reasons (not sure if needed but don't care) - case 2: //Assumption: Used to be for something, no longer used - case 3: //Assumption: Used to be for something, no longer used - case 23: //Assumption: Used to be used for something, no longer used - case 33: //Assumption: Used to be used for something, no longer used - case LEGACY_LAST_LOGIN: - case HEALTHBAR: - return "IGNORED"; - case SKILLS_MINING: - case SKILLS_REPAIR: - case SKILLS_UNARMED: - case SKILLS_HERBALISM: - case SKILLS_EXCAVATION: - case SKILLS_ARCHERY: - case SKILLS_SWORDS: - case SKILLS_AXES: - case SKILLS_WOODCUTTING: - case SKILLS_ACROBATICS: - case SKILLS_TAMING: - case SKILLS_FISHING: - case SKILLS_ALCHEMY: - case SKILLS_CROSSBOWS: - case SKILLS_TRIDENTS: - return String.valueOf(startingLevel); - case OVERHAUL_LAST_LOGIN: - return String.valueOf(-1L); - case COOLDOWN_BERSERK: - case COOLDOWN_GIGA_DRILL_BREAKER: - case COOLDOWN_TREE_FELLER: - case COOLDOWN_GREEN_TERRA: - case COOLDOWN_SERRATED_STRIKES: - case COOLDOWN_SKULL_SPLITTER: - case COOLDOWN_SUPER_BREAKER: - case COOLDOWN_BLAST_MINING: - case COOLDOWN_SUPER_SHOTGUN: - case COOLDOWN_TRIDENTS: - case COOLDOWN_ARCHERY: - case SCOREBOARD_TIPS: - case COOLDOWN_CHIMAERA_WING: - case EXP_MINING: - case EXP_WOODCUTTING: - case EXP_REPAIR: - case EXP_UNARMED: - case EXP_HERBALISM: - case EXP_EXCAVATION: - case EXP_ARCHERY: - case EXP_SWORDS: - case EXP_AXES: - case EXP_ACROBATICS: - case EXP_TAMING: - case EXP_FISHING: - case EXP_ALCHEMY: - case EXP_CROSSBOWS: - case EXP_TRIDENTS: - return "0"; - case UUID_INDEX: - throw new IndexOutOfBoundsException(); //TODO: Add UUID recovery? Might not even be worth it. - } + //TODO: Add UUID recovery? Might not even be worth it. + return switch (index) { + case USERNAME_INDEX -> + LEGACY_INVALID_OLD_USERNAME; //We'll keep using this value for legacy compatibility reasons (not sure if needed but don't care) + //Assumption: Used to be for something, no longer used + //Assumption: Used to be for something, no longer used + //Assumption: Used to be used for something, no longer used + //Assumption: Used to be used for something, no longer used + case 2, 3, 23, 33, LEGACY_LAST_LOGIN, HEALTHBAR -> "IGNORED"; + case SKILLS_MINING, SKILLS_REPAIR, SKILLS_UNARMED, SKILLS_HERBALISM, SKILLS_EXCAVATION, SKILLS_ARCHERY, + SKILLS_SWORDS, SKILLS_AXES, SKILLS_WOODCUTTING, SKILLS_ACROBATICS, SKILLS_TAMING, SKILLS_FISHING, + SKILLS_ALCHEMY, SKILLS_CROSSBOWS, SKILLS_TRIDENTS, SKILLS_MACES -> String.valueOf(startingLevel); + case OVERHAUL_LAST_LOGIN -> String.valueOf(-1L); + case COOLDOWN_BERSERK, COOLDOWN_GIGA_DRILL_BREAKER, COOLDOWN_TREE_FELLER, COOLDOWN_GREEN_TERRA, + COOLDOWN_SERRATED_STRIKES, COOLDOWN_SKULL_SPLITTER, COOLDOWN_SUPER_BREAKER, COOLDOWN_BLAST_MINING, + COOLDOWN_SUPER_SHOTGUN, COOLDOWN_TRIDENTS, COOLDOWN_ARCHERY, COOLDOWN_MACES, SCOREBOARD_TIPS, COOLDOWN_CHIMAERA_WING, + EXP_MINING, EXP_WOODCUTTING, EXP_REPAIR, EXP_UNARMED, EXP_HERBALISM, EXP_EXCAVATION, EXP_ARCHERY, + EXP_SWORDS, EXP_AXES, EXP_ACROBATICS, EXP_TAMING, EXP_FISHING, EXP_ALCHEMY, EXP_CROSSBOWS, + EXP_TRIDENTS, EXP_MACES -> "0"; + case UUID_INDEX -> + throw new IndexOutOfBoundsException(); //TODO: Add UUID recovery? Might not even be worth it. + default -> throw new IndexOutOfBoundsException(); + }; - throw new IndexOutOfBoundsException(); } } diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index ea9b09f15..d2653718f 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -32,6 +32,7 @@ import com.gmail.nossr50.skills.crossbows.CrossbowsManager; import com.gmail.nossr50.skills.excavation.ExcavationManager; import com.gmail.nossr50.skills.fishing.FishingManager; import com.gmail.nossr50.skills.herbalism.HerbalismManager; +import com.gmail.nossr50.skills.maces.MacesManager; import com.gmail.nossr50.skills.mining.MiningManager; import com.gmail.nossr50.skills.repair.RepairManager; import com.gmail.nossr50.skills.salvage.SalvageManager; @@ -220,6 +221,9 @@ public class McMMOPlayer implements Identified { case WOODCUTTING: skillManagers.put(primarySkillType, new WoodcuttingManager(this)); break; + case MACES: + skillManagers.put(primarySkillType, new MacesManager(this)); + break; default: throw new InvalidSkillException("The skill named has no manager! Contact the devs!"); } @@ -313,6 +317,10 @@ public class McMMOPlayer implements Identified { return (TridentsManager) skillManagers.get(PrimarySkillType.TRIDENTS); } + public MacesManager getMacesManager() { + return (MacesManager) skillManagers.get(PrimarySkillType.MACES); + } + public ExcavationManager getExcavationManager() { return (ExcavationManager) skillManagers.get(PrimarySkillType.EXCAVATION); } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java index 9dfecd55b..31f315c1f 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java @@ -20,6 +20,7 @@ public enum PrimarySkillType { EXCAVATION, FISHING, HERBALISM, + MACES, MINING, REPAIR, SALVAGE, diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java index 48910bb77..1cf028e88 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java @@ -57,6 +57,9 @@ public enum SubSkillType { HERBALISM_HYLIAN_LUCK, HERBALISM_SHROOM_THUMB, + /* Maces */ + MACES_MACES_LIMIT_BREAK(10), + /* Mining */ MINING_BIGGER_BOMBS(1), MINING_BLAST_MINING(8), diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java index f876ce53e..f83bce316 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java @@ -72,19 +72,26 @@ public enum SuperAbilityType { "Swords.Skills.SS.Other.Off", "Swords.SubSkill.SerratedStrikes.Name"), SUPER_SHOTGUN( - null, - null, - "Crossbows.Skills.SSG.Other.On", - "Crossbows.Skills.SSG.Refresh", - null, - "Crossbows.SubSkill.SuperShotgun.Name"), + "Placeholder", + "Placeholder", + "Placeholder", + "Placeholder", + "Placeholder", + "Placeholder"), TRIDENTS_SUPER_ABILITY( - "Tridents.Skills.TA.On", - "Tridents.Skills.TA.Off", - "Tridents.Skills.TA.Other.On", - "Tridents.Skills.TA.Refresh", - "Tridents.Skills.TA.Other.Off", - "Tridents.SubSkill.TridentAbility.Name"), + "Placeholder", + "Placeholder", + "Placeholder", + "Placeholder", + "Placeholder", + "Placeholder"), + MACES_SUPER_ABILITY( + "Placeholder", + "Placeholder", + "Placeholder", + "Placeholder", + "Placeholder", + "Placeholder"), /** * Has cooldown - but has to share a skill with Super Breaker, so needs special treatment @@ -209,6 +216,7 @@ public enum SuperAbilityType { case SUPER_SHOTGUN -> Permissions.superShotgun(player); case TREE_FELLER -> Permissions.treeFeller(player); case TRIDENTS_SUPER_ABILITY -> Permissions.tridentsSuper(player); + case MACES_SUPER_ABILITY -> Permissions.macesSuper(player); }; } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/ToolType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/ToolType.java index dd61867d5..69422c1a2 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/ToolType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/ToolType.java @@ -13,7 +13,8 @@ public enum ToolType { SWORD("Swords.Ability.Lower", "Swords.Ability.Ready"), CROSSBOW("Crossbows.Ability.Lower", "Crossbows.Ability.Ready"), BOW("Archery.Ability.Lower", "Archery.Ability.Ready"), - TRIDENTS("Tridents.Ability.Lower", "Tridents.Ability.Ready"); + TRIDENTS("Tridents.Ability.Lower", "Tridents.Ability.Ready"), + MACES("Maces.Ability.Lower", "Maces.Ability.Ready"); private final String lowerTool; private final String raiseTool; @@ -45,6 +46,8 @@ public enum ToolType { return ItemUtils.isCrossbow(itemStack); case TRIDENTS: return ItemUtils.isTrident(itemStack); + case MACES: + return ItemUtils.isMace(itemStack); case FISTS: return itemStack.getType() == Material.AIR; diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/alchemy/AlchemyPotion.java b/src/main/java/com/gmail/nossr50/datatypes/skills/alchemy/AlchemyPotion.java index c767004df..c2e2ee656 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/alchemy/AlchemyPotion.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/alchemy/AlchemyPotion.java @@ -1,167 +1,120 @@ package com.gmail.nossr50.datatypes.skills.alchemy; -import com.gmail.nossr50.config.skills.alchemy.PotionConfig; -import org.bukkit.Color; +import com.gmail.nossr50.mcMMO; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.PotionMeta; -import org.bukkit.potion.Potion; -import org.bukkit.potion.PotionData; -import org.bukkit.potion.PotionEffect; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.util.List; +import java.util.ArrayList; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; + +import static com.gmail.nossr50.util.PotionUtil.samePotionType; +import static java.util.Objects.requireNonNull; public class AlchemyPotion { - private final Material material; - private PotionData data; - private String name; - private List lore; - private List effects; - private Color color; - private Map children; + private final ItemStack potion; + private final Map alchemyPotionChildren; - public AlchemyPotion(Material material, PotionData data, String name, List lore, List effects, Color color, Map children) { - this.material = material; - this.data = data; - this.lore = lore; - this.name = name; - this.effects = effects; - this.children = children; - this.color = color; + public AlchemyPotion(ItemStack potion, Map alchemyPotionChildren) { + this.potion = requireNonNull(potion, "potion cannot be null"); + this.alchemyPotionChildren = requireNonNull(alchemyPotionChildren, "alchemyPotionChildren cannot be null"); } - public String toString() { - return "AlchemyPotion{" + data + ", " + name + ", Effects[" + effects.size() + "], Children[" + children.size() + "]}"; - } - - public ItemStack toItemStack(int amount) { - ItemStack potion = new ItemStack(material, amount); - PotionMeta meta = (PotionMeta) potion.getItemMeta(); - - meta.setBasePotionData(data); - if (this.getName() != null) { - meta.setDisplayName(this.getName()); - } - - if (this.getLore() != null && !this.getLore().isEmpty()) { - meta.setLore(this.getLore()); - } - - if (!this.getEffects().isEmpty()) { - for (PotionEffect effect : this.getEffects()) { - meta.addCustomEffect(effect, true); - } - } - - if (this.getColor() != null) { - meta.setColor(this.getColor()); - } - - potion.setItemMeta(meta); + public @NotNull ItemStack toItemStack(int amount) { + final ItemStack potion = new ItemStack(this.potion); + potion.setAmount(Math.max(1, amount)); return potion; } - public Material getMaterial() { - return material; + public Map getAlchemyPotionChildren() { + return alchemyPotionChildren; } - public Potion toPotion(int amount) { - return Potion.fromItemStack(this.toItemStack(amount)); - } - - public PotionData getData() { - return data; - } - - public void setData(PotionData data) { - this.data = data; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public List getLore() { - return lore; - } - - public void setLore(List lore) { - this.lore = lore; - } - - public List getEffects() { - return effects; - } - - public void setEffects(List effects) { - this.effects = effects; - } - - public Color getColor() { - return color; - } - - public void setColor(Color color) { - this.color = color; - } - - public Map getChildren() { - return children; - } - - public void setChildren(Map children) { - this.children = children; - } - - public AlchemyPotion getChild(ItemStack ingredient) { - if (!children.isEmpty()) { - for (Entry child : children.entrySet()) { + public @Nullable AlchemyPotion getChild(@NotNull ItemStack ingredient) { + if (!alchemyPotionChildren.isEmpty()) { + for (Entry child : alchemyPotionChildren.entrySet()) { if (ingredient.isSimilar(child.getKey())) { - return PotionConfig.getInstance().getPotion(child.getValue()); + return mcMMO.p.getPotionConfig().getPotion(child.getValue()); } } } return null; } - public boolean isSimilar(ItemStack item) { - if (item.getType() != material) { + public boolean isSimilarPotion(@NotNull ItemStack otherPotion) { + requireNonNull(otherPotion, "otherPotion cannot be null"); + // TODO: Investigate? + // We currently don't compare base potion effects, likely because they are derived from the potion type + if (otherPotion.getType() != potion.getType() || !otherPotion.hasItemMeta()) { return false; } - if (!item.hasItemMeta()) { - return false; - } - PotionMeta meta = (PotionMeta) item.getItemMeta(); - PotionData that = meta.getBasePotionData(); - if (data.getType() != that.getType()) { - return false; - } - if (data.isExtended() != that.isExtended()) { - return false; - } - if (data.isUpgraded() != that.isUpgraded()) { - return false; - } - for (PotionEffect effect : effects) { - if (!meta.hasCustomEffect(effect.getType())) { + + final PotionMeta otherPotionMeta = (PotionMeta) otherPotion.getItemMeta(); + + // all custom effects must be present + for (var effect : getAlchemyPotionMeta().getCustomEffects()) { + if (!otherPotionMeta.hasCustomEffect(effect.getType())) { return false; } } - if (!meta.hasLore() && !lore.isEmpty()) { + + if (!samePotionType(getAlchemyPotionMeta(), otherPotionMeta)) { return false; } - if (!(lore.isEmpty() && !meta.hasLore()) && !meta.getLore().equals(lore)) { + + if (!otherPotionMeta.hasLore() && getAlchemyPotionMeta().hasLore() + || !getAlchemyPotionMeta().hasLore() && otherPotionMeta.hasLore()) { return false; } - if (!meta.hasDisplayName() && name != null) { + + if (otherPotionMeta.hasLore() && getAlchemyPotionMeta().hasLore() + && !otherPotionMeta.getLore().equals(getAlchemyPotionMeta().getLore())) { return false; } - return (name == null && !meta.hasDisplayName()) || meta.getDisplayName().equals(name); + + if (!otherPotionMeta.hasDisplayName() && getAlchemyPotionMeta().hasDisplayName()) { + return false; + } + + var alchemyPotionName = getAlchemyPotionMeta().hasDisplayName() ? getAlchemyPotionMeta().getDisplayName() : null; + + return (alchemyPotionName == null && !otherPotionMeta.hasDisplayName()) || otherPotionMeta.getDisplayName().equals(alchemyPotionName); + } + + public PotionMeta getAlchemyPotionMeta() { + return (PotionMeta) potion.getItemMeta(); + } + + public boolean isSplash() { + return potion.getType() == Material.SPLASH_POTION; + } + + public boolean isLingering() { + return potion.getType() == Material.LINGERING_POTION; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AlchemyPotion that = (AlchemyPotion) o; + return Objects.equals(potion, that.potion) && Objects.equals(alchemyPotionChildren, that.alchemyPotionChildren); + } + + @Override + public int hashCode() { + return Objects.hash(potion, alchemyPotionChildren); + } + + @Override + public String toString() { + return "AlchemyPotion{" + + "potion=" + potion + + ", alchemyPotionChildren=" + alchemyPotionChildren + + '}'; } } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/alchemy/PotionStage.java b/src/main/java/com/gmail/nossr50/datatypes/skills/alchemy/PotionStage.java index fe2778eed..4515835d1 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/alchemy/PotionStage.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/alchemy/PotionStage.java @@ -1,11 +1,10 @@ package com.gmail.nossr50.datatypes.skills.alchemy; -import org.bukkit.Material; -import org.bukkit.potion.PotionData; +import com.gmail.nossr50.util.PotionUtil; +import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionType; -import java.util.List; +import static com.gmail.nossr50.util.PotionUtil.*; public enum PotionStage { FIVE(5), @@ -43,27 +42,27 @@ public enum PotionStage { return potionStage; } - private static boolean isWaterBottle(AlchemyPotion input) { - return input.getData().getType() == PotionType.WATER; + private static boolean isWaterBottle(AlchemyPotion alchemyPotion) { + return isPotionTypeWater(alchemyPotion.getAlchemyPotionMeta()); } public static PotionStage getPotionStage(AlchemyPotion alchemyPotion) { - PotionData data = alchemyPotion.getData(); - List effects = alchemyPotion.getEffects(); + final PotionMeta potionMeta = alchemyPotion.getAlchemyPotionMeta(); int stage = 1; // Check if potion has an effect of any sort - if (data.getType().getEffectType() != null || !effects.isEmpty()) { + if (!potionMeta.getCustomEffects().isEmpty() + || PotionUtil.hasBasePotionEffects(potionMeta)) { stage++; } // Check if potion has a glowstone dust amplifier // Else check if the potion has a custom effect with an amplifier added by mcMMO - if (data.isUpgraded()) { + if (isStrong(potionMeta)) { stage++; - } else if(!effects.isEmpty()) { - for (PotionEffect effect : effects){ + } else if (!potionMeta.getCustomEffects().isEmpty()) { + for (PotionEffect effect : potionMeta.getCustomEffects()){ if(effect.getAmplifier() > 0){ stage++; break; @@ -72,12 +71,12 @@ public enum PotionStage { } // Check if potion has a redstone dust amplifier - if (data.isExtended()) { + if (isLong(potionMeta)) { stage++; } // Check if potion has a gunpowder amplifier - if (alchemyPotion.getMaterial() == Material.SPLASH_POTION || alchemyPotion.getMaterial() == Material.LINGERING_POTION) { + if (alchemyPotion.isSplash() || alchemyPotion.isLingering()) { stage++; } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java index 15ea49679..1ea4692a0 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java @@ -26,7 +26,6 @@ import net.kyori.adventure.text.TextComponent; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.SoundCategory; -import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.EventPriority; @@ -317,7 +316,7 @@ public class Roll extends AcrobaticsSubSkill { ItemStack boots = player.getInventory().getBoots(); float xp = (float) (damage * (isRoll ? ExperienceConfig.getInstance().getRollXPModifier() : ExperienceConfig.getInstance().getFallXPModifier())); - if (boots != null && boots.containsEnchantment(Enchantment.PROTECTION_FALL)) { + if (boots != null && boots.containsEnchantment(mcMMO.p.getEnchantmentMapper().getFeatherFalling())) { xp *= ExperienceConfig.getInstance().getFeatherFallXPModifier(); } diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index 18edee783..d309669fc 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -120,7 +120,7 @@ public class EntityListener implements Listener { if (bow == null) return; - if (bow.containsEnchantment(Enchantment.ARROW_INFINITE)) { + if (bow.containsEnchantment(mcMMO.p.getEnchantmentMapper().getInfinity())) { projectile.setMetadata(MetadataConstants.METADATA_KEY_INF_ARROW, MetadataConstants.MCMMO_METADATA_VALUE); } diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index a8c1c8601..3a806e8be 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -78,8 +78,6 @@ import java.util.ArrayList; import java.util.List; public class mcMMO extends JavaPlugin { - - /* Managers & Services */ private static PlatformManager platformManager; private static MetadataService metadataService; @@ -140,21 +138,14 @@ public class mcMMO extends JavaPlugin { private GeneralConfig generalConfig; private AdvancedConfig advancedConfig; private PartyConfig partyConfig; + private PotionConfig potionConfig; private CustomItemSupportConfig customItemSupportConfig; + private EnchantmentMapper enchantmentMapper; + private AttributeMapper attributeMapper; private FoliaLib foliaLib; private PartyManager partyManager; -// private RepairConfig repairConfig; -// private SalvageConfig salvageConfig; -// private PersistentDataConfig persistentDataConfig; -// private ChatConfig chatConfig; -// private CoreSkillsConfig coreSkillsConfig; -// private RankConfig rankConfig; -// private TreasureConfig treasureConfig; -// private FishingTreasureConfig fishingTreasureConfig; -// private SoundConfig soundConfig; - public mcMMO() { p = this; } @@ -207,8 +198,11 @@ public class mcMMO extends JavaPlugin { modManager = new ModManager(); - //Init Material Maps + // Init Material Maps materialMapStore = new MaterialMapStore(); + // Init compatibility mappers + enchantmentMapper = new EnchantmentMapper(this); + attributeMapper = new AttributeMapper(this); loadConfigFiles(); @@ -567,7 +561,11 @@ public class mcMMO extends JavaPlugin { FishingTreasureConfig.getInstance(); HiddenConfig.getInstance(); mcMMO.p.getAdvancedConfig(); - PotionConfig.getInstance(); + + // init potion config + potionConfig = new PotionConfig(); + potionConfig.loadPotions(); + CoreSkillsConfig.getInstance(); SoundConfig.getInstance(); RankConfig.getInstance(); @@ -812,6 +810,18 @@ public class mcMMO extends JavaPlugin { return customItemSupportConfig; } + public PotionConfig getPotionConfig() { + return potionConfig; + } + + public EnchantmentMapper getEnchantmentMapper() { + return enchantmentMapper; + } + + public AttributeMapper getAttributeMapper() { + return attributeMapper; + } + public @NotNull FoliaLib getFoliaLib() { return foliaLib; } diff --git a/src/main/java/com/gmail/nossr50/metadata/ItemMetadataService.java b/src/main/java/com/gmail/nossr50/metadata/ItemMetadataService.java index f1d1e9471..a6734a53e 100644 --- a/src/main/java/com/gmail/nossr50/metadata/ItemMetadataService.java +++ b/src/main/java/com/gmail/nossr50/metadata/ItemMetadataService.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.metadata; import com.gmail.nossr50.mcMMO; -import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.persistence.PersistentDataContainer; @@ -74,12 +73,12 @@ public class ItemMetadataService { if(itemMeta != null) { //TODO: can be optimized - if (itemMeta.hasEnchant(Enchantment.DIG_SPEED)) { - itemMeta.removeEnchant(Enchantment.DIG_SPEED); + if (itemMeta.hasEnchant(mcMMO.p.getEnchantmentMapper().getEfficiency())) { + itemMeta.removeEnchant(mcMMO.p.getEnchantmentMapper().getEfficiency()); } if (originalSpeed > 0) { - itemMeta.addEnchant(Enchantment.DIG_SPEED, originalSpeed, true); + itemMeta.addEnchant(mcMMO.p.getEnchantmentMapper().getEfficiency(), originalSpeed, true); } PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer(); diff --git a/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyManager.java b/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyManager.java index 16b1dd2ac..4224ad123 100644 --- a/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyManager.java +++ b/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyManager.java @@ -1,13 +1,13 @@ package com.gmail.nossr50.skills.alchemy; import com.gmail.nossr50.config.experience.ExperienceConfig; -import com.gmail.nossr50.config.skills.alchemy.PotionConfig; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.experience.XPGainSource; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.alchemy.PotionStage; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.text.StringUtils; @@ -27,7 +27,7 @@ public class AlchemyManager extends SkillManager { } public List getIngredients() { - return PotionConfig.getInstance().getIngredients(getTier()); + return mcMMO.p.getPotionConfig().getIngredients(getTier()); } public String getIngredientList() { diff --git a/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyPotionBrewer.java b/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyPotionBrewer.java index 2a11b0159..a41ea2f2f 100644 --- a/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyPotionBrewer.java +++ b/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyPotionBrewer.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.skills.alchemy; -import com.gmail.nossr50.config.skills.alchemy.PotionConfig; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.alchemy.AlchemyPotion; import com.gmail.nossr50.datatypes.skills.alchemy.PotionStage; @@ -36,7 +35,7 @@ public final class AlchemyPotionBrewer { continue; } - if (getChildPotion(PotionConfig.getInstance().getPotion(contents[i]), contents[Alchemy.INGREDIENT_SLOT]) != null) { + if (getChildPotion(mcMMO.p.getPotionConfig().getPotion(contents[i]), contents[Alchemy.INGREDIENT_SLOT]) != null) { return true; } } @@ -94,12 +93,11 @@ public final class AlchemyPotionBrewer { } private static List getValidIngredients(Player player) { - if(player == null || UserManager.getPlayer(player) == null) - { - return PotionConfig.getInstance().getIngredients(1); + if(player == null || UserManager.getPlayer(player) == null) { + return mcMMO.p.getPotionConfig().getIngredients(1); } - return PotionConfig.getInstance().getIngredients(!Permissions.isSubSkillEnabled(player, SubSkillType.ALCHEMY_CONCOCTIONS) ? 1 : UserManager.getPlayer(player).getAlchemyManager().getTier()); + return mcMMO.p.getPotionConfig().getIngredients(!Permissions.isSubSkillEnabled(player, SubSkillType.ALCHEMY_CONCOCTIONS) ? 1 : UserManager.getPlayer(player).getAlchemyManager().getTier()); } public static void finishBrewing(BlockState brewingStand, Player player, boolean forced) { @@ -120,11 +118,11 @@ public final class AlchemyPotionBrewer { for (int i = 0; i < 3; i++) { ItemStack item = inventory.getItem(i); - if (isEmpty(item) || item.getType() == Material.GLASS_BOTTLE || !PotionConfig.getInstance().isValidPotion(item)) { + if (isEmpty(item) || item.getType() == Material.GLASS_BOTTLE || !mcMMO.p.getPotionConfig().isValidPotion(item)) { continue; } - AlchemyPotion input = PotionConfig.getInstance().getPotion(item); + AlchemyPotion input = mcMMO.p.getPotionConfig().getPotion(item); AlchemyPotion output = input.getChild(ingredient); inputList.set(i, input); diff --git a/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java b/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java index 7cc028e8f..16237f548 100644 --- a/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java +++ b/src/main/java/com/gmail/nossr50/skills/archery/ArcheryManager.java @@ -18,7 +18,8 @@ import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; + +import static com.gmail.nossr50.util.PotionEffectMapper.getNausea; public class ArcheryManager extends SkillManager { public ArcheryManager(McMMOPlayer mcMMOPlayer) { @@ -95,10 +96,8 @@ public class ArcheryManager extends SkillManager { Location dazedLocation = defender.getLocation(); dazedLocation.setPitch(90 - Misc.getRandom().nextInt(181)); -// defender.teleport(dazedLocation); mcMMO.p.getFoliaLib().getImpl().teleportAsync(defender, dazedLocation); - defender.addPotionEffect(new PotionEffect(PotionEffectType.CONFUSION, 20 * 10, 10)); - + defender.addPotionEffect(new PotionEffect(getNausea(), 20 * 10, 10)); if (NotificationManager.doesPlayerUseNotifications(defender)) { NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, "Combat.TouchedFuzzy"); diff --git a/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java b/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java index 6063add73..5d0e24314 100644 --- a/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java @@ -573,11 +573,13 @@ public class FishingManager extends SkillManager { int luck; if (getPlayer().getInventory().getItemInMainHand().getType() == Material.FISHING_ROD) { - luck = getPlayer().getInventory().getItemInMainHand().getEnchantmentLevel(Enchantment.LUCK); + luck = getPlayer().getInventory().getItemInMainHand().getEnchantmentLevel( + mcMMO.p.getEnchantmentMapper().getLuckOfTheSea()); } else { // We know something was caught, so if the rod wasn't in the main hand it must be in the offhand - luck = getPlayer().getInventory().getItemInOffHand().getEnchantmentLevel(Enchantment.LUCK); + luck = getPlayer().getInventory().getItemInOffHand().getEnchantmentLevel( + mcMMO.p.getEnchantmentMapper().getLuckOfTheSea()); } // Rather than subtracting luck (and causing a minimum 3% chance for every drop), scale by luck. diff --git a/src/main/java/com/gmail/nossr50/skills/maces/MacesManager.java b/src/main/java/com/gmail/nossr50/skills/maces/MacesManager.java new file mode 100644 index 000000000..194c1400b --- /dev/null +++ b/src/main/java/com/gmail/nossr50/skills/maces/MacesManager.java @@ -0,0 +1,21 @@ +package com.gmail.nossr50.skills.maces; + +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.datatypes.skills.ToolType; +import com.gmail.nossr50.skills.SkillManager; +import com.gmail.nossr50.util.Permissions; + +public class MacesManager extends SkillManager { + public MacesManager(McMMOPlayer mmoPlayer) { + super(mmoPlayer, PrimarySkillType.MACES); + } + + /** + * Checks if the player can activate the Super Ability for Maces + * @return true if the player can activate the Super Ability, false otherwise + */ + public boolean canActivateAbility() { + return mmoPlayer.getToolPreparationMode(ToolType.MACES) && Permissions.macesSuper(getPlayer()); + } +} diff --git a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java index dcee2e0bd..cd793aa71 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java @@ -233,7 +233,7 @@ public class TamingManager extends SkillManager { // Bred mules & donkeys can actually have horse-like stats, but llamas cannot. if (beast instanceof AbstractHorse horseLikeCreature && !(beast instanceof Llama)) { - AttributeInstance jumpAttribute = horseLikeCreature.getAttribute(Attribute.HORSE_JUMP_STRENGTH); + AttributeInstance jumpAttribute = horseLikeCreature.getAttribute(mcMMO.p.getAttributeMapper().getHorseJumpStrength()); if(jumpAttribute != null) { double jumpStrength = jumpAttribute.getValue(); diff --git a/src/main/java/com/gmail/nossr50/util/AttributeMapper.java b/src/main/java/com/gmail/nossr50/util/AttributeMapper.java new file mode 100644 index 000000000..2d15d55bd --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/AttributeMapper.java @@ -0,0 +1,45 @@ +package com.gmail.nossr50.util; + +import com.gmail.nossr50.mcMMO; +import org.bukkit.Registry; +import org.bukkit.attribute.Attribute; + +public class AttributeMapper { + private final mcMMO pluginRef; + private static final String GENERIC_JUMP_STRENGTH = "generic.jump_strength"; + private static final String HORSE_JUMP_STRENGTH = "horse.jump_strength"; + private final Attribute horseJumpStrength; + + public AttributeMapper(mcMMO pluginRef) { + this.pluginRef = pluginRef; + this.horseJumpStrength = initHorseJumpStrength(); + } + + private Attribute initHorseJumpStrength() { + // TODO: Use modern matching? +// if (Registry.ATTRIBUTE.match(GENERIC_JUMP_STRENGTH) != null) { +// return Registry.ATTRIBUTE.match(GENERIC_JUMP_STRENGTH); +// } +// +// if (Registry.ATTRIBUTE.match(HORSE_JUMP_STRENGTH) != null) { +// return Registry.ATTRIBUTE.match(HORSE_JUMP_STRENGTH); +// } + + for (Attribute attr : Registry.ATTRIBUTE) { + if (attr.getKey().getKey().equalsIgnoreCase(HORSE_JUMP_STRENGTH) + || attr.getKey().getKey().equalsIgnoreCase(GENERIC_JUMP_STRENGTH) + || attr.name().equalsIgnoreCase(HORSE_JUMP_STRENGTH) + || attr.name().equalsIgnoreCase(GENERIC_JUMP_STRENGTH)) { + return attr; + } + } + + pluginRef.getLogger().severe("Unable to find the Generic Jump Strength or Horse Jump Strength attribute, " + + "mcMMO will not function properly."); + throw new IllegalStateException("Unable to find the Generic Jump Strength or Horse Jump Strength attribute"); + } + + public Attribute getHorseJumpStrength() { + return horseJumpStrength; + } +} diff --git a/src/main/java/com/gmail/nossr50/util/EnchantmentMapper.java b/src/main/java/com/gmail/nossr50/util/EnchantmentMapper.java new file mode 100644 index 000000000..798ad289e --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/EnchantmentMapper.java @@ -0,0 +1,149 @@ +package com.gmail.nossr50.util; + +import com.gmail.nossr50.mcMMO; +import org.bukkit.Registry; +import org.bukkit.enchantments.Enchantment; + +public class EnchantmentMapper { + private final mcMMO pluginRef; + private final Enchantment efficiency; + private final Enchantment unbreaking; + private final Enchantment infinity; + private final Enchantment featherFalling; + private final Enchantment luckOfTheSea; + + public EnchantmentMapper(mcMMO pluginRef) { + this.pluginRef = pluginRef; + this.efficiency = initEfficiency(); + this.unbreaking = initUnbreaking(); + this.infinity = initInfinity(); + this.featherFalling = initFeatherFalling(); + this.luckOfTheSea = initLuckOfTheSea(); + } + + private Enchantment initLuckOfTheSea() { + // TODO: Make use of match if present +// if (Registry.ENCHANTMENT.match("luck_of_the_sea") != null) { +// return Registry.ENCHANTMENT.match("luck_of_the_sea"); +// } + + // Look for the enchantment by name + for (Enchantment enchantment : Registry.ENCHANTMENT) { + if (enchantment.getKey().getKey().equalsIgnoreCase("LUCK_OF_THE_SEA") + || enchantment.getKey().getKey().equalsIgnoreCase("LUCK") + || enchantment.getName().equalsIgnoreCase("LUCK_OF_THE_SEA") + || enchantment.getName().equalsIgnoreCase("LUCK")) { + return enchantment; + } + } + + pluginRef.getLogger().severe("Unable to find the Luck of the Sea enchantment, " + + "mcMMO will not function properly."); + throw new IllegalStateException("Unable to find the Luck of the Sea enchantment"); + } + + private Enchantment initFeatherFalling() { +// if (Registry.ENCHANTMENT.match("feather_falling") != null) { +// return Registry.ENCHANTMENT.match("feather_falling"); +// } + + // Look for the enchantment by name + for (Enchantment enchantment : Registry.ENCHANTMENT) { + if (enchantment.getKey().getKey().equalsIgnoreCase("FEATHER_FALLING") + || enchantment.getKey().getKey().equalsIgnoreCase("PROTECTION_FALL") + || enchantment.getName().equalsIgnoreCase("FEATHER_FALLING") + || enchantment.getName().equalsIgnoreCase("PROTECTION_FALL")) { + return enchantment; + } + } + + pluginRef.getLogger().severe("Unable to find the Feather Falling enchantment, " + + "mcMMO will not function properly."); + throw new IllegalStateException("Unable to find the Feather Falling enchantment"); + } + + private Enchantment initInfinity() { +// if(Registry.ENCHANTMENT.match("infinity") != null) { +// return Registry.ENCHANTMENT.match("infinity"); +// } + + // Look for the enchantment by name + for (Enchantment enchantment : Registry.ENCHANTMENT) { + if (enchantment.getKey().getKey().equalsIgnoreCase("INFINITY") + || enchantment.getKey().getKey().equalsIgnoreCase("ARROW_INFINITE") + || enchantment.getName().equalsIgnoreCase("INFINITY") + || enchantment.getName().equalsIgnoreCase("ARROW_INFINITE")) { + return enchantment; + } + } + + pluginRef.getLogger().severe("Unable to find the Infinity enchantment, " + + "mcMMO will not function properly."); + throw new IllegalStateException("Unable to find the Infinity enchantment"); + } + + private Enchantment initEfficiency() { +// if (Registry.ENCHANTMENT.match("efficiency") != null) { +// return Registry.ENCHANTMENT.match("efficiency"); +// } + + // Look for the enchantment by name + for (Enchantment enchantment : Registry.ENCHANTMENT) { + if (enchantment.getKey().getKey().equalsIgnoreCase("EFFICIENCY") + || enchantment.getKey().getKey().equalsIgnoreCase("DIG_SPEED") + || enchantment.getName().equalsIgnoreCase("EFFICIENCY") + || enchantment.getName().equalsIgnoreCase("DIG_SPEED")) { + return enchantment; + } + } + + pluginRef.getLogger().severe("Unable to find the Efficiency enchantment, " + + "mcMMO will not function properly."); + throw new IllegalStateException("Unable to find the Efficiency enchantment"); + } + + private Enchantment initUnbreaking() { +// if (Registry.ENCHANTMENT.match("unbreaking") != null) { +// return Registry.ENCHANTMENT.match("unbreaking"); +// } + + // Look for the enchantment by name + for (Enchantment enchantment : Registry.ENCHANTMENT) { + if (enchantment.getKey().getKey().equalsIgnoreCase("UNBREAKING") + || enchantment.getKey().getKey().equalsIgnoreCase("DURABILITY") + || enchantment.getName().equalsIgnoreCase("UNBREAKING") + || enchantment.getName().equalsIgnoreCase("DURABILITY")) { + return enchantment; + } + } + + pluginRef.getLogger().severe("Unable to find the Unbreaking enchantment, " + + "mcMMO will not function properly."); + throw new IllegalStateException("Unable to find the Unbreaking enchantment"); + } + + /** + * Get the efficiency enchantment + * + * @return The efficiency enchantment + */ + public Enchantment getEfficiency() { + return efficiency; + } + + public Enchantment getUnbreaking() { + return unbreaking; + } + + public Enchantment getInfinity() { + return infinity; + } + + public Enchantment getFeatherFalling() { + return featherFalling; + } + + public Enchantment getLuckOfTheSea() { + return luckOfTheSea; + } +} diff --git a/src/main/java/com/gmail/nossr50/util/EnchantmentUtils.java b/src/main/java/com/gmail/nossr50/util/EnchantmentUtils.java index 6aab49b3d..9e0850ed7 100644 --- a/src/main/java/com/gmail/nossr50/util/EnchantmentUtils.java +++ b/src/main/java/com/gmail/nossr50/util/EnchantmentUtils.java @@ -1,39 +1,34 @@ package com.gmail.nossr50.util; import org.bukkit.enchantments.Enchantment; +import org.jetbrains.annotations.Nullable; import java.util.HashMap; public class EnchantmentUtils { - private static final HashMap enchants = new HashMap<>(); + private static final HashMap legacyEnchantments = new HashMap<>(); static { - enchants.put("SHARPNESS", Enchantment.DAMAGE_ALL); - enchants.put("POWER", Enchantment.ARROW_DAMAGE); - enchants.put("FIRE_PROTECTION", Enchantment.PROTECTION_FIRE); - enchants.put("FEATHER_FALLING", Enchantment.PROTECTION_FALL); - enchants.put("PROTECTION", Enchantment.PROTECTION_ENVIRONMENTAL); - enchants.put("BLAST_PROTECTION", Enchantment.PROTECTION_EXPLOSIONS); - enchants.put("PROJECTILE_PROTECTION", Enchantment.PROTECTION_PROJECTILE); - enchants.put("RESPIRATION", Enchantment.OXYGEN); - enchants.put("INFINITY", Enchantment.ARROW_INFINITE); - enchants.put("AQUA_AFFINITY", Enchantment.WATER_WORKER); - enchants.put("UNBREAKING", Enchantment.DURABILITY); - enchants.put("SMITE", Enchantment.DAMAGE_UNDEAD); - enchants.put("BANE_OF_ARTHROPODS", Enchantment.DAMAGE_ARTHROPODS); - enchants.put("EFFICIENCY", Enchantment.DIG_SPEED); - enchants.put("FIRE_ASPECT", Enchantment.FIRE_ASPECT); - enchants.put("SILK_TOUCH", Enchantment.SILK_TOUCH); - enchants.put("FORTUNE", Enchantment.LOOT_BONUS_BLOCKS); - enchants.put("LOOTING", Enchantment.LOOT_BONUS_MOBS); - enchants.put("PUNCH", Enchantment.ARROW_KNOCKBACK); - enchants.put("FLAME", Enchantment.ARROW_FIRE); - enchants.put("KNOCKBACK", Enchantment.KNOCKBACK); - enchants.put("THORNS", Enchantment.THORNS); - enchants.put("MENDING", Enchantment.MENDING); - enchants.put("DEPTH_STRIDER", Enchantment.DEPTH_STRIDER); - enchants.put("FROST_WALKER", Enchantment.FROST_WALKER); + // backwards compatibility for looking up legacy bukkit enums + addLegacyEnchantmentLookup("SHARPNESS", "DAMAGE_ALL"); + addLegacyEnchantmentLookup("POWER", "ARROW_DAMAGE"); + addLegacyEnchantmentLookup("FIRE_PROTECTION", "PROTECTION_FIRE"); + addLegacyEnchantmentLookup("FEATHER_FALLING", "PROTECTION_FALL"); + addLegacyEnchantmentLookup("PROTECTION", "PROTECTION_ENVIRONMENTAL"); + addLegacyEnchantmentLookup("BLAST_PROTECTION", "PROTECTION_EXPLOSIONS"); + addLegacyEnchantmentLookup("PROJECTILE_PROTECTION", "PROTECTION_PROJECTILE"); + addLegacyEnchantmentLookup("RESPIRATION", "OXYGEN"); + addLegacyEnchantmentLookup("INFINITY", "ARROW_INFINITE"); + addLegacyEnchantmentLookup("AQUA_AFFINITY", "WATER_WORKER"); + addLegacyEnchantmentLookup("UNBREAKING", "DURABILITY"); + addLegacyEnchantmentLookup("SMITE", "DAMAGE_UNDEAD"); + addLegacyEnchantmentLookup("BANE_OF_ARTHROPODS", "DAMAGE_ARTHROPODS"); + addLegacyEnchantmentLookup("EFFICIENCY", "DIG_SPEED"); + addLegacyEnchantmentLookup("FORTUNE", "LOOT_BONUS_BLOCKS"); + addLegacyEnchantmentLookup("LOOTING", "LOOT_BONUS_MOBS"); + addLegacyEnchantmentLookup("PUNCH", "ARROW_KNOCKBACK"); + addLegacyEnchantmentLookup("FLAME", "ARROW_FIRE"); } /** @@ -43,11 +38,19 @@ public class EnchantmentUtils { * * @return Enchantment or null if no enchantment was found */ - public static Enchantment getByName(String enchantmentName) { - if (enchants.containsKey(enchantmentName)) { - return enchants.get(enchantmentName); + @SuppressWarnings("deprecation") + public static @Nullable Enchantment getByName(String enchantmentName) { + if (legacyEnchantments.containsKey(enchantmentName)) { + return legacyEnchantments.get(enchantmentName); } return Enchantment.getByName(enchantmentName); } + + @SuppressWarnings("deprecation") + private static void addLegacyEnchantmentLookup(String enchantmentName, String legacyBukkitName) { + if (Enchantment.getByName(legacyBukkitName) != null) { + legacyEnchantments.put(enchantmentName, Enchantment.getByName(legacyBukkitName)); + } + } } diff --git a/src/main/java/com/gmail/nossr50/util/ItemUtils.java b/src/main/java/com/gmail/nossr50/util/ItemUtils.java index 6055582e3..2b7cccc48 100644 --- a/src/main/java/com/gmail/nossr50/util/ItemUtils.java +++ b/src/main/java/com/gmail/nossr50/util/ItemUtils.java @@ -23,6 +23,8 @@ import org.jetbrains.annotations.Nullable; import java.util.Collections; import java.util.List; +import static java.util.Objects.requireNonNull; + public final class ItemUtils { /** * This is a static utility class, therefore we don't want any instances of @@ -41,6 +43,37 @@ public final class ItemUtils { return mcMMO.getMaterialMapStore().isBow(item.getType().getKey().getKey()); } + /** + * Exhaustive lookup for a Material by name. + *

+ * This method will first try a normal lookup, then a legacy lookup, then a lookup by ENUM name, + * and finally a lookup by ENUM name with legacy name. + * @param materialName The name of the material to lookup + * @return The Material if found, or null if not found + */ + public static @Nullable Material exhaustiveMaterialLookup(@NotNull String materialName) { + requireNonNull(materialName, "materialName cannot be null"); + + // First try a normal lookup + Material material = Material.matchMaterial(materialName); + + // If that fails, try a legacy lookup + if (material == null) { + material = Material.matchMaterial(materialName, true); + } + + // try to match to Material ENUM + if (material == null) { + material = Material.getMaterial(materialName.toUpperCase()); + } + + // try to match to Material ENUM with legacy name + if (material == null) { + material = Material.getMaterial(materialName.toUpperCase(), true); + } + return material; + } + /** * Checks if a player has an item in their inventory or offhand. * @@ -100,6 +133,10 @@ public final class ItemUtils { return mcMMO.getMaterialMapStore().isTrident(item.getType().getKey().getKey()); } + public static boolean isMace(@NotNull ItemStack item) { + return mcMMO.getMaterialMapStore().isMace(item.getType().getKey().getKey()); + } + public static boolean hasItemInEitherHand(@NotNull Player player, Material material) { return player.getInventory().getItemInMainHand().getType() == material || player.getInventory().getItemInOffHand().getType() == material; } @@ -681,7 +718,8 @@ public final class ItemUtils { if(itemMeta == null) return; - itemMeta.addEnchant(Enchantment.DIG_SPEED, existingEnchantLevel + mcMMO.p.getAdvancedConfig().getEnchantBuff(), true); + itemMeta.addEnchant(mcMMO.p.getEnchantmentMapper().getEfficiency(), + existingEnchantLevel + mcMMO.p.getAdvancedConfig().getEnchantBuff(), true); itemStack.setItemMeta(itemMeta); } diff --git a/src/main/java/com/gmail/nossr50/util/MaterialMapStore.java b/src/main/java/com/gmail/nossr50/util/MaterialMapStore.java index b0f623602..a0ad84326 100644 --- a/src/main/java/com/gmail/nossr50/util/MaterialMapStore.java +++ b/src/main/java/com/gmail/nossr50/util/MaterialMapStore.java @@ -50,6 +50,7 @@ public class MaterialMapStore { private final @NotNull HashSet crossbows; private final @NotNull HashSet tools; private final @NotNull HashSet enchantables; + private final @NotNull HashSet maces; private final @NotNull HashSet ores; private final @NotNull HashSet intendedToolPickAxe; @@ -97,6 +98,7 @@ public class MaterialMapStore { shovels = new HashSet<>(); hoes = new HashSet<>(); tridents = new HashSet<>(); + maces = new HashSet<>(); enchantables = new HashSet<>(); @@ -453,6 +455,7 @@ public class MaterialMapStore { enchantables.addAll(tridents); enchantables.addAll(bows); enchantables.addAll(crossbows); + enchantables.addAll(maces); enchantables.add("shears"); enchantables.add("fishing_rod"); @@ -476,6 +479,7 @@ public class MaterialMapStore { fillHoes(); fillShovels(); fillTridents(); + fillMaces(); fillStringTools(); fillBows(); fillCrossbows(); @@ -491,6 +495,7 @@ public class MaterialMapStore { tools.addAll(stringTools); tools.addAll(bows); tools.addAll(crossbows); + tools.addAll(maces); } private void fillBows() { @@ -507,6 +512,10 @@ public class MaterialMapStore { stringTools.add("carrot_on_a_stick"); } + private void fillMaces() { + maces.add("mace"); + } + private void fillTridents() { tridents.add("trident"); } @@ -824,6 +833,14 @@ public class MaterialMapStore { return tridents.contains(id); } + public boolean isMace(@NotNull Material material) { + return isMace(material.getKey().getKey()); + } + + public boolean isMace(@NotNull String id) { + return maces.contains(id); + } + public boolean isLeatherArmor(@NotNull Material material) { return isLeatherArmor(material.getKey().getKey()); } diff --git a/src/main/java/com/gmail/nossr50/util/Permissions.java b/src/main/java/com/gmail/nossr50/util/Permissions.java index 6dcd9b800..5a78bcf18 100644 --- a/src/main/java/com/gmail/nossr50/util/Permissions.java +++ b/src/main/java/com/gmail/nossr50/util/Permissions.java @@ -246,6 +246,14 @@ public final class Permissions { } public static boolean tridentsLimitBreak(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.tridents.superability"); } + /* MACES */ + public static boolean macesSuper(Permissible permissible) { + // TODO: When a super is added, change this + return false; + } + + public static boolean macesLimitBreak(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.maces.limitbreak"); } + /* * PARTY */ diff --git a/src/main/java/com/gmail/nossr50/util/PotionCompatibilityType.java b/src/main/java/com/gmail/nossr50/util/PotionCompatibilityType.java new file mode 100644 index 000000000..ea070814d --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/PotionCompatibilityType.java @@ -0,0 +1,6 @@ +package com.gmail.nossr50.util; + +public enum PotionCompatibilityType { + PRE_1_20_5, + POST_1_20_5 +} diff --git a/src/main/java/com/gmail/nossr50/util/PotionEffectMapper.java b/src/main/java/com/gmail/nossr50/util/PotionEffectMapper.java new file mode 100644 index 000000000..f58c66834 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/PotionEffectMapper.java @@ -0,0 +1,142 @@ +package com.gmail.nossr50.util; + +import com.gmail.nossr50.mcMMO; +import org.bukkit.potion.PotionEffectType; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +final public class PotionEffectMapper { + private static final PotionEffectType haste; + private static final PotionEffectType nausea; + private static final Method potionEffectTypeWrapperGetPotionEffectType; + private static final Class classPotionEffectTypeWrapper; + + private PotionEffectMapper() { + // Utility class + } + + static { + potionEffectTypeWrapperGetPotionEffectType = getPotionEffectTypeWrapperGetPotionEffectType(); + classPotionEffectTypeWrapper = getClassPotionEffectTypeWrapper(); + + haste = initHaste(); + nausea = initNausea(); + } + + private static Method getPotionEffectTypeWrapperGetPotionEffectType() { + try { + return classPotionEffectTypeWrapper.getMethod("getType"); + } catch (NoSuchMethodException e) { + return null; + } + } + + private static Class getClassPotionEffectTypeWrapper() { + try { + return Class.forName("org.bukkit.potion.PotionEffectTypeWrapper"); + } catch (ClassNotFoundException e) { + return null; + } + } + + private static PotionEffectType initNausea() { + if (classPotionEffectTypeWrapper != null) { + return getNauseaLegacy(); + } else { + return getNauseaModern(); + } + } + + private static PotionEffectType getNauseaModern() { +// PotionEffectType potionEffectType = Registry.EFFECT.match("nausea"); +// if (potionEffectType != null) { +// return potionEffectType; +// } +// +// // Look for the potion effect type by name +// for (PotionEffectType pet : Registry.EFFECT) { +// if (pet.getKey().getKey().equalsIgnoreCase("CONFUSION") +// || pet.getKey().getKey().equalsIgnoreCase("NAUSEA") +// || pet.getName().equalsIgnoreCase("CONFUSION") +// || pet.getName().equalsIgnoreCase("NAUSEA")) { +// return pet; +// } +// } + + try { + return (PotionEffectType) PotionEffectType.class.getField("NAUSEA").get(null); + } catch (NoSuchFieldException | IllegalAccessException e) { + mcMMO.p.getLogger().severe("Unable to find the Nausea potion effect type, " + + "mcMMO will not function properly."); + throw new IllegalStateException("Unable to find the Nausea potion effect type"); + } + } + + private static PotionEffectType getNauseaLegacy() { + try { + Object potionEffectTypeWrapper = PotionEffectType.class.getField("CONFUSION").get(null); + PotionEffectType potionEffectType = (PotionEffectType) potionEffectTypeWrapperGetPotionEffectType + .invoke(potionEffectTypeWrapper); + return potionEffectType; + } catch (IllegalAccessException | NoSuchFieldException | InvocationTargetException e) { + mcMMO.p.getLogger().severe("Unable to find the Nausea potion effect type, " + + "mcMMO will not function properly."); + throw new IllegalStateException("Unable to find the Nausea potion effect type"); + } + } + + private static PotionEffectType initHaste() { + + + mcMMO.p.getLogger().severe("Unable to find the Haste potion effect type, " + + "mcMMO will not function properly."); + throw new IllegalStateException("Unable to find the Haste potion effect type"); + } + + private static PotionEffectType getHasteLegacy() { + try { + Object potionEffectTypeWrapper = PotionEffectType.class.getField("FAST_DIGGING").get(null); + PotionEffectType potionEffectType = (PotionEffectType) potionEffectTypeWrapperGetPotionEffectType + .invoke(potionEffectTypeWrapper); + return potionEffectType; + } catch (IllegalAccessException | NoSuchFieldException | InvocationTargetException e) { + mcMMO.p.getLogger().severe("Unable to find the Haste potion effect type, " + + "mcMMO will not function properly."); + throw new IllegalStateException("Unable to find the Haste potion effect type"); + } + } + + private static PotionEffectType getHasteModern() { +// PotionEffectType potionEffectType = Registry.EFFECT.match("haste"); +// if (potionEffectType != null) { +// return potionEffectType; +// } +// +// // Look for the potion effect type by name +// for (PotionEffectType pet : Registry.EFFECT) { +// if (pet.getKey().getKey().equalsIgnoreCase("HASTE") +// || pet.getKey().getKey().equalsIgnoreCase("FAST_DIGGING") +// || pet.getName().equalsIgnoreCase("HASTE") +// || pet.getName().equalsIgnoreCase("FAST_DIGGING")) { +// return pet; +// } +// } + + try { + return (PotionEffectType) PotionEffectType.class.getField("HASTE").get(null); + } catch (NoSuchFieldException | IllegalAccessException e) { + mcMMO.p.getLogger().severe("Unable to find the Haste potion effect type, " + + "mcMMO will not function properly."); + throw new IllegalStateException("Unable to find the Haste potion effect type"); + } + } + + public static PotionEffectType getHaste() { + return haste; + } + + public static PotionEffectType getNausea() { + return nausea; + } +} diff --git a/src/main/java/com/gmail/nossr50/util/PotionUtil.java b/src/main/java/com/gmail/nossr50/util/PotionUtil.java new file mode 100644 index 000000000..d1e255bde --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/PotionUtil.java @@ -0,0 +1,447 @@ +package com.gmail.nossr50.util; + +import com.gmail.nossr50.mcMMO; +import org.bukkit.NamespacedKey; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.potion.PotionType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class PotionUtil { + // Some of the old potion types got renamed, our configs can still contain these old names + private static final Map legacyPotionTypes = new HashMap<>(); + private static final Method methodPotionTypeGetKey; + private static final Method methodPotionTypeGetEffectType; + private static final Method methodPotionTypeGetPotionEffects; + private static final Method methodPotionDataIsUpgraded; + private static final Method methodPotionDataIsExtended; + private static final Method methodPotionDataGetType; + private static final Method methodPotionMetaGetBasePotionData; + private static final Method methodPotionMetaGetBasePotionType; + private static final Method methodPotionMetaSetBasePotionType; + private static final Method methodSetBasePotionData; + private static final Class potionDataClass; + + public static final String STRONG = "STRONG"; + public static final String LONG = "LONG"; + public static final String LEGACY_WATER_POTION_TYPE = "WATER"; + + private static final PotionCompatibilityType COMPATIBILITY_MODE; + + static { + // We used to use uncraftable as the potion type + // this type isn't available anymore, so water will do + legacyPotionTypes.put("UNCRAFTABLE", "WATER"); + legacyPotionTypes.put("JUMP", "LEAPING"); + legacyPotionTypes.put("SPEED", "SWIFTNESS"); + legacyPotionTypes.put("INSTANT_HEAL", "HEALING"); + legacyPotionTypes.put("INSTANT_DAMAGE", "HARMING"); + legacyPotionTypes.put("REGEN", "REGENERATION"); + methodPotionTypeGetKey = getKeyMethod(); + methodPotionDataIsUpgraded = getPotionDataIsUpgraded(); + methodPotionDataIsExtended = getIsExtended(); + methodPotionMetaGetBasePotionData = getBasePotionData(); + methodPotionMetaGetBasePotionType = getBasePotionType(); + methodPotionMetaSetBasePotionType = getMethodPotionMetaSetBasePotionType(); + methodPotionDataGetType = getPotionDataGetType(); + methodPotionTypeGetEffectType = getPotionTypeEffectType(); + methodPotionTypeGetPotionEffects = getPotionTypeGetPotionEffects(); + methodSetBasePotionData = getSetBasePotionData(); + potionDataClass = getPotionDataClass(); + + if (methodPotionMetaGetBasePotionData != null) { + COMPATIBILITY_MODE = PotionCompatibilityType.PRE_1_20_5; + } else { + COMPATIBILITY_MODE = PotionCompatibilityType.POST_1_20_5; + } + } + + /** + * Derive a potion from a partial name, and whether it should be upgraded or extended. + * @param partialName potion type as a string, can be a substring of the potion type but must match exactly + * @return The potion type + */ + public static PotionType matchPotionType(String partialName, boolean isUpgraded, boolean isExtended) { + if (COMPATIBILITY_MODE == PotionCompatibilityType.PRE_1_20_5) { + return matchLegacyPotionType(partialName); + } else { + String updatedName = convertLegacyNames(partialName); + return Arrays.stream(PotionType.values()) + .filter(potionType -> getKeyGetKey(potionType).toUpperCase().contains(partialName) + || getKeyGetKey(potionType).toUpperCase().contains(convertLegacyNames(updatedName))) + .filter(potionType -> !isUpgraded || potionType.name().toUpperCase().contains(STRONG)) + .filter(potionType -> !isExtended || potionType.name().toUpperCase().contains(LONG)) + .findAny().orElse(null); + } + } + + public static String getKeyGetKey(PotionType potionType) { + try { + if (getKeyMethod() != null) { + NamespacedKey key = (NamespacedKey) methodPotionTypeGetKey.invoke(potionType); + return key.getKey(); + } else { + return potionType.name(); + } + } catch (InvocationTargetException | IllegalAccessException e) { + mcMMO.p.getLogger().warning("Failed to get potion key for " + potionType.name()); + return potionType.name(); + } + } + + private static Class getPotionDataClass() { + try { + return Class.forName("org.bukkit.potion.PotionData"); + } catch (ClassNotFoundException e) { + return null; + } + } + + /** + * Older versions of Spigot do not have getKey() in PotionType + * We need to check for the existence of this method before calling it + * @return The getKey method + */ + private static @Nullable Method getKeyMethod() { + try { + return PotionType.class.getMethod("getKey"); + } catch (NoSuchMethodException e) { + return null; + } + } + + private static Method getMethodPotionMetaSetBasePotionType() { + try { + return PotionMeta.class.getMethod("setBasePotionType", PotionType.class); + } catch (NoSuchMethodException e) { + return null; + } + } + + private static Method getSetBasePotionData() { + try { + return PotionMeta.class.getMethod("setBasePotionData", potionDataClass); + } catch (NoSuchMethodException e) { + return null; + } + } + + private static @Nullable Method getPotionDataIsUpgraded() { + try { + // TODO: Needed? + final Class clazz = Class.forName("org.bukkit.potion.PotionData"); + return clazz.getMethod("isUpgraded"); + } catch (NoSuchMethodException | ClassNotFoundException e) { + return null; + } + } + + private static @Nullable Method getIsExtended() { + try { + // TODO: Needed? + final Class clazz = Class.forName("org.bukkit.potion.PotionData"); + return clazz.getMethod("isExtended"); + } catch (NoSuchMethodException | ClassNotFoundException e) { + return null; + } + } + + /** + * Newer versions of Spigot do not have getBasePotionData() in PotionMeta + * + * @return the getBasePotionData method, or null if it does not exist + */ + private static @Nullable Method getBasePotionData() { + try { + return PotionType.class.getMethod("getBasePotionData"); + } catch (NoSuchMethodException e) { + return null; + } + } + + private static Method getBasePotionType() { + try { + return PotionMeta.class.getMethod("getBasePotionType"); + } catch (NoSuchMethodException e) { + return null; + } + } + + private static Method getPotionDataGetType() { + try { + final Class clazz = Class.forName("org.bukkit.potion.PotionData"); + return clazz.getMethod("getType"); + } catch (NoSuchMethodException | ClassNotFoundException e) { + return null; + } + } + + private static Method getPotionTypeEffectType() { + try { + return PotionType.class.getMethod("getEffectType"); + } catch (NoSuchMethodException e) { + return null; + } + } + + private static Method getPotionTypeGetPotionEffects() { + try { + return PotionType.class.getMethod("getPotionEffects"); + } catch (NoSuchMethodException e) { + return null; + } + } + + /** + * Legacy matching for {@link PotionType} + * + * @param partialName The partial name of the potion + * @return The potion type + */ + private static PotionType matchLegacyPotionType(String partialName) { + String updatedName = convertLegacyNames(partialName); + + return Arrays.stream(PotionType.values()) + .filter(potionType -> getKeyGetKey(potionType).equalsIgnoreCase(partialName) + || getKeyGetKey(potionType).equalsIgnoreCase(convertLegacyNames(updatedName)) + || potionType.name().equalsIgnoreCase(partialName) + || potionType.name().equalsIgnoreCase(convertLegacyNames(updatedName))) + .findAny().orElse(null); + } + + public static String convertPotionConfigName(String legacyName) { + String replacementName = legacyName; + + // Remove generated potions.yml config naming convention + if (replacementName.contains("POTION_OF_")) { + replacementName = replacementName.replace("POTION_OF_", ""); + } + + if (replacementName.contains("_II")) { + replacementName = replacementName.replace("_II", ""); + replacementName = "STRONG_" + replacementName; + } else if (replacementName.contains("_EXTENDED")) { + replacementName = replacementName.replace("_EXTENDED", ""); + replacementName = "LONG_" + replacementName; + } + return replacementName; + } + + public static String convertLegacyNames(String legacyPotionType) { + String modernized = legacyPotionType; + // check for legacy names + for (var key : legacyPotionTypes.keySet()) { + if (modernized.contains(key)) { + // Replace the legacy name with the new name + modernized = modernized.replace(key, legacyPotionTypes.get(key)); + break; + } + } + return modernized; + } + + public static boolean hasLegacyName(String potionType) { + for (var key : legacyPotionTypes.keySet()) { + if (potionType.contains(key)) { + return true; + } + } + return false; + } + + public static boolean isStrong(PotionMeta potionMeta) { + if (methodPotionMetaGetBasePotionData == null) { + return isStrongModern(potionMeta); + } else { + return isStrongLegacy(potionMeta); + } + + } + + public static boolean isLong(PotionMeta potionMeta) { + if (methodPotionMetaGetBasePotionData == null) { + return isLongModern(potionMeta); + } else { + return isLongLegacy(potionMeta); + } + } + + private static boolean isLongLegacy(PotionMeta potionMeta) { + try { + Object potionData = methodPotionMetaGetBasePotionData.invoke(potionMeta); + return (boolean) methodPotionDataIsExtended.invoke(potionData); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + private static boolean isLongModern(PotionMeta potionMeta) { + try { + return getModernPotionTypeKey(potionMeta).getKey().startsWith(LONG); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + private static boolean isStrongLegacy(PotionMeta potionMeta) { + try { + Object potionData = methodPotionMetaGetBasePotionData.invoke(potionMeta); + return (boolean) methodPotionDataIsUpgraded.invoke(potionData); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + private static boolean isStrongModern(PotionMeta potionMeta) { + try { + return getModernPotionTypeKey(potionMeta).getKey().startsWith(STRONG); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + private static NamespacedKey getModernPotionTypeKey(PotionMeta potionMeta) throws IllegalAccessException, InvocationTargetException { + PotionType potionType = (PotionType) methodPotionMetaGetBasePotionType.invoke(potionMeta); + return (NamespacedKey) methodPotionTypeGetKey.invoke(potionType); + } + + public static boolean isPotionTypeWater(@NotNull PotionMeta potionMeta) { + if (COMPATIBILITY_MODE == PotionCompatibilityType.PRE_1_20_5) { + return isPotionTypeWaterLegacy(potionMeta); + } else { + return isPotionTypeWaterModern(potionMeta); + } + } + + private static boolean isPotionTypeWaterLegacy(@NotNull PotionMeta potionMeta) { + try { + Object potionData = methodPotionMetaGetBasePotionData.invoke(potionMeta); + PotionType potionType = (PotionType) methodPotionDataGetType.invoke(potionData); + return potionType.name().equalsIgnoreCase(LEGACY_WATER_POTION_TYPE) + || PotionType.valueOf(LEGACY_WATER_POTION_TYPE) == potionType; + } catch (InvocationTargetException | IllegalAccessException ex) { + throw new RuntimeException(ex); + } + } + + private static boolean isPotionTypeWaterModern(@NotNull PotionMeta potionMeta) { + try { + return getModernPotionTypeKey(potionMeta).getKey().equalsIgnoreCase(LEGACY_WATER_POTION_TYPE); + } catch (IllegalAccessException | InvocationTargetException ex) { + throw new RuntimeException(ex); + } + } + + public static boolean samePotionType(PotionMeta potionMeta, PotionMeta otherPotionMeta) { + if (COMPATIBILITY_MODE == PotionCompatibilityType.PRE_1_20_5) { + return samePotionTypeLegacy(potionMeta, otherPotionMeta); + } else { + return samePotionTypeModern(potionMeta, otherPotionMeta); + } + } + + private static boolean samePotionTypeLegacy(PotionMeta potionMeta, PotionMeta otherPotionMeta) { + try { + Object potionData = methodPotionMetaGetBasePotionData.invoke(potionMeta); + Object otherPotionData = methodPotionMetaGetBasePotionData.invoke(otherPotionMeta); + PotionType potionType = (PotionType) methodPotionDataGetType.invoke(potionData); + PotionType otherPotionType = (PotionType) methodPotionDataGetType.invoke(otherPotionData); + return potionType == otherPotionType; + } catch (IllegalAccessException | InvocationTargetException ex) { + throw new RuntimeException(ex); + } + } + + private static boolean samePotionTypeModern(PotionMeta potionMeta, PotionMeta otherPotionMeta) { + try { + PotionType potionType = (PotionType) methodPotionMetaGetBasePotionType.invoke(potionMeta); + PotionType otherPotionType = (PotionType) methodPotionMetaGetBasePotionType.invoke(otherPotionMeta); + return potionType == otherPotionType; + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + public static boolean samePotionEffects(PotionMeta potionMeta, PotionMeta otherPotionMeta) { + if (COMPATIBILITY_MODE == PotionCompatibilityType.PRE_1_20_5) { + return true; + } else { + return samePotionEffectsModern(potionMeta, otherPotionMeta); + } + } + + private static boolean samePotionEffectsModern(PotionMeta potionMeta, PotionMeta otherPotionMeta) { + return potionMeta.getCustomEffects().equals(otherPotionMeta.getCustomEffects()); + } + + public static boolean hasBasePotionEffects(PotionMeta potionMeta) { + if (COMPATIBILITY_MODE == PotionCompatibilityType.PRE_1_20_5) { + return hasBasePotionEffectsLegacy(potionMeta); + } else { + return hasBasePotionEffectsModern(potionMeta); + } + } + + private static boolean hasBasePotionEffectsLegacy(PotionMeta potionMeta) { + try { + Object potionData = methodPotionMetaGetBasePotionData.invoke(potionMeta); + PotionType potionType = (PotionType) methodPotionDataGetType.invoke(potionData); + return methodPotionTypeGetEffectType.invoke(potionType) != null; + } catch (IllegalAccessException | InvocationTargetException ex) { + throw new RuntimeException(ex); + } + } + + private static boolean hasBasePotionEffectsModern(PotionMeta potionMeta) { + try { + PotionType potionType = (PotionType) methodPotionMetaGetBasePotionType.invoke(potionMeta); + List potionEffectTypeList = (List) methodPotionTypeGetPotionEffects.invoke(potionType); + return potionEffectTypeList != null || !potionEffectTypeList.isEmpty(); + } catch (IllegalAccessException | InvocationTargetException ex) { + throw new RuntimeException(ex); + } + } + + /** + * Set the base potion type of a potion meta. + * Note that extended/upgraded are ignored in 1.20.5 and later. + * + * @param potionMeta the potion meta + * @param extended true if the potion is extended + * @param upgraded true if the potion is upgraded + */ + public static void setBasePotionType(PotionMeta potionMeta, PotionType potionType, boolean extended, boolean upgraded) { + if (COMPATIBILITY_MODE == PotionCompatibilityType.PRE_1_20_5) { + setBasePotionTypeLegacy(potionMeta, potionType, extended, upgraded); + } else { + setBasePotionTypeModern(potionMeta, potionType); + } + } + + private static void setBasePotionTypeLegacy(PotionMeta potionMeta, PotionType potionType, boolean extended, + boolean upgraded) { + try { + Object potionData = potionDataClass.getConstructor(PotionType.class, boolean.class, boolean.class) + .newInstance(potionType, extended, upgraded); + methodSetBasePotionData.invoke(potionMeta, potionData); + } catch (IllegalAccessException | InvocationTargetException | InstantiationException | NoSuchMethodException ex) { + throw new RuntimeException(ex); + } + } + + private static void setBasePotionTypeModern(PotionMeta potionMeta, PotionType potionType) { + try { + methodPotionMetaSetBasePotionType.invoke(potionMeta, potionType); + } catch (IllegalAccessException | InvocationTargetException ex) { + throw new RuntimeException(ex); + } + } +} diff --git a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java b/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java index 0946b4cc5..ced2cbf25 100644 --- a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java +++ b/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java @@ -33,6 +33,9 @@ public final class CommandRegistrationManager { private static void registerSkillCommands() { for (PrimarySkillType skill : PrimarySkillType.values()) { + if (skill == PrimarySkillType.MACES) + continue; + String commandName = skill.toString().toLowerCase(Locale.ENGLISH); String localizedName = mcMMO.p.getSkillTools().getLocalizedSkillName(skill).toLowerCase(Locale.ENGLISH); @@ -77,6 +80,10 @@ public final class CommandRegistrationManager { command.setExecutor(new HerbalismCommand()); break; + case MACES: + // command.setExecutor(new MacesCommand()); + break; + case MINING: command.setExecutor(new MiningCommand()); break; @@ -113,7 +120,7 @@ public final class CommandRegistrationManager { break; default: - break; + throw new IllegalStateException("Unexpected value: " + skill); } } } diff --git a/src/main/java/com/gmail/nossr50/util/compat/CompatibilityManager.java b/src/main/java/com/gmail/nossr50/util/compat/CompatibilityManager.java index 11d4a6d68..012524adb 100644 --- a/src/main/java/com/gmail/nossr50/util/compat/CompatibilityManager.java +++ b/src/main/java/com/gmail/nossr50/util/compat/CompatibilityManager.java @@ -23,7 +23,6 @@ import java.util.HashMap; * In 2.2 we are switching to modules and that will clean things up significantly * */ -//TODO: I need to delete this crap public class CompatibilityManager { private @NotNull HashMap supportedLayers; private boolean isFullyCompatibleServerSoftware = true; //true if all compatibility layers load successfully @@ -159,7 +158,7 @@ public class CompatibilityManager { return masterAnglerCompatibility; } - public @Nullable MinecraftGameVersion getMinecraftGameVersion() { + public @NotNull MinecraftGameVersion getMinecraftGameVersion() { return minecraftGameVersion; } } diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index fd2d240c2..168d778a3 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -111,6 +111,7 @@ public final class CombatUtils { } } } + private static void processTridentCombatMelee(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event) { if (event.getCause() == DamageCause.THORNS) { return; @@ -214,6 +215,32 @@ public final class CombatUtils { delayArrowMetaCleanup(arrow); } + private static void processMacesCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event) { + if (event.getCause() == DamageCause.THORNS) { + return; + } + + double boostedDamage = event.getDamage(); + + McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + + //Make sure the profiles been loaded + if(mcMMOPlayer == null) { + return; + } + + // MacesManager macesManager = mcMMOPlayer.getMacesManager(); + + if(canUseLimitBreak(player, target, SubSkillType.MACES_MACES_LIMIT_BREAK)) { + boostedDamage += (getLimitBreakDamage(player, target, SubSkillType.MACES_MACES_LIMIT_BREAK) * mcMMOPlayer.getAttackStrength()); + } + + event.setDamage(boostedDamage); + processCombatXP(mcMMOPlayer, target, PrimarySkillType.MACES); + + printFinalDamageDebug(player, event, mcMMOPlayer); + } + private static void processAxeCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event) { if (event.getCause() == DamageCause.THORNS) { return; @@ -498,6 +525,15 @@ public final class CombatUtils { processTridentCombatMelee(target, player, event); } } + else if (ItemUtils.isMace(heldItem)) { + if (!mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.MACES, target)) { + return; + } + + if (mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.MACES)) { + processMacesCombat(target, player, event); + } + } } else if (entityType == EntityType.WOLF) { diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java index 39ddfbd24..d9f25db2c 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java @@ -198,6 +198,7 @@ public class SkillTools { case SUPER_SHOTGUN -> PrimarySkillType.CROSSBOWS; case TRIDENTS_SUPER_ABILITY -> PrimarySkillType.TRIDENTS; case EXPLOSIVE_SHOT -> PrimarySkillType.ARCHERY; + case MACES_SUPER_ABILITY -> PrimarySkillType.MACES; }; } diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java index b0d406ae6..17589c2fa 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java @@ -20,7 +20,6 @@ import com.gmail.nossr50.util.text.StringUtils; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.Recipe; @@ -28,12 +27,13 @@ import org.bukkit.inventory.ShapedRecipe; import org.bukkit.inventory.ShapelessRecipe; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Iterator; +import static com.gmail.nossr50.util.PotionEffectMapper.getHaste; + public final class SkillUtils { /** * This is a static utility class, therefore we don't want any instances of @@ -148,13 +148,8 @@ public final class SkillUtils { return; } - int originalDigSpeed = heldItem.getEnchantmentLevel(Enchantment.DIG_SPEED); - - //Add dig speed - - //Lore no longer gets added, no point to it afaik - //ItemUtils.addAbilityLore(heldItem); //lore can be a secondary failsafe for 1.13 and below - ItemUtils.addDigSpeedToItem(heldItem, heldItem.getEnchantmentLevel(Enchantment.DIG_SPEED)); + int originalDigSpeed = heldItem.getEnchantmentLevel(mcMMO.p.getEnchantmentMapper().getEfficiency()); + ItemUtils.addDigSpeedToItem(heldItem, heldItem.getEnchantmentLevel(mcMMO.p.getEnchantmentMapper().getEfficiency())); //1.13.2+ will have persistent metadata for this item mcMMO.getMetadataService().getItemMetadataService().setSuperAbilityBoostedItem(heldItem, originalDigSpeed); @@ -162,9 +157,9 @@ public final class SkillUtils { int duration = 0; int amplifier = 0; - if (player.hasPotionEffect(PotionEffectType.FAST_DIGGING)) { + if (player.hasPotionEffect(getHaste())) { for (PotionEffect effect : player.getActivePotionEffects()) { - if (effect.getType() == PotionEffectType.FAST_DIGGING) { + if (effect.getType() == getHaste()) { duration = effect.getDuration(); amplifier = effect.getAmplifier(); break; @@ -194,7 +189,7 @@ public final class SkillUtils { mcMMO.p.getSkillTools().getSuperAbilityMaxLength(mcMMO.p.getSkillTools().getSuperAbility(skill))) * Misc.TICK_CONVERSION_FACTOR; } - PotionEffect abilityBuff = new PotionEffect(PotionEffectType.FAST_DIGGING, duration + ticks, amplifier + 10); + PotionEffect abilityBuff = new PotionEffect(getHaste(), duration + ticks, amplifier + 10); player.addPotionEffect(abilityBuff, true); } } @@ -221,7 +216,7 @@ public final class SkillUtils { if(itemMeta != null) { // This is safe to call without prior checks. - itemMeta.removeEnchant(Enchantment.DIG_SPEED); + itemMeta.removeEnchant(mcMMO.p.getEnchantmentMapper().getEfficiency()); itemStack.setItemMeta(itemMeta); ItemUtils.removeAbilityLore(itemStack); @@ -251,7 +246,7 @@ public final class SkillUtils { Material type = itemStack.getType(); short maxDurability = mcMMO.getRepairableManager().isRepairable(type) ? mcMMO.getRepairableManager().getRepairable(type).getMaximumDurability() : type.getMaxDurability(); - durabilityModifier = (int) Math.min(durabilityModifier / (itemStack.getEnchantmentLevel(Enchantment.DURABILITY) + 1), maxDurability * maxDamageModifier); + durabilityModifier = (int) Math.min(durabilityModifier / (itemStack.getEnchantmentLevel(mcMMO.p.getEnchantmentMapper().getUnbreaking()) + 1), maxDurability * maxDamageModifier); itemStack.setDurability((short) Math.min(itemStack.getDurability() + durabilityModifier, maxDurability)); } @@ -281,7 +276,7 @@ public final class SkillUtils { Material type = itemStack.getType(); short maxDurability = mcMMO.getRepairableManager().isRepairable(type) ? mcMMO.getRepairableManager().getRepairable(type).getMaximumDurability() : type.getMaxDurability(); - durabilityModifier = (int) Math.min(durabilityModifier * (0.6 + 0.4/ (itemStack.getEnchantmentLevel(Enchantment.DURABILITY) + 1)), maxDurability * maxDamageModifier); + durabilityModifier = (int) Math.min(durabilityModifier * (0.6 + 0.4/ (itemStack.getEnchantmentLevel(mcMMO.p.getEnchantmentMapper().getUnbreaking()) + 1)), maxDurability * maxDamageModifier); itemStack.setDurability((short) Math.min(itemStack.getDurability() + durabilityModifier, maxDurability)); } diff --git a/src/main/resources/experience.yml b/src/main/resources/experience.yml index a41609521..a4838cd67 100644 --- a/src/main/resources/experience.yml +++ b/src/main/resources/experience.yml @@ -1,13 +1,3 @@ -# -# Experience configuration -# Last updated on ${project.version}-b${BUILD_NUMBER} -# -# Configure the experience formula and experience settings here. -# -##### - - - # https://hub.spigotmc.org/javadocs/spigot/org/bukkit/boss/BarColor.html # These are the only valid colors for Experience Bars, use the exact name found here # BLUE, GREEN, PINK, PURPLE, RED, WHITE, YELLOW (As of the time of this update these are the only Bar colors available, this could change in the future so check the BarColor enum to see if it has) @@ -48,7 +38,7 @@ Fishing_ExploitFix_Options: MoveRange: 3 OverFishLimit: 10 Experience_Bars: - # Turn this to false if you wanna disable XP bars + # Turn this to false if you want to disable XP bars Enable: true Update: # XP that you gained from your party but not yourself @@ -98,6 +88,10 @@ Experience_Bars: Enable: true Color: YELLOW BarStyle: SEGMENTED_6 + Maces: + Enable: true + Color: BLUE + BarStyle: SEGMENTED_6 Repair: Enable: true Color: PURPLE @@ -170,6 +164,7 @@ Experience_Formula: # Experience gained will get multiplied by these values. 1.0 by default, 0.5 means half XP gained. This happens right before multiplying the XP by the global multiplier. Skill_Multiplier: + Maces: 1.0 Crossbows: 1.0 Tridents: 1.0 Swords: 1.0 @@ -217,6 +212,9 @@ Diminished_Returns: Repair: 20000 Fishing: 20000 Alchemy: 20000 + Crossbows: 20000 + Tridents: 20000 + Maces: 20000 Time_Interval: 10 diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 11e550b20..f2fcc7a26 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -1,3 +1,4 @@ +Placeholder= This value is for any WIP locale entries that will not be displayed to users JSON.Rank=Rank JSON.DescriptionHeader=Description: JSON.JWrapper.Header=Details @@ -26,6 +27,7 @@ JSON.Salvage=Salvage JSON.Swords=Swords JSON.Taming=Taming JSON.Tridents=Tridents +JSON.Maces=Maces JSON.Unarmed=Unarmed JSON.Woodcutting=Woodcutting JSON.URL.Website=The official mcMMO Website! @@ -96,6 +98,7 @@ Overhaul.Name.Smelting=Smelting Overhaul.Name.Swords=Swords Overhaul.Name.Taming=Taming Overhaul.Name.Tridents=Tridents +Overhaul.Name.Maces=Maces Overhaul.Name.Unarmed=Unarmed Overhaul.Name.Woodcutting=Woodcutting # /mcMMO Command Style Stuff @@ -122,6 +125,7 @@ XPBar.Smelting=Smelting Lv.&6{0} XPBar.Swords=Swords Lv.&6{0} XPBar.Taming=Taming Lv.&6{0} XPBar.Tridents=Tridents Lv.&6{0} +XPBar.Maces=Maces Lv.&6{0} XPBar.Unarmed=Unarmed Lv.&6{0} XPBar.Woodcutting=Woodcutting Lv.&6{0} #This is just a preset template that gets used if the 'ExtraDetails' setting is turned on in experience.yml (off by default), you can ignore this template and just edit the strings above @@ -457,9 +461,6 @@ Tridents.Listener=Tridents: Maces.SkillName=MACES Maces.Ability.Lower=&7You lower your mace. Maces.Ability.Ready=&3You &6ready&3 your Mace. -Maces.Skills.MaceSmash.Refresh=&aYour &eGiga Smash &aability is refreshed! -Maces.Skills.MaceSmash.Other.On=&a{0}&2 used &cGiga Smash! -Maces.SubSkill.GigaSmash.Name=Giga Smash Maces.SubSkill.MacesLimitBreak.Name=Maces Limit Break Maces.SubSkill.MacesLimitBreak.Description=Breaking your limits. Increased damage against tough opponents. Intended for PVP, up to server settings for whether it will boost damage in PVE. Maces.SubSkill.MacesLimitBreak.Stat=Limit Break Max DMG diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 198d465fc..457a7e54b 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -154,6 +154,9 @@ commands: salvage: description: Detailed mcMMO skill info permission: mcmmo.commands.salvage + maces: + description: Detailed mcMMO skill info + permission: mcmmo.commands.maces mmopower: description: Shows skill mastery and power level info permission: mcmmo.commands.mmopower diff --git a/src/main/resources/skillranks.yml b/src/main/resources/skillranks.yml index 590ddde11..2df17807a 100644 --- a/src/main/resources/skillranks.yml +++ b/src/main/resources/skillranks.yml @@ -443,6 +443,30 @@ Salvage: Rank_6: 750 Rank_7: 850 Rank_8: 1000 +Maces: + TridentsLimitBreak: + Standard: + Rank_1: 10 + Rank_2: 20 + Rank_3: 30 + Rank_4: 40 + Rank_5: 50 + Rank_6: 60 + Rank_7: 70 + Rank_8: 80 + Rank_9: 90 + Rank_10: 100 + RetroMode: + Rank_1: 100 + Rank_2: 200 + Rank_3: 300 + Rank_4: 400 + Rank_5: 500 + Rank_6: 600 + Rank_7: 700 + Rank_8: 800 + Rank_9: 900 + Rank_10: 1000 Mining: MotherLode: Standard: diff --git a/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java b/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java index d995ed569..47e2126aa 100644 --- a/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java +++ b/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java @@ -16,13 +16,12 @@ import com.gmail.nossr50.util.blockmeta.ChunkManager; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillTools; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.Server; -import org.bukkit.World; +import org.bukkit.*; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemFactory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; +import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.plugin.PluginManager; import org.mockito.MockedStatic; import org.mockito.Mockito; @@ -31,9 +30,10 @@ import java.util.UUID; import java.util.logging.Logger; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; public abstract class MMOTestEnvironment { + protected MockedStatic mockedBukkit; protected MockedStatic mockedMcMMO; protected MockedStatic mockedChatConfig; protected MockedStatic experienceConfig; @@ -63,26 +63,27 @@ public abstract class MMOTestEnvironment { protected PlayerProfile playerProfile; protected McMMOPlayer mmoPlayer; protected String playerName = "testPlayer"; + protected ItemFactory itemFactory; protected ChunkManager chunkManager; protected MaterialMapStore materialMapStore; protected void mockBaseEnvironment(Logger logger) throws InvalidSkillException { - mockedMcMMO = Mockito.mockStatic(mcMMO.class); - mcMMO.p = Mockito.mock(mcMMO.class); + mockedMcMMO = mockStatic(mcMMO.class); + mcMMO.p = mock(mcMMO.class); when(mcMMO.p.getLogger()).thenReturn(logger); // place store - chunkManager = Mockito.mock(ChunkManager.class); + chunkManager = mock(ChunkManager.class); when(mcMMO.getPlaceStore()).thenReturn(chunkManager); // shut off mod manager for woodcutting - when(mcMMO.getModManager()).thenReturn(Mockito.mock(ModManager.class)); + when(mcMMO.getModManager()).thenReturn(mock(ModManager.class)); when(mcMMO.getModManager().isCustomLog(any())).thenReturn(false); // chat config - mockedChatConfig = Mockito.mockStatic(ChatConfig.class); - when(ChatConfig.getInstance()).thenReturn(Mockito.mock(ChatConfig.class)); + mockedChatConfig = mockStatic(ChatConfig.class); + when(ChatConfig.getInstance()).thenReturn(mock(ChatConfig.class)); // general config mockGeneralConfig(); @@ -108,29 +109,34 @@ public abstract class MMOTestEnvironment { mockPermissions(); - mockedRankUtils = Mockito.mockStatic(RankUtils.class); + mockedRankUtils = mockStatic(RankUtils.class); // wire server - this.server = Mockito.mock(Server.class); + this.server = mock(Server.class); when(mcMMO.p.getServer()).thenReturn(server); + mockedBukkit = mockStatic(Bukkit.class); + when(Bukkit.getItemFactory()).thenReturn(itemFactory); + itemFactory = mock(ItemFactory.class); + // when(itemFactory.getItemMeta(any())).thenReturn(mock(ItemMeta.class)); + // wire plugin manager - this.pluginManager = Mockito.mock(PluginManager.class); + this.pluginManager = mock(PluginManager.class); when(server.getPluginManager()).thenReturn(pluginManager); // wire world - this.world = Mockito.mock(World.class); + this.world = mock(World.class); // wire Misc - this.mockedMisc = Mockito.mockStatic(Misc.class); + this.mockedMisc = mockStatic(Misc.class); when(Misc.getBlockCenter(any())).thenReturn(new Location(world, 0, 0, 0)); // setup player and player related mocks after everything else - this.player = Mockito.mock(Player.class); + this.player = mock(Player.class); when(player.getUniqueId()).thenReturn(playerUUID); // wire inventory - this.playerInventory = Mockito.mock(PlayerInventory.class); + this.playerInventory = mock(PlayerInventory.class); when(player.getInventory()).thenReturn(playerInventory); // PlayerProfile and McMMOPlayer are partially mocked @@ -138,7 +144,7 @@ public abstract class MMOTestEnvironment { mmoPlayer = Mockito.spy(new McMMOPlayer(player, playerProfile)); // wire user manager - this.mockedUserManager = Mockito.mockStatic(UserManager.class); + this.mockedUserManager = mockStatic(UserManager.class); when(UserManager.getPlayer(player)).thenReturn(mmoPlayer); this.materialMapStore = new MaterialMapStore(); @@ -146,7 +152,7 @@ public abstract class MMOTestEnvironment { } private void mockPermissions() { - mockedPermissions = Mockito.mockStatic(Permissions.class); + mockedPermissions = mockStatic(Permissions.class); when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true); when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn(true); when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true); @@ -155,16 +161,16 @@ public abstract class MMOTestEnvironment { } private void mockRankConfig() { - rankConfig = Mockito.mock(RankConfig.class); + rankConfig = mock(RankConfig.class); } private void mockAdvancedConfig() { - this.advancedConfig = Mockito.mock(AdvancedConfig.class); + this.advancedConfig = mock(AdvancedConfig.class); when(mcMMO.p.getAdvancedConfig()).thenReturn(advancedConfig); } private void mockGeneralConfig() { - generalConfig = Mockito.mock(GeneralConfig.class); + generalConfig = mock(GeneralConfig.class); when(generalConfig.getTreeFellerThreshold()).thenReturn(100); when(generalConfig.getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, Material.OAK_LOG)).thenReturn(true); when(generalConfig.getLocale()).thenReturn("en_US"); @@ -172,15 +178,15 @@ public abstract class MMOTestEnvironment { } private void mockPartyConfig() { - partyConfig = Mockito.mock(PartyConfig.class); + partyConfig = mock(PartyConfig.class); when(partyConfig.isPartyEnabled()).thenReturn(false); when(mcMMO.p.getPartyConfig()).thenReturn(partyConfig); } private void mockExperienceConfig() { - experienceConfig = Mockito.mockStatic(ExperienceConfig.class); + experienceConfig = mockStatic(ExperienceConfig.class); - when(ExperienceConfig.getInstance()).thenReturn(Mockito.mock(ExperienceConfig.class)); + when(ExperienceConfig.getInstance()).thenReturn(mock(ExperienceConfig.class)); // Combat when(ExperienceConfig.getInstance().getCombatXP("Cow")).thenReturn(1D); @@ -212,5 +218,8 @@ public abstract class MMOTestEnvironment { if (mockedEventUtils != null) { mockedEventUtils.close(); } + if (mockedBukkit != null) { + mockedBukkit.close(); + } } } diff --git a/src/test/java/com/gmail/nossr50/config/skills/alchemy/PotionConfigTest.java b/src/test/java/com/gmail/nossr50/config/skills/alchemy/PotionConfigTest.java new file mode 100644 index 000000000..b9b648046 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/config/skills/alchemy/PotionConfigTest.java @@ -0,0 +1,69 @@ +//package com.gmail.nossr50.config.skills.alchemy; +// +//import com.gmail.nossr50.MMOTestEnvironment; +//import org.bukkit.inventory.meta.ItemMeta; +//import org.bukkit.inventory.meta.PotionMeta; +//import org.junit.jupiter.api.AfterEach; +//import org.junit.jupiter.api.BeforeEach; +//import org.junit.jupiter.api.Test; +// +//import java.io.File; +//import java.net.URL; +//import java.util.logging.Logger; +// +//import static org.junit.jupiter.api.Assertions.assertNotNull; +//import static org.mockito.ArgumentMatchers.any; +//import static org.mockito.Mockito.mock; +//import static org.mockito.Mockito.when; +// +//class PotionConfigTest extends MMOTestEnvironment { +// +// public static final String POTION_LEGACY_POTION_YML = "potion/legacy_potion.yml"; +// public static final String POTION_MODERN_YML = "potion/modern_potion.yml"; +// public static final Logger logger = Logger.getLogger(PotionConfigTest.class.getName()); +// +// @BeforeEach +// void setUp() { +// mockBaseEnvironment(logger); +// final PotionMeta potionMeta = mock(PotionMeta.class); +// when(itemFactory.getItemMeta(any())).thenReturn(potionMeta); +// } +// +// @AfterEach +// void tearDown() { +// cleanupBaseEnvironment(); +// } +// +// @Test +// void testLoadLegacyConfig() { +// final PotionConfig potionConfig = getPotionConfig(POTION_LEGACY_POTION_YML); +// assertNotNull(potionConfig); +// +// potionConfig.loadConcoctions(); +// int loaded = potionConfig.loadPotionMap(); +// System.out.println("Loaded " + loaded + " potions"); +// } +// +// @Test +// void testModernConfig() { +// final PotionConfig potionConfig = getPotionConfig(POTION_MODERN_YML); +// assertNotNull(potionConfig); +// +// potionConfig.loadConcoctions(); +// int loaded = potionConfig.loadPotionMap(); +// System.out.println("Loaded " + loaded + " potions"); +// } +// +// private PotionConfig getPotionConfig(String path) { +// // Get the file URL using the class loader +// final URL resource = getClass().getClassLoader().getResource(path); +// if (resource == null) { +// throw new IllegalArgumentException("file not found!"); +// } else { +// // Convert URL to a File object +// final File potionFile = new File(resource.getFile()); +// System.out.println("File path: " + potionFile.getAbsolutePath()); +// return new PotionConfig(potionFile); +// } +// } +//} \ No newline at end of file diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index 23463cbdb..8e6d04c2a 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -10,7 +10,6 @@ import com.gmail.nossr50.util.skills.SkillTools; import com.google.common.io.Files; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; @@ -38,32 +37,30 @@ class FlatFileDatabaseManagerTest { public static final @NotNull String BAD_DATA_FILE_LINE_TWENTY_THREE = "nossr51:baddata:::baddata:baddata:640:baddata:1000:1000:1000:baddata:baddata:baddata:baddata:16:0:500:20273:0:0:0:0::1000:0:0:baddata:1593543012:0:0:0:0::1000:0:0:baddata:IGNORED:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1:0:"; public static final @NotNull String DB_BADDATA = "baddatadb.users"; public static final @NotNull String DB_HEALTHY = "healthydb.users"; - public static final @NotNull String HEALTHY_DB_LINE_1 = "nossr50:1:IGNORED:IGNORED:10:2:20:3:4:5:6:7:8:9:10:30:40:50:60:70:80:90:100:IGNORED:11:110:111:222:333:444:555:666:777:IGNORED:12:120:888:IGNORED:HEARTS:13:130:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1111:999:2020:140:14:150:15:1111:2222:3333"; public static final @NotNull String HEALTHY_DB_LINE_ONE_UUID_STR = "588fe472-1c82-4c4e-9aa1-7eefccb277e3"; public static final String DB_MISSING_LAST_LOGIN = "missinglastlogin.users"; - public static final String LINE_TWO_FROM_MISSING_DB = "nossr50:1:IGNORED:IGNORED:10:2:20:3:4:5:6:7:8:9:10:30:40:50:60:70:80:90:100:IGNORED:11:110:111:222:333:444:555:666:777:IGNORED:12:120:888:0:HEARTS:13:130:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1111:999:"; private static File tempDir; private final static @NotNull Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); private final long PURGE_TIME = 2630000000L; - private static @Nullable FlatFileDatabaseManager db; //Making them all unique makes it easier on us to edit this stuff later int expectedLvlMining = 1, expectedLvlWoodcutting = 2, expectedLvlRepair = 3, expectedLvlUnarmed = 4, expectedLvlHerbalism = 5, expectedLvlExcavation = 6, expectedLvlArchery = 7, expectedLvlSwords = 8, expectedLvlAxes = 9, expectedLvlAcrobatics = 10, expectedLvlTaming = 11, expectedLvlFishing = 12, expectedLvlAlchemy = 13, expectedLvlCrossbows = 14, - expectedLvlTridents = 15; + expectedLvlTridents = 15, expectedLvlMaces = 16; float expectedExpMining = 10, expectedExpWoodcutting = 20, expectedExpRepair = 30, expectedExpUnarmed = 40, expectedExpHerbalism = 50, expectedExpExcavation = 60, expectedExpArchery = 70, expectedExpSwords = 80, expectedExpAxes = 90, expectedExpAcrobatics = 100, expectedExpTaming = 110, expectedExpFishing = 120, expectedExpAlchemy = 130, expectedExpCrossbows = 140, - expectedExpTridents = 150; + expectedExpTridents = 150, expectedExpMaces = 160; long expectedBerserkCd = 111, expectedGigaDrillBreakerCd = 222, expectedTreeFellerCd = 333, expectedGreenTerraCd = 444, expectedSerratedStrikesCd = 555, expectedSkullSplitterCd = 666, expectedSuperBreakerCd = 777, expectedBlastMiningCd = 888, expectedChimaeraWingCd = 999, - expectedSuperShotgunCd = 1111, expectedTridentSuperCd = 2222, expectedExplosiveShotCd = 3333; + expectedSuperShotgunCd = 1111, expectedTridentSuperCd = 2222, expectedExplosiveShotCd = 3333, + expectedMacesSuperCd = 4444; int expectedScoreboardTips = 1111; Long expectedLastLogin = 2020L; @@ -75,10 +72,8 @@ class FlatFileDatabaseManagerTest { @BeforeEach void init() { - assertNull(db); //noinspection UnstableApiUsage tempDir = Files.createTempDir(); - db = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); } private @NotNull String getTemporaryUserFilePath() { @@ -88,7 +83,6 @@ class FlatFileDatabaseManagerTest { @AfterEach void tearDown() { recursiveDelete(tempDir); - db = null; } //Nothing wrong with this database @@ -150,17 +144,19 @@ class FlatFileDatabaseManagerTest { @Test void testDefaultInit() { - db = new FlatFileDatabaseManager(getTemporaryUserFilePath(), logger, PURGE_TIME, 0); + new FlatFileDatabaseManager(getTemporaryUserFilePath(), logger, PURGE_TIME, 0); } @Test void testUpdateLeaderboards() { - assertNotNull(db); - assertEquals(LeaderboardStatus.UPDATED, db.updateLeaderboards()); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + assertNotNull(flatFileDatabaseManager); + assertEquals(LeaderboardStatus.UPDATED, flatFileDatabaseManager.updateLeaderboards()); } @Test void testSaveUser() { + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); //Make a Profile to save and check to see if it worked UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); String playerName = "nossr50"; @@ -168,15 +164,15 @@ class FlatFileDatabaseManagerTest { //The above profile should be "zero" initialized //Save the zero version and see if it looks correct - assertNotNull(db); - assertTrue(db.getUsersFile().exists()); //Users file should have been created from the above com.gmail.nossr50.database.FlatFileDatabaseManager.checkFileHealthAndStructure - assertNotNull(db.getUsersFile()); + assertNotNull(flatFileDatabaseManager); + assertTrue(flatFileDatabaseManager.getUsersFile().exists()); //Users file should have been created from the above com.gmail.nossr50.database.FlatFileDatabaseManager.checkFileHealthAndStructure + assertNotNull(flatFileDatabaseManager.getUsersFile()); - //The DB is empty at this point, add our user - assertTrue(db.saveUser(testProfile)); //True means we saved the user + //The flatFileDatabaseManager is empty at this point, add our user + assertTrue(flatFileDatabaseManager.saveUser(testProfile)); //True means we saved the user //Check for the empty profile - PlayerProfile retrievedFromData = db.loadPlayerProfile(uuid); + PlayerProfile retrievedFromData = flatFileDatabaseManager.loadPlayerProfile(uuid); assertTrue(retrievedFromData.isLoaded()); //PlayerProfile::isLoaded returns true if the data was created from the file, false if it wasn't found and a dummy profile was returned assertEquals(uuid, retrievedFromData.getUniqueId()); assertEquals(playerName, retrievedFromData.getPlayerName()); @@ -187,9 +183,9 @@ class FlatFileDatabaseManagerTest { String alteredName = "changedmyname"; PlayerProfile changedNameProfile = new PlayerProfile(alteredName, uuid, 0); - assertTrue(db.saveUser(changedNameProfile)); //True means we saved the user + assertTrue(flatFileDatabaseManager.saveUser(changedNameProfile)); //True means we saved the user - retrievedFromData = db.loadPlayerProfile(uuid); + retrievedFromData = flatFileDatabaseManager.loadPlayerProfile(uuid); assertTrue(retrievedFromData.isLoaded()); //PlayerProfile::isLoaded returns true if the data was created from the file, false if it wasn't found and a dummy profile was returned assertEquals(uuid, retrievedFromData.getUniqueId()); assertEquals(alteredName, retrievedFromData.getPlayerName()); @@ -198,49 +194,27 @@ class FlatFileDatabaseManagerTest { @Test void testAddedMissingLastLoginValues() { File dbFile = prepareDatabaseTestResource(DB_MISSING_LAST_LOGIN); - - //This makes sure our private method is working before the tests run afterwards - ArrayList dataFromFile = getSplitDataFromFile(dbFile); - logger.info("File Path: "+ dbFile.getAbsolutePath()); - assertArrayEquals(LINE_TWO_FROM_MISSING_DB.split(":"), dataFromFile.get(1)); - assertEquals(dataFromFile.get(1)[FlatFileDatabaseManager.UUID_INDEX], HEALTHY_DB_LINE_ONE_UUID_STR); - - db = new FlatFileDatabaseManager(dbFile, logger, PURGE_TIME, 0, true); - List flagsFound = db.checkFileHealthAndStructure(); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(dbFile, logger, PURGE_TIME, 0, true); + List flagsFound = flatFileDatabaseManager.checkFileHealthAndStructure(); assertNotNull(flagsFound); assertTrue(flagsFound.contains(FlatFileDataFlag.LAST_LOGIN_SCHEMA_UPGRADE)); //Check for the fixed value - PlayerProfile profile = db.loadPlayerProfile("nossr50"); + PlayerProfile profile = flatFileDatabaseManager.loadPlayerProfile("nossr50"); assertEquals(-1, (long) profile.getLastLogin()); } @Test void testLoadByName() { File healthyDB = prepareDatabaseTestResource(DB_HEALTHY); - - /* - * We have established the files are in good order, so now for the actual testing - */ - - //This makes sure our private method is working before the tests run afterwards - ArrayList dataFromFile = getSplitDataFromFile(healthyDB); - logger.info("File Path: "+healthyDB.getAbsolutePath()); - assertArrayEquals(HEALTHY_DB_LINE_1.split(":"), dataFromFile.get(0)); - assertEquals(dataFromFile.get(0)[FlatFileDatabaseManager.UUID_INDEX], HEALTHY_DB_LINE_ONE_UUID_STR); - - db = new FlatFileDatabaseManager(healthyDB, logger, PURGE_TIME, 0, true); - List flagsFound = db.checkFileHealthAndStructure(); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(healthyDB, logger, PURGE_TIME, 0, true); + List flagsFound = flatFileDatabaseManager.checkFileHealthAndStructure(); assertNull(flagsFound); //No flags should be found - /* - * Once the DB looks fine load the profile - */ - String playerName = "nossr50"; UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); - PlayerProfile profile = db.loadPlayerProfile(playerName); + PlayerProfile profile = flatFileDatabaseManager.loadPlayerProfile(playerName); testHealthyDataProfileValues(playerName, uuid, profile); } @@ -251,16 +225,16 @@ class FlatFileDatabaseManagerTest { String playerName = "nossr50"; int newUserTestStartingLvl = 1337; - db = new FlatFileDatabaseManager(new File(tempDir.getPath() + File.separator + TEST_FILE_NAME), logger, PURGE_TIME, newUserTestStartingLvl, true); - db.checkFileHealthAndStructure(); + var flatFileDatabaseManager = new FlatFileDatabaseManager(new File(tempDir.getPath() + File.separator + TEST_FILE_NAME), logger, PURGE_TIME, newUserTestStartingLvl, true); + flatFileDatabaseManager.checkFileHealthAndStructure(); - PlayerProfile playerProfile = db.newUser(playerName, uuid); + PlayerProfile playerProfile = flatFileDatabaseManager.newUser(playerName, uuid); assertTrue(playerProfile.isLoaded()); assertEquals(playerName, playerProfile.getPlayerName()); assertEquals(uuid, playerProfile.getUniqueId()); - PlayerProfile retrievedFromDisk = db.loadPlayerProfile(uuid); + PlayerProfile retrievedFromDisk = flatFileDatabaseManager.loadPlayerProfile(uuid); assertTrue(retrievedFromDisk.isLoaded()); assertEquals(playerName, retrievedFromDisk.getPlayerName()); assertEquals(uuid, retrievedFromDisk.getUniqueId()); @@ -270,11 +244,11 @@ class FlatFileDatabaseManagerTest { checkNewUserValues(retrievedFromDisk, newUserTestStartingLvl); //TODO: Should we do any dupe checking? Probably not needed as it would be caught on the next load - db.newUser("disco", new UUID(3, 3)); - db.newUser("dingus", new UUID(3, 4)); - db.newUser("duped_dingus", new UUID(3, 4)); + flatFileDatabaseManager.newUser("disco", new UUID(3, 3)); + flatFileDatabaseManager.newUser("dingus", new UUID(3, 4)); + flatFileDatabaseManager.newUser("duped_dingus", new UUID(3, 4)); - assertEquals(5, getSplitDataFromFile(db.getUsersFile()).size()); + assertEquals(5, getSplitDataFromFile(flatFileDatabaseManager.getUsersFile()).size()); } @Test @@ -286,16 +260,16 @@ class FlatFileDatabaseManagerTest { File file = prepareDatabaseTestResource(DB_HEALTHY); //Existing DB int newUserTestStartingLvl = 1337; - db = new FlatFileDatabaseManager(file, logger, PURGE_TIME, newUserTestStartingLvl, true); - db.checkFileHealthAndStructure(); + var flatFileDatabaseManager = new FlatFileDatabaseManager(file, logger, PURGE_TIME, newUserTestStartingLvl, true); + flatFileDatabaseManager.checkFileHealthAndStructure(); - PlayerProfile playerProfile = db.newUser(playerName, uuid); + PlayerProfile playerProfile = flatFileDatabaseManager.newUser(playerName, uuid); assertTrue(playerProfile.isLoaded()); assertEquals(playerName, playerProfile.getPlayerName()); assertEquals(uuid, playerProfile.getUniqueId()); - PlayerProfile retrievedFromDisk = db.loadPlayerProfile(uuid); + PlayerProfile retrievedFromDisk = flatFileDatabaseManager.loadPlayerProfile(uuid); assertTrue(retrievedFromDisk.isLoaded()); assertEquals(playerName, retrievedFromDisk.getPlayerName()); assertEquals(uuid, retrievedFromDisk.getUniqueId()); @@ -305,15 +279,15 @@ class FlatFileDatabaseManagerTest { checkNewUserValues(retrievedFromDisk, newUserTestStartingLvl); //TODO: Should we do any dupe checking? Probably not needed as it would be caught on the next load - db.newUser("bidoof", new UUID(3, 3)); - db.newUser("derp", new UUID(3, 4)); - db.newUser("pizza", new UUID(3, 4)); + flatFileDatabaseManager.newUser("bidoof", new UUID(3, 3)); + flatFileDatabaseManager.newUser("derp", new UUID(3, 4)); + flatFileDatabaseManager.newUser("pizza", new UUID(3, 4)); - assertEquals(7, getSplitDataFromFile(db.getUsersFile()).size()); + assertEquals(7, getSplitDataFromFile(flatFileDatabaseManager.getUsersFile()).size()); - //Now we *fix* the DB and there should be one less - db.checkFileHealthAndStructure(); - assertEquals(6, getSplitDataFromFile(db.getUsersFile()).size()); + //Now we *fix* the flatFileDatabaseManager and there should be one less + flatFileDatabaseManager.checkFileHealthAndStructure(); + assertEquals(6, getSplitDataFromFile(flatFileDatabaseManager.getUsersFile()).size()); } private void checkNewUserValues(@NotNull PlayerProfile playerProfile, int startingLevel) { @@ -338,71 +312,45 @@ class FlatFileDatabaseManagerTest { @Test void testLoadByUUID() { File dbFile = prepareDatabaseTestResource(DB_HEALTHY); - - /* - * We have established the files are in good order, so now for the actual testing - */ - - //This makes sure our private method is working before the tests run afterwards - ArrayList dataFromFile = getSplitDataFromFile(dbFile); - logger.info("File Path: " + dbFile.getAbsolutePath()); - assertArrayEquals(HEALTHY_DB_LINE_1.split(":"), dataFromFile.get(0)); - assertEquals(dataFromFile.get(0)[FlatFileDatabaseManager.UUID_INDEX], HEALTHY_DB_LINE_ONE_UUID_STR); - - db = new FlatFileDatabaseManager(dbFile, logger, PURGE_TIME, 0, true); - List flagsFound = db.checkFileHealthAndStructure(); + var flatFileDatabaseManager = new FlatFileDatabaseManager(dbFile, logger, PURGE_TIME, 0, true); + List flagsFound = flatFileDatabaseManager.checkFileHealthAndStructure(); assertNull(flagsFound); //No flags should be found /* - * Once the DB looks fine load the profile + * Once the flatFileDatabaseManager looks fine load the profile */ String playerName = "nossr50"; UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); - PlayerProfile profile1 = db.loadPlayerProfile(uuid); + PlayerProfile profile1 = flatFileDatabaseManager.loadPlayerProfile(uuid); testHealthyDataProfileValues(playerName, uuid, profile1); - assertFalse(db.loadPlayerProfile(new UUID(0, 1)).isLoaded()); //This profile should not exist and therefor will return unloaded + assertFalse(flatFileDatabaseManager.loadPlayerProfile(new UUID(0, 1)).isLoaded()); //This profile should not exist and therefor will return unloaded } @Test void testLoadByUUIDAndName() { File dbFile = prepareDatabaseTestResource(DB_HEALTHY); - - /* - * We have established the files are in good order, so now for the actual testing - */ - - //This makes sure our private method is working before the tests run afterwards - ArrayList dataFromFile = getSplitDataFromFile(dbFile); - logger.info("File Path: " + dbFile.getAbsolutePath()); - assertArrayEquals(HEALTHY_DB_LINE_1.split(":"), dataFromFile.get(0)); - assertEquals(dataFromFile.get(0)[FlatFileDatabaseManager.UUID_INDEX], HEALTHY_DB_LINE_ONE_UUID_STR); - - db = new FlatFileDatabaseManager(dbFile, logger, PURGE_TIME, 0, true); - List flagsFound = db.checkFileHealthAndStructure(); + var flatFileDatabaseManager = new FlatFileDatabaseManager(dbFile, logger, PURGE_TIME, 0, true); + List flagsFound = flatFileDatabaseManager.checkFileHealthAndStructure(); assertNull(flagsFound); //No flags should be found - /* - * Once the DB looks fine load the profile - */ - String playerName = "nossr50"; UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); Player player = initMockPlayer(playerName, uuid); - PlayerProfile profile1 = db.loadPlayerProfile(player); + PlayerProfile profile1 = flatFileDatabaseManager.loadPlayerProfile(player); testHealthyDataProfileValues(playerName, uuid, profile1); String updatedName = "updatedName"; Player updatedNamePlayer = initMockPlayer(updatedName, uuid); - PlayerProfile updatedNameProfile = db.loadPlayerProfile(updatedNamePlayer); + PlayerProfile updatedNameProfile = flatFileDatabaseManager.loadPlayerProfile(updatedNamePlayer); testHealthyDataProfileValues(updatedName, uuid, updatedNameProfile); Player shouldNotExist = initMockPlayer("doesntexist", new UUID(0, 1)); - PlayerProfile profile3 = db.loadPlayerProfile(shouldNotExist); + PlayerProfile profile3 = flatFileDatabaseManager.loadPlayerProfile(shouldNotExist); assertFalse(profile3.isLoaded()); } @@ -484,6 +432,7 @@ class FlatFileDatabaseManagerTest { case BLAST_MINING -> expectedBlastMiningCd; case TRIDENTS_SUPER_ABILITY -> expectedTridentSuperCd; case EXPLOSIVE_SHOT -> expectedExplosiveShotCd; + case MACES_SUPER_ABILITY -> expectedMacesSuperCd; default -> throw new RuntimeException("Values not defined for super ability please add " + "values for " + superAbilityType.toString() + " to the test"); }; @@ -491,165 +440,147 @@ class FlatFileDatabaseManagerTest { } private float getExpectedExperienceHealthyDBEntryOne(@NotNull PrimarySkillType primarySkillType) { - switch(primarySkillType) { - case ACROBATICS: - return expectedExpAcrobatics; - case ALCHEMY: - return expectedExpAlchemy; - case ARCHERY: - return expectedExpArchery; - case AXES: - return expectedExpAxes; - case CROSSBOWS: - return expectedExpCrossbows; - case EXCAVATION: - return expectedExpExcavation; - case FISHING: - return expectedExpFishing; - case HERBALISM: - return expectedExpHerbalism; - case MINING: - return expectedExpMining; - case REPAIR: - return expectedExpRepair; - case SALVAGE: - case SMELTING: - return 0; - case SWORDS: - return expectedExpSwords; - case TAMING: - return expectedExpTaming; - case TRIDENTS: - return expectedExpTridents; - case UNARMED: - return expectedExpUnarmed; - case WOODCUTTING: - return expectedExpWoodcutting; - } + return switch (primarySkillType) { + case ACROBATICS -> expectedExpAcrobatics; + case ALCHEMY -> expectedExpAlchemy; + case ARCHERY -> expectedExpArchery; + case AXES -> expectedExpAxes; + case CROSSBOWS -> expectedExpCrossbows; + case EXCAVATION -> expectedExpExcavation; + case FISHING -> expectedExpFishing; + case HERBALISM -> expectedExpHerbalism; + case MINING -> expectedExpMining; + case REPAIR -> expectedExpRepair; + case SALVAGE, SMELTING -> 0; + case SWORDS -> expectedExpSwords; + case TAMING -> expectedExpTaming; + case TRIDENTS -> expectedExpTridents; + case UNARMED -> expectedExpUnarmed; + case WOODCUTTING -> expectedExpWoodcutting; + case MACES -> expectedExpMaces; + default -> + throw new RuntimeException("Values for skill not defined, please add values for " + primarySkillType.toString() + " to the test"); + }; - throw new RuntimeException("Values for skill not defined, please add values for " + primarySkillType.toString() + " to the test"); } private int getExpectedLevelHealthyDBEntryOne(@NotNull PrimarySkillType primarySkillType) { - switch(primarySkillType) { - case ACROBATICS: - return expectedLvlAcrobatics; - case ALCHEMY: - return expectedLvlAlchemy; - case ARCHERY: - return expectedLvlArchery; - case AXES: - return expectedLvlAxes; - case CROSSBOWS: - return expectedLvlCrossbows; - case EXCAVATION: - return expectedLvlExcavation; - case FISHING: - return expectedLvlFishing; - case HERBALISM: - return expectedLvlHerbalism; - case MINING: - return expectedLvlMining; - case REPAIR: - return expectedLvlRepair; - case SALVAGE: - case SMELTING: - return 0; - case SWORDS: - return expectedLvlSwords; - case TAMING: - return expectedLvlTaming; - case TRIDENTS: - return expectedLvlTridents; - case UNARMED: - return expectedLvlUnarmed; - case WOODCUTTING: - return expectedLvlWoodcutting; - } + return switch (primarySkillType) { + case ACROBATICS -> expectedLvlAcrobatics; + case ALCHEMY -> expectedLvlAlchemy; + case ARCHERY -> expectedLvlArchery; + case AXES -> expectedLvlAxes; + case CROSSBOWS -> expectedLvlCrossbows; + case EXCAVATION -> expectedLvlExcavation; + case FISHING -> expectedLvlFishing; + case HERBALISM -> expectedLvlHerbalism; + case MINING -> expectedLvlMining; + case REPAIR -> expectedLvlRepair; + case SALVAGE, SMELTING -> 0; + case SWORDS -> expectedLvlSwords; + case TAMING -> expectedLvlTaming; + case TRIDENTS -> expectedLvlTridents; + case UNARMED -> expectedLvlUnarmed; + case WOODCUTTING -> expectedLvlWoodcutting; + case MACES -> expectedLvlMaces; + default -> + throw new RuntimeException("Values for skill not defined, please add values for " + primarySkillType.toString() + " to the test"); + }; - throw new RuntimeException("Values for skill not defined, please add values for " + primarySkillType.toString() + " to the test"); } @Test void testOverwriteName() { - overwriteDataAndCheckForFlag(db, duplicateNameDatabaseData, FlatFileDataFlag.DUPLICATE_NAME); - ArrayList splitDataLines = getSplitDataFromFile(db.getUsersFile()); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + overwriteDataAndCheckForFlag(flatFileDatabaseManager, duplicateNameDatabaseData, FlatFileDataFlag.DUPLICATE_NAME); + ArrayList splitDataLines = getSplitDataFromFile(flatFileDatabaseManager.getUsersFile()); assertNotEquals(splitDataLines.get(1)[0], splitDataLines.get(0)[0]); //Name comparison } @Test void testDataNotFound() { + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); //Save the zero version and see if it looks correct - assertNotNull(db); - assertTrue(db.getUsersFile().exists()); - assertNotNull(db.getUsersFile()); + assertNotNull(flatFileDatabaseManager); + assertTrue(flatFileDatabaseManager.getUsersFile().exists()); + assertNotNull(flatFileDatabaseManager.getUsersFile()); //Check for the "unloaded" profile - PlayerProfile retrievedFromData = db.loadPlayerProfile("nossr50"); + PlayerProfile retrievedFromData = flatFileDatabaseManager.loadPlayerProfile("nossr50"); assertFalse(retrievedFromData.isLoaded()); //PlayerProfile::isLoaded returns false if data doesn't exist for the user } @Test void testPurgePowerlessUsers() { - replaceDataInFile(db, normalDatabaseData); - int purgeCount = db.purgePowerlessUsers(); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + replaceDataInFile(flatFileDatabaseManager, normalDatabaseData); + int purgeCount = flatFileDatabaseManager.purgePowerlessUsers(); assertEquals(purgeCount, 1); //1 User should have been purged } @Test void testCheckFileHealthAndStructure() { - replaceDataInFile(db, badDatabaseData); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + replaceDataInFile(flatFileDatabaseManager, badDatabaseData); - List dataFlags = db.checkFileHealthAndStructure(); + List dataFlags = flatFileDatabaseManager.checkFileHealthAndStructure(); assertNotNull(dataFlags); assertNotEquals(dataFlags.size(), 0); } @Test void testFindFixableDuplicateNames() { - overwriteDataAndCheckForFlag(db, duplicateNameDatabaseData, FlatFileDataFlag.DUPLICATE_NAME); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + overwriteDataAndCheckForFlag(flatFileDatabaseManager, duplicateNameDatabaseData, FlatFileDataFlag.DUPLICATE_NAME); } @Test void testFindDuplicateUUIDs() { - overwriteDataAndCheckForFlag(db, duplicateUUIDDatabaseData, FlatFileDataFlag.DUPLICATE_UUID); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + overwriteDataAndCheckForFlag(flatFileDatabaseManager, duplicateUUIDDatabaseData, FlatFileDataFlag.DUPLICATE_UUID); } @Test() void findBadUUIDData() { - overwriteDataAndCheckForFlag(db, badUUIDDatabaseData, FlatFileDataFlag.BAD_UUID_DATA); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + overwriteDataAndCheckForFlag(flatFileDatabaseManager, badUUIDDatabaseData, FlatFileDataFlag.BAD_UUID_DATA); } @Test void testFindCorruptData() { - overwriteDataAndCheckForFlag(db, corruptDatabaseData, FlatFileDataFlag.CORRUPTED_OR_UNRECOGNIZABLE); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + overwriteDataAndCheckForFlag(flatFileDatabaseManager, corruptDatabaseData, FlatFileDataFlag.CORRUPTED_OR_UNRECOGNIZABLE); } @Test void testFindEmptyNames() { - overwriteDataAndCheckForFlag(db, emptyNameDatabaseData, FlatFileDataFlag.MISSING_NAME); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + overwriteDataAndCheckForFlag(flatFileDatabaseManager, emptyNameDatabaseData, FlatFileDataFlag.MISSING_NAME); } @Test void testFindBadValues() { - overwriteDataAndCheckForFlag(db, badDatabaseData, FlatFileDataFlag.BAD_VALUES); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + overwriteDataAndCheckForFlag(flatFileDatabaseManager, badDatabaseData, FlatFileDataFlag.BAD_VALUES); } @Test void testFindOutdatedData() { - overwriteDataAndCheckForFlag(db, outdatedDatabaseData, FlatFileDataFlag.INCOMPLETE); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + overwriteDataAndCheckForFlag(flatFileDatabaseManager, outdatedDatabaseData, FlatFileDataFlag.INCOMPLETE); } @Test void testGetDatabaseType() { - assertNotNull(db); - assertEquals(db.getDatabaseType(), DatabaseType.FLATFILE); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + assertNotNull(flatFileDatabaseManager); + assertEquals(flatFileDatabaseManager.getDatabaseType(), DatabaseType.FLATFILE); } @Test void testReadRank() { //This is an empty DB - assertNotNull(db); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); String rankBoyName = "rankBoy"; UUID rankBoyUUID = new UUID(1337, 1337); String rankGirlName = "rankGirl"; @@ -658,9 +589,9 @@ class FlatFileDatabaseManagerTest { PlayerProfile rankGirlProfile = addPlayerProfileWithLevelsAndSave(rankGirlName, rankGirlUUID, 100); //Rank 1 PlayerProfile rankBoyProfile = addPlayerProfileWithLevelsAndSave(rankBoyName, rankBoyUUID, 10); //Rank 2 - assertEquals(LeaderboardStatus.UPDATED, db.updateLeaderboards()); - Map rankGirlPositions = db.readRank(rankGirlName); - Map rankBoyPositions = db.readRank(rankBoyName); + assertEquals(LeaderboardStatus.UPDATED, flatFileDatabaseManager.updateLeaderboards()); + Map rankGirlPositions = flatFileDatabaseManager.readRank(rankGirlName); + Map rankBoyPositions = flatFileDatabaseManager.readRank(rankBoyName); for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { if(primarySkillType.isChildSkill()) { @@ -672,8 +603,8 @@ class FlatFileDatabaseManagerTest { } } - assertEquals(1, db.readRank(rankGirlName).get(null)); //Girl should be position 1 - assertEquals(2, db.readRank(rankBoyName).get(null)); //Boy should be position 2 + assertEquals(1, flatFileDatabaseManager.readRank(rankGirlName).get(null)); //Girl should be position 1 + assertEquals(2, flatFileDatabaseManager.readRank(rankBoyName).get(null)); //Boy should be position 2 } @Test @@ -741,11 +672,11 @@ class FlatFileDatabaseManagerTest { } private @NotNull PlayerProfile addPlayerProfileWithLevelsAndSave(String playerName, UUID uuid, int levels) { - assertNotNull(db); - assertFalse(db.loadPlayerProfile(uuid).isLoaded()); + FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + assertFalse(flatFileDatabaseManager.loadPlayerProfile(uuid).isLoaded()); - db.newUser(playerName, uuid); - PlayerProfile leveledProfile = db.loadPlayerProfile(uuid); + flatFileDatabaseManager.newUser(playerName, uuid); + PlayerProfile leveledProfile = flatFileDatabaseManager.loadPlayerProfile(uuid); assertTrue(leveledProfile.isLoaded()); assertEquals(playerName, leveledProfile.getPlayerName()); @@ -758,8 +689,8 @@ class FlatFileDatabaseManagerTest { leveledProfile.modifySkill(primarySkillType, levels); //TODO: This method also resets XP, not cool } - db.saveUser(leveledProfile); - leveledProfile = db.loadPlayerProfile(uuid); + flatFileDatabaseManager.saveUser(leveledProfile); + leveledProfile = flatFileDatabaseManager.loadPlayerProfile(uuid); for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { if(SkillTools.isChildSkill(primarySkillType)) { diff --git a/src/test/java/com/gmail/nossr50/util/PotionUtilTest.java b/src/test/java/com/gmail/nossr50/util/PotionUtilTest.java new file mode 100644 index 000000000..8b01720f7 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/util/PotionUtilTest.java @@ -0,0 +1,51 @@ +package com.gmail.nossr50.util; + +import org.bukkit.potion.PotionType; +import org.junit.jupiter.api.Test; + +import static com.gmail.nossr50.util.PotionUtil.convertLegacyNames; +import static com.gmail.nossr50.util.PotionUtil.matchPotionType; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class PotionUtilTest { + + @Test + void testDisplay() { +// System.out.println("\n"); +// System.out.println("\n"); +// System.out.println("\n"); +// System.out.println("\n"); +// for(var s : PotionType.values()) { +// System.out.println("PotionType.getKey().getKey(): " + s.getKey().getKey()); +// System.out.println("PotionType.name(): " + s.name()); +// System.out.println("PotionType.toString():" + s.toString()); +// System.out.println("\n"); +// } + } + + @Test + void testMatchPotionType() { + String potionTypeStr = "UNCRAFTABLE"; + PotionType potionType = matchPotionType(potionTypeStr, false, false); + assertEquals(PotionType.WATER, potionType); + + String potionTypeStr2 = "NIGHT_VISION"; + PotionType potionType2 = matchPotionType(potionTypeStr2, false, false); + assertEquals(PotionType.NIGHT_VISION, potionType2); + + String nightVisionLong = "NIGHT_VISION"; + PotionType potionType3 = matchPotionType(nightVisionLong, false, true); + assertEquals(PotionType.LONG_NIGHT_VISION, potionType3); + + nightVisionLong = "LONG_NIGHT_VISION"; + potionType3 = matchPotionType(nightVisionLong, false, true); + assertEquals(PotionType.LONG_NIGHT_VISION, potionType3); + } + + @Test + void testConvertLegacyNames() { + final String potionTypeStr = "UNCRAFTABLE"; + final String converted = convertLegacyNames(potionTypeStr); + assertEquals("WATER", converted); + } +} \ No newline at end of file diff --git a/src/test/resources/healthydb.users b/src/test/resources/healthydb.users index 79a2c7e70..c2561b38d 100644 --- a/src/test/resources/healthydb.users +++ b/src/test/resources/healthydb.users @@ -1,3 +1,3 @@ -nossr50:1:IGNORED:IGNORED:10:2:20:3:4:5:6:7:8:9:10:30:40:50:60:70:80:90:100:IGNORED:11:110:111:222:333:444:555:666:777:IGNORED:12:120:888:IGNORED:HEARTS:13:130:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1111:999:2020:140:14:150:15:1111:2222:3333: -mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:3030:0:0:0:0:0:0:0: -powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1337:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:4040:0:0:0:0:0:0:0: \ No newline at end of file +nossr50:1:IGNORED:IGNORED:10:2:20:3:4:5:6:7:8:9:10:30:40:50:60:70:80:90:100:IGNORED:11:110:111:222:333:444:555:666:777:IGNORED:12:120:888:IGNORED:HEARTS:13:130:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1111:999:2020:140:14:150:15:1111:2222:3333:160:16:4444: +mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:3030:0:0:0:0:0:0:0:0:0:0: +powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1337:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:4040:0:0:0:0:0:0:0:0:0:0: \ No newline at end of file