WIP 1.20.6 support

This commit is contained in:
nossr50 2024-05-02 06:28:20 -07:00
parent 5628df988f
commit 78558107b3
51 changed files with 1874 additions and 736 deletions

View File

@ -1,6 +1,13 @@
Version 2.2.007 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 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 Version 2.2.006
Added new config custom_item_support.yml Added new config custom_item_support.yml
Added support for hex color codes in the locale file, uses the format &#RRGGBB (see notes) Added support for hex color codes in the locale file, uses the format &#RRGGBB (see notes)

33
pom.xml
View File

@ -254,8 +254,11 @@
<id>devmart-other</id> <id>devmart-other</id>
<url>https://nexuslite.gcnt.net/repos/other/</url> <url>https://nexuslite.gcnt.net/repos/other/</url>
</repository> </repository>
<!-- ... --> <!-- MockBukkit -->
<!-- ... --> <repository>
<id>papermc</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
</repositories> </repositories>
<dependencies> <dependencies>
<!-- https://mvnrepository.com/artifact/com.h2database/h2 --> <!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
@ -361,7 +364,7 @@
<dependency> <dependency>
<groupId>org.spigotmc</groupId> <groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId> <artifactId>spigot-api</artifactId>
<version>1.20.4-R0.1-SNAPSHOT</version> <version>1.20.5-R0.1-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -435,5 +438,29 @@
<version>0.3.1</version> <version>0.3.1</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<!-- <dependency>-->
<!-- <groupId>org.apache.logging.log4j</groupId>-->
<!-- <artifactId>log4j-core</artifactId>-->
<!-- <version>2.22.1</version> &lt;!&ndash; Make sure this version matches the other log4j dependencies &ndash;&gt;-->
<!-- <scope>test</scope>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.apache.logging.log4j</groupId>-->
<!-- <artifactId>log4j-api</artifactId>-->
<!-- <version>2.22.1</version>-->
<!-- <scope>test</scope>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.apache.logging.log4j</groupId>-->
<!-- <artifactId>log4j-slf4j-impl</artifactId>-->
<!-- <version>2.22.1</version>-->
<!-- <scope>test</scope>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>com.github.seeseemelk</groupId>-->
<!-- <artifactId>MockBukkit-v1.19</artifactId>-->
<!-- <version>LATEST</version>-->
<!-- <scope>test</scope>-->
<!-- </dependency>-->
</dependencies> </dependencies>
</project> </project>

View File

@ -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<String> statsDisplay(Player player, float skillValue, boolean hasEndurance, boolean isLucky) {
// List<String> 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<Component> getTextComponents(Player player) {
// List<Component> textComponents = new ArrayList<>();
//
// TextComponentFactory.getSubSkillTextComponents(player, textComponents, PrimarySkillType.MACES);
//
// return textComponents;
// }
//}

View File

@ -4,31 +4,40 @@ import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.LogUtils; import com.gmail.nossr50.util.LogUtils;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.VisibleForTesting;
import java.io.File; import java.io.File;
import java.util.List; import java.util.List;
@Deprecated @Deprecated
public abstract class LegacyConfigLoader { public abstract class LegacyConfigLoader {
protected final File configFile; protected final @NotNull File configFile;
protected final @NotNull File dataFolder; protected final @NotNull File dataFolder;
protected String fileName; protected @NotNull String fileName;
protected YamlConfiguration config; 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.fileName = fileName;
this.dataFolder = dataFolder; this.dataFolder = dataFolder;
configFile = new File(dataFolder, relativePath + File.separator + fileName); configFile = new File(dataFolder, relativePath + File.separator + fileName);
loadFile(); loadFile();
} }
public LegacyConfigLoader(String fileName, @NotNull File dataFolder) { public LegacyConfigLoader(@NotNull String fileName, @NotNull File dataFolder) {
this.fileName = fileName; this.fileName = fileName;
this.dataFolder = dataFolder; this.dataFolder = dataFolder;
configFile = new File(dataFolder, fileName); configFile = new File(dataFolder, fileName);
loadFile(); loadFile();
} }
@VisibleForTesting
public LegacyConfigLoader(@NotNull File file) {
this.fileName = file.getName();
this.dataFolder = file.getParentFile();
configFile = new File(dataFolder, fileName);
loadFile();
}
@Deprecated @Deprecated
public LegacyConfigLoader(String relativePath, String fileName) { public LegacyConfigLoader(String relativePath, String fileName) {
this.fileName = fileName; this.fileName = fileName;

View File

@ -2,22 +2,30 @@ package com.gmail.nossr50.config.skills.alchemy;
import com.gmail.nossr50.config.LegacyConfigLoader; import com.gmail.nossr50.config.LegacyConfigLoader;
import com.gmail.nossr50.datatypes.skills.alchemy.AlchemyPotion; import com.gmail.nossr50.datatypes.skills.alchemy.AlchemyPotion;
import com.gmail.nossr50.locale.LocaleLoader;
import com.gmail.nossr50.mcMMO; 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.ChatColor;
import org.bukkit.Color; import org.bukkit.Color;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.inventory.ItemStack; 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.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static com.gmail.nossr50.util.PotionUtil.*;
public class PotionConfig extends LegacyConfigLoader { public class PotionConfig extends LegacyConfigLoader {
private static PotionConfig instance;
private final List<ItemStack> concoctionsIngredientsTierOne = new ArrayList<>(); private final List<ItemStack> concoctionsIngredientsTierOne = new ArrayList<>();
private final List<ItemStack> concoctionsIngredientsTierTwo = new ArrayList<>(); private final List<ItemStack> concoctionsIngredientsTierTwo = new ArrayList<>();
@ -28,30 +36,34 @@ public class PotionConfig extends LegacyConfigLoader {
private final List<ItemStack> concoctionsIngredientsTierSeven = new ArrayList<>(); private final List<ItemStack> concoctionsIngredientsTierSeven = new ArrayList<>();
private final List<ItemStack> concoctionsIngredientsTierEight = new ArrayList<>(); private final List<ItemStack> concoctionsIngredientsTierEight = new ArrayList<>();
private final Map<String, AlchemyPotion> potionMap = new HashMap<>(); /**
* Map of potion names to AlchemyPotion objects.
*/
private final Map<String, AlchemyPotion> loadedPotions = new HashMap<>();
private PotionConfig() { public PotionConfig() {
super("potions.yml"); super("potions.yml");
loadKeys();
} }
public static PotionConfig getInstance() { @VisibleForTesting
if (instance == null) { PotionConfig(File file) {
instance = new PotionConfig(); super(file);
}
return instance;
} }
@Override @Override
protected void loadKeys() { protected void loadKeys() {
}
public void loadPotions() {
loadConcoctions(); loadConcoctions();
loadPotionMap(); loadPotionMap();
} }
private void loadConcoctions() { @VisibleForTesting
ConfigurationSection concoctionSection = config.getConfigurationSection("Concoctions"); void loadConcoctions() {
final ConfigurationSection concoctionSection = config.getConfigurationSection("Concoctions");
// Load the ingredients for each tier
loadConcoctionsTier(concoctionsIngredientsTierOne, concoctionSection.getStringList("Tier_One_Ingredients")); loadConcoctionsTier(concoctionsIngredientsTierOne, concoctionSection.getStringList("Tier_One_Ingredients"));
loadConcoctionsTier(concoctionsIngredientsTierTwo, concoctionSection.getStringList("Tier_Two_Ingredients")); loadConcoctionsTier(concoctionsIngredientsTierTwo, concoctionSection.getStringList("Tier_Two_Ingredients"));
loadConcoctionsTier(concoctionsIngredientsTierThree, concoctionSection.getStringList("Tier_Three_Ingredients")); loadConcoctionsTier(concoctionsIngredientsTierThree, concoctionSection.getStringList("Tier_Three_Ingredients"));
@ -71,7 +83,7 @@ public class PotionConfig extends LegacyConfigLoader {
} }
private void loadConcoctionsTier(List<ItemStack> ingredientList, List<String> ingredientStrings) { private void loadConcoctionsTier(List<ItemStack> ingredientList, List<String> ingredientStrings) {
if (ingredientStrings != null && ingredientStrings.size() > 0) { if (ingredientStrings != null && !ingredientStrings.isEmpty()) {
for (String ingredientString : ingredientStrings) { for (String ingredientString : ingredientStrings) {
ItemStack ingredient = loadIngredient(ingredientString); ItemStack ingredient = loadIngredient(ingredientString);
@ -85,23 +97,24 @@ public class PotionConfig extends LegacyConfigLoader {
/** /**
* Find the Potions configuration section and load all defined potions. * Find the Potions configuration section and load all defined potions.
*/ */
private void loadPotionMap() { int loadPotionMap() {
ConfigurationSection potionSection = config.getConfigurationSection("Potions"); ConfigurationSection potionSection = config.getConfigurationSection("Potions");
int pass = 0; int potionsLoaded = 0;
int fail = 0; int failures = 0;
for (String potionName : potionSection.getKeys(false)) { for (String potionName : potionSection.getKeys(false)) {
AlchemyPotion potion = loadPotion(potionSection.getConfigurationSection(potionName)); AlchemyPotion potion = loadPotion(potionSection.getConfigurationSection(potionName));
if (potion != null) { if (potion != null) {
potionMap.put(potionName, potion); loadedPotions.put(potionName, potion);
pass++; potionsLoaded++;
} else { } 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) { private AlchemyPotion loadPotion(ConfigurationSection potion_section) {
try { 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 (potionData != null) {
if (name != null) { extended = potionData.getBoolean("Extended", false);
name = ChatColor.translateAlternateColorCodes('&', name); upgraded = potionData.getBoolean("Upgraded", false);
} }
PotionData data; Material material;
if (!potion_section.contains("PotionData")) { // Backwards config compatability final String materialString = potion_section.getString("Material", null);
short dataValue = Short.parseShort(potion_section.getName()); if (materialString != null) {
Potion potion = Potion.fromDamage(dataValue); material = ItemUtils.exhaustiveMaterialLookup(materialString);
data = new PotionData(potion.getType(), potion.hasExtendedDuration(), potion.getLevel() == 2); 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 { } else {
ConfigurationSection potionData = potion_section.getConfigurationSection("PotionData"); mcMMO.p.getLogger().warning("PotionConfig: Missing Material config entry for potion " + key + "," +
data = new PotionData(PotionType.valueOf(potionData.getString("PotionType", "WATER")), potionData.getBoolean("Extended", false), potionData.getBoolean("Upgraded", false)); " from configuration section: " + potion_section + ", defaulting to POTION");
material = Material.POTION;
} }
Material material = Material.POTION; final ItemStack itemStack = new ItemStack(material, 1);
String mat = potion_section.getString("Material", null); final PotionMeta potionMeta = (PotionMeta) itemStack.getItemMeta();
if (mat != null) {
material = Material.valueOf(mat); 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<String> lore = new ArrayList<>(); List<String> lore = new ArrayList<>();
if (potion_section.contains("Lore")) { if (potion_section.contains("Lore")) {
for (String line : potion_section.getStringList("Lore")) { for (String line : potion_section.getStringList("Lore")) {
lore.add(ChatColor.translateAlternateColorCodes('&', line)); lore.add(ChatColor.translateAlternateColorCodes('&', line));
} }
} }
potionMeta.setLore(lore);
List<PotionEffect> effects = new ArrayList<>();
if (potion_section.contains("Effects")) { if (potion_section.contains("Effects")) {
for (String effect : potion_section.getStringList("Effects")) { for (String effect : potion_section.getStringList("Effects")) {
String[] parts = effect.split(" "); String[] parts = effect.split(" ");
@ -154,9 +218,9 @@ public class PotionConfig extends LegacyConfigLoader {
int duration = parts.length > 2 ? Integer.parseInt(parts[2]) : 0; int duration = parts.length > 2 ? Integer.parseInt(parts[2]) : 0;
if (type != null) { if (type != null) {
effects.add(new PotionEffect(type, duration, amplifier)); potionMeta.addCustomEffect(new PotionEffect(type, duration, amplifier), true);
} else { } 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")) { if (potion_section.contains("Color")) {
color = Color.fromRGB(potion_section.getInt("Color")); color = Color.fromRGB(potion_section.getInt("Color"));
} else { } else {
color = this.generateColor(effects); color = this.generateColor(potionMeta.getCustomEffects());
} }
potionMeta.setColor(color);
Map<ItemStack, String> children = new HashMap<>(); Map<ItemStack, String> children = new HashMap<>();
if (potion_section.contains("Children")) { if (potion_section.contains("Children")) {
@ -175,14 +240,15 @@ public class PotionConfig extends LegacyConfigLoader {
if (ingredient != null) { if (ingredient != null) {
children.put(ingredient, potion_section.getConfigurationSection("Children").getString(child)); children.put(ingredient, potion_section.getConfigurationSection("Children").getString(child));
} else { } 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);
} }
} }
} }
// TODO: Might not need to .setItemMeta
return new AlchemyPotion(material, data, name, lore, effects, color, children); itemStack.setItemMeta(potionMeta);
return new AlchemyPotion(itemStack, children);
} catch (Exception e) { } 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; return null;
} }
} }
@ -210,39 +276,52 @@ public class PotionConfig extends LegacyConfigLoader {
return null; 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<ItemStack> getIngredients(int tier) { public List<ItemStack> getIngredients(int tier) {
switch (tier) { return switch (tier) {
case 8: case 8 -> concoctionsIngredientsTierEight;
return concoctionsIngredientsTierEight; case 7 -> concoctionsIngredientsTierSeven;
case 7: case 6 -> concoctionsIngredientsTierSix;
return concoctionsIngredientsTierSeven; case 5 -> concoctionsIngredientsTierFive;
case 6: case 4 -> concoctionsIngredientsTierFour;
return concoctionsIngredientsTierSix; case 3 -> concoctionsIngredientsTierThree;
case 5: case 2 -> concoctionsIngredientsTierTwo;
return concoctionsIngredientsTierFive; default -> concoctionsIngredientsTierOne;
case 4: };
return concoctionsIngredientsTierFour;
case 3:
return concoctionsIngredientsTierThree;
case 2:
return concoctionsIngredientsTierTwo;
case 1:
default:
return 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) { public boolean isValidPotion(ItemStack item) {
return getPotion(item) != null; 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) { 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) { public AlchemyPotion getPotion(ItemStack item) {
for (AlchemyPotion potion : potionMap.values()) { for (AlchemyPotion potion : loadedPotions.values()) {
if (potion.isSimilar(item)) { if (potion.isSimilarPotion(item)) {
return potion; return potion;
} }
} }

View File

@ -5,6 +5,7 @@ import com.gmail.nossr50.datatypes.treasure.*;
import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.EnchantmentUtils; import com.gmail.nossr50.util.EnchantmentUtils;
import com.gmail.nossr50.util.LogUtils; import com.gmail.nossr50.util.LogUtils;
import com.gmail.nossr50.util.PotionUtil;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
@ -13,12 +14,13 @@ import org.bukkit.entity.EntityType;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.PotionData;
import org.bukkit.potion.PotionType; import org.bukkit.potion.PotionType;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.*; import java.util.*;
import static com.gmail.nossr50.util.PotionUtil.matchPotionType;
public class FishingTreasureConfig extends BukkitConfig { public class FishingTreasureConfig extends BukkitConfig {
public static final String FILENAME = "fishing_treasures.yml"; public static final String FILENAME = "fishing_treasures.yml";
@ -204,30 +206,40 @@ public class FishingTreasureConfig extends BukkitConfig {
} }
if (materialName.contains("POTION")) { if (materialName.contains("POTION")) {
// Update for 1.20.5
Material mat = Material.matchMaterial(materialName); Material mat = Material.matchMaterial(materialName);
if (mat == null) { if (mat == null) {
reason.add("Potion format for " + FILENAME + " has changed"); reason.add("Potion format for " + FILENAME + " has changed");
continue;
} else { } else {
item = new ItemStack(mat, amount, data); item = new ItemStack(mat, amount, data);
PotionMeta itemMeta = (PotionMeta) item.getItemMeta(); PotionMeta potionMeta = (PotionMeta) item.getItemMeta();
if (itemMeta == null) { if (potionMeta == null) {
mcMMO.p.getLogger().severe("Item meta when adding potion to fishing treasure was null, contact the mcMMO devs!"); 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; continue;
} }
PotionType potionType = null; String potionTypeStr;
try { potionTypeStr = config.getString(type + "." + treasureName + ".PotionData.PotionType", "WATER");
potionType = PotionType.valueOf(config.getString(type + "." + treasureName + ".PotionData.PotionType", "WATER"));
} catch (IllegalArgumentException ex) {
reason.add("Invalid Potion_Type: " + config.getString(type + "." + treasureName + ".PotionData.PotionType", "WATER"));
}
boolean extended = config.getBoolean(type + "." + treasureName + ".PotionData.Extended", false); boolean extended = config.getBoolean(type + "." + treasureName + ".PotionData.Extended", false);
boolean upgraded = config.getBoolean(type + "." + treasureName + ".PotionData.Upgraded", 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) { if (customName != null) {
itemMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', customName)); potionMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', customName));
} }
if (config.contains(type + "." + treasureName + ".Lore")) { if (config.contains(type + "." + treasureName + ".Lore")) {
@ -235,9 +247,9 @@ public class FishingTreasureConfig extends BukkitConfig {
for (String s : config.getStringList(type + "." + treasureName + ".Lore")) { for (String s : config.getStringList(type + "." + treasureName + ".Lore")) {
lore.add(ChatColor.translateAlternateColorCodes('&', s)); lore.add(ChatColor.translateAlternateColorCodes('&', s));
} }
itemMeta.setLore(lore); potionMeta.setLore(lore);
} }
item.setItemMeta(itemMeta); item.setItemMeta(potionMeta);
} }
} else if (material == Material.ENCHANTED_BOOK) { } else if (material == Material.ENCHANTED_BOOK) {
//If any whitelisted enchants exist we use whitelist-based matching //If any whitelisted enchants exist we use whitelist-based matching
@ -355,7 +367,8 @@ public class FishingTreasureConfig extends BukkitConfig {
Enchantment enchantment = EnchantmentUtils.getByName(enchantmentName); Enchantment enchantment = EnchantmentUtils.getByName(enchantmentName);
if (enchantment == null) { 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; continue;
} }

View File

@ -6,6 +6,7 @@ import com.gmail.nossr50.datatypes.treasure.HylianTreasure;
import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.util.BlockUtils; import com.gmail.nossr50.util.BlockUtils;
import com.gmail.nossr50.util.LogUtils; import com.gmail.nossr50.util.LogUtils;
import com.gmail.nossr50.util.PotionUtil;
import com.gmail.nossr50.util.text.StringUtils; import com.gmail.nossr50.util.text.StringUtils;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Material; import org.bukkit.Material;
@ -14,7 +15,6 @@ import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.PotionData;
import org.bukkit.potion.PotionType; import org.bukkit.potion.PotionType;
import java.io.IOException; import java.io.IOException;
@ -165,22 +165,33 @@ public class TreasureConfig extends BukkitConfig {
Material mat = Material.matchMaterial(materialName); Material mat = Material.matchMaterial(materialName);
if (mat == null) { if (mat == null) {
reason.add("Potion format for " + FILENAME + " has changed"); reason.add("Potion format for " + FILENAME + " has changed");
continue;
} else { } else {
item = new ItemStack(mat, amount, data); item = new ItemStack(mat, amount, data);
PotionMeta itemMeta = (PotionMeta) item.getItemMeta(); PotionMeta potionMeta = (PotionMeta) item.getItemMeta();
if (potionMeta == null) {
PotionType potionType = null; mcMMO.p.getLogger().severe("Item meta when adding potion to treasure was null, contact the mcMMO devs!");
try { reason.add("Item meta when adding potion to treasure was null, contact the mcMMO devs!");
potionType = PotionType.valueOf(config.getString(type + "." + treasureName + ".PotionData.PotionType", "WATER")); continue;
} 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 extended = config.getBoolean(type + "." + treasureName + ".PotionData.Extended", false);
boolean upgraded = config.getBoolean(type + "." + treasureName + ".PotionData.Upgraded", 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")) { 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")) { if (config.contains(type + "." + treasureName + ".Lore")) {
@ -188,9 +199,9 @@ public class TreasureConfig extends BukkitConfig {
for (String s : config.getStringList(type + "." + treasureName + ".Lore")) { for (String s : config.getStringList(type + "." + treasureName + ".Lore")) {
lore.add(ChatColor.translateAlternateColorCodes('&', s)); lore.add(ChatColor.translateAlternateColorCodes('&', s));
} }
itemMeta.setLore(lore); potionMeta.setLore(lore);
} }
item.setItemMeta(itemMeta); item.setItemMeta(potionMeta);
} }
} else if (material != null) { } else if (material != null) {
item = new ItemStack(material, amount, data); item = new ItemStack(material, amount, data);

View File

@ -253,68 +253,26 @@ public class FlatFileDataProcessor {
} }
public static @NotNull ExpectedType getExpectedValueType(int dataIndex) throws IndexOutOfBoundsException { public static @NotNull ExpectedType getExpectedValueType(int dataIndex) throws IndexOutOfBoundsException {
switch(dataIndex) { return switch (dataIndex) {
case USERNAME_INDEX: case USERNAME_INDEX -> ExpectedType.STRING; //Assumption: Used to be for something, no longer used
return ExpectedType.STRING; //Assumption: Used to be for something, no longer used
case 2: //Assumption: Used to be for something, no longer used //Assumption: Used to be used for something, no longer used
case 3: //Assumption: Used to be for something, no longer used //Assumption: Used to be used for something, no longer used
case 23: //Assumption: Used to be used for something, no longer used case 2, 3, 23, 33, HEALTHBAR, LEGACY_LAST_LOGIN -> ExpectedType.IGNORED;
case 33: //Assumption: Used to be used for something, no longer used case SKILLS_MINING, SKILLS_REPAIR, SKILLS_UNARMED, SKILLS_HERBALISM, SKILLS_EXCAVATION, SKILLS_ARCHERY,
case HEALTHBAR: SKILLS_SWORDS, SKILLS_AXES, SKILLS_WOODCUTTING, SKILLS_ACROBATICS, SKILLS_TAMING, SKILLS_FISHING,
case LEGACY_LAST_LOGIN: SKILLS_ALCHEMY, SKILLS_CROSSBOWS, SKILLS_TRIDENTS, SKILLS_MACES, COOLDOWN_BERSERK,
return ExpectedType.IGNORED; COOLDOWN_GIGA_DRILL_BREAKER, COOLDOWN_TREE_FELLER, COOLDOWN_GREEN_TERRA, COOLDOWN_SERRATED_STRIKES,
case SKILLS_MINING: COOLDOWN_SKULL_SPLITTER, COOLDOWN_SUPER_BREAKER, COOLDOWN_BLAST_MINING, SCOREBOARD_TIPS,
case SKILLS_REPAIR: COOLDOWN_CHIMAERA_WING, COOLDOWN_SUPER_SHOTGUN, COOLDOWN_TRIDENTS, COOLDOWN_ARCHERY, COOLDOWN_MACES ->
case SKILLS_UNARMED: ExpectedType.INTEGER;
case SKILLS_HERBALISM: case EXP_MINING, EXP_WOODCUTTING, EXP_REPAIR, EXP_UNARMED, EXP_HERBALISM, EXP_EXCAVATION, EXP_ARCHERY,
case SKILLS_EXCAVATION: EXP_SWORDS, EXP_AXES, EXP_ACROBATICS, EXP_TAMING, EXP_FISHING, EXP_ALCHEMY, EXP_CROSSBOWS,
case SKILLS_ARCHERY: EXP_TRIDENTS, EXP_MACES -> ExpectedType.FLOAT;
case SKILLS_SWORDS: case UUID_INDEX -> ExpectedType.UUID;
case SKILLS_AXES: case OVERHAUL_LAST_LOGIN -> ExpectedType.LONG;
case SKILLS_WOODCUTTING: default -> throw new IndexOutOfBoundsException();
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();
} }
public @NotNull List<FlatFileDataContainer> getFlatFileDataContainers() { public @NotNull List<FlatFileDataContainer> getFlatFileDataContainers() {

View File

@ -87,8 +87,11 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
public static final int COOLDOWN_SUPER_SHOTGUN = 49; public static final int COOLDOWN_SUPER_SHOTGUN = 49;
public static final int COOLDOWN_TRIDENTS = 50; public static final int COOLDOWN_TRIDENTS = 50;
public static final int COOLDOWN_ARCHERY = 51; 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 //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) { FlatFileDatabaseManager(@NotNull File usersFile, @NotNull Logger logger, long purgeTime, int startingLevel, boolean testing) {
this.usersFile = usersFile; 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.getSkillLevel(PrimarySkillType.CROSSBOWS))).append(":");
appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.TRIDENTS))).append(":"); appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.TRIDENTS))).append(":");
appendable.append(String.valueOf(profile.getSkillLevel(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"); appendable.append("\r\n");
} }
@ -987,6 +1002,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
List<PlayerStat> alchemy = new ArrayList<>(); List<PlayerStat> alchemy = new ArrayList<>();
List<PlayerStat> crossbows = new ArrayList<>(); List<PlayerStat> crossbows = new ArrayList<>();
List<PlayerStat> tridents = new ArrayList<>(); List<PlayerStat> tridents = new ArrayList<>();
List<PlayerStat> maces = new ArrayList<>();
BufferedReader in = null; BufferedReader in = null;
String playerName = null; String playerName = null;
@ -1022,6 +1038,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
powerLevel += putStat(woodcutting, playerName, skills.get(PrimarySkillType.WOODCUTTING)); powerLevel += putStat(woodcutting, playerName, skills.get(PrimarySkillType.WOODCUTTING));
powerLevel += putStat(crossbows, playerName, skills.get(PrimarySkillType.CROSSBOWS)); powerLevel += putStat(crossbows, playerName, skills.get(PrimarySkillType.CROSSBOWS));
powerLevel += putStat(tridents, playerName, skills.get(PrimarySkillType.TRIDENTS)); powerLevel += putStat(tridents, playerName, skills.get(PrimarySkillType.TRIDENTS));
powerLevel += putStat(maces, playerName, skills.get(PrimarySkillType.MACES));
putStat(powerLevels, playerName, powerLevel); putStat(powerLevels, playerName, powerLevel);
} }
@ -1059,6 +1076,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
alchemy.sort(c); alchemy.sort(c);
crossbows.sort(c); crossbows.sort(c);
tridents.sort(c); tridents.sort(c);
maces.sort(c);
powerLevels.sort(c); powerLevels.sort(c);
playerStatHash.put(PrimarySkillType.MINING, mining); playerStatHash.put(PrimarySkillType.MINING, mining);
@ -1076,6 +1094,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
playerStatHash.put(PrimarySkillType.ALCHEMY, alchemy); playerStatHash.put(PrimarySkillType.ALCHEMY, alchemy);
playerStatHash.put(PrimarySkillType.CROSSBOWS, crossbows); playerStatHash.put(PrimarySkillType.CROSSBOWS, crossbows);
playerStatHash.put(PrimarySkillType.TRIDENTS, tridents); playerStatHash.put(PrimarySkillType.TRIDENTS, tridents);
playerStatHash.put(PrimarySkillType.MACES, maces);
return LeaderboardStatus.UPDATED; 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.ALCHEMY, EXP_ALCHEMY, username);
tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.CROSSBOWS, EXP_CROSSBOWS, username); tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.CROSSBOWS, EXP_CROSSBOWS, username);
tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.TRIDENTS, EXP_TRIDENTS, username); tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.TRIDENTS, EXP_TRIDENTS, username);
tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.MACES, EXP_MACES, username);
// Taming - Unused // Taming - Unused
tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SUPER_BREAKER, COOLDOWN_SUPER_BREAKER, username); 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.BLAST_MINING, COOLDOWN_BLAST_MINING, username);
tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SUPER_SHOTGUN, COOLDOWN_SUPER_SHOTGUN, 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.TRIDENTS_SUPER_ABILITY, COOLDOWN_TRIDENTS, username);
tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.MACES_SUPER_ABILITY, COOLDOWN_MACES, username);
UUID uuid; UUID uuid;
try { try {
@ -1343,6 +1364,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.ALCHEMY, SKILLS_ALCHEMY, username); tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.ALCHEMY, SKILLS_ALCHEMY, username);
tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.CROSSBOWS, SKILLS_CROSSBOWS, username); tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.CROSSBOWS, SKILLS_CROSSBOWS, username);
tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.TRIDENTS, SKILLS_TRIDENTS, username); tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.TRIDENTS, SKILLS_TRIDENTS, username);
tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.MACES, SKILLS_MACES, username);
return skills; return skills;
} }

View File

@ -169,7 +169,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
+ "taming = 0 AND mining = 0 AND woodcutting = 0 AND repair = 0 " + "taming = 0 AND mining = 0 AND woodcutting = 0 AND repair = 0 "
+ "AND unarmed = 0 AND herbalism = 0 AND excavation = 0 AND " + "AND unarmed = 0 AND herbalism = 0 AND excavation = 0 AND "
+ "archery = 0 AND swords = 0 AND axes = 0 AND acrobatics = 0 " + "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 + "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`)"); 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 = ?" + " taming = ?, mining = ?, repair = ?, woodcutting = ?"
+ ", unarmed = ?, herbalism = ?, excavation = ?" + ", unarmed = ?, herbalism = ?, excavation = ?"
+ ", archery = ?, swords = ?, axes = ?, acrobatics = ?" + ", 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(1, profile.getSkillLevel(PrimarySkillType.TAMING));
statement.setInt(2, profile.getSkillLevel(PrimarySkillType.MINING)); statement.setInt(2, profile.getSkillLevel(PrimarySkillType.MINING));
statement.setInt(3, profile.getSkillLevel(PrimarySkillType.REPAIR)); 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(13, profile.getSkillLevel(PrimarySkillType.ALCHEMY));
statement.setInt(14, profile.getSkillLevel(PrimarySkillType.CROSSBOWS)); statement.setInt(14, profile.getSkillLevel(PrimarySkillType.CROSSBOWS));
statement.setInt(15, profile.getSkillLevel(PrimarySkillType.TRIDENTS)); statement.setInt(15, profile.getSkillLevel(PrimarySkillType.TRIDENTS));
statement.setInt(16, profile.getSkillLevel(PrimarySkillType.MACES));
int total = 0; int total = 0;
for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS)
total += profile.getSkillLevel(primarySkillType); total += profile.getSkillLevel(primarySkillType);
statement.setInt(16, total); statement.setInt(17, total);
statement.setInt(17, id); statement.setInt(18, id);
success &= (statement.executeUpdate() != 0); success &= (statement.executeUpdate() != 0);
statement.close(); statement.close();
if (!success) { if (!success) {
@ -323,7 +324,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
+ " taming = ?, mining = ?, repair = ?, woodcutting = ?" + " taming = ?, mining = ?, repair = ?, woodcutting = ?"
+ ", unarmed = ?, herbalism = ?, excavation = ?" + ", unarmed = ?, herbalism = ?, excavation = ?"
+ ", archery = ?, swords = ?, axes = ?, acrobatics = ?" + ", 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(1, profile.getSkillXpLevel(PrimarySkillType.TAMING));
statement.setInt(2, profile.getSkillXpLevel(PrimarySkillType.MINING)); statement.setInt(2, profile.getSkillXpLevel(PrimarySkillType.MINING));
statement.setInt(3, profile.getSkillXpLevel(PrimarySkillType.REPAIR)); 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(13, profile.getSkillXpLevel(PrimarySkillType.ALCHEMY));
statement.setInt(14, profile.getSkillXpLevel(PrimarySkillType.CROSSBOWS)); statement.setInt(14, profile.getSkillXpLevel(PrimarySkillType.CROSSBOWS));
statement.setInt(15, profile.getSkillXpLevel(PrimarySkillType.TRIDENTS)); 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); success &= (statement.executeUpdate() != 0);
statement.close(); statement.close();
if (!success) { if (!success) {
@ -350,7 +352,8 @@ public final class SQLDatabaseManager implements DatabaseManager {
statement = connection.prepareStatement("UPDATE " + tablePrefix + "cooldowns SET " statement = connection.prepareStatement("UPDATE " + tablePrefix + "cooldowns SET "
+ " mining = ?, woodcutting = ?, unarmed = ?" + " mining = ?, woodcutting = ?, unarmed = ?"
+ ", herbalism = ?, excavation = ?, swords = ?" + ", 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(1, profile.getAbilityDATS(SuperAbilityType.SUPER_BREAKER));
statement.setLong(2, profile.getAbilityDATS(SuperAbilityType.TREE_FELLER)); statement.setLong(2, profile.getAbilityDATS(SuperAbilityType.TREE_FELLER));
statement.setLong(3, profile.getAbilityDATS(SuperAbilityType.BERSERK)); 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(9, profile.getUniqueData(UniqueDataType.CHIMAERA_WING_DATS));
statement.setLong(10, profile.getAbilityDATS(SuperAbilityType.SUPER_SHOTGUN)); statement.setLong(10, profile.getAbilityDATS(SuperAbilityType.SUPER_SHOTGUN));
statement.setLong(11, profile.getAbilityDATS(SuperAbilityType.TRIDENTS_SUPER_ABILITY)); 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); success = (statement.executeUpdate() != 0);
statement.close(); statement.close();
if (!success) { if (!success) {
@ -648,9 +652,9 @@ public final class SQLDatabaseManager implements DatabaseManager {
statement = connection.prepareStatement( statement = connection.prepareStatement(
"SELECT " + "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, " + "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.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.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` " "h.mobhealthbar, h.scoreboardtips, u.uuid, u.`user` "
+ "FROM " + tablePrefix + "users u " + "FROM " + tablePrefix + "users u "
+ "JOIN " + tablePrefix + "skills s ON (u.id = s.user_id) " + "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'," + "`chimaera_wing` int(32) unsigned NOT NULL DEFAULT '0',"
+ "`crossbows` int(32) unsigned NOT NULL DEFAULT '0'," + "`crossbows` int(32) unsigned NOT NULL DEFAULT '0',"
+ "`tridents` 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`)) " + "PRIMARY KEY (`user_id`)) "
+ "DEFAULT CHARSET=" + CHARSET_SQL + ";"); + "DEFAULT CHARSET=" + CHARSET_SQL + ";");
tryClose(createStatement); tryClose(createStatement);
@ -950,6 +955,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
+ "`alchemy` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," + "`alchemy` int(10) unsigned NOT NULL DEFAULT "+startingLevel+","
+ "`crossbows` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," + "`crossbows` int(10) unsigned NOT NULL DEFAULT "+startingLevel+","
+ "`tridents` 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+"," + "`total` int(10) unsigned NOT NULL DEFAULT "+totalLevel+","
+ "PRIMARY KEY (`user_id`)) " + "PRIMARY KEY (`user_id`)) "
+ "DEFAULT CHARSET=" + CHARSET_SQL + ";"); + "DEFAULT CHARSET=" + CHARSET_SQL + ";");
@ -1017,20 +1023,24 @@ public final class SQLDatabaseManager implements DatabaseManager {
tryClose(connection); tryClose(connection);
} }
String skills = "skills"; final String skills = "skills";
String crossbows = "crossbows"; final String crossbows = "crossbows";
String tridents = "tridents"; final String tridents = "tridents";
String experience = "experience"; final String maces = "maces";
String cooldowns = "cooldowns"; final String experience = "experience";
final String cooldowns = "cooldowns";
updateStructure(skills, crossbows, String.valueOf(32)); updateStructure(skills, crossbows, String.valueOf(32));
updateStructure(skills, tridents, String.valueOf(32)); updateStructure(skills, tridents, String.valueOf(32));
updateStructure(skills, maces, String.valueOf(32));
updateStructure(experience, crossbows, String.valueOf(10)); updateStructure(experience, crossbows, String.valueOf(10));
updateStructure(experience, tridents, String.valueOf(10)); updateStructure(experience, tridents, String.valueOf(10));
updateStructure(experience, maces, String.valueOf(10));
updateStructure(cooldowns, crossbows, String.valueOf(10)); updateStructure(cooldowns, crossbows, String.valueOf(10));
updateStructure(cooldowns, tridents, String.valueOf(10)); updateStructure(cooldowns, tridents, String.valueOf(10));
updateStructure(cooldowns, maces, String.valueOf(10));
} }
private void updateStructure(String tableName, String columnName, String columnSize) { private void updateStructure(String tableName, String columnName, String columnSize) {
@ -1213,15 +1223,14 @@ public final class SQLDatabaseManager implements DatabaseManager {
Map<PrimarySkillType, Float> skillsXp = new EnumMap<>(PrimarySkillType.class); // Skill & XP Map<PrimarySkillType, Float> skillsXp = new EnumMap<>(PrimarySkillType.class); // Skill & XP
Map<SuperAbilityType, Integer> skillsDATS = new EnumMap<>(SuperAbilityType.class); // Ability & Cooldown Map<SuperAbilityType, Integer> skillsDATS = new EnumMap<>(SuperAbilityType.class); // Ability & Cooldown
Map<UniqueDataType, Integer> uniqueData = new EnumMap<>(UniqueDataType.class); //Chimaera wing cooldown and other misc info Map<UniqueDataType, Integer> uniqueData = new EnumMap<>(UniqueDataType.class); //Chimaera wing cooldown and other misc info
MobHealthbarType mobHealthbarType;
UUID uuid; UUID uuid;
int scoreboardTipsShown; int scoreboardTipsShown;
final int OFFSET_SKILLS = 0; // TODO update these numbers when the query final int OFFSET_SKILLS = 0; // TODO update these numbers when the query
// changes (a new skill is added) // changes (a new skill is added)
final int OFFSET_XP = 15; final int OFFSET_XP = 16;
final int OFFSET_DATS = 28; final int OFFSET_DATS = 29;
final int OFFSET_OTHER = 41; final int OFFSET_OTHER = 42;
skills.put(PrimarySkillType.TAMING, result.getInt(OFFSET_SKILLS + 1)); skills.put(PrimarySkillType.TAMING, result.getInt(OFFSET_SKILLS + 1));
skills.put(PrimarySkillType.MINING, result.getInt(OFFSET_SKILLS + 2)); 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.ALCHEMY, result.getInt(OFFSET_SKILLS + 13));
skills.put(PrimarySkillType.CROSSBOWS, result.getInt(OFFSET_SKILLS + 14)); skills.put(PrimarySkillType.CROSSBOWS, result.getInt(OFFSET_SKILLS + 14));
skills.put(PrimarySkillType.TRIDENTS, result.getInt(OFFSET_SKILLS + 15)); 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.TAMING, result.getFloat(OFFSET_XP + 1));
skillsXp.put(PrimarySkillType.MINING, result.getFloat(OFFSET_XP + 2)); 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.ALCHEMY, result.getFloat(OFFSET_XP + 13));
skillsXp.put(PrimarySkillType.CROSSBOWS, result.getFloat(OFFSET_XP + 14)); skillsXp.put(PrimarySkillType.CROSSBOWS, result.getFloat(OFFSET_XP + 14));
skillsXp.put(PrimarySkillType.TRIDENTS, result.getFloat(OFFSET_XP + 15)); 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) // Taming - Unused - result.getInt(OFFSET_DATS + 1)
skillsDATS.put(SuperAbilityType.SUPER_BREAKER, result.getInt(OFFSET_DATS + 2)); 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)); uniqueData.put(UniqueDataType.CHIMAERA_WING_DATS, result.getInt(OFFSET_DATS + 13));
skillsDATS.put(SuperAbilityType.SUPER_SHOTGUN, result.getInt(OFFSET_DATS + 14)); skillsDATS.put(SuperAbilityType.SUPER_SHOTGUN, result.getInt(OFFSET_DATS + 14));
skillsDATS.put(SuperAbilityType.TRIDENTS_SUPER_ABILITY, result.getInt(OFFSET_DATS + 15)); skillsDATS.put(SuperAbilityType.TRIDENTS_SUPER_ABILITY, result.getInt(OFFSET_DATS + 15));
skillsDATS.put(SuperAbilityType.MACES_SUPER_ABILITY, result.getInt(OFFSET_DATS + 16));
try { try {
scoreboardTipsShown = result.getInt(OFFSET_OTHER + 2); scoreboardTipsShown = result.getInt(OFFSET_OTHER + 2);

View File

@ -56,67 +56,29 @@ public class FlatFileDataUtil {
* @return the "zero" initialized data corresponding to the index * @return the "zero" initialized data corresponding to the index
*/ */
public static @NotNull String getZeroInitialisedData(int index, int startingLevel) throws IndexOutOfBoundsException { public static @NotNull String getZeroInitialisedData(int index, int startingLevel) throws IndexOutOfBoundsException {
switch(index) { //TODO: Add UUID recovery? Might not even be worth it.
case USERNAME_INDEX: return switch (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 USERNAME_INDEX ->
case 2: //Assumption: Used to be for something, no longer used LEGACY_INVALID_OLD_USERNAME; //We'll keep using this value for legacy compatibility reasons (not sure if needed but don't care)
case 3: //Assumption: Used to be for something, no longer used //Assumption: Used to be for something, no longer used
case 23: //Assumption: Used to be used for something, no longer used //Assumption: Used to be for something, no longer used
case 33: //Assumption: Used to be used for something, no longer used //Assumption: Used to be used for something, no longer used
case LEGACY_LAST_LOGIN: //Assumption: Used to be used for something, no longer used
case HEALTHBAR: case 2, 3, 23, 33, LEGACY_LAST_LOGIN, HEALTHBAR -> "IGNORED";
return "IGNORED"; case SKILLS_MINING, SKILLS_REPAIR, SKILLS_UNARMED, SKILLS_HERBALISM, SKILLS_EXCAVATION, SKILLS_ARCHERY,
case SKILLS_MINING: SKILLS_SWORDS, SKILLS_AXES, SKILLS_WOODCUTTING, SKILLS_ACROBATICS, SKILLS_TAMING, SKILLS_FISHING,
case SKILLS_REPAIR: SKILLS_ALCHEMY, SKILLS_CROSSBOWS, SKILLS_TRIDENTS, SKILLS_MACES -> String.valueOf(startingLevel);
case SKILLS_UNARMED: case OVERHAUL_LAST_LOGIN -> String.valueOf(-1L);
case SKILLS_HERBALISM: case COOLDOWN_BERSERK, COOLDOWN_GIGA_DRILL_BREAKER, COOLDOWN_TREE_FELLER, COOLDOWN_GREEN_TERRA,
case SKILLS_EXCAVATION: COOLDOWN_SERRATED_STRIKES, COOLDOWN_SKULL_SPLITTER, COOLDOWN_SUPER_BREAKER, COOLDOWN_BLAST_MINING,
case SKILLS_ARCHERY: COOLDOWN_SUPER_SHOTGUN, COOLDOWN_TRIDENTS, COOLDOWN_ARCHERY, COOLDOWN_MACES, SCOREBOARD_TIPS, COOLDOWN_CHIMAERA_WING,
case SKILLS_SWORDS: EXP_MINING, EXP_WOODCUTTING, EXP_REPAIR, EXP_UNARMED, EXP_HERBALISM, EXP_EXCAVATION, EXP_ARCHERY,
case SKILLS_AXES: EXP_SWORDS, EXP_AXES, EXP_ACROBATICS, EXP_TAMING, EXP_FISHING, EXP_ALCHEMY, EXP_CROSSBOWS,
case SKILLS_WOODCUTTING: EXP_TRIDENTS, EXP_MACES -> "0";
case SKILLS_ACROBATICS: case UUID_INDEX ->
case SKILLS_TAMING: throw new IndexOutOfBoundsException(); //TODO: Add UUID recovery? Might not even be worth it.
case SKILLS_FISHING: default -> throw new IndexOutOfBoundsException();
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.
}
throw new IndexOutOfBoundsException();
} }
} }

View File

@ -32,6 +32,7 @@ import com.gmail.nossr50.skills.crossbows.CrossbowsManager;
import com.gmail.nossr50.skills.excavation.ExcavationManager; import com.gmail.nossr50.skills.excavation.ExcavationManager;
import com.gmail.nossr50.skills.fishing.FishingManager; import com.gmail.nossr50.skills.fishing.FishingManager;
import com.gmail.nossr50.skills.herbalism.HerbalismManager; 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.mining.MiningManager;
import com.gmail.nossr50.skills.repair.RepairManager; import com.gmail.nossr50.skills.repair.RepairManager;
import com.gmail.nossr50.skills.salvage.SalvageManager; import com.gmail.nossr50.skills.salvage.SalvageManager;
@ -220,6 +221,9 @@ public class McMMOPlayer implements Identified {
case WOODCUTTING: case WOODCUTTING:
skillManagers.put(primarySkillType, new WoodcuttingManager(this)); skillManagers.put(primarySkillType, new WoodcuttingManager(this));
break; break;
case MACES:
skillManagers.put(primarySkillType, new MacesManager(this));
break;
default: default:
throw new InvalidSkillException("The skill named has no manager! Contact the devs!"); 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); return (TridentsManager) skillManagers.get(PrimarySkillType.TRIDENTS);
} }
public MacesManager getMacesManager() {
return (MacesManager) skillManagers.get(PrimarySkillType.MACES);
}
public ExcavationManager getExcavationManager() { public ExcavationManager getExcavationManager() {
return (ExcavationManager) skillManagers.get(PrimarySkillType.EXCAVATION); return (ExcavationManager) skillManagers.get(PrimarySkillType.EXCAVATION);
} }

View File

@ -20,6 +20,7 @@ public enum PrimarySkillType {
EXCAVATION, EXCAVATION,
FISHING, FISHING,
HERBALISM, HERBALISM,
MACES,
MINING, MINING,
REPAIR, REPAIR,
SALVAGE, SALVAGE,

View File

@ -57,6 +57,9 @@ public enum SubSkillType {
HERBALISM_HYLIAN_LUCK, HERBALISM_HYLIAN_LUCK,
HERBALISM_SHROOM_THUMB, HERBALISM_SHROOM_THUMB,
/* Maces */
MACES_MACES_LIMIT_BREAK(10),
/* Mining */ /* Mining */
MINING_BIGGER_BOMBS(1), MINING_BIGGER_BOMBS(1),
MINING_BLAST_MINING(8), MINING_BLAST_MINING(8),

View File

@ -72,19 +72,26 @@ public enum SuperAbilityType {
"Swords.Skills.SS.Other.Off", "Swords.Skills.SS.Other.Off",
"Swords.SubSkill.SerratedStrikes.Name"), "Swords.SubSkill.SerratedStrikes.Name"),
SUPER_SHOTGUN( SUPER_SHOTGUN(
null, "Placeholder",
null, "Placeholder",
"Crossbows.Skills.SSG.Other.On", "Placeholder",
"Crossbows.Skills.SSG.Refresh", "Placeholder",
null, "Placeholder",
"Crossbows.SubSkill.SuperShotgun.Name"), "Placeholder"),
TRIDENTS_SUPER_ABILITY( TRIDENTS_SUPER_ABILITY(
"Tridents.Skills.TA.On", "Placeholder",
"Tridents.Skills.TA.Off", "Placeholder",
"Tridents.Skills.TA.Other.On", "Placeholder",
"Tridents.Skills.TA.Refresh", "Placeholder",
"Tridents.Skills.TA.Other.Off", "Placeholder",
"Tridents.SubSkill.TridentAbility.Name"), "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 * 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 SUPER_SHOTGUN -> Permissions.superShotgun(player);
case TREE_FELLER -> Permissions.treeFeller(player); case TREE_FELLER -> Permissions.treeFeller(player);
case TRIDENTS_SUPER_ABILITY -> Permissions.tridentsSuper(player); case TRIDENTS_SUPER_ABILITY -> Permissions.tridentsSuper(player);
case MACES_SUPER_ABILITY -> Permissions.macesSuper(player);
}; };
} }

View File

@ -13,7 +13,8 @@ public enum ToolType {
SWORD("Swords.Ability.Lower", "Swords.Ability.Ready"), SWORD("Swords.Ability.Lower", "Swords.Ability.Ready"),
CROSSBOW("Crossbows.Ability.Lower", "Crossbows.Ability.Ready"), CROSSBOW("Crossbows.Ability.Lower", "Crossbows.Ability.Ready"),
BOW("Archery.Ability.Lower", "Archery.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 lowerTool;
private final String raiseTool; private final String raiseTool;
@ -45,6 +46,8 @@ public enum ToolType {
return ItemUtils.isCrossbow(itemStack); return ItemUtils.isCrossbow(itemStack);
case TRIDENTS: case TRIDENTS:
return ItemUtils.isTrident(itemStack); return ItemUtils.isTrident(itemStack);
case MACES:
return ItemUtils.isMace(itemStack);
case FISTS: case FISTS:
return itemStack.getType() == Material.AIR; return itemStack.getType() == Material.AIR;

View File

@ -1,167 +1,120 @@
package com.gmail.nossr50.datatypes.skills.alchemy; package com.gmail.nossr50.datatypes.skills.alchemy;
import com.gmail.nossr50.config.skills.alchemy.PotionConfig; import com.gmail.nossr50.mcMMO;
import org.bukkit.Color;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.Potion; import org.jetbrains.annotations.NotNull;
import org.bukkit.potion.PotionData; import org.jetbrains.annotations.Nullable;
import org.bukkit.potion.PotionEffect;
import java.util.List; import java.util.ArrayList;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; 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 { public class AlchemyPotion {
private final Material material; private final ItemStack potion;
private PotionData data; private final Map<ItemStack, String> alchemyPotionChildren;
private String name;
private List<String> lore;
private List<PotionEffect> effects;
private Color color;
private Map<ItemStack, String> children;
public AlchemyPotion(Material material, PotionData data, String name, List<String> lore, List<PotionEffect> effects, Color color, Map<ItemStack, String> children) { public AlchemyPotion(ItemStack potion, Map<ItemStack, String> alchemyPotionChildren) {
this.material = material; this.potion = requireNonNull(potion, "potion cannot be null");
this.data = data; this.alchemyPotionChildren = requireNonNull(alchemyPotionChildren, "alchemyPotionChildren cannot be null");
this.lore = lore;
this.name = name;
this.effects = effects;
this.children = children;
this.color = color;
} }
public String toString() { public @NotNull ItemStack toItemStack(int amount) {
return "AlchemyPotion{" + data + ", " + name + ", Effects[" + effects.size() + "], Children[" + children.size() + "]}"; final ItemStack potion = new ItemStack(this.potion);
} potion.setAmount(Math.max(1, amount));
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);
return potion; return potion;
} }
public Material getMaterial() { public Map<ItemStack, String> getAlchemyPotionChildren() {
return material; return alchemyPotionChildren;
} }
public Potion toPotion(int amount) { public @Nullable AlchemyPotion getChild(@NotNull ItemStack ingredient) {
return Potion.fromItemStack(this.toItemStack(amount)); if (!alchemyPotionChildren.isEmpty()) {
} for (Entry<ItemStack, String> child : alchemyPotionChildren.entrySet()) {
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<String> getLore() {
return lore;
}
public void setLore(List<String> lore) {
this.lore = lore;
}
public List<PotionEffect> getEffects() {
return effects;
}
public void setEffects(List<PotionEffect> effects) {
this.effects = effects;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public Map<ItemStack, String> getChildren() {
return children;
}
public void setChildren(Map<ItemStack, String> children) {
this.children = children;
}
public AlchemyPotion getChild(ItemStack ingredient) {
if (!children.isEmpty()) {
for (Entry<ItemStack, String> child : children.entrySet()) {
if (ingredient.isSimilar(child.getKey())) { if (ingredient.isSimilar(child.getKey())) {
return PotionConfig.getInstance().getPotion(child.getValue()); return mcMMO.p.getPotionConfig().getPotion(child.getValue());
} }
} }
} }
return null; return null;
} }
public boolean isSimilar(ItemStack item) { public boolean isSimilarPotion(@NotNull ItemStack otherPotion) {
if (item.getType() != material) { 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; return false;
} }
if (!item.hasItemMeta()) {
return false; final PotionMeta otherPotionMeta = (PotionMeta) otherPotion.getItemMeta();
}
PotionMeta meta = (PotionMeta) item.getItemMeta(); // all custom effects must be present
PotionData that = meta.getBasePotionData(); for (var effect : getAlchemyPotionMeta().getCustomEffects()) {
if (data.getType() != that.getType()) { if (!otherPotionMeta.hasCustomEffect(effect.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())) {
return false; return false;
} }
} }
if (!meta.hasLore() && !lore.isEmpty()) {
if (!samePotionType(getAlchemyPotionMeta(), otherPotionMeta)) {
return false; return false;
} }
if (!(lore.isEmpty() && !meta.hasLore()) && !meta.getLore().equals(lore)) {
if (!otherPotionMeta.hasLore() && getAlchemyPotionMeta().hasLore()
|| !getAlchemyPotionMeta().hasLore() && otherPotionMeta.hasLore()) {
return false; return false;
} }
if (!meta.hasDisplayName() && name != null) {
if (otherPotionMeta.hasLore() && getAlchemyPotionMeta().hasLore()
&& !otherPotionMeta.getLore().equals(getAlchemyPotionMeta().getLore())) {
return false; 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 +
'}';
} }
} }

View File

@ -1,11 +1,10 @@
package com.gmail.nossr50.datatypes.skills.alchemy; package com.gmail.nossr50.datatypes.skills.alchemy;
import org.bukkit.Material; import com.gmail.nossr50.util.PotionUtil;
import org.bukkit.potion.PotionData; import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionType;
import java.util.List; import static com.gmail.nossr50.util.PotionUtil.*;
public enum PotionStage { public enum PotionStage {
FIVE(5), FIVE(5),
@ -43,27 +42,27 @@ public enum PotionStage {
return potionStage; return potionStage;
} }
private static boolean isWaterBottle(AlchemyPotion input) { private static boolean isWaterBottle(AlchemyPotion alchemyPotion) {
return input.getData().getType() == PotionType.WATER; return isPotionTypeWater(alchemyPotion.getAlchemyPotionMeta());
} }
public static PotionStage getPotionStage(AlchemyPotion alchemyPotion) { public static PotionStage getPotionStage(AlchemyPotion alchemyPotion) {
PotionData data = alchemyPotion.getData(); final PotionMeta potionMeta = alchemyPotion.getAlchemyPotionMeta();
List<PotionEffect> effects = alchemyPotion.getEffects();
int stage = 1; int stage = 1;
// Check if potion has an effect of any sort // Check if potion has an effect of any sort
if (data.getType().getEffectType() != null || !effects.isEmpty()) { if (!potionMeta.getCustomEffects().isEmpty()
|| PotionUtil.hasBasePotionEffects(potionMeta)) {
stage++; stage++;
} }
// Check if potion has a glowstone dust amplifier // Check if potion has a glowstone dust amplifier
// Else check if the potion has a custom effect with an amplifier added by mcMMO // Else check if the potion has a custom effect with an amplifier added by mcMMO
if (data.isUpgraded()) { if (isStrong(potionMeta)) {
stage++; stage++;
} else if(!effects.isEmpty()) { } else if (!potionMeta.getCustomEffects().isEmpty()) {
for (PotionEffect effect : effects){ for (PotionEffect effect : potionMeta.getCustomEffects()){
if(effect.getAmplifier() > 0){ if(effect.getAmplifier() > 0){
stage++; stage++;
break; break;
@ -72,12 +71,12 @@ public enum PotionStage {
} }
// Check if potion has a redstone dust amplifier // Check if potion has a redstone dust amplifier
if (data.isExtended()) { if (isLong(potionMeta)) {
stage++; stage++;
} }
// Check if potion has a gunpowder amplifier // Check if potion has a gunpowder amplifier
if (alchemyPotion.getMaterial() == Material.SPLASH_POTION || alchemyPotion.getMaterial() == Material.LINGERING_POTION) { if (alchemyPotion.isSplash() || alchemyPotion.isLingering()) {
stage++; stage++;
} }

View File

@ -26,7 +26,6 @@ import net.kyori.adventure.text.TextComponent;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.SoundCategory; import org.bukkit.SoundCategory;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.Event; import org.bukkit.event.Event;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
@ -317,7 +316,7 @@ public class Roll extends AcrobaticsSubSkill {
ItemStack boots = player.getInventory().getBoots(); ItemStack boots = player.getInventory().getBoots();
float xp = (float) (damage * (isRoll ? ExperienceConfig.getInstance().getRollXPModifier() : ExperienceConfig.getInstance().getFallXPModifier())); 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(); xp *= ExperienceConfig.getInstance().getFeatherFallXPModifier();
} }

View File

@ -120,7 +120,7 @@ public class EntityListener implements Listener {
if (bow == null) if (bow == null)
return; 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); projectile.setMetadata(MetadataConstants.METADATA_KEY_INF_ARROW, MetadataConstants.MCMMO_METADATA_VALUE);
} }

View File

@ -78,8 +78,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
public class mcMMO extends JavaPlugin { public class mcMMO extends JavaPlugin {
/* Managers & Services */ /* Managers & Services */
private static PlatformManager platformManager; private static PlatformManager platformManager;
private static MetadataService metadataService; private static MetadataService metadataService;
@ -140,21 +138,14 @@ public class mcMMO extends JavaPlugin {
private GeneralConfig generalConfig; private GeneralConfig generalConfig;
private AdvancedConfig advancedConfig; private AdvancedConfig advancedConfig;
private PartyConfig partyConfig; private PartyConfig partyConfig;
private PotionConfig potionConfig;
private CustomItemSupportConfig customItemSupportConfig; private CustomItemSupportConfig customItemSupportConfig;
private EnchantmentMapper enchantmentMapper;
private AttributeMapper attributeMapper;
private FoliaLib foliaLib; private FoliaLib foliaLib;
private PartyManager partyManager; 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() { public mcMMO() {
p = this; p = this;
} }
@ -207,8 +198,11 @@ public class mcMMO extends JavaPlugin {
modManager = new ModManager(); modManager = new ModManager();
//Init Material Maps // Init Material Maps
materialMapStore = new MaterialMapStore(); materialMapStore = new MaterialMapStore();
// Init compatibility mappers
enchantmentMapper = new EnchantmentMapper(this);
attributeMapper = new AttributeMapper(this);
loadConfigFiles(); loadConfigFiles();
@ -567,7 +561,11 @@ public class mcMMO extends JavaPlugin {
FishingTreasureConfig.getInstance(); FishingTreasureConfig.getInstance();
HiddenConfig.getInstance(); HiddenConfig.getInstance();
mcMMO.p.getAdvancedConfig(); mcMMO.p.getAdvancedConfig();
PotionConfig.getInstance();
// init potion config
potionConfig = new PotionConfig();
potionConfig.loadPotions();
CoreSkillsConfig.getInstance(); CoreSkillsConfig.getInstance();
SoundConfig.getInstance(); SoundConfig.getInstance();
RankConfig.getInstance(); RankConfig.getInstance();
@ -812,6 +810,18 @@ public class mcMMO extends JavaPlugin {
return customItemSupportConfig; return customItemSupportConfig;
} }
public PotionConfig getPotionConfig() {
return potionConfig;
}
public EnchantmentMapper getEnchantmentMapper() {
return enchantmentMapper;
}
public AttributeMapper getAttributeMapper() {
return attributeMapper;
}
public @NotNull FoliaLib getFoliaLib() { public @NotNull FoliaLib getFoliaLib() {
return foliaLib; return foliaLib;
} }

View File

@ -1,7 +1,6 @@
package com.gmail.nossr50.metadata; package com.gmail.nossr50.metadata;
import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.mcMMO;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataContainer;
@ -74,12 +73,12 @@ public class ItemMetadataService {
if(itemMeta != null) { if(itemMeta != null) {
//TODO: can be optimized //TODO: can be optimized
if (itemMeta.hasEnchant(Enchantment.DIG_SPEED)) { if (itemMeta.hasEnchant(mcMMO.p.getEnchantmentMapper().getEfficiency())) {
itemMeta.removeEnchant(Enchantment.DIG_SPEED); itemMeta.removeEnchant(mcMMO.p.getEnchantmentMapper().getEfficiency());
} }
if (originalSpeed > 0) { if (originalSpeed > 0) {
itemMeta.addEnchant(Enchantment.DIG_SPEED, originalSpeed, true); itemMeta.addEnchant(mcMMO.p.getEnchantmentMapper().getEfficiency(), originalSpeed, true);
} }
PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer(); PersistentDataContainer dataContainer = itemMeta.getPersistentDataContainer();

View File

@ -1,13 +1,13 @@
package com.gmail.nossr50.skills.alchemy; package com.gmail.nossr50.skills.alchemy;
import com.gmail.nossr50.config.experience.ExperienceConfig; 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.XPGainReason;
import com.gmail.nossr50.datatypes.experience.XPGainSource; import com.gmail.nossr50.datatypes.experience.XPGainSource;
import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.datatypes.skills.alchemy.PotionStage; import com.gmail.nossr50.datatypes.skills.alchemy.PotionStage;
import com.gmail.nossr50.mcMMO;
import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.skills.SkillManager;
import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.text.StringUtils; import com.gmail.nossr50.util.text.StringUtils;
@ -27,7 +27,7 @@ public class AlchemyManager extends SkillManager {
} }
public List<ItemStack> getIngredients() { public List<ItemStack> getIngredients() {
return PotionConfig.getInstance().getIngredients(getTier()); return mcMMO.p.getPotionConfig().getIngredients(getTier());
} }
public String getIngredientList() { public String getIngredientList() {

View File

@ -1,6 +1,5 @@
package com.gmail.nossr50.skills.alchemy; 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.SubSkillType;
import com.gmail.nossr50.datatypes.skills.alchemy.AlchemyPotion; import com.gmail.nossr50.datatypes.skills.alchemy.AlchemyPotion;
import com.gmail.nossr50.datatypes.skills.alchemy.PotionStage; import com.gmail.nossr50.datatypes.skills.alchemy.PotionStage;
@ -36,7 +35,7 @@ public final class AlchemyPotionBrewer {
continue; 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; return true;
} }
} }
@ -94,12 +93,11 @@ public final class AlchemyPotionBrewer {
} }
private static List<ItemStack> getValidIngredients(Player player) { private static List<ItemStack> getValidIngredients(Player player) {
if(player == null || UserManager.getPlayer(player) == null) if(player == null || UserManager.getPlayer(player) == null) {
{ return mcMMO.p.getPotionConfig().getIngredients(1);
return PotionConfig.getInstance().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) { 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++) { for (int i = 0; i < 3; i++) {
ItemStack item = inventory.getItem(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; continue;
} }
AlchemyPotion input = PotionConfig.getInstance().getPotion(item); AlchemyPotion input = mcMMO.p.getPotionConfig().getPotion(item);
AlchemyPotion output = input.getChild(ingredient); AlchemyPotion output = input.getChild(ingredient);
inputList.set(i, input); inputList.set(i, input);

View File

@ -18,7 +18,8 @@ import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile; import org.bukkit.entity.Projectile;
import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import static com.gmail.nossr50.util.PotionEffectMapper.getNausea;
public class ArcheryManager extends SkillManager { public class ArcheryManager extends SkillManager {
public ArcheryManager(McMMOPlayer mcMMOPlayer) { public ArcheryManager(McMMOPlayer mcMMOPlayer) {
@ -95,10 +96,8 @@ public class ArcheryManager extends SkillManager {
Location dazedLocation = defender.getLocation(); Location dazedLocation = defender.getLocation();
dazedLocation.setPitch(90 - Misc.getRandom().nextInt(181)); dazedLocation.setPitch(90 - Misc.getRandom().nextInt(181));
// defender.teleport(dazedLocation);
mcMMO.p.getFoliaLib().getImpl().teleportAsync(defender, 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)) { if (NotificationManager.doesPlayerUseNotifications(defender)) {
NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, "Combat.TouchedFuzzy"); NotificationManager.sendPlayerInformation(defender, NotificationType.SUBSKILL_MESSAGE, "Combat.TouchedFuzzy");

View File

@ -573,11 +573,13 @@ public class FishingManager extends SkillManager {
int luck; int luck;
if (getPlayer().getInventory().getItemInMainHand().getType() == Material.FISHING_ROD) { 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 { else {
// We know something was caught, so if the rod wasn't in the main hand it must be in the offhand // 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. // Rather than subtracting luck (and causing a minimum 3% chance for every drop), scale by luck.

View File

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

View File

@ -233,7 +233,7 @@ public class TamingManager extends SkillManager {
// Bred mules & donkeys can actually have horse-like stats, but llamas cannot. // Bred mules & donkeys can actually have horse-like stats, but llamas cannot.
if (beast instanceof AbstractHorse horseLikeCreature && !(beast instanceof Llama)) { 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) { if(jumpAttribute != null) {
double jumpStrength = jumpAttribute.getValue(); double jumpStrength = jumpAttribute.getValue();

View File

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

View File

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

View File

@ -1,39 +1,34 @@
package com.gmail.nossr50.util; package com.gmail.nossr50.util;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap; import java.util.HashMap;
public class EnchantmentUtils { public class EnchantmentUtils {
private static final HashMap<String, Enchantment> enchants = new HashMap<>(); private static final HashMap<String, Enchantment> legacyEnchantments = new HashMap<>();
static { static {
enchants.put("SHARPNESS", Enchantment.DAMAGE_ALL); // backwards compatibility for looking up legacy bukkit enums
enchants.put("POWER", Enchantment.ARROW_DAMAGE); addLegacyEnchantmentLookup("SHARPNESS", "DAMAGE_ALL");
enchants.put("FIRE_PROTECTION", Enchantment.PROTECTION_FIRE); addLegacyEnchantmentLookup("POWER", "ARROW_DAMAGE");
enchants.put("FEATHER_FALLING", Enchantment.PROTECTION_FALL); addLegacyEnchantmentLookup("FIRE_PROTECTION", "PROTECTION_FIRE");
enchants.put("PROTECTION", Enchantment.PROTECTION_ENVIRONMENTAL); addLegacyEnchantmentLookup("FEATHER_FALLING", "PROTECTION_FALL");
enchants.put("BLAST_PROTECTION", Enchantment.PROTECTION_EXPLOSIONS); addLegacyEnchantmentLookup("PROTECTION", "PROTECTION_ENVIRONMENTAL");
enchants.put("PROJECTILE_PROTECTION", Enchantment.PROTECTION_PROJECTILE); addLegacyEnchantmentLookup("BLAST_PROTECTION", "PROTECTION_EXPLOSIONS");
enchants.put("RESPIRATION", Enchantment.OXYGEN); addLegacyEnchantmentLookup("PROJECTILE_PROTECTION", "PROTECTION_PROJECTILE");
enchants.put("INFINITY", Enchantment.ARROW_INFINITE); addLegacyEnchantmentLookup("RESPIRATION", "OXYGEN");
enchants.put("AQUA_AFFINITY", Enchantment.WATER_WORKER); addLegacyEnchantmentLookup("INFINITY", "ARROW_INFINITE");
enchants.put("UNBREAKING", Enchantment.DURABILITY); addLegacyEnchantmentLookup("AQUA_AFFINITY", "WATER_WORKER");
enchants.put("SMITE", Enchantment.DAMAGE_UNDEAD); addLegacyEnchantmentLookup("UNBREAKING", "DURABILITY");
enchants.put("BANE_OF_ARTHROPODS", Enchantment.DAMAGE_ARTHROPODS); addLegacyEnchantmentLookup("SMITE", "DAMAGE_UNDEAD");
enchants.put("EFFICIENCY", Enchantment.DIG_SPEED); addLegacyEnchantmentLookup("BANE_OF_ARTHROPODS", "DAMAGE_ARTHROPODS");
enchants.put("FIRE_ASPECT", Enchantment.FIRE_ASPECT); addLegacyEnchantmentLookup("EFFICIENCY", "DIG_SPEED");
enchants.put("SILK_TOUCH", Enchantment.SILK_TOUCH); addLegacyEnchantmentLookup("FORTUNE", "LOOT_BONUS_BLOCKS");
enchants.put("FORTUNE", Enchantment.LOOT_BONUS_BLOCKS); addLegacyEnchantmentLookup("LOOTING", "LOOT_BONUS_MOBS");
enchants.put("LOOTING", Enchantment.LOOT_BONUS_MOBS); addLegacyEnchantmentLookup("PUNCH", "ARROW_KNOCKBACK");
enchants.put("PUNCH", Enchantment.ARROW_KNOCKBACK); addLegacyEnchantmentLookup("FLAME", "ARROW_FIRE");
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);
} }
/** /**
@ -43,11 +38,19 @@ public class EnchantmentUtils {
* *
* @return Enchantment or null if no enchantment was found * @return Enchantment or null if no enchantment was found
*/ */
public static Enchantment getByName(String enchantmentName) { @SuppressWarnings("deprecation")
if (enchants.containsKey(enchantmentName)) { public static @Nullable Enchantment getByName(String enchantmentName) {
return enchants.get(enchantmentName); if (legacyEnchantments.containsKey(enchantmentName)) {
return legacyEnchantments.get(enchantmentName);
} }
return Enchantment.getByName(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));
}
}
} }

View File

@ -23,6 +23,8 @@ import org.jetbrains.annotations.Nullable;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import static java.util.Objects.requireNonNull;
public final class ItemUtils { public final class ItemUtils {
/** /**
* This is a static utility class, therefore we don't want any instances of * 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()); return mcMMO.getMaterialMapStore().isBow(item.getType().getKey().getKey());
} }
/**
* Exhaustive lookup for a Material by name.
* <p>
* 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. * 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()); 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) { public static boolean hasItemInEitherHand(@NotNull Player player, Material material) {
return player.getInventory().getItemInMainHand().getType() == material || player.getInventory().getItemInOffHand().getType() == material; return player.getInventory().getItemInMainHand().getType() == material || player.getInventory().getItemInOffHand().getType() == material;
} }
@ -681,7 +718,8 @@ public final class ItemUtils {
if(itemMeta == null) if(itemMeta == null)
return; 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); itemStack.setItemMeta(itemMeta);
} }

View File

@ -50,6 +50,7 @@ public class MaterialMapStore {
private final @NotNull HashSet<String> crossbows; private final @NotNull HashSet<String> crossbows;
private final @NotNull HashSet<String> tools; private final @NotNull HashSet<String> tools;
private final @NotNull HashSet<String> enchantables; private final @NotNull HashSet<String> enchantables;
private final @NotNull HashSet<String> maces;
private final @NotNull HashSet<String> ores; private final @NotNull HashSet<String> ores;
private final @NotNull HashSet<String> intendedToolPickAxe; private final @NotNull HashSet<String> intendedToolPickAxe;
@ -97,6 +98,7 @@ public class MaterialMapStore {
shovels = new HashSet<>(); shovels = new HashSet<>();
hoes = new HashSet<>(); hoes = new HashSet<>();
tridents = new HashSet<>(); tridents = new HashSet<>();
maces = new HashSet<>();
enchantables = new HashSet<>(); enchantables = new HashSet<>();
@ -453,6 +455,7 @@ public class MaterialMapStore {
enchantables.addAll(tridents); enchantables.addAll(tridents);
enchantables.addAll(bows); enchantables.addAll(bows);
enchantables.addAll(crossbows); enchantables.addAll(crossbows);
enchantables.addAll(maces);
enchantables.add("shears"); enchantables.add("shears");
enchantables.add("fishing_rod"); enchantables.add("fishing_rod");
@ -476,6 +479,7 @@ public class MaterialMapStore {
fillHoes(); fillHoes();
fillShovels(); fillShovels();
fillTridents(); fillTridents();
fillMaces();
fillStringTools(); fillStringTools();
fillBows(); fillBows();
fillCrossbows(); fillCrossbows();
@ -491,6 +495,7 @@ public class MaterialMapStore {
tools.addAll(stringTools); tools.addAll(stringTools);
tools.addAll(bows); tools.addAll(bows);
tools.addAll(crossbows); tools.addAll(crossbows);
tools.addAll(maces);
} }
private void fillBows() { private void fillBows() {
@ -507,6 +512,10 @@ public class MaterialMapStore {
stringTools.add("carrot_on_a_stick"); stringTools.add("carrot_on_a_stick");
} }
private void fillMaces() {
maces.add("mace");
}
private void fillTridents() { private void fillTridents() {
tridents.add("trident"); tridents.add("trident");
} }
@ -824,6 +833,14 @@ public class MaterialMapStore {
return tridents.contains(id); 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) { public boolean isLeatherArmor(@NotNull Material material) {
return isLeatherArmor(material.getKey().getKey()); return isLeatherArmor(material.getKey().getKey());
} }

View File

@ -246,6 +246,14 @@ public final class Permissions {
} }
public static boolean tridentsLimitBreak(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.tridents.superability"); } 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 * PARTY
*/ */

View File

@ -0,0 +1,6 @@
package com.gmail.nossr50.util;
public enum PotionCompatibilityType {
PRE_1_20_5,
POST_1_20_5
}

View File

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

View File

@ -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<String, String> 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<PotionEffectType> potionEffectTypeList = (List<PotionEffectType>) 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);
}
}
}

View File

@ -33,6 +33,9 @@ public final class CommandRegistrationManager {
private static void registerSkillCommands() { private static void registerSkillCommands() {
for (PrimarySkillType skill : PrimarySkillType.values()) { for (PrimarySkillType skill : PrimarySkillType.values()) {
if (skill == PrimarySkillType.MACES)
continue;
String commandName = skill.toString().toLowerCase(Locale.ENGLISH); String commandName = skill.toString().toLowerCase(Locale.ENGLISH);
String localizedName = mcMMO.p.getSkillTools().getLocalizedSkillName(skill).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()); command.setExecutor(new HerbalismCommand());
break; break;
case MACES:
// command.setExecutor(new MacesCommand());
break;
case MINING: case MINING:
command.setExecutor(new MiningCommand()); command.setExecutor(new MiningCommand());
break; break;
@ -113,7 +120,7 @@ public final class CommandRegistrationManager {
break; break;
default: default:
break; throw new IllegalStateException("Unexpected value: " + skill);
} }
} }
} }

View File

@ -23,7 +23,6 @@ import java.util.HashMap;
* In 2.2 we are switching to modules and that will clean things up significantly * 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 { public class CompatibilityManager {
private @NotNull HashMap<CompatibilityType, Boolean> supportedLayers; private @NotNull HashMap<CompatibilityType, Boolean> supportedLayers;
private boolean isFullyCompatibleServerSoftware = true; //true if all compatibility layers load successfully private boolean isFullyCompatibleServerSoftware = true; //true if all compatibility layers load successfully
@ -159,7 +158,7 @@ public class CompatibilityManager {
return masterAnglerCompatibility; return masterAnglerCompatibility;
} }
public @Nullable MinecraftGameVersion getMinecraftGameVersion() { public @NotNull MinecraftGameVersion getMinecraftGameVersion() {
return minecraftGameVersion; return minecraftGameVersion;
} }
} }

View File

@ -111,6 +111,7 @@ public final class CombatUtils {
} }
} }
} }
private static void processTridentCombatMelee(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event) { private static void processTridentCombatMelee(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event) {
if (event.getCause() == DamageCause.THORNS) { if (event.getCause() == DamageCause.THORNS) {
return; return;
@ -214,6 +215,32 @@ public final class CombatUtils {
delayArrowMetaCleanup(arrow); 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) { private static void processAxeCombat(@NotNull LivingEntity target, @NotNull Player player, @NotNull EntityDamageByEntityEvent event) {
if (event.getCause() == DamageCause.THORNS) { if (event.getCause() == DamageCause.THORNS) {
return; return;
@ -498,6 +525,15 @@ public final class CombatUtils {
processTridentCombatMelee(target, player, event); 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) { else if (entityType == EntityType.WOLF) {

View File

@ -198,6 +198,7 @@ public class SkillTools {
case SUPER_SHOTGUN -> PrimarySkillType.CROSSBOWS; case SUPER_SHOTGUN -> PrimarySkillType.CROSSBOWS;
case TRIDENTS_SUPER_ABILITY -> PrimarySkillType.TRIDENTS; case TRIDENTS_SUPER_ABILITY -> PrimarySkillType.TRIDENTS;
case EXPLOSIVE_SHOT -> PrimarySkillType.ARCHERY; case EXPLOSIVE_SHOT -> PrimarySkillType.ARCHERY;
case MACES_SUPER_ABILITY -> PrimarySkillType.MACES;
}; };
} }

View File

@ -20,7 +20,6 @@ import com.gmail.nossr50.util.text.StringUtils;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe; import org.bukkit.inventory.Recipe;
@ -28,12 +27,13 @@ import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.ShapelessRecipe; import org.bukkit.inventory.ShapelessRecipe;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Iterator; import java.util.Iterator;
import static com.gmail.nossr50.util.PotionEffectMapper.getHaste;
public final class SkillUtils { public final class SkillUtils {
/** /**
* This is a static utility class, therefore we don't want any instances of * This is a static utility class, therefore we don't want any instances of
@ -148,13 +148,8 @@ public final class SkillUtils {
return; return;
} }
int originalDigSpeed = heldItem.getEnchantmentLevel(Enchantment.DIG_SPEED); int originalDigSpeed = heldItem.getEnchantmentLevel(mcMMO.p.getEnchantmentMapper().getEfficiency());
ItemUtils.addDigSpeedToItem(heldItem, heldItem.getEnchantmentLevel(mcMMO.p.getEnchantmentMapper().getEfficiency()));
//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));
//1.13.2+ will have persistent metadata for this item //1.13.2+ will have persistent metadata for this item
mcMMO.getMetadataService().getItemMetadataService().setSuperAbilityBoostedItem(heldItem, originalDigSpeed); mcMMO.getMetadataService().getItemMetadataService().setSuperAbilityBoostedItem(heldItem, originalDigSpeed);
@ -162,9 +157,9 @@ public final class SkillUtils {
int duration = 0; int duration = 0;
int amplifier = 0; int amplifier = 0;
if (player.hasPotionEffect(PotionEffectType.FAST_DIGGING)) { if (player.hasPotionEffect(getHaste())) {
for (PotionEffect effect : player.getActivePotionEffects()) { for (PotionEffect effect : player.getActivePotionEffects()) {
if (effect.getType() == PotionEffectType.FAST_DIGGING) { if (effect.getType() == getHaste()) {
duration = effect.getDuration(); duration = effect.getDuration();
amplifier = effect.getAmplifier(); amplifier = effect.getAmplifier();
break; break;
@ -194,7 +189,7 @@ public final class SkillUtils {
mcMMO.p.getSkillTools().getSuperAbilityMaxLength(mcMMO.p.getSkillTools().getSuperAbility(skill))) * Misc.TICK_CONVERSION_FACTOR; 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); player.addPotionEffect(abilityBuff, true);
} }
} }
@ -221,7 +216,7 @@ public final class SkillUtils {
if(itemMeta != null) { if(itemMeta != null) {
// This is safe to call without prior checks. // This is safe to call without prior checks.
itemMeta.removeEnchant(Enchantment.DIG_SPEED); itemMeta.removeEnchant(mcMMO.p.getEnchantmentMapper().getEfficiency());
itemStack.setItemMeta(itemMeta); itemStack.setItemMeta(itemMeta);
ItemUtils.removeAbilityLore(itemStack); ItemUtils.removeAbilityLore(itemStack);
@ -251,7 +246,7 @@ public final class SkillUtils {
Material type = itemStack.getType(); Material type = itemStack.getType();
short maxDurability = mcMMO.getRepairableManager().isRepairable(type) ? mcMMO.getRepairableManager().getRepairable(type).getMaximumDurability() : type.getMaxDurability(); 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)); itemStack.setDurability((short) Math.min(itemStack.getDurability() + durabilityModifier, maxDurability));
} }
@ -281,7 +276,7 @@ public final class SkillUtils {
Material type = itemStack.getType(); Material type = itemStack.getType();
short maxDurability = mcMMO.getRepairableManager().isRepairable(type) ? mcMMO.getRepairableManager().getRepairable(type).getMaximumDurability() : type.getMaxDurability(); 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)); itemStack.setDurability((short) Math.min(itemStack.getDurability() + durabilityModifier, maxDurability));
} }

View File

@ -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 # 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 # 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) # 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 MoveRange: 3
OverFishLimit: 10 OverFishLimit: 10
Experience_Bars: 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 Enable: true
Update: Update:
# XP that you gained from your party but not yourself # XP that you gained from your party but not yourself
@ -98,6 +88,10 @@ Experience_Bars:
Enable: true Enable: true
Color: YELLOW Color: YELLOW
BarStyle: SEGMENTED_6 BarStyle: SEGMENTED_6
Maces:
Enable: true
Color: BLUE
BarStyle: SEGMENTED_6
Repair: Repair:
Enable: true Enable: true
Color: PURPLE 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. # 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: Skill_Multiplier:
Maces: 1.0
Crossbows: 1.0 Crossbows: 1.0
Tridents: 1.0 Tridents: 1.0
Swords: 1.0 Swords: 1.0
@ -217,6 +212,9 @@ Diminished_Returns:
Repair: 20000 Repair: 20000
Fishing: 20000 Fishing: 20000
Alchemy: 20000 Alchemy: 20000
Crossbows: 20000
Tridents: 20000
Maces: 20000
Time_Interval: 10 Time_Interval: 10

View File

@ -1,3 +1,4 @@
Placeholder= This value is for any WIP locale entries that will not be displayed to users
JSON.Rank=Rank JSON.Rank=Rank
JSON.DescriptionHeader=Description: JSON.DescriptionHeader=Description:
JSON.JWrapper.Header=Details JSON.JWrapper.Header=Details
@ -26,6 +27,7 @@ JSON.Salvage=Salvage
JSON.Swords=Swords JSON.Swords=Swords
JSON.Taming=Taming JSON.Taming=Taming
JSON.Tridents=Tridents JSON.Tridents=Tridents
JSON.Maces=Maces
JSON.Unarmed=Unarmed JSON.Unarmed=Unarmed
JSON.Woodcutting=Woodcutting JSON.Woodcutting=Woodcutting
JSON.URL.Website=The official mcMMO Website! JSON.URL.Website=The official mcMMO Website!
@ -96,6 +98,7 @@ Overhaul.Name.Smelting=Smelting
Overhaul.Name.Swords=Swords Overhaul.Name.Swords=Swords
Overhaul.Name.Taming=Taming Overhaul.Name.Taming=Taming
Overhaul.Name.Tridents=Tridents Overhaul.Name.Tridents=Tridents
Overhaul.Name.Maces=Maces
Overhaul.Name.Unarmed=Unarmed Overhaul.Name.Unarmed=Unarmed
Overhaul.Name.Woodcutting=Woodcutting Overhaul.Name.Woodcutting=Woodcutting
# /mcMMO Command Style Stuff # /mcMMO Command Style Stuff
@ -122,6 +125,7 @@ XPBar.Smelting=Smelting Lv.&6{0}
XPBar.Swords=Swords Lv.&6{0} XPBar.Swords=Swords Lv.&6{0}
XPBar.Taming=Taming Lv.&6{0} XPBar.Taming=Taming Lv.&6{0}
XPBar.Tridents=Tridents Lv.&6{0} XPBar.Tridents=Tridents Lv.&6{0}
XPBar.Maces=Maces Lv.&6{0}
XPBar.Unarmed=Unarmed Lv.&6{0} XPBar.Unarmed=Unarmed Lv.&6{0}
XPBar.Woodcutting=Woodcutting 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 #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.SkillName=MACES
Maces.Ability.Lower=&7You lower your mace. Maces.Ability.Lower=&7You lower your mace.
Maces.Ability.Ready=&3You &6ready&3 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.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.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 Maces.SubSkill.MacesLimitBreak.Stat=Limit Break Max DMG

View File

@ -154,6 +154,9 @@ commands:
salvage: salvage:
description: Detailed mcMMO skill info description: Detailed mcMMO skill info
permission: mcmmo.commands.salvage permission: mcmmo.commands.salvage
maces:
description: Detailed mcMMO skill info
permission: mcmmo.commands.maces
mmopower: mmopower:
description: Shows skill mastery and power level info description: Shows skill mastery and power level info
permission: mcmmo.commands.mmopower permission: mcmmo.commands.mmopower

View File

@ -443,6 +443,30 @@ Salvage:
Rank_6: 750 Rank_6: 750
Rank_7: 850 Rank_7: 850
Rank_8: 1000 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: Mining:
MotherLode: MotherLode:
Standard: Standard:

View File

@ -16,13 +16,12 @@ import com.gmail.nossr50.util.blockmeta.ChunkManager;
import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.player.UserManager;
import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.RankUtils;
import com.gmail.nossr50.util.skills.SkillTools; import com.gmail.nossr50.util.skills.SkillTools;
import org.bukkit.Location; import org.bukkit.*;
import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemFactory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
import org.mockito.MockedStatic; import org.mockito.MockedStatic;
import org.mockito.Mockito; import org.mockito.Mockito;
@ -31,9 +30,10 @@ import java.util.UUID;
import java.util.logging.Logger; import java.util.logging.Logger;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.*;
public abstract class MMOTestEnvironment { public abstract class MMOTestEnvironment {
protected MockedStatic<Bukkit> mockedBukkit;
protected MockedStatic<mcMMO> mockedMcMMO; protected MockedStatic<mcMMO> mockedMcMMO;
protected MockedStatic<ChatConfig> mockedChatConfig; protected MockedStatic<ChatConfig> mockedChatConfig;
protected MockedStatic<ExperienceConfig> experienceConfig; protected MockedStatic<ExperienceConfig> experienceConfig;
@ -63,26 +63,27 @@ public abstract class MMOTestEnvironment {
protected PlayerProfile playerProfile; protected PlayerProfile playerProfile;
protected McMMOPlayer mmoPlayer; protected McMMOPlayer mmoPlayer;
protected String playerName = "testPlayer"; protected String playerName = "testPlayer";
protected ItemFactory itemFactory;
protected ChunkManager chunkManager; protected ChunkManager chunkManager;
protected MaterialMapStore materialMapStore; protected MaterialMapStore materialMapStore;
protected void mockBaseEnvironment(Logger logger) throws InvalidSkillException { protected void mockBaseEnvironment(Logger logger) throws InvalidSkillException {
mockedMcMMO = Mockito.mockStatic(mcMMO.class); mockedMcMMO = mockStatic(mcMMO.class);
mcMMO.p = Mockito.mock(mcMMO.class); mcMMO.p = mock(mcMMO.class);
when(mcMMO.p.getLogger()).thenReturn(logger); when(mcMMO.p.getLogger()).thenReturn(logger);
// place store // place store
chunkManager = Mockito.mock(ChunkManager.class); chunkManager = mock(ChunkManager.class);
when(mcMMO.getPlaceStore()).thenReturn(chunkManager); when(mcMMO.getPlaceStore()).thenReturn(chunkManager);
// shut off mod manager for woodcutting // 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); when(mcMMO.getModManager().isCustomLog(any())).thenReturn(false);
// chat config // chat config
mockedChatConfig = Mockito.mockStatic(ChatConfig.class); mockedChatConfig = mockStatic(ChatConfig.class);
when(ChatConfig.getInstance()).thenReturn(Mockito.mock(ChatConfig.class)); when(ChatConfig.getInstance()).thenReturn(mock(ChatConfig.class));
// general config // general config
mockGeneralConfig(); mockGeneralConfig();
@ -108,29 +109,34 @@ public abstract class MMOTestEnvironment {
mockPermissions(); mockPermissions();
mockedRankUtils = Mockito.mockStatic(RankUtils.class); mockedRankUtils = mockStatic(RankUtils.class);
// wire server // wire server
this.server = Mockito.mock(Server.class); this.server = mock(Server.class);
when(mcMMO.p.getServer()).thenReturn(server); 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 // wire plugin manager
this.pluginManager = Mockito.mock(PluginManager.class); this.pluginManager = mock(PluginManager.class);
when(server.getPluginManager()).thenReturn(pluginManager); when(server.getPluginManager()).thenReturn(pluginManager);
// wire world // wire world
this.world = Mockito.mock(World.class); this.world = mock(World.class);
// wire Misc // wire Misc
this.mockedMisc = Mockito.mockStatic(Misc.class); this.mockedMisc = mockStatic(Misc.class);
when(Misc.getBlockCenter(any())).thenReturn(new Location(world, 0, 0, 0)); when(Misc.getBlockCenter(any())).thenReturn(new Location(world, 0, 0, 0));
// setup player and player related mocks after everything else // 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); when(player.getUniqueId()).thenReturn(playerUUID);
// wire inventory // wire inventory
this.playerInventory = Mockito.mock(PlayerInventory.class); this.playerInventory = mock(PlayerInventory.class);
when(player.getInventory()).thenReturn(playerInventory); when(player.getInventory()).thenReturn(playerInventory);
// PlayerProfile and McMMOPlayer are partially mocked // PlayerProfile and McMMOPlayer are partially mocked
@ -138,7 +144,7 @@ public abstract class MMOTestEnvironment {
mmoPlayer = Mockito.spy(new McMMOPlayer(player, playerProfile)); mmoPlayer = Mockito.spy(new McMMOPlayer(player, playerProfile));
// wire user manager // wire user manager
this.mockedUserManager = Mockito.mockStatic(UserManager.class); this.mockedUserManager = mockStatic(UserManager.class);
when(UserManager.getPlayer(player)).thenReturn(mmoPlayer); when(UserManager.getPlayer(player)).thenReturn(mmoPlayer);
this.materialMapStore = new MaterialMapStore(); this.materialMapStore = new MaterialMapStore();
@ -146,7 +152,7 @@ public abstract class MMOTestEnvironment {
} }
private void mockPermissions() { 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.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true);
when(Permissions.canUseSubSkill(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); when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true);
@ -155,16 +161,16 @@ public abstract class MMOTestEnvironment {
} }
private void mockRankConfig() { private void mockRankConfig() {
rankConfig = Mockito.mock(RankConfig.class); rankConfig = mock(RankConfig.class);
} }
private void mockAdvancedConfig() { private void mockAdvancedConfig() {
this.advancedConfig = Mockito.mock(AdvancedConfig.class); this.advancedConfig = mock(AdvancedConfig.class);
when(mcMMO.p.getAdvancedConfig()).thenReturn(advancedConfig); when(mcMMO.p.getAdvancedConfig()).thenReturn(advancedConfig);
} }
private void mockGeneralConfig() { private void mockGeneralConfig() {
generalConfig = Mockito.mock(GeneralConfig.class); generalConfig = mock(GeneralConfig.class);
when(generalConfig.getTreeFellerThreshold()).thenReturn(100); when(generalConfig.getTreeFellerThreshold()).thenReturn(100);
when(generalConfig.getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, Material.OAK_LOG)).thenReturn(true); when(generalConfig.getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, Material.OAK_LOG)).thenReturn(true);
when(generalConfig.getLocale()).thenReturn("en_US"); when(generalConfig.getLocale()).thenReturn("en_US");
@ -172,15 +178,15 @@ public abstract class MMOTestEnvironment {
} }
private void mockPartyConfig() { private void mockPartyConfig() {
partyConfig = Mockito.mock(PartyConfig.class); partyConfig = mock(PartyConfig.class);
when(partyConfig.isPartyEnabled()).thenReturn(false); when(partyConfig.isPartyEnabled()).thenReturn(false);
when(mcMMO.p.getPartyConfig()).thenReturn(partyConfig); when(mcMMO.p.getPartyConfig()).thenReturn(partyConfig);
} }
private void mockExperienceConfig() { 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 // Combat
when(ExperienceConfig.getInstance().getCombatXP("Cow")).thenReturn(1D); when(ExperienceConfig.getInstance().getCombatXP("Cow")).thenReturn(1D);
@ -212,5 +218,8 @@ public abstract class MMOTestEnvironment {
if (mockedEventUtils != null) { if (mockedEventUtils != null) {
mockedEventUtils.close(); mockedEventUtils.close();
} }
if (mockedBukkit != null) {
mockedBukkit.close();
}
} }
} }

View File

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

View File

@ -10,7 +10,6 @@ import com.gmail.nossr50.util.skills.SkillTools;
import com.google.common.io.Files; import com.google.common.io.Files;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach; 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 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_BADDATA = "baddatadb.users";
public static final @NotNull String DB_HEALTHY = "healthydb.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 @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 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 static File tempDir;
private final static @NotNull Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); private final static @NotNull Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
private final long PURGE_TIME = 2630000000L; 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 //Making them all unique makes it easier on us to edit this stuff later
int expectedLvlMining = 1, expectedLvlWoodcutting = 2, expectedLvlRepair = 3, int expectedLvlMining = 1, expectedLvlWoodcutting = 2, expectedLvlRepair = 3,
expectedLvlUnarmed = 4, expectedLvlHerbalism = 5, expectedLvlExcavation = 6, expectedLvlUnarmed = 4, expectedLvlHerbalism = 5, expectedLvlExcavation = 6,
expectedLvlArchery = 7, expectedLvlSwords = 8, expectedLvlAxes = 9, expectedLvlAcrobatics = 10, expectedLvlArchery = 7, expectedLvlSwords = 8, expectedLvlAxes = 9, expectedLvlAcrobatics = 10,
expectedLvlTaming = 11, expectedLvlFishing = 12, expectedLvlAlchemy = 13, expectedLvlCrossbows = 14, expectedLvlTaming = 11, expectedLvlFishing = 12, expectedLvlAlchemy = 13, expectedLvlCrossbows = 14,
expectedLvlTridents = 15; expectedLvlTridents = 15, expectedLvlMaces = 16;
float expectedExpMining = 10, expectedExpWoodcutting = 20, expectedExpRepair = 30, float expectedExpMining = 10, expectedExpWoodcutting = 20, expectedExpRepair = 30,
expectedExpUnarmed = 40, expectedExpHerbalism = 50, expectedExpExcavation = 60, expectedExpUnarmed = 40, expectedExpHerbalism = 50, expectedExpExcavation = 60,
expectedExpArchery = 70, expectedExpSwords = 80, expectedExpAxes = 90, expectedExpAcrobatics = 100, expectedExpArchery = 70, expectedExpSwords = 80, expectedExpAxes = 90, expectedExpAcrobatics = 100,
expectedExpTaming = 110, expectedExpFishing = 120, expectedExpAlchemy = 130, expectedExpCrossbows = 140, expectedExpTaming = 110, expectedExpFishing = 120, expectedExpAlchemy = 130, expectedExpCrossbows = 140,
expectedExpTridents = 150; expectedExpTridents = 150, expectedExpMaces = 160;
long expectedBerserkCd = 111, expectedGigaDrillBreakerCd = 222, expectedTreeFellerCd = 333, long expectedBerserkCd = 111, expectedGigaDrillBreakerCd = 222, expectedTreeFellerCd = 333,
expectedGreenTerraCd = 444, expectedSerratedStrikesCd = 555, expectedSkullSplitterCd = 666, expectedGreenTerraCd = 444, expectedSerratedStrikesCd = 555, expectedSkullSplitterCd = 666,
expectedSuperBreakerCd = 777, expectedBlastMiningCd = 888, expectedChimaeraWingCd = 999, expectedSuperBreakerCd = 777, expectedBlastMiningCd = 888, expectedChimaeraWingCd = 999,
expectedSuperShotgunCd = 1111, expectedTridentSuperCd = 2222, expectedExplosiveShotCd = 3333; expectedSuperShotgunCd = 1111, expectedTridentSuperCd = 2222, expectedExplosiveShotCd = 3333,
expectedMacesSuperCd = 4444;
int expectedScoreboardTips = 1111; int expectedScoreboardTips = 1111;
Long expectedLastLogin = 2020L; Long expectedLastLogin = 2020L;
@ -75,10 +72,8 @@ class FlatFileDatabaseManagerTest {
@BeforeEach @BeforeEach
void init() { void init() {
assertNull(db);
//noinspection UnstableApiUsage //noinspection UnstableApiUsage
tempDir = Files.createTempDir(); tempDir = Files.createTempDir();
db = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true);
} }
private @NotNull String getTemporaryUserFilePath() { private @NotNull String getTemporaryUserFilePath() {
@ -88,7 +83,6 @@ class FlatFileDatabaseManagerTest {
@AfterEach @AfterEach
void tearDown() { void tearDown() {
recursiveDelete(tempDir); recursiveDelete(tempDir);
db = null;
} }
//Nothing wrong with this database //Nothing wrong with this database
@ -150,17 +144,19 @@ class FlatFileDatabaseManagerTest {
@Test @Test
void testDefaultInit() { void testDefaultInit() {
db = new FlatFileDatabaseManager(getTemporaryUserFilePath(), logger, PURGE_TIME, 0); new FlatFileDatabaseManager(getTemporaryUserFilePath(), logger, PURGE_TIME, 0);
} }
@Test @Test
void testUpdateLeaderboards() { void testUpdateLeaderboards() {
assertNotNull(db); FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true);
assertEquals(LeaderboardStatus.UPDATED, db.updateLeaderboards()); assertNotNull(flatFileDatabaseManager);
assertEquals(LeaderboardStatus.UPDATED, flatFileDatabaseManager.updateLeaderboards());
} }
@Test @Test
void testSaveUser() { 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 //Make a Profile to save and check to see if it worked
UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3");
String playerName = "nossr50"; String playerName = "nossr50";
@ -168,15 +164,15 @@ class FlatFileDatabaseManagerTest {
//The above profile should be "zero" initialized //The above profile should be "zero" initialized
//Save the zero version and see if it looks correct //Save the zero version and see if it looks correct
assertNotNull(db); assertNotNull(flatFileDatabaseManager);
assertTrue(db.getUsersFile().exists()); //Users file should have been created from the above com.gmail.nossr50.database.FlatFileDatabaseManager.checkFileHealthAndStructure assertTrue(flatFileDatabaseManager.getUsersFile().exists()); //Users file should have been created from the above com.gmail.nossr50.database.FlatFileDatabaseManager.checkFileHealthAndStructure
assertNotNull(db.getUsersFile()); assertNotNull(flatFileDatabaseManager.getUsersFile());
//The DB is empty at this point, add our user //The flatFileDatabaseManager is empty at this point, add our user
assertTrue(db.saveUser(testProfile)); //True means we saved the user assertTrue(flatFileDatabaseManager.saveUser(testProfile)); //True means we saved the user
//Check for the empty profile //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 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(uuid, retrievedFromData.getUniqueId());
assertEquals(playerName, retrievedFromData.getPlayerName()); assertEquals(playerName, retrievedFromData.getPlayerName());
@ -187,9 +183,9 @@ class FlatFileDatabaseManagerTest {
String alteredName = "changedmyname"; String alteredName = "changedmyname";
PlayerProfile changedNameProfile = new PlayerProfile(alteredName, uuid, 0); 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 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(uuid, retrievedFromData.getUniqueId());
assertEquals(alteredName, retrievedFromData.getPlayerName()); assertEquals(alteredName, retrievedFromData.getPlayerName());
@ -198,49 +194,27 @@ class FlatFileDatabaseManagerTest {
@Test @Test
void testAddedMissingLastLoginValues() { void testAddedMissingLastLoginValues() {
File dbFile = prepareDatabaseTestResource(DB_MISSING_LAST_LOGIN); File dbFile = prepareDatabaseTestResource(DB_MISSING_LAST_LOGIN);
FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(dbFile, logger, PURGE_TIME, 0, true);
//This makes sure our private method is working before the tests run afterwards List<FlatFileDataFlag> flagsFound = flatFileDatabaseManager.checkFileHealthAndStructure();
ArrayList<String[]> 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<FlatFileDataFlag> flagsFound = db.checkFileHealthAndStructure();
assertNotNull(flagsFound); assertNotNull(flagsFound);
assertTrue(flagsFound.contains(FlatFileDataFlag.LAST_LOGIN_SCHEMA_UPGRADE)); assertTrue(flagsFound.contains(FlatFileDataFlag.LAST_LOGIN_SCHEMA_UPGRADE));
//Check for the fixed value //Check for the fixed value
PlayerProfile profile = db.loadPlayerProfile("nossr50"); PlayerProfile profile = flatFileDatabaseManager.loadPlayerProfile("nossr50");
assertEquals(-1, (long) profile.getLastLogin()); assertEquals(-1, (long) profile.getLastLogin());
} }
@Test @Test
void testLoadByName() { void testLoadByName() {
File healthyDB = prepareDatabaseTestResource(DB_HEALTHY); File healthyDB = prepareDatabaseTestResource(DB_HEALTHY);
FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(healthyDB, logger, PURGE_TIME, 0, true);
/* List<FlatFileDataFlag> flagsFound = flatFileDatabaseManager.checkFileHealthAndStructure();
* 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<String[]> 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<FlatFileDataFlag> flagsFound = db.checkFileHealthAndStructure();
assertNull(flagsFound); //No flags should be found assertNull(flagsFound); //No flags should be found
/*
* Once the DB looks fine load the profile
*/
String playerName = "nossr50"; String playerName = "nossr50";
UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3");
PlayerProfile profile = db.loadPlayerProfile(playerName); PlayerProfile profile = flatFileDatabaseManager.loadPlayerProfile(playerName);
testHealthyDataProfileValues(playerName, uuid, profile); testHealthyDataProfileValues(playerName, uuid, profile);
} }
@ -251,16 +225,16 @@ class FlatFileDatabaseManagerTest {
String playerName = "nossr50"; String playerName = "nossr50";
int newUserTestStartingLvl = 1337; int newUserTestStartingLvl = 1337;
db = new FlatFileDatabaseManager(new File(tempDir.getPath() + File.separator + TEST_FILE_NAME), logger, PURGE_TIME, newUserTestStartingLvl, true); var flatFileDatabaseManager = new FlatFileDatabaseManager(new File(tempDir.getPath() + File.separator + TEST_FILE_NAME), logger, PURGE_TIME, newUserTestStartingLvl, true);
db.checkFileHealthAndStructure(); flatFileDatabaseManager.checkFileHealthAndStructure();
PlayerProfile playerProfile = db.newUser(playerName, uuid); PlayerProfile playerProfile = flatFileDatabaseManager.newUser(playerName, uuid);
assertTrue(playerProfile.isLoaded()); assertTrue(playerProfile.isLoaded());
assertEquals(playerName, playerProfile.getPlayerName()); assertEquals(playerName, playerProfile.getPlayerName());
assertEquals(uuid, playerProfile.getUniqueId()); assertEquals(uuid, playerProfile.getUniqueId());
PlayerProfile retrievedFromDisk = db.loadPlayerProfile(uuid); PlayerProfile retrievedFromDisk = flatFileDatabaseManager.loadPlayerProfile(uuid);
assertTrue(retrievedFromDisk.isLoaded()); assertTrue(retrievedFromDisk.isLoaded());
assertEquals(playerName, retrievedFromDisk.getPlayerName()); assertEquals(playerName, retrievedFromDisk.getPlayerName());
assertEquals(uuid, retrievedFromDisk.getUniqueId()); assertEquals(uuid, retrievedFromDisk.getUniqueId());
@ -270,11 +244,11 @@ class FlatFileDatabaseManagerTest {
checkNewUserValues(retrievedFromDisk, newUserTestStartingLvl); checkNewUserValues(retrievedFromDisk, newUserTestStartingLvl);
//TODO: Should we do any dupe checking? Probably not needed as it would be caught on the next load //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)); flatFileDatabaseManager.newUser("disco", new UUID(3, 3));
db.newUser("dingus", new UUID(3, 4)); flatFileDatabaseManager.newUser("dingus", new UUID(3, 4));
db.newUser("duped_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 @Test
@ -286,16 +260,16 @@ class FlatFileDatabaseManagerTest {
File file = prepareDatabaseTestResource(DB_HEALTHY); //Existing DB File file = prepareDatabaseTestResource(DB_HEALTHY); //Existing DB
int newUserTestStartingLvl = 1337; int newUserTestStartingLvl = 1337;
db = new FlatFileDatabaseManager(file, logger, PURGE_TIME, newUserTestStartingLvl, true); var flatFileDatabaseManager = new FlatFileDatabaseManager(file, logger, PURGE_TIME, newUserTestStartingLvl, true);
db.checkFileHealthAndStructure(); flatFileDatabaseManager.checkFileHealthAndStructure();
PlayerProfile playerProfile = db.newUser(playerName, uuid); PlayerProfile playerProfile = flatFileDatabaseManager.newUser(playerName, uuid);
assertTrue(playerProfile.isLoaded()); assertTrue(playerProfile.isLoaded());
assertEquals(playerName, playerProfile.getPlayerName()); assertEquals(playerName, playerProfile.getPlayerName());
assertEquals(uuid, playerProfile.getUniqueId()); assertEquals(uuid, playerProfile.getUniqueId());
PlayerProfile retrievedFromDisk = db.loadPlayerProfile(uuid); PlayerProfile retrievedFromDisk = flatFileDatabaseManager.loadPlayerProfile(uuid);
assertTrue(retrievedFromDisk.isLoaded()); assertTrue(retrievedFromDisk.isLoaded());
assertEquals(playerName, retrievedFromDisk.getPlayerName()); assertEquals(playerName, retrievedFromDisk.getPlayerName());
assertEquals(uuid, retrievedFromDisk.getUniqueId()); assertEquals(uuid, retrievedFromDisk.getUniqueId());
@ -305,15 +279,15 @@ class FlatFileDatabaseManagerTest {
checkNewUserValues(retrievedFromDisk, newUserTestStartingLvl); checkNewUserValues(retrievedFromDisk, newUserTestStartingLvl);
//TODO: Should we do any dupe checking? Probably not needed as it would be caught on the next load //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)); flatFileDatabaseManager.newUser("bidoof", new UUID(3, 3));
db.newUser("derp", new UUID(3, 4)); flatFileDatabaseManager.newUser("derp", new UUID(3, 4));
db.newUser("pizza", 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 //Now we *fix* the flatFileDatabaseManager and there should be one less
db.checkFileHealthAndStructure(); flatFileDatabaseManager.checkFileHealthAndStructure();
assertEquals(6, getSplitDataFromFile(db.getUsersFile()).size()); assertEquals(6, getSplitDataFromFile(flatFileDatabaseManager.getUsersFile()).size());
} }
private void checkNewUserValues(@NotNull PlayerProfile playerProfile, int startingLevel) { private void checkNewUserValues(@NotNull PlayerProfile playerProfile, int startingLevel) {
@ -338,71 +312,45 @@ class FlatFileDatabaseManagerTest {
@Test @Test
void testLoadByUUID() { void testLoadByUUID() {
File dbFile = prepareDatabaseTestResource(DB_HEALTHY); File dbFile = prepareDatabaseTestResource(DB_HEALTHY);
var flatFileDatabaseManager = new FlatFileDatabaseManager(dbFile, logger, PURGE_TIME, 0, true);
/* List<FlatFileDataFlag> flagsFound = flatFileDatabaseManager.checkFileHealthAndStructure();
* 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<String[]> 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<FlatFileDataFlag> flagsFound = db.checkFileHealthAndStructure();
assertNull(flagsFound); //No flags should be found 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"; String playerName = "nossr50";
UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3");
PlayerProfile profile1 = db.loadPlayerProfile(uuid); PlayerProfile profile1 = flatFileDatabaseManager.loadPlayerProfile(uuid);
testHealthyDataProfileValues(playerName, uuid, profile1); 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 @Test
void testLoadByUUIDAndName() { void testLoadByUUIDAndName() {
File dbFile = prepareDatabaseTestResource(DB_HEALTHY); File dbFile = prepareDatabaseTestResource(DB_HEALTHY);
var flatFileDatabaseManager = new FlatFileDatabaseManager(dbFile, logger, PURGE_TIME, 0, true);
/* List<FlatFileDataFlag> flagsFound = flatFileDatabaseManager.checkFileHealthAndStructure();
* 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<String[]> 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<FlatFileDataFlag> flagsFound = db.checkFileHealthAndStructure();
assertNull(flagsFound); //No flags should be found assertNull(flagsFound); //No flags should be found
/*
* Once the DB looks fine load the profile
*/
String playerName = "nossr50"; String playerName = "nossr50";
UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3");
Player player = initMockPlayer(playerName, uuid); Player player = initMockPlayer(playerName, uuid);
PlayerProfile profile1 = db.loadPlayerProfile(player); PlayerProfile profile1 = flatFileDatabaseManager.loadPlayerProfile(player);
testHealthyDataProfileValues(playerName, uuid, profile1); testHealthyDataProfileValues(playerName, uuid, profile1);
String updatedName = "updatedName"; String updatedName = "updatedName";
Player updatedNamePlayer = initMockPlayer(updatedName, uuid); Player updatedNamePlayer = initMockPlayer(updatedName, uuid);
PlayerProfile updatedNameProfile = db.loadPlayerProfile(updatedNamePlayer); PlayerProfile updatedNameProfile = flatFileDatabaseManager.loadPlayerProfile(updatedNamePlayer);
testHealthyDataProfileValues(updatedName, uuid, updatedNameProfile); testHealthyDataProfileValues(updatedName, uuid, updatedNameProfile);
Player shouldNotExist = initMockPlayer("doesntexist", new UUID(0, 1)); Player shouldNotExist = initMockPlayer("doesntexist", new UUID(0, 1));
PlayerProfile profile3 = db.loadPlayerProfile(shouldNotExist); PlayerProfile profile3 = flatFileDatabaseManager.loadPlayerProfile(shouldNotExist);
assertFalse(profile3.isLoaded()); assertFalse(profile3.isLoaded());
} }
@ -484,6 +432,7 @@ class FlatFileDatabaseManagerTest {
case BLAST_MINING -> expectedBlastMiningCd; case BLAST_MINING -> expectedBlastMiningCd;
case TRIDENTS_SUPER_ABILITY -> expectedTridentSuperCd; case TRIDENTS_SUPER_ABILITY -> expectedTridentSuperCd;
case EXPLOSIVE_SHOT -> expectedExplosiveShotCd; case EXPLOSIVE_SHOT -> expectedExplosiveShotCd;
case MACES_SUPER_ABILITY -> expectedMacesSuperCd;
default -> throw new RuntimeException("Values not defined for super ability please add " + default -> throw new RuntimeException("Values not defined for super ability please add " +
"values for " + superAbilityType.toString() + " to the test"); "values for " + superAbilityType.toString() + " to the test");
}; };
@ -491,165 +440,147 @@ class FlatFileDatabaseManagerTest {
} }
private float getExpectedExperienceHealthyDBEntryOne(@NotNull PrimarySkillType primarySkillType) { private float getExpectedExperienceHealthyDBEntryOne(@NotNull PrimarySkillType primarySkillType) {
switch(primarySkillType) { return switch (primarySkillType) {
case ACROBATICS: case ACROBATICS -> expectedExpAcrobatics;
return expectedExpAcrobatics; case ALCHEMY -> expectedExpAlchemy;
case ALCHEMY: case ARCHERY -> expectedExpArchery;
return expectedExpAlchemy; case AXES -> expectedExpAxes;
case ARCHERY: case CROSSBOWS -> expectedExpCrossbows;
return expectedExpArchery; case EXCAVATION -> expectedExpExcavation;
case AXES: case FISHING -> expectedExpFishing;
return expectedExpAxes; case HERBALISM -> expectedExpHerbalism;
case CROSSBOWS: case MINING -> expectedExpMining;
return expectedExpCrossbows; case REPAIR -> expectedExpRepair;
case EXCAVATION: case SALVAGE, SMELTING -> 0;
return expectedExpExcavation; case SWORDS -> expectedExpSwords;
case FISHING: case TAMING -> expectedExpTaming;
return expectedExpFishing; case TRIDENTS -> expectedExpTridents;
case HERBALISM: case UNARMED -> expectedExpUnarmed;
return expectedExpHerbalism; case WOODCUTTING -> expectedExpWoodcutting;
case MINING: case MACES -> expectedExpMaces;
return expectedExpMining; default ->
case REPAIR: throw new RuntimeException("Values for skill not defined, please add values for " + primarySkillType.toString() + " to the test");
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;
}
throw new RuntimeException("Values for skill not defined, please add values for " + primarySkillType.toString() + " to the test");
} }
private int getExpectedLevelHealthyDBEntryOne(@NotNull PrimarySkillType primarySkillType) { private int getExpectedLevelHealthyDBEntryOne(@NotNull PrimarySkillType primarySkillType) {
switch(primarySkillType) { return switch (primarySkillType) {
case ACROBATICS: case ACROBATICS -> expectedLvlAcrobatics;
return expectedLvlAcrobatics; case ALCHEMY -> expectedLvlAlchemy;
case ALCHEMY: case ARCHERY -> expectedLvlArchery;
return expectedLvlAlchemy; case AXES -> expectedLvlAxes;
case ARCHERY: case CROSSBOWS -> expectedLvlCrossbows;
return expectedLvlArchery; case EXCAVATION -> expectedLvlExcavation;
case AXES: case FISHING -> expectedLvlFishing;
return expectedLvlAxes; case HERBALISM -> expectedLvlHerbalism;
case CROSSBOWS: case MINING -> expectedLvlMining;
return expectedLvlCrossbows; case REPAIR -> expectedLvlRepair;
case EXCAVATION: case SALVAGE, SMELTING -> 0;
return expectedLvlExcavation; case SWORDS -> expectedLvlSwords;
case FISHING: case TAMING -> expectedLvlTaming;
return expectedLvlFishing; case TRIDENTS -> expectedLvlTridents;
case HERBALISM: case UNARMED -> expectedLvlUnarmed;
return expectedLvlHerbalism; case WOODCUTTING -> expectedLvlWoodcutting;
case MINING: case MACES -> expectedLvlMaces;
return expectedLvlMining; default ->
case REPAIR: throw new RuntimeException("Values for skill not defined, please add values for " + primarySkillType.toString() + " to the test");
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;
}
throw new RuntimeException("Values for skill not defined, please add values for " + primarySkillType.toString() + " to the test");
} }
@Test @Test
void testOverwriteName() { void testOverwriteName() {
overwriteDataAndCheckForFlag(db, duplicateNameDatabaseData, FlatFileDataFlag.DUPLICATE_NAME); FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true);
ArrayList<String[]> splitDataLines = getSplitDataFromFile(db.getUsersFile()); overwriteDataAndCheckForFlag(flatFileDatabaseManager, duplicateNameDatabaseData, FlatFileDataFlag.DUPLICATE_NAME);
ArrayList<String[]> splitDataLines = getSplitDataFromFile(flatFileDatabaseManager.getUsersFile());
assertNotEquals(splitDataLines.get(1)[0], splitDataLines.get(0)[0]); //Name comparison assertNotEquals(splitDataLines.get(1)[0], splitDataLines.get(0)[0]); //Name comparison
} }
@Test @Test
void testDataNotFound() { void testDataNotFound() {
FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true);
//Save the zero version and see if it looks correct //Save the zero version and see if it looks correct
assertNotNull(db); assertNotNull(flatFileDatabaseManager);
assertTrue(db.getUsersFile().exists()); assertTrue(flatFileDatabaseManager.getUsersFile().exists());
assertNotNull(db.getUsersFile()); assertNotNull(flatFileDatabaseManager.getUsersFile());
//Check for the "unloaded" profile //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 assertFalse(retrievedFromData.isLoaded()); //PlayerProfile::isLoaded returns false if data doesn't exist for the user
} }
@Test @Test
void testPurgePowerlessUsers() { void testPurgePowerlessUsers() {
replaceDataInFile(db, normalDatabaseData); FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true);
int purgeCount = db.purgePowerlessUsers(); replaceDataInFile(flatFileDatabaseManager, normalDatabaseData);
int purgeCount = flatFileDatabaseManager.purgePowerlessUsers();
assertEquals(purgeCount, 1); //1 User should have been purged assertEquals(purgeCount, 1); //1 User should have been purged
} }
@Test @Test
void testCheckFileHealthAndStructure() { void testCheckFileHealthAndStructure() {
replaceDataInFile(db, badDatabaseData); FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true);
replaceDataInFile(flatFileDatabaseManager, badDatabaseData);
List<FlatFileDataFlag> dataFlags = db.checkFileHealthAndStructure(); List<FlatFileDataFlag> dataFlags = flatFileDatabaseManager.checkFileHealthAndStructure();
assertNotNull(dataFlags); assertNotNull(dataFlags);
assertNotEquals(dataFlags.size(), 0); assertNotEquals(dataFlags.size(), 0);
} }
@Test @Test
void testFindFixableDuplicateNames() { 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 @Test
void testFindDuplicateUUIDs() { 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() @Test()
void findBadUUIDData() { 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 @Test
void testFindCorruptData() { 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 @Test
void testFindEmptyNames() { 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 @Test
void testFindBadValues() { 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 @Test
void testFindOutdatedData() { 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 @Test
void testGetDatabaseType() { void testGetDatabaseType() {
assertNotNull(db); FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true);
assertEquals(db.getDatabaseType(), DatabaseType.FLATFILE); assertNotNull(flatFileDatabaseManager);
assertEquals(flatFileDatabaseManager.getDatabaseType(), DatabaseType.FLATFILE);
} }
@Test @Test
void testReadRank() { void testReadRank() {
//This is an empty DB //This is an empty DB
assertNotNull(db); FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true);
String rankBoyName = "rankBoy"; String rankBoyName = "rankBoy";
UUID rankBoyUUID = new UUID(1337, 1337); UUID rankBoyUUID = new UUID(1337, 1337);
String rankGirlName = "rankGirl"; String rankGirlName = "rankGirl";
@ -658,9 +589,9 @@ class FlatFileDatabaseManagerTest {
PlayerProfile rankGirlProfile = addPlayerProfileWithLevelsAndSave(rankGirlName, rankGirlUUID, 100); //Rank 1 PlayerProfile rankGirlProfile = addPlayerProfileWithLevelsAndSave(rankGirlName, rankGirlUUID, 100); //Rank 1
PlayerProfile rankBoyProfile = addPlayerProfileWithLevelsAndSave(rankBoyName, rankBoyUUID, 10); //Rank 2 PlayerProfile rankBoyProfile = addPlayerProfileWithLevelsAndSave(rankBoyName, rankBoyUUID, 10); //Rank 2
assertEquals(LeaderboardStatus.UPDATED, db.updateLeaderboards()); assertEquals(LeaderboardStatus.UPDATED, flatFileDatabaseManager.updateLeaderboards());
Map<PrimarySkillType, Integer> rankGirlPositions = db.readRank(rankGirlName); Map<PrimarySkillType, Integer> rankGirlPositions = flatFileDatabaseManager.readRank(rankGirlName);
Map<PrimarySkillType, Integer> rankBoyPositions = db.readRank(rankBoyName); Map<PrimarySkillType, Integer> rankBoyPositions = flatFileDatabaseManager.readRank(rankBoyName);
for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { for(PrimarySkillType primarySkillType : PrimarySkillType.values()) {
if(primarySkillType.isChildSkill()) { if(primarySkillType.isChildSkill()) {
@ -672,8 +603,8 @@ class FlatFileDatabaseManagerTest {
} }
} }
assertEquals(1, db.readRank(rankGirlName).get(null)); //Girl should be position 1 assertEquals(1, flatFileDatabaseManager.readRank(rankGirlName).get(null)); //Girl should be position 1
assertEquals(2, db.readRank(rankBoyName).get(null)); //Boy should be position 2 assertEquals(2, flatFileDatabaseManager.readRank(rankBoyName).get(null)); //Boy should be position 2
} }
@Test @Test
@ -741,11 +672,11 @@ class FlatFileDatabaseManagerTest {
} }
private @NotNull PlayerProfile addPlayerProfileWithLevelsAndSave(String playerName, UUID uuid, int levels) { private @NotNull PlayerProfile addPlayerProfileWithLevelsAndSave(String playerName, UUID uuid, int levels) {
assertNotNull(db); FlatFileDatabaseManager flatFileDatabaseManager = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true);
assertFalse(db.loadPlayerProfile(uuid).isLoaded()); assertFalse(flatFileDatabaseManager.loadPlayerProfile(uuid).isLoaded());
db.newUser(playerName, uuid); flatFileDatabaseManager.newUser(playerName, uuid);
PlayerProfile leveledProfile = db.loadPlayerProfile(uuid); PlayerProfile leveledProfile = flatFileDatabaseManager.loadPlayerProfile(uuid);
assertTrue(leveledProfile.isLoaded()); assertTrue(leveledProfile.isLoaded());
assertEquals(playerName, leveledProfile.getPlayerName()); assertEquals(playerName, leveledProfile.getPlayerName());
@ -758,8 +689,8 @@ class FlatFileDatabaseManagerTest {
leveledProfile.modifySkill(primarySkillType, levels); //TODO: This method also resets XP, not cool leveledProfile.modifySkill(primarySkillType, levels); //TODO: This method also resets XP, not cool
} }
db.saveUser(leveledProfile); flatFileDatabaseManager.saveUser(leveledProfile);
leveledProfile = db.loadPlayerProfile(uuid); leveledProfile = flatFileDatabaseManager.loadPlayerProfile(uuid);
for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { for(PrimarySkillType primarySkillType : PrimarySkillType.values()) {
if(SkillTools.isChildSkill(primarySkillType)) { if(SkillTools.isChildSkill(primarySkillType)) {

View File

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

View File

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