diff --git a/Changelog.txt b/Changelog.txt index 56540e32b..389a79e2a 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -103,8 +103,59 @@ Version 2.2.000 Parties got unnecessarily complex in my absence, I have removed many party features in order to simplify parties and bring them closer to my vision. I have also added new features which should improve parties where it matters. About the removed party features, all the features I removed I consider poor quality features and I don't think they belong in mcMMO. Feel free to yell at me in discord if you disagree. I don't know what genius decided to make parties public by default, when I found out that parties had been changed to such a system I could barely contain my disgust. Parties are back to being private, you get invited by a party leader or party officer. That is the only way to join a party. +Version 2.1.182 + Fixed several errors in de locale (Thanks TheBusyBiscuit & w1tcherrr) + Fixed a bug where double smelt never succeeded if the furnace was empty + Added some safety so that mcMMO automatic save interval is never more frequent than 1 minute + +Version 2.1.181 + mcMMO no longer pointlessly tries to check for missing UUIDs for FlatFile database + Removed the "name change detected" message as some plugins (such as Plan) invoke API calls which spams the console with this message + Refactored code related to loading player data from the database + (API) Added DatabaseManager::loadPlayerProfile(String) + (API) Removed DatabaseManager::loadPlayerProfile(String, UUID, boolean) + (API) Removed DatabaseManager::loadPlayerProfile(String, boolean) + +Version 2.1.180 + mcMMO will now automatically remove corrupted data from mcmmo.users instead of catastrophic failure + When using FlatFile database (the default) mcMMO will try its best to inform you which players had corrupted data when it does repairs + Various minor optimizations and tweaks to the FlatFile database + mcMMO is now much more verbose when things go wrong with the FlatFile database (removed some silent errors, added more error messages/warnings) + mcMMO now uses UTF-8 compliant encoding for SQL databases (utf8mb4) + Fixed a bug where mcMMO could in some circumstances fail to update SQL schema and mark it as successful + Renamed updates.yml to updates_overhaul.yml to avoid some potential issues when upgrading from classic + + NOTES: + This update was tested pretty thoroughly so it should be pretty safe, let me know if you have issues in the mcMMO discord or GitHub issues page for mcMMO! + +Version 2.1.179 + Fixed a bug for FlatFile databases where some players with changed nicknames would have their levels not loaded upon login (possibly wiping their data) + + NOTES: + Players affected by this bug (introduced in 2.1.177) may have their data lost, but this patch reverts the change which caused this bug. + I suspect their data isn't lost and may be restored after this patch is loaded up, however if it is lost mcMMO makes regular backups so you can load one of those (check /plugins/mcMMO/) or manually edit their levels via MMOEDIT as a solution of sorts. + +Version 2.1.178 + Item replacement in vanilla fishing override back to SALMON from AIR (see notes) + + NOTES: + Apparently can't set items to AIR, my bad. I'll look into another solution for fishing plugin compatibility soon. + +Version 2.1.177 + Environmentally aware will now protect Wolves from Magma blocks + Fixed a bug where mcMMO would fail to update a players name when it detected a name change + mcMMO will treat vanished players as if they are offline when using the inspect command on them now (see notes) + mcMMO now listens to PlayerFishEvent at HIGH event priority instead of HIGHEST + Changed how vanilla fishing treasures are overridden (AIR instead of SALMON) + (API) Added McMMOReplaceVanillaTreasureEvent -- see notes + + NOTES: + A few changes were made to the inspect command, it used to reject you when used on vanished players, now it will be processed as if they are offline. + Additionally if you do inspect a vanished player, it will not use their display name (consistent with offline players) as that would give them away for being online + McMMOReplaceVanillaTreasureEvent is an event which is fired when mcMMO replaces a vanilla treasure with AIR if the server config file is set to override vanilla treasures, this causes some issues for other fishing plugins so this event helps those plugins be more compatible + Version 2.1.176 - Added another measure to prevent item stacks from reaching 65 from double smelt + Another fix for Double Smelt bringing item stack size to illegal values Version 2.1.175 Fixed a bug where mcMMO would occasionally give a 65 item stack from a double smelt on a furnace diff --git a/pom.xml b/pom.xml index 6dca8b41e..12514aa67 100755 --- a/pom.xml +++ b/pom.xml @@ -16,6 +16,16 @@ GitHub jar + + + neetgames + https://nexus.neetgames.com/repository/maven-releases/ + + + neetgames + https://nexus.neetgames.com/repository/maven-snapshots/ + + ${project.artifactId} ${basedir}/src/main/java @@ -236,27 +246,27 @@ net.kyori adventure-text-serializer-gson - 4.5.1 + 4.7.0 net.kyori adventure-api - 4.5.1 + 4.7.0 net.kyori adventure-nbt - 4.5.1 + 4.7.0 net.kyori adventure-key - 4.5.1 + 4.7.0 net.kyori adventure-text-serializer-gson-legacy-impl - 4.5.1 + 4.7.0 net.kyori diff --git a/src/main/java/com/gmail/nossr50/api/DatabaseAPI.java b/src/main/java/com/gmail/nossr50/api/DatabaseAPI.java index b44496ab5..a03a48490 100644 --- a/src/main/java/com/gmail/nossr50/api/DatabaseAPI.java +++ b/src/main/java/com/gmail/nossr50/api/DatabaseAPI.java @@ -22,7 +22,7 @@ public class DatabaseAPI { * @return true if the player exists in the DB, false if they do not */ public boolean doesPlayerExistInDB(UUID uuid) { - PlayerProfile playerProfile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(uuid); + PlayerProfile playerProfile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(uuid, null); return playerProfile.isLoaded(); } diff --git a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java index 668a66b5f..be325c281 100644 --- a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java +++ b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java @@ -1,1220 +1,1225 @@ -//package com.gmail.nossr50.api; -// -//import com.gmail.nossr50.api.exceptions.*; -//import com.gmail.nossr50.config.Config; -//import com.gmail.nossr50.config.experience.ExperienceConfig; -//import com.gmail.nossr50.datatypes.experience.FormulaType; -//import com.neetgames.mcmmo.player.OnlineMMOPlayer; -//import com.gmail.nossr50.datatypes.player.PlayerProfile; -//import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -//import com.gmail.nossr50.mcMMO; -//import com.gmail.nossr50.skills.child.FamilyTree; -//import com.gmail.nossr50.util.skills.CombatUtils; -//import org.bukkit.block.BlockState; -//import org.bukkit.entity.LivingEntity; -//import org.bukkit.entity.Player; -// -//import java.util.ArrayList; -//import java.util.Set; -//import java.util.UUID; -// -//public final class ExperienceAPI { -// private ExperienceAPI() {} -// -// /** -// * Returns whether given string is a valid type of skill suitable for the -// * other API calls in this class. -// *
-// * This function is designed for API usage. -// * -// * @param skillType A string that may or may not be a skill -// * @return true if this is a valid mcMMO skill -// */ -// public static boolean isValidSkillType(String skillType) { -// return mcMMO.p.getSkillRegister().getSkill(skillType) != null; -// } -// -// /** -// * Start the task that gives combat XP. -// * Processes combat XP like mcMMO normally would, so mcMMO will check whether or not the entity should reward XP when giving out the XP -// * -// * @param mmoPlayer The attacking player -// * @param target The defending entity -// * @param primarySkillType The skill being used -// * @param multiplier final XP result will be multiplied by this -// * @deprecated Draft API -// */ -// @Deprecated -// public static void addCombatXP(OnlineMMOPlayer mmoPlayer, LivingEntity target, PrimarySkillType primarySkillType, double multiplier) { -// CombatUtils.processCombatXP(mmoPlayer, target, primarySkillType, multiplier); -// } -// -// /** -// * Start the task that gives combat XP. -// * Processes combat XP like mcMMO normally would, so mcMMO will check whether or not the entity should reward XP when giving out the XP -// * -// * @param mmoPlayer The attacking player -// * @param target The defending entity -// * @param primarySkillType The skill being used -// * @deprecated Draft API -// */ -// @Deprecated -// public static void addCombatXP(OnlineMMOPlayer mmoPlayer, LivingEntity target, PrimarySkillType primarySkillType) { -// CombatUtils.processCombatXP(mmoPlayer, target, primarySkillType); -// } -// -// /** -// * Returns whether the given skill type string is both valid and not a -// * child skill. (Child skills have no XP of their own, and their level is -// * derived from the parent(s).) -// *
-// * This function is designed for API usage. -// * -// * @param skillType the skill to check -// * @return true if this is a valid, non-child mcMMO skill -// */ -// public static boolean isNonChildSkill(String skillType) { -// PrimarySkillType skill = mcMMO.p.getSkillRegister().getSkill(skillType); -// -// return skill != null && !skill.isChildSkill(); -// } -// -// @Deprecated -// public static void addRawXP(Player player, String skillType, int XP) { -// addRawXP(player, skillType, (float) XP); -// } -// -// /** -// * Adds raw XP to the player. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to add XP to -// * @param skillType The skill to add XP to -// * @param XP The amount of XP to add -// * -// * @throws InvalidSkillException if the given skill is not valid -// */ -// @Deprecated -// public static void addRawXP(Player player, String skillType, float XP) { -// addRawXP(player, skillType, XP, "UNKNOWN"); -// } -// -// /** -// * Adds raw XP to the player. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to add XP to -// * @param skillType The skill to add XP to -// * @param XP The amount of XP to add -// * @param xpGainReason The reason to gain XP -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidXPGainReasonException if the given xpGainReason is not valid -// */ -// public static void addRawXP(Player player, String skillType, float XP, String xpGainReason) { -// addRawXP(player, skillType, XP, xpGainReason, false); -// } -// -// /** -// * Adds raw XP to the player. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to add XP to -// * @param skillType The skill to add XP to -// * @param XP The amount of XP to add -// * @param xpGainReason The reason to gain XP -// * @param isUnshared true if the XP cannot be shared with party members -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidXPGainReasonException if the given xpGainReason is not valid -// */ -// public static void addRawXP(Player player, String skillType, float XP, String xpGainReason, boolean isUnshared) { -// if (isUnshared) { -// getPlayer(player).getExperienceHandler().beginUnsharedXpGain(player, getSkillType(skillType), XP, getXPGainReason(xpGainReason), XPGainSource.CUSTOM); -// return; -// } -// -// getPlayer(player).getExperienceHandler().applyXpGain(player, getSkillType(skillType), XP, getXPGainReason(xpGainReason), XPGainSource.CUSTOM); -// } -// -// /** -// * Adds raw XP to an offline player. -// *
-// * This function is designed for API usage. -// * -// * @deprecated We're using float for our XP values now -// * replaced by {@link #addRawXPOffline(String playerName, String skillType, float XP)} -// */ -// @Deprecated -// public static void addRawXPOffline(String playerName, String skillType, int XP) { -// addRawXPOffline(playerName, skillType, (float) XP); -// } -// -// /** -// * Adds raw XP to an offline player. -// *
-// * This function is designed for API usage. -// * -// * @deprecated We're using uuids to get an offline player -// * replaced by {@link #addRawXPOffline(UUID uuid, String skillType, float XP)} -// * -// * @param playerName The player to add XP to -// * @param skillType The skill to add XP to -// * @param XP The amount of XP to add -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// */ -// @Deprecated -// public static void addRawXPOffline(String playerName, String skillType, float XP) { -// addOfflineXP(playerName, getSkillType(skillType), (int) Math.floor(XP)); -// } -// -// /** -// * Adds raw XP to an offline player. -// *
-// * This function is designed for API usage. -// * -// * @param uuid The UUID of player to add XP to -// * @param skillType The skill to add XP to -// * @param XP The amount of XP to add -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// */ -// public static void addRawXPOffline(UUID uuid, String skillType, float XP) { -// addOfflineXP(uuid, getSkillType(skillType), (int) Math.floor(XP)); -// } -// -// /** -// * Adds XP to the player, calculates for XP Rate only. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to add XP to -// * @param skillType The skill to add XP to -// * @param XP The amount of XP to add -// * -// * @throws InvalidSkillException if the given skill is not valid -// */ -// @Deprecated -// public static void addMultipliedXP(Player player, String skillType, int XP) { -// addMultipliedXP(player, skillType, XP, "UNKNOWN"); -// } -// -// /** -// * Adds XP to the player, calculates for XP Rate only. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to add XP to -// * @param skillType The skill to add XP to -// * @param XP The amount of XP to add -// * @param xpGainReason The reason to gain XP -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidXPGainReasonException if the given xpGainReason is not valid -// */ -// public static void addMultipliedXP(Player player, String skillType, int XP, String xpGainReason) { -// getPlayer(player).getExperienceHandler().applyXpGain(player, getSkillType(skillType), (int) (XP * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()), getXPGainReason(xpGainReason), XPGainSource.CUSTOM); -// } -// -// /** -// * Adds XP to an offline player, calculates for XP Rate only. -// *
-// * This function is designed for API usage. -// * -// * @param playerName The player to add XP to -// * @param skillType The skill to add XP to -// * @param XP The amount of XP to add -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// */ -// @Deprecated -// public static void addMultipliedXPOffline(String playerName, String skillType, int XP) { -// addOfflineXP(playerName, getSkillType(skillType), (int) (XP * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier())); -// } -// -// /** -// * Adds XP to the player, calculates for XP Rate and skill modifier. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to add XP to -// * @param skillType The skill to add XP to -// * @param XP The amount of XP to add -// * -// * @throws InvalidSkillException if the given skill is not valid -// */ -// @Deprecated -// public static void addModifiedXP(Player player, String skillType, int XP) { -// addModifiedXP(player, skillType, XP, "UNKNOWN"); -// } -// -// /** -// * Adds XP to the player, calculates for XP Rate and skill modifier. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to add XP to -// * @param skillType The skill to add XP to -// * @param XP The amount of XP to add -// * @param xpGainReason The reason to gain XP -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidXPGainReasonException if the given xpGainReason is not valid -// */ -// public static void addModifiedXP(Player player, String skillType, int XP, String xpGainReason) { -// addModifiedXP(player, skillType, XP, xpGainReason, false); -// } -// -// /** -// * Adds XP to the player, calculates for XP Rate and skill modifier. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to add XP to -// * @param skillType The skill to add XP to -// * @param XP The amount of XP to add -// * @param xpGainReason The reason to gain XP -// * @param isUnshared true if the XP cannot be shared with party members -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidXPGainReasonException if the given xpGainReason is not valid -// */ -// public static void addModifiedXP(Player player, String skillType, int XP, String xpGainReason, boolean isUnshared) { -// PrimarySkillType skill = getSkillType(skillType); -// -// if (isUnshared) { -// getPlayer(player).getExperienceHandler().beginUnsharedXpGain(player, skill, (int) (XP / skill.getXpModifier() * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()), getXPGainReason(xpGainReason), XPGainSource.CUSTOM); -// return; -// } -// -// getPlayer(player).getExperienceHandler().applyXpGain(player, skill, (int) (XP / skill.getXpModifier() * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()), getXPGainReason(xpGainReason), XPGainSource.CUSTOM); -// } -// -// /** -// * Adds XP to an offline player, calculates for XP Rate and skill modifier. -// *
-// * This function is designed for API usage. -// * -// * @param playerName The player to add XP to -// * @param skillType The skill to add XP to -// * @param XP The amount of XP to add -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// */ -// @Deprecated -// public static void addModifiedXPOffline(String playerName, String skillType, int XP) { -// PrimarySkillType skill = getSkillType(skillType); -// -// addOfflineXP(playerName, skill, (int) (XP / skill.getXpModifier() * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier())); -// } -// -// /** -// * Adds XP to the player, calculates for XP Rate, skill modifiers, perks, child skills, -// * and party sharing. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to add XP to -// * @param skillType The skill to add XP to -// * @param XP The amount of XP to add -// * -// * @throws InvalidSkillException if the given skill is not valid -// */ -// @Deprecated -// public static void addXP(Player player, String skillType, int XP) { -// addXP(player, skillType, XP, "UNKNOWN"); -// } -// -// /** -// * Adds XP to the player, calculates for XP Rate, skill modifiers, perks, child skills, -// * and party sharing. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to add XP to -// * @param skillType The skill to add XP to -// * @param XP The amount of XP to add -// * @param xpGainReason The reason to gain XP -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidXPGainReasonException if the given xpGainReason is not valid -// */ -// public static void addXP(Player player, String skillType, int XP, String xpGainReason) { -// addXP(player, skillType, XP, xpGainReason, false); -// } -// -// /** -// * Adds XP to the player, calculates for XP Rate, skill modifiers, perks, child skills, -// * and party sharing. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to add XP to -// * @param skillType The skill to add XP to -// * @param XP The amount of XP to add -// * @param xpGainReason The reason to gain XP -// * @param isUnshared true if the XP cannot be shared with party members -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidXPGainReasonException if the given xpGainReason is not valid -// */ -// public static void addXP(Player player, String skillType, int XP, String xpGainReason, boolean isUnshared) { -// if (isUnshared) { -// getPlayer(player).getExperienceHandler().beginUnsharedXpGain(player, getSkillType(skillType), XP, getXPGainReason(xpGainReason), XPGainSource.CUSTOM); -// return; -// } -// -// getPlayer(player).getExperienceHandler().beginXpGain(player, getSkillType(skillType), XP, getXPGainReason(xpGainReason), XPGainSource.CUSTOM); -// } -// -// /** -// * Get the amount of XP a player has in a specific skill. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to get XP for -// * @param skillType The skill to get XP for -// * @return the amount of XP in a given skill -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws UnsupportedOperationException if the given skill is a child skill -// */ -// public static int getXP(Player player, String skillType) { -// return getPlayer(player).getExperienceHandler().getSkillXpValue(getNonChildSkillType(skillType)); -// } -// -// /** -// * Get the amount of XP an offline player has in a specific skill. -// *
-// * This function is designed for API usage. -// * -// * @param playerName The player to get XP for -// * @param skillType The skill to get XP for -// * @return the amount of XP in a given skill -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// * @throws UnsupportedOperationException if the given skill is a child skill -// */ -// @Deprecated -// public static int getOfflineXP(String playerName, String skillType) { -// return getOfflineProfile(playerName).getExperienceHandler().getSkillXpValue(getNonChildSkillType(skillType)); -// } -// -// /** -// * Get the amount of XP an offline player has in a specific skill. -// *
-// * This function is designed for API usage. -// * -// * @param uuid The player to get XP for -// * @param skillType The skill to get XP for -// * @return the amount of XP in a given skill -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// * @throws UnsupportedOperationException if the given skill is a child skill -// */ -// public static int getOfflineXP(UUID uuid, String skillType) { -// return getOfflineProfile(uuid).getExperienceHandler().getSkillXpValue(getNonChildSkillType(skillType)); -// } -// -// /** -// * Get the raw amount of XP a player has in a specific skill. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to get XP for -// * @param skillType The skill to get XP for -// * @return the amount of XP in a given skill -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws UnsupportedOperationException if the given skill is a child skill -// */ -// public static float getXPRaw(Player player, String skillType) { -// return getPlayer(player).getExperienceHandler().getSkillXpLevelRaw(getNonChildSkillType(skillType)); -// } -// -// /** -// * Get the raw amount of XP an offline player has in a specific skill. -// *
-// * This function is designed for API usage. -// * -// * @param playerName The player to get XP for -// * @param skillType The skill to get XP for -// * @return the amount of XP in a given skill -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// * @throws UnsupportedOperationException if the given skill is a child skill -// */ -// @Deprecated -// public static float getOfflineXPRaw(String playerName, String skillType) { -// return getOfflineProfile(playerName).getExperienceHandler().getSkillXpLevelRaw(getNonChildSkillType(skillType)); -// } -// -// /** -// * Get the raw amount of XP an offline player has in a specific skill. -// *
-// * This function is designed for API usage. -// * -// * @param uuid The player to get XP for -// * @param skillType The skill to get XP for -// * @return the amount of XP in a given skill -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// * @throws UnsupportedOperationException if the given skill is a child skill -// */ -// public static float getOfflineXPRaw(UUID uuid, String skillType) { -// return getOfflineProfile(uuid).getExperienceHandler().getSkillXpLevelRaw(getNonChildSkillType(skillType)); -// } -// -// /** -// * Get the total amount of XP needed to reach the next level. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to get the XP amount for -// * @param skillType The skill to get the XP amount for -// * @return the total amount of XP needed to reach the next level -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws UnsupportedOperationException if the given skill is a child skill -// */ -// public static int getXPToNextLevel(Player player, String skillType) { -// return getPlayer(player).getExperienceHandler().getExperienceToNextLevel(getNonChildSkillType(skillType)); -// } -// -// /** -// * Get the total amount of XP an offline player needs to reach the next level. -// *
-// * This function is designed for API usage. -// * -// * @param playerName The player to get XP for -// * @param skillType The skill to get XP for -// * @return the total amount of XP needed to reach the next level -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// * @throws UnsupportedOperationException if the given skill is a child skill -// */ -// @Deprecated -// public static int getOfflineXPToNextLevel(String playerName, String skillType) { -// return getOfflineProfile(playerName).getExperienceHandler().getExperienceToNextLevel(getNonChildSkillType(skillType)); -// } -// -// /** -// * Get the total amount of XP an offline player needs to reach the next level. -// *
-// * This function is designed for API usage. -// * -// * @param uuid The player to get XP for -// * @param skillType The skill to get XP for -// * @return the total amount of XP needed to reach the next level -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// * @throws UnsupportedOperationException if the given skill is a child skill -// */ -// public static int getOfflineXPToNextLevel(UUID uuid, String skillType) { -// return getOfflineProfile(uuid).getExperienceHandler().getExperienceToNextLevel(getNonChildSkillType(skillType)); -// } -// -// /** -// * Get the amount of XP remaining until the next level. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to get the XP amount for -// * @param skillType The skill to get the XP amount for -// * @return the amount of XP remaining until the next level -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws UnsupportedOperationException if the given skill is a child skill -// */ -// public static int getXPRemaining(Player player, String skillType) { -// PrimarySkillType skill = getNonChildSkillType(skillType); -// -// PlayerProfile profile = getPlayer(player); -// -// return profile.getExperienceHandler().getExperienceToNextLevel(skill) - profile.getExperienceHandler().getSkillXpValue(skill); -// } -// -// /** -// * Get the amount of XP an offline player has left before leveling up. -// *
-// * This function is designed for API usage. -// * -// * @param playerName The player to get XP for -// * @param skillType The skill to get XP for -// * @return the amount of XP needed to reach the next level -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// * @throws UnsupportedOperationException if the given skill is a child skill -// */ -// @Deprecated -// public static int getOfflineXPRemaining(String playerName, String skillType) { -// PrimarySkillType skill = getNonChildSkillType(skillType); -// PlayerProfile profile = getOfflineProfile(playerName); -// -// return profile.getExperienceHandler().getExperienceToNextLevel(skill) - profile.getExperienceHandler().getSkillXpValue(skill); -// } -// -// /** -// * Get the amount of XP an offline player has left before leveling up. -// *
-// * This function is designed for API usage. -// * -// * @param uuid The player to get XP for -// * @param skillType The skill to get XP for -// * @return the amount of XP needed to reach the next level -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// * @throws UnsupportedOperationException if the given skill is a child skill -// */ -// public static float getOfflineXPRemaining(UUID uuid, String skillType) { -// PrimarySkillType skill = getNonChildSkillType(skillType); -// PlayerProfile profile = getOfflineProfile(uuid); -// -// return profile.getExperienceHandler().getExperienceToNextLevel(skill) - profile.getExperienceHandler().getSkillXpLevelRaw(skill); -// } -// -// /** -// * Add levels to a skill. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to add levels to -// * @param skillType Type of skill to add levels to -// * @param levels Number of levels to add -// * -// * @throws InvalidSkillException if the given skill is not valid -// */ -// public static void addLevel(Player player, String skillType, int levels) { -// getPlayer(player).getExperienceHandler().addLevels(getSkillType(skillType), levels); -// } -// -// /** -// * Add levels to a skill for an offline player. -// *
-// * This function is designed for API usage. -// * -// * @param playerName The player to add levels to -// * @param skillType Type of skill to add levels to -// * @param levels Number of levels to add -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// */ -// @Deprecated -// public static void addLevelOffline(String playerName, String skillType, int levels) { -// PlayerProfile profile = getOfflineProfile(playerName); -// PrimarySkillType skill = getSkillType(skillType); -// -// if (skill.isChildSkill()) { -// Set parentSkills = FamilyTree.getParents(skill); -// -// for (PrimarySkillType parentSkill : parentSkills) { -// profile.getExperienceHandler().addLevels(parentSkill, (levels / parentSkills.size())); -// } -// -// mcMMO.getUserManager().scheduleAsyncSave(profile.getPersistentPlayerData()); -// return; -// } -// -// profile.getExperienceHandler().addLevels(skill, levels); -// mcMMO.getUserManager().scheduleAsyncSave(profile.getPersistentPlayerData()); -// } -// -// /** -// * Add levels to a skill for an offline player. -// *
-// * This function is designed for API usage. -// * -// * @param uuid The player to add levels to -// * @param skillType Type of skill to add levels to -// * @param levels Number of levels to add -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// */ -// public static void addLevelOffline(UUID uuid, String skillType, int levels) { -// PlayerProfile profile = getOfflineProfile(uuid); -// PrimarySkillType skill = getSkillType(skillType); -// -// if (skill.isChildSkill()) { -// Set parentSkills = FamilyTree.getParents(skill); -// -// for (PrimarySkillType parentSkill : parentSkills) { -// profile.getExperienceHandler().addLevels(parentSkill, (levels / parentSkills.size())); -// } -// -// mcMMO.getUserManager().scheduleAsyncSave(profile.getPersistentPlayerData()); -// return; -// } -// -// profile.getExperienceHandler().addLevels(skill, levels); -// mcMMO.getUserManager().scheduleAsyncSave(profile.getPersistentPlayerData()); -// } -// -// /** -// * Get the level a player has in a specific skill. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to get the level for -// * @param skillType The skill to get the level for -// * @return the level of a given skill -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @deprecated Use getLevel(Player player, PrimarySkillType skillType) instead -// */ -// @Deprecated -// public static int getLevel(Player player, String skillType) { -// return getPlayer(player).getExperienceHandler().getSkillLevel(getSkillType(skillType)); -// } -// -// /** -// * Get the level a player has in a specific skill. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to get the level for -// * @param skillType The skill to get the level for -// * @return the level of a given skill -// * -// * @throws InvalidSkillException if the given skill is not valid -// */ -// public static int getLevel(Player player, PrimarySkillType skillType) { -// return getPlayer(player).getExperienceHandler().getSkillLevel(skillType); -// } -// -// /** -// * Get the level an offline player has in a specific skill. -// *
-// * This function is designed for API usage. -// * -// * @param playerName The player to get the level for -// * @param skillType The skill to get the level for -// * @return the level of a given skill -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// */ -// @Deprecated -// public static int getLevelOffline(String playerName, String skillType) { -// return getOfflineProfile(playerName).getExperienceHandler().getSkillLevel(getSkillType(skillType)); -// } -// -// /** -// * Get the level an offline player has in a specific skill. -// *
-// * This function is designed for API usage. -// * -// * @param uuid The player to get the level for -// * @param skillType The skill to get the level for -// * @return the level of a given skill -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// */ -// public static int getLevelOffline(UUID uuid, String skillType) { -// return getOfflineProfile(uuid).getExperienceHandler().getSkillLevel(getSkillType(skillType)); -// } -// -// /** -// * Gets the power level of a player. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to get the power level for -// * @return the power level of the player -// */ -// public static int getPowerLevel(Player player) { -// return getPlayer(player).getExperienceHandler().getPowerLevel(); -// } -// -// /** -// * Gets the power level of an offline player. -// *
-// * This function is designed for API usage. -// * -// * @param playerName The player to get the power level for -// * @return the power level of the player -// * -// * @throws InvalidPlayerException if the given player does not exist in the database -// */ -// @Deprecated -// public static int getPowerLevelOffline(String playerName) { -// int powerLevel = 0; -// PlayerProfile profile = getOfflineProfile(playerName); -// -// for (PrimarySkillType type : PrimarySkillType.NON_CHILD_SKILLS) { -// powerLevel += profile.getExperienceHandler().getSkillLevel(type); -// } -// -// return powerLevel; -// } -// -// /** -// * Gets the power level of an offline player. -// *
-// * This function is designed for API usage. -// * -// * @param uuid The player to get the power level for -// * @return the power level of the player -// * -// * @throws InvalidPlayerException if the given player does not exist in the database -// */ -// public static int getPowerLevelOffline(UUID uuid) { -// int powerLevel = 0; -// PlayerProfile profile = getOfflineProfile(uuid); -// -// for (PrimarySkillType type : PrimarySkillType.NON_CHILD_SKILLS) { -// powerLevel += profile.getExperienceHandler().getSkillLevel(type); -// } -// -// return powerLevel; -// } -// -// /** -// * Get the level cap of a specific skill. -// *
-// * This function is designed for API usage. -// * -// * @param skillType The skill to get the level cap for -// * @return the level cap of a given skill -// * -// * @throws InvalidSkillException if the given skill is not valid -// */ -// public static int getLevelCap(String skillType) { -// return Config.getInstance().getLevelCap(getSkillType(skillType)); -// } -// -// /** -// * Get the power level cap. -// *
-// * This function is designed for API usage. -// * -// * @return the overall power level cap -// */ -// public static int getPowerLevelCap() { -// return Config.getInstance().getPowerLevelCap(); -// } -// -// /** -// * Get the position on the leaderboard of a player. -// *
-// * This function is designed for API usage. -// * -// * @param playerName The name of the player to check -// * @param skillType The skill to check -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// * @throws UnsupportedOperationException if the given skill is a child skill -// * -// * @return the position on the leaderboard -// */ -// @Deprecated -// public static int getPlayerRankSkill(String playerName, String skillType) { -// return mcMMO.getDatabaseManager().readRank(mcMMO.p.getServer().getOfflinePlayer(playerName).getName()).get(getNonChildSkillType(skillType)); -// } -// -// /** -// * Get the position on the leaderboard of a player. -// *
-// * This function is designed for API usage. -// * -// * @param uuid The name of the player to check -// * @param skillType The skill to check -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// * @throws UnsupportedOperationException if the given skill is a child skill -// * -// * @return the position on the leaderboard -// */ -// public static int getPlayerRankSkill(UUID uuid, String skillType) { -// return mcMMO.getDatabaseManager().readRank(mcMMO.p.getServer().getOfflinePlayer(uuid).getName()).get(getNonChildSkillType(skillType)); -// } -// -// /** -// * Get the position on the power level leaderboard of a player. -// *
-// * This function is designed for API usage. -// * -// * @param playerName The name of the player to check -// * -// * @throws InvalidPlayerException if the given player does not exist in the database -// * -// * @return the position on the power level leaderboard -// */ -// @Deprecated -// public static int getPlayerRankOverall(String playerName) { -// return mcMMO.getDatabaseManager().readRank(mcMMO.p.getServer().getOfflinePlayer(playerName).getName()).get(null); -// } -// -// /** -// * Get the position on the power level leaderboard of a player. -// *
-// * This function is designed for API usage. -// * -// * @param uuid The name of the player to check -// * -// * @throws InvalidPlayerException if the given player does not exist in the database -// * -// * @return the position on the power level leaderboard -// */ -// public static int getPlayerRankOverall(UUID uuid) { -// return mcMMO.getDatabaseManager().readRank(mcMMO.p.getServer().getOfflinePlayer(uuid).getName()).get(null); -// } -// -// /** -// * Sets the level of a player in a specific skill type. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to set the level of -// * @param skillType The skill to set the level for -// * @param skillLevel The value to set the level to -// * -// * @throws InvalidSkillException if the given skill is not valid -// */ -// public static void setLevel(Player player, String skillType, int skillLevel) { -// getPlayer(player).getExperienceHandler().setSkillLevel(getSkillType(skillType), skillLevel); -// } -// -// /** -// * Sets the level of an offline player in a specific skill type. -// *
-// * This function is designed for API usage. -// * -// * @param playerName The player to set the level of -// * @param skillType The skill to set the level for -// * @param skillLevel The value to set the level to -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// */ -// @Deprecated -// public static void setLevelOffline(String playerName, String skillType, int skillLevel) { -// getOfflineProfile(playerName).getExperienceHandler().setSkillLevel(getSkillType(skillType), skillLevel); -// } -// -// /** -// * Sets the level of an offline player in a specific skill type. -// *
-// * This function is designed for API usage. -// * -// * @param uuid The player to set the level of -// * @param skillType The skill to set the level for -// * @param skillLevel The value to set the level to -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// */ -// public static void setLevelOffline(UUID uuid, String skillType, int skillLevel) { -// getOfflineProfile(uuid).getExperienceHandler().setSkillLevel(getSkillType(skillType), skillLevel); -// } -// -// /** -// * Sets the XP of a player in a specific skill type. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to set the XP of -// * @param skillType The skill to set the XP for -// * @param newValue The value to set the XP to -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws UnsupportedOperationException if the given skill is a child skill -// */ -// public static void setXP(Player player, String skillType, int newValue) { -// getPlayer(player).getExperienceHandler().setSkillXpValue(getNonChildSkillType(skillType), (float) newValue); -// } -// -// /** -// * Sets the XP of an offline player in a specific skill type. -// *
-// * This function is designed for API usage. -// * -// * @param playerName The player to set the XP of -// * @param skillType The skill to set the XP for -// * @param newValue The value to set the XP to -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// * @throws UnsupportedOperationException if the given skill is a child skill -// */ -// @Deprecated -// public static void setXPOffline(String playerName, String skillType, int newValue) { -// getOfflineProfile(playerName).getExperienceHandler().setSkillXpValue(getNonChildSkillType(skillType), newValue); -// } -// -// /** -// * Sets the XP of an offline player in a specific skill type. -// *
-// * This function is designed for API usage. -// * -// * @param uuid The player to set the XP of -// * @param skillType The skill to set the XP for -// * @param newValue The value to set the XP to -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// * @throws UnsupportedOperationException if the given skill is a child skill -// */ -// public static void setXPOffline(UUID uuid, String skillType, int newValue) { -// getOfflineProfile(uuid).getExperienceHandler().setSkillXpValue(getNonChildSkillType(skillType), newValue); -// } -// -// /** -// * Removes XP from a player in a specific skill type. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to change the XP of -// * @param skillType The skill to change the XP for -// * @param xp The amount of XP to remove -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws UnsupportedOperationException if the given skill is a child skill -// */ -// public static void removeXP(Player player, String skillType, int xp) { -// getPlayer(player).getExperienceHandler().removeXp(getNonChildSkillType(skillType), xp); -// } -// -// /** -// * Removes XP from an offline player in a specific skill type. -// *
-// * This function is designed for API usage. -// * -// * @param playerName The player to change the XP of -// * @param skillType The skill to change the XP for -// * @param xp The amount of XP to remove -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// * @throws UnsupportedOperationException if the given skill is a child skill -// */ -// @Deprecated -// public static void removeXPOffline(String playerName, String skillType, int xp) { -// getOfflineProfile(playerName).getExperienceHandler().removeXp(getNonChildSkillType(skillType), xp); -// } -// -// /** -// * Removes XP from an offline player in a specific skill type. -// *
-// * This function is designed for API usage. -// * -// * @param uuid The player to change the XP of -// * @param skillType The skill to change the XP for -// * @param xp The amount of XP to remove -// * -// * @throws InvalidSkillException if the given skill is not valid -// * @throws InvalidPlayerException if the given player does not exist in the database -// * @throws UnsupportedOperationException if the given skill is a child skill -// */ -// public static void removeXPOffline(UUID uuid, String skillType, int xp) { -// getOfflineProfile(uuid).getExperienceHandler().removeXp(getNonChildSkillType(skillType), xp); -// } -// -// /** -// * Check how much XP is needed for a specific level with the selected level curve. -// *
-// * This function is designed for API usage. -// * -// * @param level The level to get the amount of XP for -// * -// * @throws InvalidFormulaTypeException if the given formulaType is not valid -// */ -// public static int getXpNeededToLevel(int level) { -// return mcMMO.getFormulaManager().getXPtoNextLevel(level, ExperienceConfig.getInstance().getFormulaType()); -// } -// -// /** -// * Check how much XP is needed for a specific level with the provided level curve. -// *
-// * This function is designed for API usage. -// * -// * @param level The level to get the amount of XP for -// * @param formulaType The formula type to get the amount of XP for -// * -// * @throws InvalidFormulaTypeException if the given formulaType is not valid -// */ -// public static int getXpNeededToLevel(int level, String formulaType) { -// return mcMMO.getFormulaManager().getXPtoNextLevel(level, getFormulaType(formulaType)); -// } -// -// /** -// * Will add the appropriate type of XP from the block to the player based on the material of the blocks given -// * @param blockStates the blocks to reward XP for -// * @param mmoPlayer the target player -// */ -// public static void addXpFromBlocks(ArrayList blockStates, OnlineMMOPlayer mmoPlayer) -// { -// for(BlockState bs : blockStates) -// { -// for(PrimarySkillType skillType : PrimarySkillType.values()) -// { -// if(ExperienceConfig.getInstance().getXp(skillType, bs.getType()) > 0) -// { -// mmoPlayer.getExperienceHandler().applyXpGain(Misc.adaptPlayer(mmoPlayer), skillType, ExperienceConfig.getInstance().getXp(skillType, bs.getType()), XPGainReason.PVE, XPGainSource.SELF); -// } -// } -// } -// } -// -// /** -// * Will add the appropriate type of XP from the block to the player based on the material of the blocks given if it matches the given skillType -// * @param blockStates the blocks to reward XP for -// * @param mmoPlayer the target player -// * @param skillType target primary skill -// */ -// public static void addXpFromBlocksBySkill(ArrayList blockStates, OnlineMMOPlayer mmoPlayer, PrimarySkillType skillType) -// { -// for(BlockState bs : blockStates) -// { -// if(ExperienceConfig.getInstance().getXp(skillType, bs.getType()) > 0) -// { -// mmoPlayer.getExperienceHandler().applyXpGain(Misc.adaptPlayer(mmoPlayer), skillType, ExperienceConfig.getInstance().getXp(skillType, bs.getType()), XPGainReason.PVE, XPGainSource.SELF); -// } -// } -// } -// -// /** -// * Will add the appropriate type of XP from the block to the player based on the material of the blocks given -// * @param blockState The target blockstate -// * @param mmoPlayer The target player -// */ -// public static void addXpFromBlock(BlockState blockState, OnlineMMOPlayer mmoPlayer) -// { -// for(PrimarySkillType skillType : PrimarySkillType.values()) -// { -// if(ExperienceConfig.getInstance().getXp(skillType, blockState.getType()) > 0) -// { -// mmoPlayer.getExperienceHandler().applyXpGain(Misc.adaptPlayer(mmoPlayer), skillType, ExperienceConfig.getInstance().getXp(skillType, blockState.getType()), XPGainReason.PVE, XPGainSource.SELF); -// } -// } -// } -// -// /** -// * Will add the appropriate type of XP from the block to the player based on the material of the blocks given if it matches the given skillType -// * @param blockState The target blockstate -// * @param mmoPlayer The target player -// * @param skillType target primary skill -// */ -// public static void addXpFromBlockBySkill(BlockState blockState, OnlineMMOPlayer mmoPlayer, PrimarySkillType skillType) -// { -// if(ExperienceConfig.getInstance().getXp(skillType, blockState.getType()) > 0) -// { -// mmoPlayer.getExperienceHandler().applyXpGain(Misc.adaptPlayer(mmoPlayer), skillType, ExperienceConfig.getInstance().getXp(skillType, blockState.getType()), XPGainReason.PVE, XPGainSource.SELF); -// } -// } -// -// -// -// // Utility methods follow. -// private static void addOfflineXP(UUID playerUniqueId, PrimarySkillType skill, int XP) { -// PlayerProfile profile = getOfflineProfile(playerUniqueId); -// -// profile.getExperienceHandler().addXp(skill, XP); -// mcMMO.getUserManager().scheduleAsyncSave(profile.getPersistentPlayerData()); -// } -// -// @Deprecated -// private static void addOfflineXP(String playerName, PrimarySkillType skill, int XP) { -// PlayerProfile profile = getOfflineProfile(playerName); -// -// profile.getExperienceHandler().addXp(skill, XP); -// mcMMO.getUserManager().scheduleAsyncSave(profile.getPersistentPlayerData()); -// } -// -// private static PlayerProfile getOfflineProfile(UUID uuid) { -// PlayerProfile profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(uuid); -// -// if (profile == null) { -// throw new InvalidPlayerException(); -// } -// -// return profile; -// } -// -// @Deprecated -// private static PlayerProfile getOfflineProfile(String playerName) { -// UUID uuid = mcMMO.p.getServer().getOfflinePlayer(playerName).getUniqueId(); -// PlayerProfile profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(uuid); -// -// if (profile == null) { -// throw new InvalidPlayerException(); -// } -// -// return profile; -// } -// -// private static PrimarySkillType getSkillType(String skillType) throws InvalidSkillException { -// PrimarySkillType skill = mcMMO.p.getSkillRegister().getSkill(skillType); -// -// if (skill == null) { -// throw new InvalidSkillException(); -// } -// -// return skill; -// } -// -// private static PrimarySkillType getNonChildSkillType(String skillType) throws InvalidSkillException, UnsupportedOperationException { -// PrimarySkillType skill = getSkillType(skillType); -// -// if (skill.isChildSkill()) { -// throw new UnsupportedOperationException("Child skills do not have XP"); -// } -// -// return skill; -// } -// -// private static XPGainReason getXPGainReason(String reason) throws InvalidXPGainReasonException { -// XPGainReason xpGainReason = XPGainReason.getXPGainReason(reason); -// -// if (xpGainReason == null) { -// throw new InvalidXPGainReasonException(); -// } -// -// return xpGainReason; -// } -// -// private static FormulaType getFormulaType(String formula) throws InvalidFormulaTypeException { -// FormulaType formulaType = FormulaType.getFormulaType(formula); -// -// if (formulaType == null) { -// throw new InvalidFormulaTypeException(); -// } -// -// return formulaType; -// } -// -// /** -// * @deprecated Use UserManager::getPlayer(Player player) instead -// * @param player target player -// * @return OnlineMMOPlayer for that player if the profile is loaded, otherwise null -// * @throws McMMOPlayerNotFoundException -// */ -// @Deprecated -// private static OnlineMMOPlayer getPlayer(Player player) throws McMMOPlayerNotFoundException { -// if (!mcMMO.getUserManager().hasPlayerDataKey(player)) { -// throw new McMMOPlayerNotFoundException(player); -// } -// -// return mcMMO.getUserManager().queryPlayer(player); -// } -//} +package com.gmail.nossr50.api; + +import com.gmail.nossr50.api.exceptions.*; +import com.gmail.nossr50.config.Config; +import com.gmail.nossr50.config.experience.ExperienceConfig; +import com.gmail.nossr50.datatypes.experience.FormulaType; +import com.gmail.nossr50.datatypes.experience.XPGainReason; +import com.gmail.nossr50.datatypes.experience.XPGainSource; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.datatypes.player.PlayerProfile; +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.skills.child.FamilyTree; +import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.skills.CombatUtils; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.block.BlockState; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.Set; +import java.util.UUID; + +public final class ExperienceAPI { + private ExperienceAPI() {} + + /** + * Returns whether given string is a valid type of skill suitable for the + * other API calls in this class. + *
+ * This function is designed for API usage. + * + * @param skillType A string that may or may not be a skill + * @return true if this is a valid mcMMO skill + */ + public static boolean isValidSkillType(String skillType) { + return PrimarySkillType.getSkill(skillType) != null; + } + + /** + * Start the task that gives combat XP. + * Processes combat XP like mcMMO normally would, so mcMMO will check whether or not the entity should reward XP when giving out the XP + * + * @param mcMMOPlayer The attacking player + * @param target The defending entity + * @param primarySkillType The skill being used + * @param multiplier final XP result will be multiplied by this + * @deprecated Draft API + */ + @Deprecated + public static void addCombatXP(McMMOPlayer mcMMOPlayer, LivingEntity target, PrimarySkillType primarySkillType, double multiplier) { + CombatUtils.processCombatXP(mcMMOPlayer, target, primarySkillType, multiplier); + } + + /** + * Start the task that gives combat XP. + * Processes combat XP like mcMMO normally would, so mcMMO will check whether or not the entity should reward XP when giving out the XP + * + * @param mcMMOPlayer The attacking player + * @param target The defending entity + * @param primarySkillType The skill being used + * @deprecated Draft API + */ + @Deprecated + public static void addCombatXP(McMMOPlayer mcMMOPlayer, LivingEntity target, PrimarySkillType primarySkillType) { + CombatUtils.processCombatXP(mcMMOPlayer, target, primarySkillType); + } + + /** + * Returns whether the given skill type string is both valid and not a + * child skill. (Child skills have no XP of their own, and their level is + * derived from the parent(s).) + *
+ * This function is designed for API usage. + * + * @param skillType the skill to check + * @return true if this is a valid, non-child mcMMO skill + */ + public static boolean isNonChildSkill(String skillType) { + PrimarySkillType skill = PrimarySkillType.getSkill(skillType); + + return skill != null && !skill.isChildSkill(); + } + + @Deprecated + public static void addRawXP(Player player, String skillType, int XP) { + addRawXP(player, skillType, (float) XP); + } + + /** + * Adds raw XP to the player. + *
+ * This function is designed for API usage. + * + * @param player The player to add XP to + * @param skillType The skill to add XP to + * @param XP The amount of XP to add + * + * @throws InvalidSkillException if the given skill is not valid + */ + @Deprecated + public static void addRawXP(Player player, String skillType, float XP) { + addRawXP(player, skillType, XP, "UNKNOWN"); + } + + /** + * Adds raw XP to the player. + *
+ * This function is designed for API usage. + * + * @param player The player to add XP to + * @param skillType The skill to add XP to + * @param XP The amount of XP to add + * @param xpGainReason The reason to gain XP + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidXPGainReasonException if the given xpGainReason is not valid + */ + public static void addRawXP(Player player, String skillType, float XP, String xpGainReason) { + addRawXP(player, skillType, XP, xpGainReason, false); + } + + /** + * Adds raw XP to the player. + *
+ * This function is designed for API usage. + * + * @param player The player to add XP to + * @param skillType The skill to add XP to + * @param XP The amount of XP to add + * @param xpGainReason The reason to gain XP + * @param isUnshared true if the XP cannot be shared with party members + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidXPGainReasonException if the given xpGainReason is not valid + */ + public static void addRawXP(Player player, String skillType, float XP, String xpGainReason, boolean isUnshared) { + if (isUnshared) { + getPlayer(player).beginUnsharedXpGain(getSkillType(skillType), XP, getXPGainReason(xpGainReason), XPGainSource.CUSTOM); + return; + } + + getPlayer(player).applyXpGain(getSkillType(skillType), XP, getXPGainReason(xpGainReason), XPGainSource.CUSTOM); + } + + /** + * Adds raw XP to an offline player. + *
+ * This function is designed for API usage. + * + * @deprecated We're using float for our XP values now + * replaced by {@link #addRawXPOffline(String playerName, String skillType, float XP)} + */ + @Deprecated + public static void addRawXPOffline(String playerName, String skillType, int XP) { + addRawXPOffline(playerName, skillType, (float) XP); + } + + /** + * Adds raw XP to an offline player. + *
+ * This function is designed for API usage. + * + * @deprecated We're using uuids to get an offline player + * replaced by {@link #addRawXPOffline(UUID uuid, String skillType, float XP)} + * + * @param playerName The player to add XP to + * @param skillType The skill to add XP to + * @param XP The amount of XP to add + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + */ + @Deprecated + public static void addRawXPOffline(String playerName, String skillType, float XP) { + addOfflineXP(playerName, getSkillType(skillType), (int) Math.floor(XP)); + } + + /** + * Adds raw XP to an offline player. + *
+ * This function is designed for API usage. + * + * @param uuid The UUID of player to add XP to + * @param skillType The skill to add XP to + * @param XP The amount of XP to add + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + */ + public static void addRawXPOffline(UUID uuid, String skillType, float XP) { + addOfflineXP(uuid, getSkillType(skillType), (int) Math.floor(XP)); + } + + /** + * Adds XP to the player, calculates for XP Rate only. + *
+ * This function is designed for API usage. + * + * @param player The player to add XP to + * @param skillType The skill to add XP to + * @param XP The amount of XP to add + * + * @throws InvalidSkillException if the given skill is not valid + */ + @Deprecated + public static void addMultipliedXP(Player player, String skillType, int XP) { + addMultipliedXP(player, skillType, XP, "UNKNOWN"); + } + + /** + * Adds XP to the player, calculates for XP Rate only. + *
+ * This function is designed for API usage. + * + * @param player The player to add XP to + * @param skillType The skill to add XP to + * @param XP The amount of XP to add + * @param xpGainReason The reason to gain XP + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidXPGainReasonException if the given xpGainReason is not valid + */ + public static void addMultipliedXP(Player player, String skillType, int XP, String xpGainReason) { + getPlayer(player).applyXpGain(getSkillType(skillType), (int) (XP * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()), getXPGainReason(xpGainReason), XPGainSource.CUSTOM); + } + + /** + * Adds XP to an offline player, calculates for XP Rate only. + *
+ * This function is designed for API usage. + * + * @param playerName The player to add XP to + * @param skillType The skill to add XP to + * @param XP The amount of XP to add + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + */ + @Deprecated + public static void addMultipliedXPOffline(String playerName, String skillType, int XP) { + addOfflineXP(playerName, getSkillType(skillType), (int) (XP * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier())); + } + + /** + * Adds XP to the player, calculates for XP Rate and skill modifier. + *
+ * This function is designed for API usage. + * + * @param player The player to add XP to + * @param skillType The skill to add XP to + * @param XP The amount of XP to add + * + * @throws InvalidSkillException if the given skill is not valid + */ + @Deprecated + public static void addModifiedXP(Player player, String skillType, int XP) { + addModifiedXP(player, skillType, XP, "UNKNOWN"); + } + + /** + * Adds XP to the player, calculates for XP Rate and skill modifier. + *
+ * This function is designed for API usage. + * + * @param player The player to add XP to + * @param skillType The skill to add XP to + * @param XP The amount of XP to add + * @param xpGainReason The reason to gain XP + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidXPGainReasonException if the given xpGainReason is not valid + */ + public static void addModifiedXP(Player player, String skillType, int XP, String xpGainReason) { + addModifiedXP(player, skillType, XP, xpGainReason, false); + } + + /** + * Adds XP to the player, calculates for XP Rate and skill modifier. + *
+ * This function is designed for API usage. + * + * @param player The player to add XP to + * @param skillType The skill to add XP to + * @param XP The amount of XP to add + * @param xpGainReason The reason to gain XP + * @param isUnshared true if the XP cannot be shared with party members + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidXPGainReasonException if the given xpGainReason is not valid + */ + public static void addModifiedXP(Player player, String skillType, int XP, String xpGainReason, boolean isUnshared) { + PrimarySkillType skill = getSkillType(skillType); + + if (isUnshared) { + getPlayer(player).beginUnsharedXpGain(skill, (int) (XP / skill.getXpModifier() * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()), getXPGainReason(xpGainReason), XPGainSource.CUSTOM); + return; + } + + getPlayer(player).applyXpGain(skill, (int) (XP / skill.getXpModifier() * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()), getXPGainReason(xpGainReason), XPGainSource.CUSTOM); + } + + /** + * Adds XP to an offline player, calculates for XP Rate and skill modifier. + *
+ * This function is designed for API usage. + * + * @param playerName The player to add XP to + * @param skillType The skill to add XP to + * @param XP The amount of XP to add + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + */ + @Deprecated + public static void addModifiedXPOffline(String playerName, String skillType, int XP) { + PrimarySkillType skill = getSkillType(skillType); + + addOfflineXP(playerName, skill, (int) (XP / skill.getXpModifier() * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier())); + } + + /** + * Adds XP to the player, calculates for XP Rate, skill modifiers, perks, child skills, + * and party sharing. + *
+ * This function is designed for API usage. + * + * @param player The player to add XP to + * @param skillType The skill to add XP to + * @param XP The amount of XP to add + * + * @throws InvalidSkillException if the given skill is not valid + */ + @Deprecated + public static void addXP(Player player, String skillType, int XP) { + addXP(player, skillType, XP, "UNKNOWN"); + } + + /** + * Adds XP to the player, calculates for XP Rate, skill modifiers, perks, child skills, + * and party sharing. + *
+ * This function is designed for API usage. + * + * @param player The player to add XP to + * @param skillType The skill to add XP to + * @param XP The amount of XP to add + * @param xpGainReason The reason to gain XP + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidXPGainReasonException if the given xpGainReason is not valid + */ + public static void addXP(Player player, String skillType, int XP, String xpGainReason) { + addXP(player, skillType, XP, xpGainReason, false); + } + + /** + * Adds XP to the player, calculates for XP Rate, skill modifiers, perks, child skills, + * and party sharing. + *
+ * This function is designed for API usage. + * + * @param player The player to add XP to + * @param skillType The skill to add XP to + * @param XP The amount of XP to add + * @param xpGainReason The reason to gain XP + * @param isUnshared true if the XP cannot be shared with party members + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidXPGainReasonException if the given xpGainReason is not valid + */ + public static void addXP(Player player, String skillType, int XP, String xpGainReason, boolean isUnshared) { + if (isUnshared) { + getPlayer(player).beginUnsharedXpGain(getSkillType(skillType), XP, getXPGainReason(xpGainReason), XPGainSource.CUSTOM); + return; + } + + getPlayer(player).beginXpGain(getSkillType(skillType), XP, getXPGainReason(xpGainReason), XPGainSource.CUSTOM); + } + + /** + * Get the amount of XP a player has in a specific skill. + *
+ * This function is designed for API usage. + * + * @param player The player to get XP for + * @param skillType The skill to get XP for + * @return the amount of XP in a given skill + * + * @throws InvalidSkillException if the given skill is not valid + * @throws UnsupportedOperationException if the given skill is a child skill + */ + public static int getXP(Player player, String skillType) { + return getPlayer(player).getSkillXpLevel(getNonChildSkillType(skillType)); + } + + /** + * Get the amount of XP an offline player has in a specific skill. + *
+ * This function is designed for API usage. + * + * @param playerName The player to get XP for + * @param skillType The skill to get XP for + * @return the amount of XP in a given skill + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + * @throws UnsupportedOperationException if the given skill is a child skill + */ + @Deprecated + public static int getOfflineXP(String playerName, String skillType) { + return getOfflineProfile(playerName).getSkillXpLevel(getNonChildSkillType(skillType)); + } + + /** + * Get the amount of XP an offline player has in a specific skill. + *
+ * This function is designed for API usage. + * + * @param uuid The player to get XP for + * @param skillType The skill to get XP for + * @return the amount of XP in a given skill + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + * @throws UnsupportedOperationException if the given skill is a child skill + */ + public static int getOfflineXP(UUID uuid, String skillType) { + return getOfflineProfile(uuid).getSkillXpLevel(getNonChildSkillType(skillType)); + } + + /** + * Get the raw amount of XP a player has in a specific skill. + *
+ * This function is designed for API usage. + * + * @param player The player to get XP for + * @param skillType The skill to get XP for + * @return the amount of XP in a given skill + * + * @throws InvalidSkillException if the given skill is not valid + * @throws UnsupportedOperationException if the given skill is a child skill + */ + public static float getXPRaw(Player player, String skillType) { + return getPlayer(player).getSkillXpLevelRaw(getNonChildSkillType(skillType)); + } + + /** + * Get the raw amount of XP an offline player has in a specific skill. + *
+ * This function is designed for API usage. + * + * @param playerName The player to get XP for + * @param skillType The skill to get XP for + * @return the amount of XP in a given skill + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + * @throws UnsupportedOperationException if the given skill is a child skill + */ + @Deprecated + public static float getOfflineXPRaw(String playerName, String skillType) { + return getOfflineProfile(playerName).getSkillXpLevelRaw(getNonChildSkillType(skillType)); + } + + /** + * Get the raw amount of XP an offline player has in a specific skill. + *
+ * This function is designed for API usage. + * + * @param uuid The player to get XP for + * @param skillType The skill to get XP for + * @return the amount of XP in a given skill + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + * @throws UnsupportedOperationException if the given skill is a child skill + */ + public static float getOfflineXPRaw(UUID uuid, String skillType) { + return getOfflineProfile(uuid).getSkillXpLevelRaw(getNonChildSkillType(skillType)); + } + + /** + * Get the total amount of XP needed to reach the next level. + *
+ * This function is designed for API usage. + * + * @param player The player to get the XP amount for + * @param skillType The skill to get the XP amount for + * @return the total amount of XP needed to reach the next level + * + * @throws InvalidSkillException if the given skill is not valid + * @throws UnsupportedOperationException if the given skill is a child skill + */ + public static int getXPToNextLevel(Player player, String skillType) { + return getPlayer(player).getXpToLevel(getNonChildSkillType(skillType)); + } + + /** + * Get the total amount of XP an offline player needs to reach the next level. + *
+ * This function is designed for API usage. + * + * @param playerName The player to get XP for + * @param skillType The skill to get XP for + * @return the total amount of XP needed to reach the next level + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + * @throws UnsupportedOperationException if the given skill is a child skill + */ + @Deprecated + public static int getOfflineXPToNextLevel(String playerName, String skillType) { + return getOfflineProfile(playerName).getXpToLevel(getNonChildSkillType(skillType)); + } + + /** + * Get the total amount of XP an offline player needs to reach the next level. + *
+ * This function is designed for API usage. + * + * @param uuid The player to get XP for + * @param skillType The skill to get XP for + * @return the total amount of XP needed to reach the next level + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + * @throws UnsupportedOperationException if the given skill is a child skill + */ + public static int getOfflineXPToNextLevel(UUID uuid, String skillType) { + return getOfflineProfile(uuid).getXpToLevel(getNonChildSkillType(skillType)); + } + + /** + * Get the amount of XP remaining until the next level. + *
+ * This function is designed for API usage. + * + * @param player The player to get the XP amount for + * @param skillType The skill to get the XP amount for + * @return the amount of XP remaining until the next level + * + * @throws InvalidSkillException if the given skill is not valid + * @throws UnsupportedOperationException if the given skill is a child skill + */ + public static int getXPRemaining(Player player, String skillType) { + PrimarySkillType skill = getNonChildSkillType(skillType); + + PlayerProfile profile = getPlayer(player).getProfile(); + + return profile.getXpToLevel(skill) - profile.getSkillXpLevel(skill); + } + + /** + * Get the amount of XP an offline player has left before leveling up. + *
+ * This function is designed for API usage. + * + * @param playerName The player to get XP for + * @param skillType The skill to get XP for + * @return the amount of XP needed to reach the next level + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + * @throws UnsupportedOperationException if the given skill is a child skill + */ + @Deprecated + public static int getOfflineXPRemaining(String playerName, String skillType) { + PrimarySkillType skill = getNonChildSkillType(skillType); + PlayerProfile profile = getOfflineProfile(playerName); + + return profile.getXpToLevel(skill) - profile.getSkillXpLevel(skill); + } + + /** + * Get the amount of XP an offline player has left before leveling up. + *
+ * This function is designed for API usage. + * + * @param uuid The player to get XP for + * @param skillType The skill to get XP for + * @return the amount of XP needed to reach the next level + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + * @throws UnsupportedOperationException if the given skill is a child skill + */ + public static float getOfflineXPRemaining(UUID uuid, String skillType) { + PrimarySkillType skill = getNonChildSkillType(skillType); + PlayerProfile profile = getOfflineProfile(uuid); + + return profile.getXpToLevel(skill) - profile.getSkillXpLevelRaw(skill); + } + + /** + * Add levels to a skill. + *
+ * This function is designed for API usage. + * + * @param player The player to add levels to + * @param skillType Type of skill to add levels to + * @param levels Number of levels to add + * + * @throws InvalidSkillException if the given skill is not valid + */ + public static void addLevel(Player player, String skillType, int levels) { + getPlayer(player).addLevels(getSkillType(skillType), levels); + } + + /** + * Add levels to a skill for an offline player. + *
+ * This function is designed for API usage. + * + * @param playerName The player to add levels to + * @param skillType Type of skill to add levels to + * @param levels Number of levels to add + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + */ + @Deprecated + public static void addLevelOffline(String playerName, String skillType, int levels) { + PlayerProfile profile = getOfflineProfile(playerName); + PrimarySkillType skill = getSkillType(skillType); + + if (skill.isChildSkill()) { + Set parentSkills = FamilyTree.getParents(skill); + + for (PrimarySkillType parentSkill : parentSkills) { + profile.addLevels(parentSkill, (levels / parentSkills.size())); + } + + profile.scheduleAsyncSave(); + return; + } + + profile.addLevels(skill, levels); + profile.scheduleAsyncSave(); + } + + /** + * Add levels to a skill for an offline player. + *
+ * This function is designed for API usage. + * + * @param uuid The player to add levels to + * @param skillType Type of skill to add levels to + * @param levels Number of levels to add + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + */ + public static void addLevelOffline(UUID uuid, String skillType, int levels) { + PlayerProfile profile = getOfflineProfile(uuid); + PrimarySkillType skill = getSkillType(skillType); + + if (skill.isChildSkill()) { + Set parentSkills = FamilyTree.getParents(skill); + + for (PrimarySkillType parentSkill : parentSkills) { + profile.addLevels(parentSkill, (levels / parentSkills.size())); + } + + profile.scheduleAsyncSave(); + return; + } + + profile.addLevels(skill, levels); + profile.scheduleAsyncSave(); + } + + /** + * Get the level a player has in a specific skill. + *
+ * This function is designed for API usage. + * + * @param player The player to get the level for + * @param skillType The skill to get the level for + * @return the level of a given skill + * + * @throws InvalidSkillException if the given skill is not valid + * @deprecated Use getLevel(Player player, PrimarySkillType skillType) instead + */ + @Deprecated + public static int getLevel(Player player, String skillType) { + return getPlayer(player).getSkillLevel(getSkillType(skillType)); + } + + /** + * Get the level a player has in a specific skill. + *
+ * This function is designed for API usage. + * + * @param player The player to get the level for + * @param skillType The skill to get the level for + * @return the level of a given skill + * + * @throws InvalidSkillException if the given skill is not valid + */ + public static int getLevel(Player player, PrimarySkillType skillType) { + return getPlayer(player).getSkillLevel(skillType); + } + + /** + * Get the level an offline player has in a specific skill. + *
+ * This function is designed for API usage. + * + * @param playerName The player to get the level for + * @param skillType The skill to get the level for + * @return the level of a given skill + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + */ + public static int getLevelOffline(String playerName, String skillType) { + return getOfflineProfile(playerName).getSkillLevel(getSkillType(skillType)); + } + + /** + * Get the level an offline player has in a specific skill. + *
+ * This function is designed for API usage. + * + * @param uuid The player to get the level for + * @param skillType The skill to get the level for + * @return the level of a given skill + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + */ + public static int getLevelOffline(UUID uuid, String skillType) { + return getOfflineProfile(uuid).getSkillLevel(getSkillType(skillType)); + } + + /** + * Gets the power level of a player. + *
+ * This function is designed for API usage. + * + * @param player The player to get the power level for + * @return the power level of the player + */ + public static int getPowerLevel(Player player) { + return getPlayer(player).getPowerLevel(); + } + + /** + * Gets the power level of an offline player. + *
+ * This function is designed for API usage. + * + * @param playerName The player to get the power level for + * @return the power level of the player + * + * @throws InvalidPlayerException if the given player does not exist in the database + */ + @Deprecated + public static int getPowerLevelOffline(String playerName) { + int powerLevel = 0; + PlayerProfile profile = getOfflineProfile(playerName); + + for (PrimarySkillType type : PrimarySkillType.NON_CHILD_SKILLS) { + powerLevel += profile.getSkillLevel(type); + } + + return powerLevel; + } + + /** + * Gets the power level of an offline player. + *
+ * This function is designed for API usage. + * + * @param uuid The player to get the power level for + * @return the power level of the player + * + * @throws InvalidPlayerException if the given player does not exist in the database + */ + public static int getPowerLevelOffline(UUID uuid) { + int powerLevel = 0; + PlayerProfile profile = getOfflineProfile(uuid); + + for (PrimarySkillType type : PrimarySkillType.NON_CHILD_SKILLS) { + powerLevel += profile.getSkillLevel(type); + } + + return powerLevel; + } + + /** + * Get the level cap of a specific skill. + *
+ * This function is designed for API usage. + * + * @param skillType The skill to get the level cap for + * @return the level cap of a given skill + * + * @throws InvalidSkillException if the given skill is not valid + */ + public static int getLevelCap(String skillType) { + return Config.getInstance().getLevelCap(getSkillType(skillType)); + } + + /** + * Get the power level cap. + *
+ * This function is designed for API usage. + * + * @return the overall power level cap + */ + public static int getPowerLevelCap() { + return Config.getInstance().getPowerLevelCap(); + } + + /** + * Get the position on the leaderboard of a player. + *
+ * This function is designed for API usage. + * + * @param playerName The name of the player to check + * @param skillType The skill to check + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + * @throws UnsupportedOperationException if the given skill is a child skill + * + * @return the position on the leaderboard + */ + @Deprecated + public static int getPlayerRankSkill(String playerName, String skillType) { + return mcMMO.getDatabaseManager().readRank(mcMMO.p.getServer().getOfflinePlayer(playerName).getName()).get(getNonChildSkillType(skillType)); + } + + /** + * Get the position on the leaderboard of a player. + *
+ * This function is designed for API usage. + * + * @param uuid The name of the player to check + * @param skillType The skill to check + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + * @throws UnsupportedOperationException if the given skill is a child skill + * + * @return the position on the leaderboard + */ + public static int getPlayerRankSkill(UUID uuid, String skillType) { + return mcMMO.getDatabaseManager().readRank(mcMMO.p.getServer().getOfflinePlayer(uuid).getName()).get(getNonChildSkillType(skillType)); + } + + /** + * Get the position on the power level leaderboard of a player. + *
+ * This function is designed for API usage. + * + * @param playerName The name of the player to check + * + * @throws InvalidPlayerException if the given player does not exist in the database + * + * @return the position on the power level leaderboard + */ + @Deprecated + public static int getPlayerRankOverall(String playerName) { + return mcMMO.getDatabaseManager().readRank(mcMMO.p.getServer().getOfflinePlayer(playerName).getName()).get(null); + } + + /** + * Get the position on the power level leaderboard of a player. + *
+ * This function is designed for API usage. + * + * @param uuid The name of the player to check + * + * @throws InvalidPlayerException if the given player does not exist in the database + * + * @return the position on the power level leaderboard + */ + public static int getPlayerRankOverall(UUID uuid) { + return mcMMO.getDatabaseManager().readRank(mcMMO.p.getServer().getOfflinePlayer(uuid).getName()).get(null); + } + + /** + * Sets the level of a player in a specific skill type. + *
+ * This function is designed for API usage. + * + * @param player The player to set the level of + * @param skillType The skill to set the level for + * @param skillLevel The value to set the level to + * + * @throws InvalidSkillException if the given skill is not valid + */ + public static void setLevel(Player player, String skillType, int skillLevel) { + getPlayer(player).modifySkill(getSkillType(skillType), skillLevel); + } + + /** + * Sets the level of an offline player in a specific skill type. + *
+ * This function is designed for API usage. + * + * @param playerName The player to set the level of + * @param skillType The skill to set the level for + * @param skillLevel The value to set the level to + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + */ + @Deprecated + public static void setLevelOffline(String playerName, String skillType, int skillLevel) { + getOfflineProfile(playerName).modifySkill(getSkillType(skillType), skillLevel); + } + + /** + * Sets the level of an offline player in a specific skill type. + *
+ * This function is designed for API usage. + * + * @param uuid The player to set the level of + * @param skillType The skill to set the level for + * @param skillLevel The value to set the level to + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + */ + public static void setLevelOffline(UUID uuid, String skillType, int skillLevel) { + getOfflineProfile(uuid).modifySkill(getSkillType(skillType), skillLevel); + } + + /** + * Sets the XP of a player in a specific skill type. + *
+ * This function is designed for API usage. + * + * @param player The player to set the XP of + * @param skillType The skill to set the XP for + * @param newValue The value to set the XP to + * + * @throws InvalidSkillException if the given skill is not valid + * @throws UnsupportedOperationException if the given skill is a child skill + */ + public static void setXP(Player player, String skillType, int newValue) { + getPlayer(player).setSkillXpLevel(getNonChildSkillType(skillType), newValue); + } + + /** + * Sets the XP of an offline player in a specific skill type. + *
+ * This function is designed for API usage. + * + * @param playerName The player to set the XP of + * @param skillType The skill to set the XP for + * @param newValue The value to set the XP to + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + * @throws UnsupportedOperationException if the given skill is a child skill + */ + @Deprecated + public static void setXPOffline(String playerName, String skillType, int newValue) { + getOfflineProfile(playerName).setSkillXpLevel(getNonChildSkillType(skillType), newValue); + } + + /** + * Sets the XP of an offline player in a specific skill type. + *
+ * This function is designed for API usage. + * + * @param uuid The player to set the XP of + * @param skillType The skill to set the XP for + * @param newValue The value to set the XP to + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + * @throws UnsupportedOperationException if the given skill is a child skill + */ + public static void setXPOffline(UUID uuid, String skillType, int newValue) { + getOfflineProfile(uuid).setSkillXpLevel(getNonChildSkillType(skillType), newValue); + } + + /** + * Removes XP from a player in a specific skill type. + *
+ * This function is designed for API usage. + * + * @param player The player to change the XP of + * @param skillType The skill to change the XP for + * @param xp The amount of XP to remove + * + * @throws InvalidSkillException if the given skill is not valid + * @throws UnsupportedOperationException if the given skill is a child skill + */ + public static void removeXP(Player player, String skillType, int xp) { + getPlayer(player).removeXp(getNonChildSkillType(skillType), xp); + } + + /** + * Removes XP from an offline player in a specific skill type. + *
+ * This function is designed for API usage. + * + * @param playerName The player to change the XP of + * @param skillType The skill to change the XP for + * @param xp The amount of XP to remove + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + * @throws UnsupportedOperationException if the given skill is a child skill + */ + @Deprecated + public static void removeXPOffline(String playerName, String skillType, int xp) { + getOfflineProfile(playerName).removeXp(getNonChildSkillType(skillType), xp); + } + + /** + * Removes XP from an offline player in a specific skill type. + *
+ * This function is designed for API usage. + * + * @param uuid The player to change the XP of + * @param skillType The skill to change the XP for + * @param xp The amount of XP to remove + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + * @throws UnsupportedOperationException if the given skill is a child skill + */ + public static void removeXPOffline(UUID uuid, String skillType, int xp) { + getOfflineProfile(uuid).removeXp(getNonChildSkillType(skillType), xp); + } + + /** + * Check how much XP is needed for a specific level with the selected level curve. + *
+ * This function is designed for API usage. + * + * @param level The level to get the amount of XP for + * + * @throws InvalidFormulaTypeException if the given formulaType is not valid + */ + public static int getXpNeededToLevel(int level) { + return mcMMO.getFormulaManager().getXPtoNextLevel(level, ExperienceConfig.getInstance().getFormulaType()); + } + + /** + * Check how much XP is needed for a specific level with the provided level curve. + *
+ * This function is designed for API usage. + * + * @param level The level to get the amount of XP for + * @param formulaType The formula type to get the amount of XP for + * + * @throws InvalidFormulaTypeException if the given formulaType is not valid + */ + public static int getXpNeededToLevel(int level, String formulaType) { + return mcMMO.getFormulaManager().getXPtoNextLevel(level, getFormulaType(formulaType)); + } + + /** + * Will add the appropriate type of XP from the block to the player based on the material of the blocks given + * @param blockStates the blocks to reward XP for + * @param mcMMOPlayer the target player + */ + public static void addXpFromBlocks(ArrayList blockStates, McMMOPlayer mcMMOPlayer) + { + for(BlockState bs : blockStates) + { + for(PrimarySkillType skillType : PrimarySkillType.values()) + { + if(ExperienceConfig.getInstance().getXp(skillType, bs.getType()) > 0) + { + mcMMOPlayer.applyXpGain(skillType, ExperienceConfig.getInstance().getXp(skillType, bs.getType()), XPGainReason.PVE, XPGainSource.SELF); + } + } + } + } + + /** + * Will add the appropriate type of XP from the block to the player based on the material of the blocks given if it matches the given skillType + * @param blockStates the blocks to reward XP for + * @param mcMMOPlayer the target player + * @param skillType target primary skill + */ + public static void addXpFromBlocksBySkill(ArrayList blockStates, McMMOPlayer mcMMOPlayer, PrimarySkillType skillType) + { + for(BlockState bs : blockStates) + { + if(ExperienceConfig.getInstance().getXp(skillType, bs.getType()) > 0) + { + mcMMOPlayer.applyXpGain(skillType, ExperienceConfig.getInstance().getXp(skillType, bs.getType()), XPGainReason.PVE, XPGainSource.SELF); + } + } + } + + /** + * Will add the appropriate type of XP from the block to the player based on the material of the blocks given + * @param blockState The target blockstate + * @param mcMMOPlayer The target player + */ + public static void addXpFromBlock(BlockState blockState, McMMOPlayer mcMMOPlayer) + { + for(PrimarySkillType skillType : PrimarySkillType.values()) + { + if(ExperienceConfig.getInstance().getXp(skillType, blockState.getType()) > 0) + { + mcMMOPlayer.applyXpGain(skillType, ExperienceConfig.getInstance().getXp(skillType, blockState.getType()), XPGainReason.PVE, XPGainSource.SELF); + } + } + } + + /** + * Will add the appropriate type of XP from the block to the player based on the material of the blocks given if it matches the given skillType + * @param blockState The target blockstate + * @param mcMMOPlayer The target player + * @param skillType target primary skill + */ + public static void addXpFromBlockBySkill(BlockState blockState, McMMOPlayer mcMMOPlayer, PrimarySkillType skillType) + { + if(ExperienceConfig.getInstance().getXp(skillType, blockState.getType()) > 0) + { + mcMMOPlayer.applyXpGain(skillType, ExperienceConfig.getInstance().getXp(skillType, blockState.getType()), XPGainReason.PVE, XPGainSource.SELF); + } + } + + // Utility methods follow. + private static void addOfflineXP(UUID playerUniqueId, PrimarySkillType skill, int XP) { + PlayerProfile profile = getOfflineProfile(playerUniqueId); + + profile.addXp(skill, XP); + profile.save(true); + } + + @Deprecated + private static void addOfflineXP(String playerName, PrimarySkillType skill, int XP) { + PlayerProfile profile = getOfflineProfile(playerName); + + profile.addXp(skill, XP); + profile.scheduleAsyncSave(); + } + + private static PlayerProfile getOfflineProfile(UUID uuid) throws InvalidPlayerException { + OfflinePlayer offlinePlayer = Bukkit.getServer().getOfflinePlayer(uuid); + String playerName = offlinePlayer.getName(); + PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid, playerName); + + if (!profile.isLoaded()) { + throw new InvalidPlayerException(); + } + + return profile; + } + + @Deprecated + private static PlayerProfile getOfflineProfile(String playerName) throws InvalidPlayerException { + OfflinePlayer offlinePlayer = Bukkit.getServer().getOfflinePlayer(playerName); + UUID uuid = offlinePlayer.getUniqueId(); + PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid, playerName); + + if (!profile.isLoaded()) { + throw new InvalidPlayerException(); + } + + return profile; + } + + private static PrimarySkillType getSkillType(String skillType) throws InvalidSkillException { + PrimarySkillType skill = PrimarySkillType.getSkill(skillType); + + if (skill == null) { + throw new InvalidSkillException(); + } + + return skill; + } + + private static PrimarySkillType getNonChildSkillType(String skillType) throws InvalidSkillException, UnsupportedOperationException { + PrimarySkillType skill = getSkillType(skillType); + + if (skill.isChildSkill()) { + throw new UnsupportedOperationException("Child skills do not have XP"); + } + + return skill; + } + + private static XPGainReason getXPGainReason(String reason) throws InvalidXPGainReasonException { + XPGainReason xpGainReason = XPGainReason.getXPGainReason(reason); + + if (xpGainReason == null) { + throw new InvalidXPGainReasonException(); + } + + return xpGainReason; + } + + private static FormulaType getFormulaType(String formula) throws InvalidFormulaTypeException { + FormulaType formulaType = FormulaType.getFormulaType(formula); + + if (formulaType == null) { + throw new InvalidFormulaTypeException(); + } + + return formulaType; + } + + /** + * @deprecated Use UserManager::getPlayer(Player player) instead + * @param player target player + * @return McMMOPlayer for that player if the profile is loaded, otherwise null + * @throws McMMOPlayerNotFoundException + */ + @Deprecated + private static McMMOPlayer getPlayer(Player player) throws McMMOPlayerNotFoundException { + if (!UserManager.hasPlayerDataKey(player)) { + throw new McMMOPlayerNotFoundException(player); + } + + return UserManager.getPlayer(player); + } +} diff --git a/src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java b/src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java index e7290d308..e37f4267f 100644 --- a/src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java @@ -58,7 +58,7 @@ public class ConvertDatabaseCommand implements CommandExecutor { } for (Player player : mcMMO.p.getServer().getOnlinePlayers()) { - PlayerProfile profile = oldDatabase.queryPlayerDataByUUID(player.getUniqueId()); + PlayerProfile profile = oldDatabase.queryPlayerDataByUUID(player.getUniqueId(), null); if(profile == null) continue; diff --git a/src/main/java/com/gmail/nossr50/commands/database/DatabaseRemovePlayerCommand.java b/src/main/java/com/gmail/nossr50/commands/database/DatabaseRemovePlayerCommand.java index cfa6bd4ab..577dd0d76 100644 --- a/src/main/java/com/gmail/nossr50/commands/database/DatabaseRemovePlayerCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/database/DatabaseRemovePlayerCommand.java @@ -23,7 +23,7 @@ public class DatabaseRemovePlayerCommand implements TabExecutor { String playerName = CommandUtils.getMatchedPlayerName(args[0]); if (mcMMO.getUserManager().queryPlayer(playerName) == null - && CommandUtils.hasNoProfile(sender, mcMMO.getDatabaseManager().queryPlayerDataByUUID(playerName, false))) { + && CommandUtils.hasNoProfile(sender, mcMMO.getDatabaseManager().queryPlayerDataByUUID(playerName))) { sender.sendMessage(LocaleLoader.getString("Commands.Offline")); return true; } diff --git a/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java index c48d4f043..11684ebf8 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java @@ -1,14 +1,13 @@ package com.gmail.nossr50.commands.experience; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.commands.CommandUtils; +import com.gmail.nossr50.util.player.UserManager; import com.google.common.collect.ImmutableList; -import com.neetgames.mcmmo.player.MMOPlayer; -import com.neetgames.mcmmo.player.OnlineMMOPlayer; -import com.neetgames.mcmmo.skill.RootSkill; import org.bukkit.OfflinePlayer; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -16,7 +15,6 @@ import org.bukkit.command.TabExecutor; import org.bukkit.entity.Player; import org.bukkit.util.StringUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; @@ -25,7 +23,7 @@ import java.util.UUID; public abstract class ExperienceCommand implements TabExecutor { @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { - RootSkill rootSkill; + PrimarySkillType skill; if(args.length < 2) { return false; @@ -46,27 +44,27 @@ public abstract class ExperienceCommand implements TabExecutor { return true; } - rootSkill = mcMMO.p.getSkillRegister().getSkill(args[0]); + skill = PrimarySkillType.getSkill(args[0]); if (args[1].equalsIgnoreCase("all")) { - rootSkill = null; + skill = null; } - if (rootSkill != null && rootSkill.isChildSkill()) { + if (skill != null && skill.isChildSkill()) + { sender.sendMessage(LocaleLoader.getString("Commands.Skill.ChildSkill")); return true; } //Profile not loaded - Player player = (Player) sender; - OnlineMMOPlayer mmoPlayer = mcMMO.getUserManager().queryPlayer(player); - if(mmoPlayer == null) { + if(UserManager.getPlayer(sender.getName()) == null) + { sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad")); return true; } - editValues(mmoPlayer, rootSkill, Integer.parseInt(args[1]), isSilent(args)); + editValues((Player) sender, UserManager.getPlayer(sender.getName()).getProfile(), skill, Integer.parseInt(args[1]), isSilent(args)); return true; } else if((args.length == 3 && !isSilent(args)) || (args.length == 4 && isSilent(args))) { @@ -79,13 +77,13 @@ public abstract class ExperienceCommand implements TabExecutor { return true; } - rootSkill = mcMMO.p.getSkillRegister().getSkill(args[1]); + skill = PrimarySkillType.getSkill(args[1]); if (args[1].equalsIgnoreCase("all")) { - rootSkill = null; + skill = null; } - if (rootSkill != null && rootSkill.isChildSkill()) + if (skill != null && skill.isChildSkill()) { sender.sendMessage(LocaleLoader.getString("Commands.Skill.ChildSkill")); return true; @@ -94,25 +92,31 @@ public abstract class ExperienceCommand implements TabExecutor { int value = Integer.parseInt(args[2]); String playerName = CommandUtils.getMatchedPlayerName(args[0]); - OnlineMMOPlayer mmoPlayer = mcMMO.getUserManager().queryPlayer(playerName); + McMMOPlayer mcMMOPlayer = UserManager.getOfflinePlayer(playerName); - // If the mmoPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process. - if (mmoPlayer == null) { + // If the mcMMOPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process. + if (mcMMOPlayer == null) { UUID uuid = null; - OfflinePlayer player = mcMMO.p.getServer().getOfflinePlayer(playerName); - if (player != null) { - uuid = player.getUniqueId(); - } - PlayerProfile profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(playerName, uuid, false); + OfflinePlayer offlinePlayer = mcMMO.p.getServer().getOfflinePlayer(playerName); + PlayerProfile profile; - if (CommandUtils.hasNoProfile(sender, profile)) { - return true; + uuid = offlinePlayer.getUniqueId(); + profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid, null); + + //Check loading by UUID + if (CommandUtils.unloadedProfile(sender, profile)) { + //Check loading by name + profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName); + + if(CommandUtils.unloadedProfile(sender, profile)) { + return true; + } } - editValues(null, profile, rootSkill, value, isSilent(args)); + editValues(null, profile, skill, value, isSilent(args)); } else { - editValues(Misc.adaptPlayer(mmoPlayer), mcMMOPlayer.getProfile(), rootSkill, value, isSilent(args)); + editValues(mcMMOPlayer.getPlayer(), mcMMOPlayer.getProfile(), skill, value, isSilent(args)); } handleSenderMessage(sender, playerName, skill); @@ -148,27 +152,27 @@ public abstract class ExperienceCommand implements TabExecutor { protected abstract boolean permissionsCheckSelf(CommandSender sender); protected abstract boolean permissionsCheckOthers(CommandSender sender); - protected abstract void handleCommand(Player player, PlayerProfile profile, RootSkill rootSkill, int value); + protected abstract void handleCommand(Player player, PlayerProfile profile, PrimarySkillType skill, int value); protected abstract void handlePlayerMessageAll(Player player, int value, boolean isSilent); - protected abstract void handlePlayerMessageSkill(Player player, int value, RootSkill rootSkill, boolean isSilent); + protected abstract void handlePlayerMessageSkill(Player player, int value, PrimarySkillType skill, boolean isSilent); private boolean validateArguments(CommandSender sender, String skillName, String value) { return !(CommandUtils.isInvalidInteger(sender, value) || (!skillName.equalsIgnoreCase("all") && CommandUtils.isInvalidSkill(sender, skillName))); } - protected static void handleSenderMessage(CommandSender sender, String playerName, RootSkill rootSkill) { - if (rootSkill == null) { + protected static void handleSenderMessage(CommandSender sender, String playerName, PrimarySkillType skill) { + if (skill == null) { sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardAll.2", playerName)); } else { - sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", rootSkill.getName(), playerName)); + sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", skill.getName(), playerName)); } } - protected void editValues(@NotNull MMOPlayer mmoPlayer, @Nullable RootSkill rootSkill, int value, boolean isSilent) { - if (primarySkillType == null) { - for (PrimarySkillType type : PrimarySkillType.NON_CHILD_SKILLS) { - handleCommand(player, profile, type, value); + protected void editValues(Player player, PlayerProfile profile, PrimarySkillType skill, int value, boolean isSilent) { + if (skill == null) { + for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { + handleCommand(player, profile, primarySkillType, value); } if (player != null) { @@ -176,10 +180,10 @@ public abstract class ExperienceCommand implements TabExecutor { } } else { - handleCommand(player, profile, primarySkillType, value); + handleCommand(player, profile, skill, value); if (player != null) { - handlePlayerMessageSkill(player, value, primarySkillType, isSilent); + handlePlayerMessageSkill(player, value, skill, isSilent); } } } diff --git a/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java index 3162beeb0..9b97fa77a 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java @@ -1,14 +1,16 @@ package com.gmail.nossr50.commands.experience; +import com.gmail.nossr50.datatypes.experience.XPGainReason; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.EventUtils; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.commands.CommandUtils; +import com.gmail.nossr50.util.player.UserManager; import com.google.common.collect.ImmutableList; -import com.neetgames.mcmmo.player.OnlineMMOPlayer; -import com.neetgames.mcmmo.skill.RootSkill; import org.bukkit.OfflinePlayer; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -28,7 +30,7 @@ import java.util.UUID; public class SkillresetCommand implements TabExecutor { @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { - RootSkill rootSkill; + PrimarySkillType skill; switch (args.length) { case 1: if (CommandUtils.noConsoleUsage(sender)) { @@ -45,14 +47,13 @@ public class SkillresetCommand implements TabExecutor { } if (args[0].equalsIgnoreCase("all")) { - rootSkill = null; + skill = null; } else { - rootSkill = mcMMO.p.getSkillRegister().getSkill(args[0]); + skill = PrimarySkillType.getSkill(args[0]); } - editValues((Player) sender, mcMMO.getUserManager().queryPlayer(player) -, skill); + editValues((Player) sender, UserManager.getPlayer(sender.getName()).getProfile(), skill); return true; case 2: @@ -66,32 +67,38 @@ public class SkillresetCommand implements TabExecutor { } if (args[1].equalsIgnoreCase("all")) { - rootSkill = null; + skill = null; } else { - rootSkill = mcMMO.p.getSkillRegister().getSkill(args[1]); + skill = PrimarySkillType.getSkill(args[1]); } String playerName = CommandUtils.getMatchedPlayerName(args[0]); - OnlineMMOPlayer mmoPlayer = mcMMO.getUserManager().queryPlayer(playerName); + McMMOPlayer mcMMOPlayer = UserManager.getOfflinePlayer(playerName); - // If the mmoPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process. - if (mmoPlayer == null) { + // If the mcMMOPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process. + if (mcMMOPlayer == null) { UUID uuid = null; OfflinePlayer player = mcMMO.p.getServer().getOfflinePlayer(playerName); - if (player != null) { - uuid = player.getUniqueId(); - } - PlayerProfile profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(playerName, uuid, false); + uuid = player.getUniqueId(); - if (CommandUtils.hasNoProfile(sender, profile)) { - return true; + PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid, playerName); + + //Check loading by UUID + if (CommandUtils.unloadedProfile(sender, profile)) { + //Didn't find it by UUID so try to find it by name + profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName); + + //Check if it was present in DB + if(CommandUtils.unloadedProfile(sender, profile)) { + return true; + } } editValues(null, profile, skill); } else { - editValues(Misc.adaptPlayer(mmoPlayer), mmoPlayer, skill); + editValues(mcMMOPlayer.getPlayer(), mcMMOPlayer.getProfile(), skill); } handleSenderMessage(sender, playerName, skill); @@ -115,18 +122,18 @@ public class SkillresetCommand implements TabExecutor { } } - protected void handleCommand(Player player, PlayerProfile profile, RootSkill rootSkill) { - int levelsRemoved = profile.getSkillLevel(rootSkill); - float xpRemoved = profile.getSkillXpLevelRaw(rootSkill); + protected void handleCommand(Player player, PlayerProfile profile, PrimarySkillType skill) { + int levelsRemoved = profile.getSkillLevel(skill); + float xpRemoved = profile.getSkillXpLevelRaw(skill); - profile.modifySkill(rootSkill, 0); + profile.modifySkill(skill, 0); if (player == null) { profile.scheduleAsyncSave(); return; } - EventUtils.tryLevelChangeEvent(player, rootSkill, levelsRemoved, xpRemoved, false, XPGainReason.COMMAND); + EventUtils.tryLevelChangeEvent(player, skill, levelsRemoved, xpRemoved, false, XPGainReason.COMMAND); } protected boolean permissionsCheckSelf(CommandSender sender) { @@ -141,26 +148,26 @@ public class SkillresetCommand implements TabExecutor { player.sendMessage(LocaleLoader.getString("Commands.Reset.All")); } - protected void handlePlayerMessageSkill(Player player, RootSkill rootSkill) { - player.sendMessage(LocaleLoader.getString("Commands.Reset.Single", rootSkill.getName())); + protected void handlePlayerMessageSkill(Player player, PrimarySkillType skill) { + player.sendMessage(LocaleLoader.getString("Commands.Reset.Single", skill.getName())); } private boolean validateArguments(CommandSender sender, String skillName) { return skillName.equalsIgnoreCase("all") || !CommandUtils.isInvalidSkill(sender, skillName); } - protected static void handleSenderMessage(CommandSender sender, String playerName, RootSkill rootSkill) { - if (rootSkill == null) { + protected static void handleSenderMessage(CommandSender sender, String playerName, PrimarySkillType skill) { + if (skill == null) { sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardAll.2", playerName)); } else { - sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", rootSkill.getName(), playerName)); + sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", skill.getName(), playerName)); } } - protected void editValues(Player player, PlayerProfile profile, RootSkill rootSkill) { - if (rootSkill == null) { - for (RootSkill rootSkill : PrimarySkillType.NON_CHILD_SKILLS) { + protected void editValues(Player player, PlayerProfile profile, PrimarySkillType skill) { + if (skill == null) { + for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { handleCommand(player, profile, primarySkillType); } diff --git a/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java b/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java index 1322d8b69..a65004417 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java @@ -1,15 +1,16 @@ package com.gmail.nossr50.commands.player; import com.gmail.nossr50.config.Config; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.commands.CommandUtils; +import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.google.common.collect.ImmutableList; -import com.neetgames.mcmmo.skill.RootSkill; -import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; @@ -25,19 +26,15 @@ public class InspectCommand implements TabExecutor { public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { if (args.length == 1) { String playerName = CommandUtils.getMatchedPlayerName(args[0]); + McMMOPlayer mcMMOPlayer = UserManager.getOfflinePlayer(playerName); - PlayerProfile playerProfile = mcMMO.getUserManager().queryPlayer(playerName); - Player targetPlayer = Bukkit.getPlayer(playerName); + // If the mcMMOPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process. + if (mcMMOPlayer == null) { + PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName); // Temporary Profile - if(playerProfile == null) { - //TODO: Localize - sender.sendMessage("Data was not found in the database for the given player name!"); - return true; - } - - - if(targetPlayer == null) { - //Target is offline + if (!CommandUtils.isLoaded(sender, profile)) { + return true; + } if (Config.getInstance().getScoreboardsEnabled() && sender instanceof Player @@ -52,42 +49,48 @@ public class InspectCommand implements TabExecutor { sender.sendMessage(LocaleLoader.getString("Inspect.OfflineStats", playerName)); sender.sendMessage(LocaleLoader.getString("Stats.Header.Gathering")); - for (RootSkill rootSkill : PrimarySkillType.GATHERING_SKILLS) { + for (PrimarySkillType skill : PrimarySkillType.GATHERING_SKILLS) { sender.sendMessage(CommandUtils.displaySkill(profile, skill)); } sender.sendMessage(LocaleLoader.getString("Stats.Header.Combat")); - for (RootSkill rootSkill : PrimarySkillType.COMBAT_SKILLS) { + for (PrimarySkillType skill : PrimarySkillType.COMBAT_SKILLS) { sender.sendMessage(CommandUtils.displaySkill(profile, skill)); } sender.sendMessage(LocaleLoader.getString("Stats.Header.Misc")); - for (RootSkill rootSkill : PrimarySkillType.MISC_SKILLS) { + for (PrimarySkillType skill : PrimarySkillType.MISC_SKILLS) { sender.sendMessage(CommandUtils.displaySkill(profile, skill)); } - } else { - if (CommandUtils.hidden(sender, targetPlayer, Permissions.inspectHidden(sender))) { - sender.sendMessage(LocaleLoader.getString("Inspect.Offline")); - return true; - } else if (CommandUtils.tooFar(sender, targetPlayer, Permissions.inspectFar(sender))) { + } else { + Player target = mcMMOPlayer.getPlayer(); + boolean isVanished = false; + + if (CommandUtils.hidden(sender, target, Permissions.inspectHidden(sender))) { + isVanished = true; + } + + //Only distance check players who are online and not vanished + if (!isVanished && CommandUtils.tooFar(sender, target, Permissions.inspectFar(sender))) { return true; } if (Config.getInstance().getScoreboardsEnabled() - && sender instanceof Player && Config.getInstance().getInspectUseBoard()) { - ScoreboardManager.enablePlayerInspectScoreboard((Player) sender, playerProfile); + && sender instanceof Player + && Config.getInstance().getInspectUseBoard()) { + ScoreboardManager.enablePlayerInspectScoreboard((Player) sender, mcMMOPlayer); if (!Config.getInstance().getInspectUseChat()) { return true; } } - sender.sendMessage(LocaleLoader.getString("Inspect.Stats", targetPlayer.getName())); - CommandUtils.printGatheringSkills(targetPlayer, sender); - CommandUtils.printCombatSkills(targetPlayer, sender); - CommandUtils.printMiscSkills(targetPlayer, sender); - sender.sendMessage(LocaleLoader.getString("Commands.PowerLevel", playerProfile.getExperienceHandler().getPowerLevel())); + sender.sendMessage(LocaleLoader.getString("Inspect.Stats", target.getName())); + CommandUtils.printGatheringSkills(target, sender); + CommandUtils.printCombatSkills(target, sender); + CommandUtils.printMiscSkills(target, sender); + sender.sendMessage(LocaleLoader.getString("Commands.PowerLevel", mcMMOPlayer.getPowerLevel())); } return true; diff --git a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java index e9fb27a74..7b6fc41cd 100644 --- a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java @@ -1,16 +1,11 @@ package com.gmail.nossr50.database; +import com.gmail.nossr50.api.exceptions.InvalidSkillException; import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.database.DatabaseType; import com.gmail.nossr50.datatypes.database.PlayerStat; -import com.gmail.nossr50.datatypes.player.MMODataSnapshot; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -import com.neetgames.mcmmo.exceptions.InvalidSkillException; -import com.neetgames.mcmmo.exceptions.ProfileRetrievalException; -import com.neetgames.mcmmo.player.MMOPlayerData; -import com.neetgames.mcmmo.skill.RootSkill; -import org.apache.commons.lang.NullArgumentException; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -39,35 +34,36 @@ public interface DatabaseManager { * Remove a user from the database. * * @param playerName The name of the user to remove - * @param uuid uuid of player to remove, can be null + * @param uuid player UUID, can be null * @return true if the user was successfully removed, false otherwise */ - boolean removeUser(@NotNull String playerName, @Nullable UUID uuid); + boolean removeUser(String playerName, UUID uuid); /** * Removes any cache used for faster lookups * Currently only used for SQL * @param uuid target UUID to cleanup */ - void removeCache(@NotNull UUID uuid); + void cleanupUser(UUID uuid); /** * Save a user to the database. * - * @param mmoDataSnapshot Snapshot of player data to save + * @param profile The profile of the player to save + * @return true if successful, false on failure */ - boolean saveUser(@NotNull MMODataSnapshot mmoDataSnapshot); + boolean saveUser(PlayerProfile profile); /** * Retrieve leaderboard info. * Will never be null but it may be empty * - * @param rootSkill The skill to retrieve info on + * @param skill The skill to retrieve info on * @param pageNumber Which page in the leaderboards to retrieve * @param statsPerPage The number of stats per page * @return the requested leaderboard information */ - @NotNull List readLeaderboard(@NotNull RootSkill rootSkill, int pageNumber, int statsPerPage) throws InvalidSkillException; + @NotNull List readLeaderboard(@Nullable PrimarySkillType skill, int pageNumber, int statsPerPage) throws InvalidSkillException; /** * Retrieve rank info into a HashMap from PrimarySkillType to the rank. @@ -78,74 +74,60 @@ public interface DatabaseManager { * @param playerName The name of the user to retrieve the rankings for * @return the requested rank information */ - @NotNull Map readRank(@NotNull String playerName); + Map readRank(String playerName); /** * Add a new user to the database. - * @param playerName The name of the player to be added to the database + * + * @param playerName The name of the player to be added to the database * @param uuid The uuid of the player to be added to the database */ - void insertNewUser(@NotNull String playerName, @NotNull UUID uuid) throws Exception; + void newUser(String playerName, UUID uuid); - @Nullable MMOPlayerData queryPlayerDataByPlayer(@NotNull Player player) throws ProfileRetrievalException, NullArgumentException; + @NotNull PlayerProfile newUser(@NotNull Player player); /** - * Load player data (in the form of {@link PlayerProfile}) if player data exists - * Returns null if it doesn't + * Load a player from the database. + * + * @param playerName The name of the player to load from the database + * @return The player's data, or an unloaded PlayerProfile if not found + * and createNew is false + */ + @NotNull PlayerProfile loadPlayerProfile(@NotNull String playerName); + + /** + * Load a player from the database. * * @param uuid The uuid of the player to load from the database - * @param playerName the current player name for this player - * @return The player's data, or null if not found + * @return The player's data, or an unloaded PlayerProfile if not found */ - @Nullable MMOPlayerData queryPlayerDataByUUID(@NotNull UUID uuid, @NotNull String playerName) throws ProfileRetrievalException, NullArgumentException; - - /** - * Load player data (in the form of {@link PlayerProfile}) if player data exists - * Returns null if it doesn't - * - * @param playerName the current player name for this player - * @return The player's data, or null if not found - */ - @Nullable MMOPlayerData queryPlayerByName(@NotNull String playerName) throws ProfileRetrievalException; - - /** - * This method queries the DB for player data for target player - * If it fails to find data for this player, or if it does find data but the data is corrupted, - * it will then proceed to make brand new data for the target player, which will be saved to the DB during the next save - * - * This method will return null for all other errors, which indicates a problem with the DB, in which case mcMMO - * will try to load the player data periodically, but that isn't handled in this method - * - * @param player target player - * @return {@link PlayerProfile} for the target player - */ - @Nullable MMOPlayerData initPlayerProfile(@NotNull Player player) throws Exception; + @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid, @Nullable String playerName); /** * Get all users currently stored in the database. * * @return list of playernames */ - @NotNull List getStoredUsers(); + List getStoredUsers(); /** * Convert all users from this database to the provided database using - * {@link #saveUser(MMODataSnapshot)}. + * {@link #saveUser(PlayerProfile)}. * * @param destination The DatabaseManager to save to */ - void convertUsers(@NotNull DatabaseManager destination); + void convertUsers(DatabaseManager destination); -// boolean saveUserUUID(String userName, UUID uuid); + boolean saveUserUUID(String userName, UUID uuid); -// boolean saveUserUUIDs(Map fetchedUUIDs); + boolean saveUserUUIDs(Map fetchedUUIDs); /** * Retrieve the type of database in use. Custom databases should return CUSTOM. * * @return The type of database */ - @NotNull DatabaseType getDatabaseType(); + DatabaseType getDatabaseType(); /** * Called when the plugin disables diff --git a/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java deleted file mode 100644 index 53c86cce7..000000000 --- a/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java +++ /dev/null @@ -1,1524 +0,0 @@ -package com.gmail.nossr50.database; - -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; -import com.gmail.nossr50.datatypes.database.DatabaseType; -import com.gmail.nossr50.datatypes.database.PlayerStat; -import com.gmail.nossr50.datatypes.database.UpgradeType; -import com.gmail.nossr50.datatypes.player.*; -import com.gmail.nossr50.datatypes.skills.CoreSkills; -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -import com.gmail.nossr50.datatypes.skills.SuperAbilityType; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.runnables.database.UUIDUpdateAsyncTask; -import com.gmail.nossr50.util.Misc; -import com.gmail.nossr50.util.experience.MMOExperienceBarManager; -import com.gmail.nossr50.util.skills.SkillUtils; -import com.gmail.nossr50.util.text.StringUtils; -import com.google.common.collect.ImmutableMap; -import com.neetgames.mcmmo.MobHealthBarType; -import com.neetgames.mcmmo.UniqueDataType; -import com.neetgames.mcmmo.exceptions.ProfileRetrievalException; -import com.neetgames.mcmmo.player.MMOPlayerData; -import com.neetgames.mcmmo.skill.RootSkill; -import com.neetgames.mcmmo.skill.SkillBossBarState; -import com.neetgames.mcmmo.skill.SuperSkill; -import it.unimi.dsi.fastutil.Hash; -import org.apache.commons.lang.NullArgumentException; -import org.bukkit.OfflinePlayer; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.*; -import java.util.*; - -public final class FlatFileDatabaseManager extends AbstractDatabaseManager { - public static final String FLATFILE_SPLIT_CHARACTER_REGEX = ":"; - private final HashMap> playerStatHash = new HashMap<>(); - private final List powerLevels = new ArrayList<>(); - private long lastUpdate = 0; - - private final long UPDATE_WAIT_TIME = 600000L; // 10 minutes - private final File usersFile; - private static final Object fileWritingLock = new Object(); - - protected FlatFileDatabaseManager() { - usersFile = new File(mcMMO.getUsersFilePath()); - checkStructure(); - updateLeaderboards(); - - if (mcMMO.getUpgradeManager().shouldUpgrade(UpgradeType.ADD_UUIDS)) { - new UUIDUpdateAsyncTask(mcMMO.p, getStoredUsers()).start(); - } - } - - public void purgePowerlessUsers() { - int purgedUsers = 0; - - mcMMO.p.getLogger().info("Purging powerless users..."); - - BufferedReader in = null; - FileWriter out = null; - String usersFilePath = mcMMO.getUsersFilePath(); - - // This code is O(n) instead of O(n²) - synchronized (fileWritingLock) { - try { - in = new BufferedReader(new FileReader(usersFilePath)); - StringBuilder writer = new StringBuilder(); - String line; - - while ((line = in.readLine()) != null) { - String[] character = line.split(":"); - Map skills = getSkillMapFromLine(character); - - boolean powerless = true; - for (int skill : skills.values()) { - if (skill != 0) { - powerless = false; - break; - } - } - - // If they're still around, rewrite them to the file. - if (!powerless) { - writer.append(line).append("\r\n"); - } - else { - purgedUsers++; - } - } - - // Write the new file - out = new FileWriter(usersFilePath); - out.write(writer.toString()); - } - catch (IOException e) { - mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString()); - } - finally { - if (in != null) { - try { - in.close(); - } - catch (IOException e) { - // Ignore - } - } - if (out != null) { - try { - out.close(); - } - catch (IOException e) { - // Ignore - } - } - } - } - - mcMMO.p.getLogger().info("Purged " + purgedUsers + " users from the database."); - } - - public void purgeOldUsers() { - int removedPlayers = 0; - long currentTime = System.currentTimeMillis(); - - mcMMO.p.getLogger().info("Purging old users..."); - - BufferedReader in = null; - FileWriter out = null; - String usersFilePath = mcMMO.getUsersFilePath(); - - // This code is O(n) instead of O(n²) - synchronized (fileWritingLock) { - try { - in = new BufferedReader(new FileReader(usersFilePath)); - StringBuilder writer = new StringBuilder(); - String line; - - while ((line = in.readLine()) != null) { - String[] character = line.split(":"); - String name = character[FlatFileMappings.USERNAME]; - long lastPlayed = 0; - boolean rewrite = false; - try { - lastPlayed = Long.parseLong(character[37]) * Misc.TIME_CONVERSION_FACTOR; - } - catch (NumberFormatException e) { - e.printStackTrace(); - } - if (lastPlayed == 0) { - OfflinePlayer player = mcMMO.p.getServer().getOfflinePlayer(name); - lastPlayed = player.getLastPlayed(); - rewrite = true; - } - - if (currentTime - lastPlayed > PURGE_TIME) { - removedPlayers++; - } - else { - if (rewrite) { - // Rewrite their data with a valid time - character[37] = Long.toString(lastPlayed); - String newLine = org.apache.commons.lang.StringUtils.join(character, ":"); - writer.append(newLine).append("\r\n"); - } - else { - writer.append(line).append("\r\n"); - } - } - } - - // Write the new file - out = new FileWriter(usersFilePath); - out.write(writer.toString()); - } - catch (IOException e) { - mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString()); - } - finally { - if (in != null) { - try { - in.close(); - } - catch (IOException e) { - // Ignore - } - } - if (out != null) { - try { - out.close(); - } - catch (IOException e) { - // Ignore - } - } - } - } - - mcMMO.p.getLogger().info("Purged " + removedPlayers + " users from the database."); - } - - public boolean removeUser(@NotNull String playerName, @Nullable UUID uuid) { - //NOTE: UUID is unused for FlatFile for this interface implementation - boolean worked = false; - - BufferedReader in = null; - FileWriter out = null; - String usersFilePath = mcMMO.getUsersFilePath(); - - synchronized (fileWritingLock) { - try { - in = new BufferedReader(new FileReader(usersFilePath)); - StringBuilder writer = new StringBuilder(); - String line; - - while ((line = in.readLine()) != null) { - // Write out the same file but when we get to the player we want to remove, we skip his line. - if (!worked && line.split(":")[FlatFileMappings.USERNAME].equalsIgnoreCase(playerName)) { - mcMMO.p.getLogger().info("User found, removing..."); - worked = true; - continue; // Skip the player - } - - writer.append(line).append("\r\n"); - } - - out = new FileWriter(usersFilePath); // Write out the new file - out.write(writer.toString()); - } - catch (Exception e) { - mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString()); - } - finally { - if (in != null) { - try { - in.close(); - } - catch (IOException e) { - // Ignore - } - } - if (out != null) { - try { - out.close(); - } - catch (IOException e) { - // Ignore - } - } - } - } - - Misc.profileCleanup(playerName); - - return worked; - } - - @Override - public void removeCache(@NotNull UUID uuid) { - //Not used in FlatFile - } - - public boolean saveUser(@NotNull MMODataSnapshot dataSnapshot) { - String playerName = dataSnapshot.getPlayerName(); - UUID uuid = dataSnapshot.getPlayerUUID(); - - BufferedReader in = null; - FileWriter out = null; - String usersFilePath = mcMMO.getUsersFilePath(); - - synchronized (fileWritingLock) { - try { - // Open the file - in = new BufferedReader(new FileReader(usersFilePath)); - StringBuilder writer = new StringBuilder(); - String line; - - boolean wroteUser = false; - // While not at the end of the file - while ((line = in.readLine()) != null) { - // Read the line in and copy it to the output if it's not the player we want to edit - String[] character = line.split(":"); - if (!character[FlatFileMappings.UUID_INDEX].equalsIgnoreCase(uuid.toString()) && !character[FlatFileMappings.USERNAME].equalsIgnoreCase(playerName)) { - writer.append(line).append("\r\n"); - } - else { - // Otherwise write the new player information - writeUserToLine(dataSnapshot, playerName, uuid, writer); - wroteUser = true; - } - } - - /* - * If we couldn't find the user in the DB we need to add him - */ - if(!wroteUser) - { - writeUserToLine(dataSnapshot, playerName, uuid, writer); - } - - // Write the new file - out = new FileWriter(usersFilePath); - out.write(writer.toString()); - return true; - } - catch (Exception e) { - e.printStackTrace(); - return false; - } - finally { - if (in != null) { - try { - in.close(); - } - catch (IOException e) { - // Ignore - } - } - if (out != null) { - try { - out.close(); - } - catch (IOException e) { - // Ignore - } - } - } - } - } - - private void writeUserToLine(@NotNull MMODataSnapshot mmoDataSnapshot, @NotNull String playerName, @NotNull UUID uuid, @NotNull StringBuilder writer) { - ImmutableMap primarySkillLevelMap = mmoDataSnapshot.getSkillLevelValues(); - ImmutableMap primarySkillExperienceValueMap = mmoDataSnapshot.getSkillExperienceValues(); - - writer.append(playerName).append(":"); - writer.append(primarySkillLevelMap.get(CoreSkills.MINING_CS)).append(":"); - writer.append(":"); - writer.append(":"); - writer.append(primarySkillExperienceValueMap.get(CoreSkills.MINING_CS)).append(":"); - writer.append(primarySkillLevelMap.get(CoreSkills.WOODCUTTING_CS)).append(":"); - writer.append(primarySkillExperienceValueMap.get(CoreSkills.WOODCUTTING_CS)).append(":"); - writer.append(primarySkillLevelMap.get(CoreSkills.REPAIR_CS)).append(":"); - writer.append(primarySkillLevelMap.get(CoreSkills.UNARMED_CS)).append(":"); - writer.append(primarySkillLevelMap.get(CoreSkills.HERBALISM_CS)).append(":"); - writer.append(primarySkillLevelMap.get(CoreSkills.EXCAVATION_CS)).append(":"); - writer.append(primarySkillLevelMap.get(CoreSkills.ARCHERY_CS)).append(":"); - writer.append(primarySkillLevelMap.get(CoreSkills.SWORDS_CS)).append(":"); - writer.append(primarySkillLevelMap.get(CoreSkills.AXES_CS)).append(":"); - writer.append(primarySkillLevelMap.get(CoreSkills.ACROBATICS_CS)).append(":"); - writer.append(primarySkillExperienceValueMap.get(CoreSkills.REPAIR_CS)).append(":"); - writer.append(primarySkillExperienceValueMap.get(CoreSkills.UNARMED_CS)).append(":"); - writer.append(primarySkillExperienceValueMap.get(CoreSkills.HERBALISM_CS)).append(":"); - writer.append(primarySkillExperienceValueMap.get(CoreSkills.EXCAVATION_CS)).append(":"); - writer.append(primarySkillExperienceValueMap.get(CoreSkills.ARCHERY_CS)).append(":"); - writer.append(primarySkillExperienceValueMap.get(CoreSkills.SWORDS_CS)).append(":"); - writer.append(primarySkillExperienceValueMap.get(CoreSkills.AXES_CS)).append(":"); - writer.append(primarySkillExperienceValueMap.get(CoreSkills.ACROBATICS_CS)).append(":"); - writer.append(":"); - writer.append(primarySkillLevelMap.get(CoreSkills.TAMING_CS)).append(":"); - writer.append(primarySkillExperienceValueMap.get(CoreSkills.TAMING_CS)).append(":"); - writer.append((int) mmoDataSnapshot.getAbilityDATS(SuperAbilityType.BERSERK)).append(":"); - writer.append((int) mmoDataSnapshot.getAbilityDATS(SuperAbilityType.GIGA_DRILL_BREAKER)).append(":"); - writer.append((int) mmoDataSnapshot.getAbilityDATS(SuperAbilityType.TREE_FELLER)).append(":"); - writer.append((int) mmoDataSnapshot.getAbilityDATS(SuperAbilityType.GREEN_TERRA)).append(":"); - writer.append((int) mmoDataSnapshot.getAbilityDATS(SuperAbilityType.SERRATED_STRIKES)).append(":"); - writer.append((int) mmoDataSnapshot.getAbilityDATS(SuperAbilityType.SKULL_SPLITTER)).append(":"); - writer.append((int) mmoDataSnapshot.getAbilityDATS(SuperAbilityType.SUPER_BREAKER)).append(":"); - writer.append(":"); - writer.append(primarySkillLevelMap.get(CoreSkills.FISHING_CS)).append(":"); - writer.append(primarySkillExperienceValueMap.get(CoreSkills.FISHING_CS)).append(":"); - writer.append((int) mmoDataSnapshot.getAbilityDATS(SuperAbilityType.BLAST_MINING)).append(":"); - writer.append(System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR).append(":"); - - MobHealthBarType mobHealthbarType = mmoDataSnapshot.getMobHealthBarType(); - writer.append(mobHealthbarType.toString()).append(":"); - - writer.append(primarySkillLevelMap.get(CoreSkills.ALCHEMY_CS)).append(":"); - writer.append(primarySkillExperienceValueMap.get(CoreSkills.ALCHEMY_CS)).append(":"); - writer.append(uuid != null ? uuid.toString() : "NULL").append(":"); - writer.append(mmoDataSnapshot.getScoreboardTipsShown()).append(":"); - writer.append(mmoDataSnapshot.getUniqueData(UniqueDataType.CHIMAERA_WING_DATS)).append(":"); - - /* - public static int SKILLS_TRIDENTS = 44; - public static int EXP_TRIDENTS = 45; - public static int SKILLS_CROSSBOWS = 46; - public static int EXP_CROSSBOWS = 47; - public static int BARSTATE_ACROBATICS = 48; - public static int BARSTATE_ALCHEMY = 49; - public static int BARSTATE_ARCHERY = 50; - public static int BARSTATE_AXES = 51; - public static int BARSTATE_EXCAVATION = 52; - public static int BARSTATE_FISHING = 53; - public static int BARSTATE_HERBALISM = 54; - public static int BARSTATE_MINING = 55; - public static int BARSTATE_REPAIR = 56; - public static int BARSTATE_SALVAGE = 57; - public static int BARSTATE_SMELTING = 58; - public static int BARSTATE_SWORDS = 59; - public static int BARSTATE_TAMING = 60; - public static int BARSTATE_UNARMED = 61; - public static int BARSTATE_WOODCUTTING = 62; - public static int BARSTATE_TRIDENTS = 63; - public static int BARSTATE_CROSSBOWS = 64; - */ - - writer.append(primarySkillLevelMap.get(CoreSkills.TRIDENTS_CS)).append(":"); - writer.append(primarySkillExperienceValueMap.get(CoreSkills.TRIDENTS_CS)).append(":"); - writer.append(primarySkillLevelMap.get(CoreSkills.CROSSBOWS_CS)).append(":"); - writer.append(primarySkillExperienceValueMap.get(CoreSkills.CROSSBOWS_CS)).append(":"); - - //XPBar States - writer.append(mmoDataSnapshot.getBarStateMap().get(CoreSkills.ACROBATICS_CS).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(CoreSkills.ALCHEMY_CS).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(CoreSkills.ARCHERY_CS).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(CoreSkills.AXES_CS).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(CoreSkills.EXCAVATION_CS).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(CoreSkills.FISHING_CS).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(CoreSkills.HERBALISM_CS).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(CoreSkills.MINING_CS).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(CoreSkills.REPAIR_CS).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(CoreSkills.SALVAGE_CS).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(CoreSkills.SMELTING_CS).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(CoreSkills.SWORDS_CS).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(CoreSkills.TAMING_CS).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(CoreSkills.UNARMED_CS).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(CoreSkills.WOODCUTTING_CS).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(CoreSkills.TRIDENTS_CS).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(CoreSkills.CROSSBOWS_CS).toString()).append(":"); - - writer.append(0).append(":"); //archery super 1 cd - writer.append(0).append(":"); //xbow super 1 cd - writer.append(0).append(":"); //tridents super 1 cd - writer.append(0).append(":"); //chatspy toggle - writer.append(0).append(":"); //leaderboard ignored - - writer.append("\r\n"); - } - - @Override - public @NotNull List readLeaderboard(@NotNull RootSkill skill, int pageNumber, int statsPerPage) { - updateLeaderboards(); - List statsList = skill == null ? powerLevels : playerStatHash.get(skill); - int fromIndex = (Math.max(pageNumber, 1) - 1) * statsPerPage; - - return statsList.subList(Math.min(fromIndex, statsList.size()), Math.min(fromIndex + statsPerPage, statsList.size())); - } - - @Override - public @NotNull Map readRank(@NotNull String playerName) { - updateLeaderboards(); - - Map skills = new HashMap<>(); - - for (RootSkill rootSkill : CoreSkills.getImmutableCoreRootSkillSet()) { - if(CoreSkills.isChildSkill(rootSkill)) - continue; - - skills.put(rootSkill, getPlayerRank(playerName, playerStatHash.get(rootSkill))); - } - - skills.put(null, getPlayerRank(playerName, powerLevels)); - - return skills; - } - - @Override - public void insertNewUser(@NotNull String playerName, @NotNull UUID uuid) { - BufferedWriter out = null; - synchronized (fileWritingLock) { - try { - // Open the file to write the player - out = new BufferedWriter(new FileWriter(mcMMO.getUsersFilePath(), true)); - - String startingLevel = AdvancedConfig.getInstance().getStartingLevel() + ":"; - - // Add the player to the end - out.append(playerName).append(":"); - out.append(startingLevel); // Mining - out.append(":"); - out.append(":"); - out.append("0:"); // Xp - out.append(startingLevel); // Woodcutting - out.append("0:"); // WoodCuttingXp - out.append(startingLevel); // Repair - out.append(startingLevel); // Unarmed - out.append(startingLevel); // Herbalism - out.append(startingLevel); // Excavation - out.append(startingLevel); // Archery - out.append(startingLevel); // Swords - out.append(startingLevel); // Axes - out.append(startingLevel); // Acrobatics - out.append("0:"); // RepairXp - out.append("0:"); // UnarmedXp - out.append("0:"); // HerbalismXp - out.append("0:"); // ExcavationXp - out.append("0:"); // ArcheryXp - out.append("0:"); // SwordsXp - out.append("0:"); // AxesXp - out.append("0:"); // AcrobaticsXp - out.append(":"); - out.append(startingLevel); // Taming - out.append("0:"); // TamingXp - out.append("0:"); // DATS - out.append("0:"); // DATS - out.append("0:"); // DATS - out.append("0:"); // DATS - out.append("0:"); // DATS - out.append("0:"); // DATS - out.append("0:"); // DATS - out.append(":"); - out.append(startingLevel); // Fishing - out.append("0:"); // FishingXp - out.append("0:"); // Blast Mining - out.append(String.valueOf(System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR)).append(":"); // LastLogin - out.append(Config.getInstance().getMobHealthbarDefault().toString()).append(":"); // Mob Healthbar HUD - out.append(startingLevel); // Alchemy - out.append("0:"); // AlchemyXp - out.append(uuid != null ? uuid.toString() : "NULL").append(":"); // UUID - out.append("0:"); // Scoreboard tips shown - out.append("0:"); // Chimaera Wing Dats - - out.append("0:"); // Tridents Skill Level - out.append("0:"); // Tridents XP - out.append("0:"); // Crossbow Skill Level - out.append("0:"); // Crossbow XP Level - - //Barstates for the 15 currently existing skills by ordinal value - out.append("NORMAL:"); // Acrobatics - out.append("NORMAL:"); // Alchemy - out.append("NORMAL:"); // Archery - out.append("NORMAL:"); // Axes - out.append("NORMAL:"); // Excavation - out.append("NORMAL:"); // Fishing - out.append("NORMAL:"); // Herbalism - out.append("NORMAL:"); // Mining - out.append("NORMAL:"); // Repair - out.append("DISABLED:"); // Salvage - out.append("DISABLED:"); // Smelting - out.append("NORMAL:"); // Swords - out.append("NORMAL:"); // Taming - out.append("NORMAL:"); // Unarmed - out.append("NORMAL:"); // Woodcutting - out.append("NORMAL:"); // Tridents - out.append("NORMAL:"); // Crossbows - - //2.2.000+ - out.append("0:"); // arch super 1 - out.append("0:"); //xbow super 1 - out.append("0:"); //tridents super 1 - out.append("0:"); //chatspy toggle - out.append("0:"); //leaderboard ignored toggle - - - // Add more in the same format as the line above - - out.newLine(); - } - catch (Exception e) { - e.printStackTrace(); - } - finally { - if (out != null) { - try { - out.close(); - } - catch (IOException e) { - // Ignore - } - } - } - } - } - - @Override - public @Nullable MMOPlayerData queryPlayerByName(@NotNull String playerName) throws ProfileRetrievalException { - BufferedReader bufferedReader = null; - String usersFilePath = mcMMO.getUsersFilePath(); - - //Retrieve player - synchronized (fileWritingLock) { - try { - // Open the user file - bufferedReader = new BufferedReader(new FileReader(usersFilePath)); - String currentLine; - - while ((currentLine = bufferedReader.readLine()) != null) { - // Split the data which is stored as a string with : as break points - String[] stringDataArray = currentLine.split(FLATFILE_SPLIT_CHARACTER_REGEX); - - //Search for matching name - if (!stringDataArray[FlatFileMappings.USERNAME].equalsIgnoreCase(playerName)) { - continue; - } - - //We found our player, load the data - return loadFromLine(stringDataArray); - } - - throw new ProfileRetrievalException("Couldn't find a matching player in the database! Using name matching - " + playerName); - } - catch (Exception e) { - e.printStackTrace(); - } - - //Cleanup resource leaks - finally { - if (bufferedReader != null) { - try { - bufferedReader.close(); - } - catch (IOException e) { - // Ignore - } - } - } - } - - //Theoretically this statement should never be reached - mcMMO.p.getLogger().severe("Critical failure in execution of loading player from DB, contact the devs!"); - return null; - } - - public @Nullable MMOPlayerData queryPlayerDataByPlayer(@NotNull Player player) throws ProfileRetrievalException, NullArgumentException { - return queryPlayerDataByUUID(player.getUniqueId(), player.getName()); - } - - /** - * Queries by UUID will always have the current player name included as this method only gets executed when players join the server - * The name will be used to update player names in the DB if the name has changed - * There exists scenarios where players can share the same name in the DB, there is no code to account for this currently - * @param uuid uuid to match - * @param playerName used to overwrite playername values in the database if an existing value that is not equal to this one is found - * @return the player profile if retrieved successfully, otherwise null - * @throws ProfileRetrievalException - * @throws NullArgumentException - */ - public @Nullable MMOPlayerData queryPlayerDataByUUID(@NotNull UUID uuid, @NotNull String playerName) throws ProfileRetrievalException, NullArgumentException { - BufferedReader bufferedReader = null; - String usersFilePath = mcMMO.getUsersFilePath(); - - //Retrieve player - synchronized (fileWritingLock) { - try { - // Open the user file - bufferedReader = new BufferedReader(new FileReader(usersFilePath)); - String currentLine; - - while ((currentLine = bufferedReader.readLine()) != null) { - // Split the data which is stored as a string with : as break points - String[] stringDataArray = currentLine.split(FLATFILE_SPLIT_CHARACTER_REGEX); - - //Search for matching UUID - if (!stringDataArray[FlatFileMappings.UUID_INDEX].equalsIgnoreCase(uuid.toString())) { - continue; - } - - //If the player has changed their name, we need to update it too - if (!stringDataArray[FlatFileMappings.USERNAME].equalsIgnoreCase(playerName)) { - mcMMO.p.getLogger().info("Name change detected: " + stringDataArray[FlatFileMappings.USERNAME] + " => " + playerName); - stringDataArray[FlatFileMappings.USERNAME] = playerName; - } - - //We found our player, load the data - return loadFromLine(stringDataArray); - } - - throw new ProfileRetrievalException("Couldn't find a matching player in the database! - "+playerName+", "+uuid.toString()); - } - catch (Exception e) { - e.printStackTrace(); - } - - //Cleanup resource leaks - finally { - if (bufferedReader != null) { - try { - bufferedReader.close(); - } - catch (IOException e) { - // Ignore - } - } - } - } - - //Theoretically this statement should never be reached - mcMMO.p.getLogger().severe("Critical failure in execution of loading player from DB, contact the devs!"); - return null; - } - - public void convertUsers(@NotNull DatabaseManager destination) { - BufferedReader in = null; - String usersFilePath = mcMMO.getUsersFilePath(); - int convertedUsers = 0; - long startMillis = System.currentTimeMillis(); - - synchronized (fileWritingLock) { - try { - // Open the user file - in = new BufferedReader(new FileReader(usersFilePath)); - String line; - - while ((line = in.readLine()) != null) { - String[] stringDataSplit = line.split(":"); - - try { - MMOPlayerData mmoPlayerData = loadFromLine(stringDataSplit); - if(mmoPlayerData == null) - continue; - - destination.saveUser(mcMMO.getUserManager().createPlayerDataSnapshot(mmoPlayerData)); - } - catch (Exception e) { - e.printStackTrace(); - } - convertedUsers++; - Misc.printProgress(convertedUsers, progressInterval, startMillis); - } - } - catch (Exception e) { - e.printStackTrace(); - } - finally { - if (in != null) { - try { - in.close(); - } - catch (IOException e) { - // Ignore - } - } - } - } - } - - public @NotNull List getStoredUsers() { - ArrayList users = new ArrayList<>(); - BufferedReader in = null; - String usersFilePath = mcMMO.getUsersFilePath(); - - synchronized (fileWritingLock) { - try { - // Open the user file - in = new BufferedReader(new FileReader(usersFilePath)); - String line; - - while ((line = in.readLine()) != null) { - String[] character = line.split(":"); - users.add(character[FlatFileMappings.USERNAME]); - } - } - catch (Exception e) { - e.printStackTrace(); - } - finally { - if (in != null) { - try { - in.close(); - } - catch (IOException e) { - // Ignore - } - } - } - } - return users; - } - - /** - * Update the leader boards. - */ - private void updateLeaderboards() { - // Only update FFS leaderboards every 10 minutes.. this puts a lot of strain on the server (depending on the size of the database) and should not be done frequently - if (System.currentTimeMillis() < lastUpdate + UPDATE_WAIT_TIME) { - return; - } - - String usersFilePath = mcMMO.getUsersFilePath(); - lastUpdate = System.currentTimeMillis(); // Log when the last update was run - powerLevels.clear(); // Clear old values from the power levels - - // Initialize lists - List mining = new ArrayList<>(); - List woodcutting = new ArrayList<>(); - List herbalism = new ArrayList<>(); - List excavation = new ArrayList<>(); - List acrobatics = new ArrayList<>(); - List repair = new ArrayList<>(); - List swords = new ArrayList<>(); - List axes = new ArrayList<>(); - List archery = new ArrayList<>(); - List unarmed = new ArrayList<>(); - List taming = new ArrayList<>(); - List fishing = new ArrayList<>(); - List alchemy = new ArrayList<>(); - - BufferedReader in = null; - String playerName = null; - // Read from the FlatFile database and fill our arrays with information - synchronized (fileWritingLock) { - try { - in = new BufferedReader(new FileReader(usersFilePath)); - String line; - - while ((line = in.readLine()) != null) { - String[] data = line.split(":"); - playerName = data[FlatFileMappings.USERNAME]; - int powerLevel = 0; - - Map skills = getSkillMapFromLine(data); - - powerLevel += putStat(acrobatics, playerName, skills.get(CoreSkills.ACROBATICS_CS)); - powerLevel += putStat(alchemy, playerName, skills.get(CoreSkills.ALCHEMY_CS)); - powerLevel += putStat(archery, playerName, skills.get(CoreSkills.ARCHERY_CS)); - powerLevel += putStat(axes, playerName, skills.get(CoreSkills.AXES_CS)); - powerLevel += putStat(excavation, playerName, skills.get(CoreSkills.EXCAVATION_CS)); - powerLevel += putStat(fishing, playerName, skills.get(CoreSkills.FISHING_CS)); - powerLevel += putStat(herbalism, playerName, skills.get(CoreSkills.HERBALISM_CS)); - powerLevel += putStat(mining, playerName, skills.get(CoreSkills.MINING_CS)); - powerLevel += putStat(repair, playerName, skills.get(CoreSkills.REPAIR_CS)); - powerLevel += putStat(swords, playerName, skills.get(CoreSkills.SWORDS_CS)); - powerLevel += putStat(taming, playerName, skills.get(CoreSkills.TAMING_CS)); - powerLevel += putStat(unarmed, playerName, skills.get(CoreSkills.UNARMED_CS)); - powerLevel += putStat(woodcutting, playerName, skills.get(CoreSkills.WOODCUTTING_CS)); - powerLevel += putStat(woodcutting, playerName, skills.get(CoreSkills.CROSSBOWS_CS)); - powerLevel += putStat(woodcutting, playerName, skills.get(CoreSkills.TRIDENTS_CS)); - - putStat(powerLevels, playerName, powerLevel); - } - } - catch (Exception e) { - mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " during user " + playerName + " (Are you sure you formatted it correctly?) " + e.toString()); - } - finally { - if (in != null) { - try { - in.close(); - } - catch (IOException e) { - // Ignore - } - } - } - } - - SkillComparator c = new SkillComparator(); - - mining.sort(c); - woodcutting.sort(c); - repair.sort(c); - unarmed.sort(c); - herbalism.sort(c); - excavation.sort(c); - archery.sort(c); - swords.sort(c); - axes.sort(c); - acrobatics.sort(c); - taming.sort(c); - fishing.sort(c); - alchemy.sort(c); - powerLevels.sort(c); - - playerStatHash.put(CoreSkills.MINING_CS, mining); - playerStatHash.put(CoreSkills.WOODCUTTING_CS, woodcutting); - playerStatHash.put(CoreSkills.REPAIR_CS, repair); - playerStatHash.put(CoreSkills.UNARMED_CS, unarmed); - playerStatHash.put(CoreSkills.HERBALISM_CS, herbalism); - playerStatHash.put(CoreSkills.EXCAVATION_CS, excavation); - playerStatHash.put(CoreSkills.ARCHERY_CS, archery); - playerStatHash.put(CoreSkills.SWORDS_CS, swords); - playerStatHash.put(CoreSkills.AXES_CS, axes); - playerStatHash.put(CoreSkills.ACROBATICS_CS, acrobatics); - playerStatHash.put(CoreSkills.TAMING_CS, taming); - playerStatHash.put(CoreSkills.FISHING_CS, fishing); - playerStatHash.put(CoreSkills.ALCHEMY_CS, alchemy); - } - - /** - * Checks that the file is present and valid - */ - private void checkStructure() { - if (usersFile.exists()) { - BufferedReader in = null; - FileWriter out = null; - String usersFilePath = mcMMO.getUsersFilePath(); - - synchronized (fileWritingLock) { - try { - in = new BufferedReader(new FileReader(usersFilePath)); - StringBuilder writer = new StringBuilder(); - String line; - HashSet usernames = new HashSet<>(); - HashSet players = new HashSet<>(); - - while ((line = in.readLine()) != null) { - // Remove empty lines from the file - if (line.isEmpty()) { - continue; - } - - // Length checks depend on last stringDataArray being ':' - if (line.charAt(line.length() - 1) != ':') { - line = line.concat(":"); - } - boolean updated = false; - String[] stringDataArray = line.split(":"); - int originalLength = stringDataArray.length; - - // Prevent the same username from being present multiple times - if (!usernames.add(stringDataArray[FlatFileMappings.USERNAME])) { - stringDataArray[FlatFileMappings.USERNAME] = "_INVALID_OLD_USERNAME_'"; - updated = true; - if (stringDataArray.length < FlatFileMappings.UUID_INDEX + 1 || stringDataArray[FlatFileMappings.UUID_INDEX].equals("NULL")) { - continue; - } - } - - - if (stringDataArray.length < 33) { - // Before Version 1.0 - Drop - mcMMO.p.getLogger().warning("Dropping malformed or before version 1.0 line from database - " + line); - continue; - } - - String oldVersion = null; - - if (stringDataArray.length > 33 && !stringDataArray[33].isEmpty()) { - // Removal of Spout Support - // Version 1.4.07-dev2 - // commit 7bac0e2ca5143bce84dc160617fed97f0b1cb968 - stringDataArray[33] = ""; - oldVersion = "1.4.07"; - updated = true; - } - - if (stringDataArray.length <= 33) { - // Introduction of HUDType - // Version 1.1.06 - // commit 78f79213cdd7190cd11ae54526f3b4ea42078e8a - stringDataArray = Arrays.copyOf(stringDataArray, stringDataArray.length + 1); - stringDataArray[stringDataArray.length - 1] = ""; - oldVersion = "1.1.06"; - updated = true; - } - - if (stringDataArray.length <= 35) { - // Introduction of Fishing - // Version 1.2.00 - // commit a814b57311bc7734661109f0e77fc8bab3a0bd29 - stringDataArray = Arrays.copyOf(stringDataArray, stringDataArray.length + 2); - stringDataArray[stringDataArray.length - 1] = "0"; - stringDataArray[stringDataArray.length - 2] = "0"; - if (oldVersion == null) { - oldVersion = "1.2.00"; - } - updated = true; - } - if (stringDataArray.length <= 36) { - // Introduction of Blast Mining cooldowns - // Version 1.3.00-dev - // commit fadbaf429d6b4764b8f1ad0efaa524a090e82ef5 - stringDataArray = Arrays.copyOf(stringDataArray, stringDataArray.length + 1); - stringDataArray[stringDataArray.length - 1] = "0"; - if (oldVersion == null) { - oldVersion = "1.3.00"; - } - updated = true; - } - if (stringDataArray.length <= 37) { - // Making old-purge work with flatfile - // Version 1.4.00-dev - // commmit 3f6c07ba6aaf44e388cc3b882cac3d8f51d0ac28 - // XXX Cannot create an OfflinePlayer at startup, use 0 and fix in purge - stringDataArray = Arrays.copyOf(stringDataArray, stringDataArray.length + 1); - stringDataArray[stringDataArray.length - 1] = "0"; - if (oldVersion == null) { - oldVersion = "1.4.00"; - } - updated = true; - } - if (stringDataArray.length <= 38) { - // Addition of mob healthbars - // Version 1.4.06 - // commit da29185b7dc7e0d992754bba555576d48fa08aa6 - stringDataArray = Arrays.copyOf(stringDataArray, stringDataArray.length + 1); - stringDataArray[stringDataArray.length - 1] = Config.getInstance().getMobHealthbarDefault().toString(); - if (oldVersion == null) { - oldVersion = "1.4.06"; - } - updated = true; - } - if (stringDataArray.length <= 39) { - // Addition of Alchemy - // Version 1.4.08 - stringDataArray = Arrays.copyOf(stringDataArray, stringDataArray.length + 2); - stringDataArray[stringDataArray.length - 1] = "0"; - stringDataArray[stringDataArray.length - 2] = "0"; - if (oldVersion == null) { - oldVersion = "1.4.08"; - } - updated = true; - } - if (stringDataArray.length <= 41) { - // Addition of UUIDs - // Version 1.5.01 - // Add a value because otherwise it gets removed - stringDataArray = Arrays.copyOf(stringDataArray, stringDataArray.length + 1); - stringDataArray[stringDataArray.length - 1] = "NULL"; - if (oldVersion == null) { - oldVersion = "1.5.01"; - } - updated = true; - } - if (stringDataArray.length <= 42) { - // Addition of scoreboard tips auto disable - // Version 1.5.02 - stringDataArray = Arrays.copyOf(stringDataArray, stringDataArray.length + 1); - stringDataArray[stringDataArray.length - 1] = "0"; - - if (oldVersion == null) { - oldVersion = "1.5.02"; - } - updated = true; - } - - if(stringDataArray.length <= 43) { - // Addition of Chimaera wing DATS - stringDataArray = Arrays.copyOf(stringDataArray, stringDataArray.length + 1); - stringDataArray[stringDataArray.length - 1] = "0"; - - if (oldVersion == null) { - oldVersion = "2.1.133"; - } - updated = true; - } - - if(stringDataArray.length <= FlatFileMappings.LENGTH_OF_SPLIT_DATA_ARRAY) { - - if (oldVersion == null) { - oldVersion = "2.1.134"; - } - - stringDataArray = Arrays.copyOf(stringDataArray, FlatFileMappings.LENGTH_OF_SPLIT_DATA_ARRAY); // new array size - - /* - public static int SKILLS_TRIDENTS = 44; - public static int EXP_TRIDENTS = 45; - public static int SKILLS_CROSSBOWS = 46; - public static int EXP_CROSSBOWS = 47; - public static int BARSTATE_ACROBATICS = 48; - public static int BARSTATE_ALCHEMY = 49; - public static int BARSTATE_ARCHERY = 50; - public static int BARSTATE_AXES = 51; - public static int BARSTATE_EXCAVATION = 52; - public static int BARSTATE_FISHING = 53; - public static int BARSTATE_HERBALISM = 54; - public static int BARSTATE_MINING = 55; - public static int BARSTATE_REPAIR = 56; - public static int BARSTATE_SALVAGE = 57; - public static int BARSTATE_SMELTING = 58; - public static int BARSTATE_SWORDS = 59; - public static int BARSTATE_TAMING = 60; - public static int BARSTATE_UNARMED = 61; - public static int BARSTATE_WOODCUTTING = 62; - public static int BARSTATE_TRIDENTS = 63; - public static int BARSTATE_CROSSBOWS = 64; - */ - - stringDataArray[FlatFileMappings.SKILLS_TRIDENTS] = "0"; //trident skill lvl - stringDataArray[FlatFileMappings.EXP_TRIDENTS] = "0"; //trident xp value - stringDataArray[FlatFileMappings.SKILLS_CROSSBOWS] = "0"; //xbow skill lvl - stringDataArray[FlatFileMappings.EXP_CROSSBOWS] = "0"; //xbow xp lvl - - //Barstates 48-64 - stringDataArray[FlatFileMappings.BARSTATE_ACROBATICS] = "NORMAL"; - stringDataArray[FlatFileMappings.BARSTATE_ALCHEMY] = "NORMAL"; - stringDataArray[FlatFileMappings.BARSTATE_ARCHERY] = "NORMAL"; - stringDataArray[FlatFileMappings.BARSTATE_AXES] = "NORMAL"; - stringDataArray[FlatFileMappings.BARSTATE_EXCAVATION] = "NORMAL"; - stringDataArray[FlatFileMappings.BARSTATE_FISHING] = "NORMAL"; - stringDataArray[FlatFileMappings.BARSTATE_HERBALISM] = "NORMAL"; - stringDataArray[FlatFileMappings.BARSTATE_MINING] = "NORMAL"; - stringDataArray[FlatFileMappings.BARSTATE_REPAIR] = "NORMAL"; - stringDataArray[FlatFileMappings.BARSTATE_SALVAGE] = "DISABLED"; //Child skills - stringDataArray[FlatFileMappings.BARSTATE_SMELTING] = "DISABLED"; //Child skills - stringDataArray[FlatFileMappings.BARSTATE_SWORDS] = "NORMAL"; - stringDataArray[FlatFileMappings.BARSTATE_TAMING] = "NORMAL"; - stringDataArray[FlatFileMappings.BARSTATE_UNARMED] = "NORMAL"; - stringDataArray[FlatFileMappings.BARSTATE_WOODCUTTING] = "NORMAL"; - stringDataArray[FlatFileMappings.BARSTATE_TRIDENTS] = "NORMAL"; - stringDataArray[FlatFileMappings.BARSTATE_CROSSBOWS] = "NORMAL"; - - stringDataArray[FlatFileMappings.COOLDOWN_ARCHERY_SUPER_1] = "0"; - stringDataArray[FlatFileMappings.COOLDOWN_CROSSBOWS_SUPER_1] = "0"; - stringDataArray[FlatFileMappings.COOLDOWN_TRIDENTS_SUPER_1] = "0"; - - stringDataArray[FlatFileMappings.CHATSPY_TOGGLE] = "0"; - stringDataArray[FlatFileMappings.LEADERBOARD_IGNORED] = "0"; - - //This part is a bit odd because lastlogin already has a place in the index but it was unused - stringDataArray[FlatFileMappings.LAST_LOGIN] = "0"; - - updated = true; - } - - //TODO: If new skills are added this needs to be rewritten - if (Config.getInstance().getTruncateSkills()) { - for (RootSkill rootSkill : CoreSkills.getImmutableCoreRootSkillSet()) { - if(CoreSkills.isChildSkill(rootSkill)) - continue; - - int index = getSkillIndex(rootSkill); - if (index >= stringDataArray.length) { - continue; - } - int cap = Config.getInstance().getLevelCap(rootSkill); - if (Integer.parseInt(stringDataArray[index]) > cap) { - mcMMO.p.getLogger().warning("Truncating " + rootSkill.getRawSkillName() + " to configured max level for player " + stringDataArray[FlatFileMappings.USERNAME]); - stringDataArray[index] = cap + ""; - updated = true; - } - } - } - - boolean corrupted = false; - - //TODO: Update this corruption code, its super out of date - //TODO: Update this corruption code, its super out of date - //TODO: Update this corruption code, its super out of date - //TODO: Update this corruption code, its super out of date - //TODO: Update this corruption code, its super out of date - //TODO: Update this corruption code, its super out of date - //TODO: Update this corruption code, its super out of date - //TODO: Update this corruption code, its super out of date - //TODO: Update this corruption code, its super out of dated - - for (int i = 0; i < stringDataArray.length; i++) { - //Sigh... this code - if (stringDataArray[i].isEmpty() && !(i == 2 || i == 3 || i == 23 || i == 33 || i == 41)) { - mcMMO.p.getLogger().info("Player data at index "+i+" appears to be empty, possible corruption of data has occurred."); - corrupted = true; - if (i == 37) { - stringDataArray[i] = String.valueOf(System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR); - } - else if (i == 38) { - stringDataArray[i] = Config.getInstance().getMobHealthbarDefault().toString(); - } - else { - stringDataArray[i] = "0"; - } - } - - if (StringUtils.isInt(stringDataArray[i]) && i == 38) { - corrupted = true; - stringDataArray[i] = Config.getInstance().getMobHealthbarDefault().toString(); - } - - if (!StringUtils.isInt(stringDataArray[i]) && !(i == 0 || i == 2 || i == 3 || i == 23 || i == 33 || i == 38 || i == 41)) { - corrupted = true; - stringDataArray[i] = "0"; - } - } - - if (corrupted) { - mcMMO.p.getLogger().info("Updating corrupted database line for player " + stringDataArray[FlatFileMappings.USERNAME]); - } - - if (oldVersion != null) { - mcMMO.p.getLogger().info("Updating database line from before version " + oldVersion + " for player " + stringDataArray[FlatFileMappings.USERNAME]); - } - - updated |= corrupted; - updated |= oldVersion != null; - - if (Config.getInstance().getTruncateSkills()) { - Map skillsMap = getSkillMapFromLine(stringDataArray); - for (RootSkill rootSkill : CoreSkills.getNonChildSkills()) { - int cap = Config.getInstance().getLevelCap(rootSkill); - if (skillsMap.get(rootSkill) > cap) { - updated = true; - } - } - } - - if (updated) { - line = org.apache.commons.lang.StringUtils.join(stringDataArray, ":") + ":"; - } - - // Prevent the same player from being present multiple times - if (stringDataArray.length == originalLength //If the length changed then the schema was expanded - && (!stringDataArray[FlatFileMappings.UUID_INDEX].isEmpty() - && !stringDataArray[FlatFileMappings.UUID_INDEX].equals("NULL") - && !players.add(stringDataArray[FlatFileMappings.UUID_INDEX]))) { - continue; - } - - writer.append(line).append("\r\n"); - } - - // Write the new file - out = new FileWriter(usersFilePath); - out.write(writer.toString()); - } - catch (IOException e) { - mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString()); - } - finally { - if (in != null) { - try { - in.close(); - } - catch (IOException e) { - // Ignore - } - } - if (out != null) { - try { - out.close(); - } - catch (IOException e) { - // Ignore - } - } - } - } - - mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_FISHING); - mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_BLAST_MINING_COOLDOWN); - mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_SQL_INDEXES); - mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_MOB_HEALTHBARS); -// mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.DROP_SQL_PARTY_NAMES); - mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.DROP_SPOUT); - mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_ALCHEMY); - return; - } - - usersFile.getParentFile().mkdir(); - - try { - mcMMO.p.getLogger().info("Creating mcmmo.users file..."); - new File(mcMMO.getUsersFilePath()).createNewFile(); - } - catch (IOException e) { - e.printStackTrace(); - } - } - - private Integer getPlayerRank(String playerName, List statsList) { - if (statsList == null) { - return null; - } - - int currentPos = 1; - - for (PlayerStat stat : statsList) { - if (stat.name.equalsIgnoreCase(playerName)) { - return currentPos; - } - - currentPos++; - } - - return null; - } - - private int putStat(List statList, String playerName, int statValue) { - statList.add(new PlayerStat(playerName, statValue)); - return statValue; - } - - private static class SkillComparator implements Comparator { - @Override - public int compare(PlayerStat o1, PlayerStat o2) { - return (o2.statVal - o1.statVal); - } - } - - private @Nullable MMOPlayerData loadFromLine(@NotNull String[] dataStrSplit) { - MMODataBuilder playerDataBuilder = new MMODataBuilder(); - - Map skillLevelMap = getSkillMapFromLine(dataStrSplit); // Skill levels - Map skillExperienceValueMap = new HashMap<>(); // Skill & XP - Map skillAbilityDeactivationTimeStamp = new HashMap<>(); // Ability & Cooldown - Map uniquePlayerDataMap = new EnumMap(UniqueDataType.class); - Map xpBarStateMap = new HashMap<>(); - int scoreboardTipsShown; - - skillExperienceValueMap.put(CoreSkills.TAMING_CS, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_TAMING])); - skillExperienceValueMap.put(CoreSkills.MINING_CS, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_MINING])); - skillExperienceValueMap.put(CoreSkills.REPAIR_CS, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_REPAIR])); - skillExperienceValueMap.put(CoreSkills.WOODCUTTING_CS, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_WOODCUTTING])); - skillExperienceValueMap.put(CoreSkills.UNARMED_CS, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_UNARMED])); - skillExperienceValueMap.put(CoreSkills.HERBALISM_CS, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_HERBALISM])); - skillExperienceValueMap.put(CoreSkills.EXCAVATION_CS, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_EXCAVATION])); - skillExperienceValueMap.put(CoreSkills.ARCHERY_CS, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_ARCHERY])); - skillExperienceValueMap.put(CoreSkills.SWORDS_CS, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_SWORDS])); - skillExperienceValueMap.put(CoreSkills.AXES_CS, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_AXES])); - skillExperienceValueMap.put(CoreSkills.ACROBATICS_CS, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_ACROBATICS])); - skillExperienceValueMap.put(CoreSkills.FISHING_CS, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_FISHING])); - skillExperienceValueMap.put(CoreSkills.ALCHEMY_CS, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_ALCHEMY])); - skillExperienceValueMap.put(CoreSkills.TRIDENTS_CS, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_TRIDENTS])); - skillExperienceValueMap.put(CoreSkills.CROSSBOWS_CS, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_CROSSBOWS])); - - //Set Skill XP - - // Taming - Unused - skillAbilityDeactivationTimeStamp.put(SuperAbilityType.SUPER_BREAKER, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_SUPER_BREAKER])); - // Repair - Unused - skillAbilityDeactivationTimeStamp.put(SuperAbilityType.TREE_FELLER, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_TREE_FELLER])); - skillAbilityDeactivationTimeStamp.put(SuperAbilityType.BERSERK, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_BERSERK])); - skillAbilityDeactivationTimeStamp.put(SuperAbilityType.GREEN_TERRA, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_GREEN_TERRA])); - skillAbilityDeactivationTimeStamp.put(SuperAbilityType.GIGA_DRILL_BREAKER, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_GIGA_DRILL_BREAKER])); - skillAbilityDeactivationTimeStamp.put(SuperAbilityType.SERRATED_STRIKES, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_SERRATED_STRIKES])); - skillAbilityDeactivationTimeStamp.put(SuperAbilityType.SKULL_SPLITTER, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_SKULL_SPLITTER])); - // Acrobatics - Unused - skillAbilityDeactivationTimeStamp.put(SuperAbilityType.BLAST_MINING, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_BLAST_MINING])); - skillAbilityDeactivationTimeStamp.put(SuperAbilityType.ARCHERY_SUPER, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_ARCHERY_SUPER_1])); - skillAbilityDeactivationTimeStamp.put(SuperAbilityType.SUPER_SHOTGUN, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_CROSSBOWS_SUPER_1])); - skillAbilityDeactivationTimeStamp.put(SuperAbilityType.TRIDENT_SUPER, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_TRIDENTS_SUPER_1])); - - -// try { -// mobHealthbarType = MobHealthBarType.valueOf(dataStrSplit[FlatFileMappings.HEALTHBAR]); -// } -// catch (Exception e) { -// mobHealthbarType = Config.getInstance().getMobHealthbarDefault(); -// } - - - //Sometimes players are retrieved by name - UUID playerUUID; - - try { - playerUUID = UUID.fromString(dataStrSplit[FlatFileMappings.UUID_INDEX]); - } - catch (Exception e) { - mcMMO.p.getLogger().severe("UUID not found for data entry, skipping entry"); - return null; - } - - try { - scoreboardTipsShown = Integer.parseInt(dataStrSplit[FlatFileMappings.SCOREBOARD_TIPS]); - } - catch (Exception e) { - scoreboardTipsShown = 0; - } - - - try { - uniquePlayerDataMap.put(UniqueDataType.CHIMAERA_WING_DATS, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_CHIMAERA_WING])); - } - catch (Exception e) { - uniquePlayerDataMap.put(UniqueDataType.CHIMAERA_WING_DATS, 0); - } - - try { - xpBarStateMap.put(CoreSkills.ACROBATICS_CS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_ACROBATICS])); - xpBarStateMap.put(CoreSkills.ALCHEMY_CS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_ALCHEMY])); - xpBarStateMap.put(CoreSkills.ARCHERY_CS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_ARCHERY])); - xpBarStateMap.put(CoreSkills.AXES_CS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_AXES])); - xpBarStateMap.put(CoreSkills.EXCAVATION_CS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_EXCAVATION])); - xpBarStateMap.put(CoreSkills.FISHING_CS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_FISHING])); - xpBarStateMap.put(CoreSkills.HERBALISM_CS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_HERBALISM])); - xpBarStateMap.put(CoreSkills.MINING_CS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_MINING])); - xpBarStateMap.put(CoreSkills.REPAIR_CS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_REPAIR])); - xpBarStateMap.put(CoreSkills.SALVAGE_CS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_SALVAGE])); - xpBarStateMap.put(CoreSkills.SMELTING_CS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_SMELTING])); - xpBarStateMap.put(CoreSkills.SWORDS_CS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_SWORDS])); - xpBarStateMap.put(CoreSkills.TAMING_CS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_TAMING])); - xpBarStateMap.put(CoreSkills.UNARMED_CS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_UNARMED])); - xpBarStateMap.put(CoreSkills.WOODCUTTING_CS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_WOODCUTTING])); - xpBarStateMap.put(CoreSkills.TRIDENTS_CS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_TRIDENTS])); - xpBarStateMap.put(CoreSkills.CROSSBOWS_CS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_CROSSBOWS])); - - } catch (Exception e) { - xpBarStateMap = MMOExperienceBarManager.generateDefaultBarStateMap(); - } - MMOPlayerData mmoPlayerData; - - try { - //Set Player Data - playerDataBuilder.setSkillLevelValues(skillLevelMap) - .setSkillExperienceValues(skillExperienceValueMap) - .setAbilityDeactivationTimestamps(skillAbilityDeactivationTimeStamp) -// .setMobHealthBarType(mobHealthbarType) - .setPlayerUUID(playerUUID) - .setScoreboardTipsShown(scoreboardTipsShown) - .setUniquePlayerData(uniquePlayerDataMap) - .setBarStateMap(xpBarStateMap); - - //Build Data - return playerDataBuilder.build(); - } catch (Exception e) { - mcMMO.p.getLogger().severe("Critical failure when trying to construct persistent player data!"); - e.printStackTrace(); - return null; - } - } - - //TODO: Add tests - private @NotNull Map getSkillMapFromLine(@NotNull String[] stringDataArray) { - HashMap skillLevelsMap = new HashMap<>(); // Skill & Level - - skillLevelsMap.put(CoreSkills.TAMING_CS, Integer.valueOf(stringDataArray[FlatFileMappings.SKILLS_TAMING])); - skillLevelsMap.put(CoreSkills.MINING_CS, Integer.valueOf(stringDataArray[FlatFileMappings.SKILLS_MINING])); - skillLevelsMap.put(CoreSkills.REPAIR_CS, Integer.valueOf(stringDataArray[FlatFileMappings.SKILLS_REPAIR])); - skillLevelsMap.put(CoreSkills.WOODCUTTING_CS, Integer.valueOf(stringDataArray[FlatFileMappings.SKILLS_WOODCUTTING])); - skillLevelsMap.put(CoreSkills.UNARMED_CS, Integer.valueOf(stringDataArray[FlatFileMappings.SKILLS_UNARMED])); - skillLevelsMap.put(CoreSkills.HERBALISM_CS, Integer.valueOf(stringDataArray[FlatFileMappings.SKILLS_HERBALISM])); - skillLevelsMap.put(CoreSkills.EXCAVATION_CS, Integer.valueOf(stringDataArray[FlatFileMappings.SKILLS_EXCAVATION])); - skillLevelsMap.put(CoreSkills.ARCHERY_CS, Integer.valueOf(stringDataArray[FlatFileMappings.SKILLS_ARCHERY])); - skillLevelsMap.put(CoreSkills.SWORDS_CS, Integer.valueOf(stringDataArray[FlatFileMappings.SKILLS_SWORDS])); - skillLevelsMap.put(CoreSkills.AXES_CS, Integer.valueOf(stringDataArray[FlatFileMappings.SKILLS_AXES])); - skillLevelsMap.put(CoreSkills.ACROBATICS_CS, Integer.valueOf(stringDataArray[FlatFileMappings.SKILLS_ACROBATICS])); - skillLevelsMap.put(CoreSkills.FISHING_CS, Integer.valueOf(stringDataArray[FlatFileMappings.SKILLS_FISHING])); - skillLevelsMap.put(CoreSkills.ALCHEMY_CS, Integer.valueOf(stringDataArray[FlatFileMappings.SKILLS_ALCHEMY])); - skillLevelsMap.put(CoreSkills.TRIDENTS_CS, Integer.valueOf(stringDataArray[FlatFileMappings.SKILLS_TRIDENTS])); - skillLevelsMap.put(CoreSkills.CROSSBOWS_CS, Integer.valueOf(stringDataArray[FlatFileMappings.SKILLS_CROSSBOWS])); - - return skillLevelsMap; - } - - public @NotNull DatabaseType getDatabaseType() { - return DatabaseType.FLATFILE; - } - - private int getSkillIndex(@NotNull RootSkill rootSkill) { - PrimarySkillType primarySkillType = CoreSkills.getSkill(rootSkill); - - switch (primarySkillType) { - case ACROBATICS: - return FlatFileMappings.SKILLS_ACROBATICS; - case ALCHEMY: - return FlatFileMappings.SKILLS_ALCHEMY; - case ARCHERY: - return FlatFileMappings.SKILLS_ARCHERY; - case AXES: - return FlatFileMappings.SKILLS_AXES; - case EXCAVATION: - return FlatFileMappings.SKILLS_EXCAVATION; - case FISHING: - return FlatFileMappings.SKILLS_FISHING; - case HERBALISM: - return FlatFileMappings.SKILLS_HERBALISM; - case MINING: - return FlatFileMappings.SKILLS_MINING; - case REPAIR: - return FlatFileMappings.SKILLS_REPAIR; - case SWORDS: - return FlatFileMappings.SKILLS_SWORDS; - case TAMING: - return FlatFileMappings.SKILLS_TAMING; - case UNARMED: - return FlatFileMappings.SKILLS_UNARMED; - case WOODCUTTING: - return FlatFileMappings.SKILLS_WOODCUTTING; - case TRIDENTS: - return FlatFileMappings.SKILLS_TRIDENTS; - case CROSSBOWS: - return FlatFileMappings.SKILLS_CROSSBOWS; - default: - throw new RuntimeException("Primary Skills only"); - - } - } - - @Override - public void onDisable() { } - - public void resetMobHealthSettings() { - BufferedReader in = null; - FileWriter out = null; - String usersFilePath = mcMMO.getUsersFilePath(); - - synchronized (fileWritingLock) { - try { - in = new BufferedReader(new FileReader(usersFilePath)); - StringBuilder writer = new StringBuilder(); - String line; - - while ((line = in.readLine()) != null) { - // Remove empty lines from the file - if (line.isEmpty()) { - continue; - } - String[] character = line.split(":"); - - character[FlatFileMappings.HEALTHBAR] = Config.getInstance().getMobHealthbarDefault().toString(); - - line = org.apache.commons.lang.StringUtils.join(character, ":") + ":"; - - writer.append(line).append("\r\n"); - } - - // Write the new file - out = new FileWriter(usersFilePath); - out.write(writer.toString()); - } - catch (IOException e) { - mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString()); - } - finally { - if (in != null) { - try { - in.close(); - } - catch (IOException e) { - // Ignore - } - } - if (out != null) { - try { - out.close(); - } - catch (IOException e) { - // Ignore - } - } - } - } - } -} diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index 5afcb3568..a2f7d3037 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -33,6 +33,9 @@ import java.util.concurrent.locks.ReentrantLock; public final class SQLDatabaseManager extends AbstractDatabaseManager { private static final String ALL_QUERY_VERSION = "total"; + public static final String MOBHEALTHBAR_VARCHAR = "VARCHAR(50)"; + public static final String UUID_VARCHAR = "VARCHAR(36)"; + public static final String USER_VARCHAR = "VARCHAR(40)"; private final String tablePrefix = Config.getInstance().getMySQLTablePrefix(); private final Map cachedUserIDs = new HashMap<>(); @@ -45,6 +48,8 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { private final ReentrantLock massUpdateLock = new ReentrantLock(); + private final String CHARSET_SQL = "utf8mb4"; //This is compliant with UTF-8 while "utf8" is not, confusing but this is how it is. + protected SQLDatabaseManager() { String connectionString = "jdbc:mysql://" + Config.getInstance().getMySQLServerName() + ":" + Config.getInstance().getMySQLServerPort() + "/" + Config.getInstance().getMySQLDatabaseName(); @@ -565,6 +570,24 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { } } + @Override + public @NotNull PlayerProfile newUser(@NotNull Player player) { + try { + Connection connection = getConnection(PoolIdentifier.SAVE); + int id = newUser(connection, player.getName(), player.getUniqueId()); + + if (id == -1) { + return new PlayerProfile(player.getName(), player.getUniqueId(), false); + } else { + return loadPlayerProfile(player.getUniqueId(), player.getName()); + } + } catch (SQLException e) { + e.printStackTrace(); + } + + return new PlayerProfile(player.getName(), player.getUniqueId(), false); + } + private int newUser(Connection connection, String playerName, UUID uuid) { ResultSet resultSet = null; PreparedStatement statement = null; @@ -603,11 +626,26 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { return -1; } + public @NotNull PlayerProfile loadPlayerProfile(@NotNull String playerName) { + try { + return loadPlayerFromDB(null, playerName); + } catch (RuntimeException e) { + e.printStackTrace(); + return new PlayerProfile(playerName, false); + } + } + + public @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid, @Nullable String playerName) { + return loadPlayerFromDB(uuid, playerName); @Override public @Nullable MMOPlayerData queryPlayerDataByPlayer(@NotNull Player player) throws ProfileRetrievalException, NullArgumentException { return loadPlayerProfile(player, player.getName(), player.getUniqueId()); } + private PlayerProfile loadPlayerFromDB(@Nullable UUID uuid, @Nullable String playerName) throws RuntimeException { + if(uuid == null && playerName == null) { + throw new RuntimeException("Error looking up player, both UUID and playerName are null and one must not be."); + } @Override public @Nullable MMOPlayerData queryPlayerDataByUUID(@NotNull UUID uuid, @NotNull String playerName) throws ProfileRetrievalException, NullArgumentException { return loadPlayerProfile(null, playerName, uuid); @@ -623,15 +661,8 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { int id = getUserID(connection, playerName, playerUUID); if (id == -1) { - // There is no such user - if (player != null) { - id = newUser(connection, playerName, playerUUID); - if (id == -1) { - return null; - } - } else { - return null; - } + // There is no such user + return new PlayerProfile(playerName, false); } // There is such a user writeMissingRows(connection, id); @@ -648,7 +679,10 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { resultSet.close(); statement.close(); - if (!playerName.isEmpty() && !playerName.equalsIgnoreCase(name) && playerUUID != null) { + if (playerName != null + && !playerName.isEmpty() + && !playerName.equalsIgnoreCase(name) + && playerUUID != null) { statement = connection.prepareStatement( "UPDATE `" + tablePrefix + "users` " + "SET user = ? " @@ -685,10 +719,11 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { tryClose(connection); } - return null; + //Return empty profile + return new PlayerProfile(playerName, false); } - public void convertUsers(@NotNull DatabaseManager destination) { + public void convertUsers(DatabaseManager destination) { PreparedStatement statement = null; Connection connection = null; ResultSet resultSet = null; @@ -867,7 +902,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { + "`lastlogin` int(32) unsigned NOT NULL," + "PRIMARY KEY (`id`)," + "INDEX(`user`(20) ASC)," - + "UNIQUE KEY `uuid` (`uuid`)) DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;"); + + "UNIQUE KEY `uuid` (`uuid`)) DEFAULT CHARSET=" + CHARSET_SQL + " AUTO_INCREMENT=1;"); tryClose(createStatement); } tryClose(resultSet); @@ -881,7 +916,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { + "`mobhealthbar` varchar(50) NOT NULL DEFAULT '" + Config.getInstance().getMobHealthbarDefault() + "'," + "`scoreboardtips` int(10) NOT NULL DEFAULT '0'," + "PRIMARY KEY (`user_id`)) " - + "DEFAULT CHARSET=latin1;"); + + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); tryClose(createStatement); } tryClose(resultSet); @@ -908,7 +943,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { + "`tridents` int(32) unsigned NOT NULL DEFAULT '0'," + "`crossbows` int(32) unsigned NOT NULL DEFAULT '0'," + "PRIMARY KEY (`user_id`)) " - + "DEFAULT CHARSET=latin1;"); + + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); tryClose(createStatement); } tryClose(resultSet); @@ -936,7 +971,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { + "`crossbows` int(10) unsigned NOT NULL DEFAULT '0'," + "`total` int(10) unsigned NOT NULL DEFAULT '0'," + "PRIMARY KEY (`user_id`)) " - + "DEFAULT CHARSET=latin1;"); + + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); tryClose(createStatement); } tryClose(resultSet); @@ -1010,7 +1045,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { + "`view_tridents` varchar(40) NOT NULL DEFAULT 'NORMAL'," + "`view_crossbows` varchar(40) NOT NULL DEFAULT 'NORMAL'," + "PRIMARY KEY (`user_id`)) " - + "DEFAULT CHARSET=latin1;"); + + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); tryClose(createStatement); } tryClose(resultSet); @@ -1135,6 +1170,11 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { case ADD_UNIQUE_PLAYER_DATA: checkUpgradeAddUniqueChimaeraWing(statement); break; + + case SQL_CHARSET_UTF8MB4: + updateCharacterSet(statement); + break; + case ADD_SQL_2_2: checkUpgradeAddTridentsAndCrossbowsSQL(statement); break; @@ -1142,8 +1182,6 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { break; } - - mcMMO.getUpgradeManager().setUpgradeCompleted(upgrade); } catch (SQLException ex) { printErrors(ex); @@ -1358,6 +1396,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { statement.execute("ALTER TABLE `" + tablePrefix + "users` " + "DROP INDEX `user`," + "ADD INDEX `user` (`user`(20) ASC)"); + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.DROP_NAME_UNIQUENESS); } catch (SQLException ex) { ex.printStackTrace(); } finally { @@ -1385,6 +1424,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { private void checkUpgradeAddAlchemy(final Statement statement) throws SQLException { try { statement.executeQuery("SELECT `alchemy` FROM `" + tablePrefix + "skills` LIMIT 1"); + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_ALCHEMY); } catch (SQLException ex) { mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Alchemy..."); @@ -1396,6 +1436,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { private void checkUpgradeAddBlastMiningCooldown(final Statement statement) throws SQLException { try { statement.executeQuery("SELECT `blast_mining` FROM `" + tablePrefix + "cooldowns` LIMIT 1"); + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_BLAST_MINING_COOLDOWN); } catch (SQLException ex) { mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Blast Mining..."); @@ -1406,6 +1447,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { private void checkUpgradeAddUniqueChimaeraWing(final Statement statement) throws SQLException { try { statement.executeQuery("SELECT `chimaera_wing` FROM `" + tablePrefix + "cooldowns` LIMIT 1"); + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_UNIQUE_PLAYER_DATA); } catch (SQLException ex) { mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Chimaera Wing..."); @@ -1416,6 +1458,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { private void checkUpgradeAddFishing(final Statement statement) throws SQLException { try { statement.executeQuery("SELECT `fishing` FROM `" + tablePrefix + "skills` LIMIT 1"); + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_FISHING); } catch (SQLException ex) { mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Fishing..."); @@ -1427,6 +1470,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { private void checkUpgradeAddMobHealthbars(final Statement statement) throws SQLException { try { statement.executeQuery("SELECT `mobhealthbar` FROM `" + tablePrefix + "huds` LIMIT 1"); + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_MOB_HEALTHBARS); } catch (SQLException ex) { mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for mob healthbars..."); @@ -1437,6 +1481,7 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { private void checkUpgradeAddScoreboardTips(final Statement statement) throws SQLException { try { statement.executeQuery("SELECT `scoreboardtips` FROM `" + tablePrefix + "huds` LIMIT 1"); + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_SCOREBOARD_TIPS); } catch (SQLException ex) { mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for scoreboard tips..."); @@ -1465,6 +1510,8 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { } } } + + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_SQL_INDEXES); } catch (SQLException ex) { printErrors(ex); @@ -1494,7 +1541,11 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { mcMMO.p.getLogger().info("Adding UUIDs to mcMMO MySQL user table..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "users` ADD `uuid` varchar(36) NULL DEFAULT NULL"); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "users` ADD UNIQUE INDEX `uuid` (`uuid`) USING BTREE"); + + new GetUUIDUpdatesRequired().runTaskLaterAsynchronously(mcMMO.p, 100); // wait until after first purge } + + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_UUIDS); } catch (SQLException ex) { printErrors(ex); @@ -1502,8 +1553,6 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { finally { tryClose(resultSet); } - - new GetUUIDUpdatesRequired().runTaskLaterAsynchronously(mcMMO.p, 100); // wait until after first purge } private class GetUUIDUpdatesRequired extends BukkitRunnable { @@ -1561,6 +1610,8 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { mcMMO.p.getLogger().info("Removing party name from users table..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "users` DROP COLUMN `party`"); } + + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.DROP_SQL_PARTY_NAMES); } catch (SQLException ex) { printErrors(ex); @@ -1596,6 +1647,8 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { statement.executeUpdate("ALTER TABLE `" + tablePrefix + "skills` ADD INDEX `idx_total` (`total`) USING BTREE"); connection.commit(); } + + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_SKILL_TOTAL); } catch (SQLException ex) { printErrors(ex); @@ -1627,6 +1680,8 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { mcMMO.p.getLogger().info("Removing Spout HUD type from huds table..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "huds` DROP COLUMN `hudtype`"); } + + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.DROP_SPOUT); } catch (SQLException ex) { printErrors(ex); @@ -1740,6 +1795,69 @@ public final class SQLDatabaseManager extends AbstractDatabaseManager { } } + private void updateCharacterSet(@NotNull Statement statement) { + //TODO: Could check the tables for being latin1 before executing queries but it seems moot because it is likely the same computational effort + /* + The following columns were set to use latin1 historically (now utf8mb4) + column user in users + column uuid in users + + column mobhealthbar in huds + */ + + //Alter users table + mcMMO.p.getLogger().info("SQL Converting tables from latin1 to utf8mb4"); + + //Update "user" column + try { + mcMMO.p.getLogger().info("Updating user column to new encoding"); + statement.executeUpdate(getUpdateUserInUsersTableSQLQuery()); + + //Update "uuid" column + mcMMO.p.getLogger().info("Updating user column to new encoding"); + statement.executeUpdate(getUpdateUUIDInUsersTableSQLQuery()); + + //Update "mobhealthbar" column + mcMMO.p.getLogger().info("Updating mobhealthbar column to new encoding"); + statement.executeUpdate(getUpdateMobHealthBarInHudsTableSQLQuery()); + + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.SQL_CHARSET_UTF8MB4); + + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @NotNull + private String getUpdateUserInUsersTableSQLQuery() { + return "ALTER TABLE\n" + + " " + tablePrefix + "users\n" + + " CHANGE user user\n" + + " " + USER_VARCHAR + "\n" + + " CHARACTER SET utf8mb4\n" + + " COLLATE utf8mb4_unicode_ci;"; + } + + @NotNull + private String getUpdateUUIDInUsersTableSQLQuery() { + return "ALTER TABLE\n" + + " " + tablePrefix + "users\n" + + " CHANGE uuid uuid\n" + + " " + UUID_VARCHAR + "\n" + + " CHARACTER SET utf8mb4\n" + + " COLLATE utf8mb4_unicode_ci;"; + } + + @NotNull + private String getUpdateMobHealthBarInHudsTableSQLQuery() { + return "ALTER TABLE\n" + + " " + tablePrefix + "huds\n" + + " CHANGE mobhealthbar mobhealthbar\n" + + " " + MOBHEALTHBAR_VARCHAR + "\n" + + " CHARACTER SET utf8mb4\n" + + " COLLATE utf8mb4_unicode_ci;"; + } + @Override public void removeCache(@NotNull UUID uuid) { cachedUserIDs.remove(uuid); diff --git a/src/main/java/com/gmail/nossr50/datatypes/database/UpgradeType.java b/src/main/java/com/gmail/nossr50/datatypes/database/UpgradeType.java index a6cc52a8b..50c31a014 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/database/UpgradeType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/database/UpgradeType.java @@ -17,5 +17,6 @@ public enum UpgradeType { ADD_SQL_2_2, FIX_SPELLING_NETHERITE_SALVAGE, FIX_SPELLING_NETHERITE_REPAIR, - FIX_NETHERITE_SALVAGE_QUANTITIES + FIX_NETHERITE_SALVAGE_QUANTITIES, + SQL_CHARSET_UTF8MB4 } diff --git a/src/main/java/com/gmail/nossr50/events/McMMOReplaceVanillaTreasureEvent.java b/src/main/java/com/gmail/nossr50/events/McMMOReplaceVanillaTreasureEvent.java new file mode 100644 index 000000000..6553bf1c1 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/events/McMMOReplaceVanillaTreasureEvent.java @@ -0,0 +1,41 @@ +package com.gmail.nossr50.events; + +import org.bukkit.entity.Item; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +public class McMMOReplaceVanillaTreasureEvent extends Event { + private @NotNull ItemStack replacementItemStack; + private final @NotNull Item originalItem; + + public McMMOReplaceVanillaTreasureEvent(@NotNull Item originalItem, @NotNull ItemStack replacementItemStack) { + this.originalItem = originalItem; + this.replacementItemStack = replacementItemStack; + } + + /** Rest of file is required boilerplate for custom events **/ + private static final @NotNull HandlerList handlers = new HandlerList(); + + @Override + public @NotNull HandlerList getHandlers() { + return handlers; + } + + public static @NotNull HandlerList getHandlerList() { + return handlers; + } + + public @NotNull ItemStack getReplacementItemStack() { + return replacementItemStack; + } + + public void setReplacementItemStack(@NotNull ItemStack replacementItemStack) { + this.replacementItemStack = replacementItemStack; + } + + public @NotNull Item getOriginalItem() { + return originalItem; + } +} diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index 0d817bd21..d16af553a 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -616,6 +616,7 @@ public class EntityListener implements Listener { switch (cause) { case CONTACT: case FIRE: + case HOT_FLOOR: case LAVA: if (tamingManager.canUseEnvironmentallyAware()) { tamingManager.processEnvironmentallyAware(wolf, event.getDamage()); diff --git a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java index 171f304a2..1be281a65 100644 --- a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java @@ -8,6 +8,9 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.neetgames.mcmmo.player.OnlineMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.datatypes.skills.subskills.taming.CallOfTheWildType; +import com.gmail.nossr50.events.McMMOReplaceVanillaTreasureEvent; +import com.gmail.nossr50.events.fake.FakePlayerAnimationEvent; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.party.ShareHandler; @@ -258,7 +261,7 @@ public class PlayerListener implements Listener { * * @param event The event to modify */ - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onPlayerFishHighest(PlayerFishEvent event) { /* WORLD BLACKLIST CHECK */ if(WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld())) @@ -292,12 +295,20 @@ public class PlayerListener implements Listener { if(event.getCaught() != null) { Item fishingCatch = (Item) event.getCaught(); - if (Config.getInstance(). getFishingOverrideTreasures() && + if (Config.getInstance().getFishingOverrideTreasures() && fishingCatch.getItemStack().getType() != Material.SALMON && fishingCatch.getItemStack().getType() != Material.COD && fishingCatch.getItemStack().getType() != Material.TROPICAL_FISH && fishingCatch.getItemStack().getType() != Material.PUFFERFISH) { - fishingCatch.setItemStack(new ItemStack(Material.SALMON, 1)); + + ItemStack replacementCatch = new ItemStack(Material.SALMON, 1); + + McMMOReplaceVanillaTreasureEvent replaceVanillaTreasureEvent = new McMMOReplaceVanillaTreasureEvent(fishingCatch, replacementCatch); + Bukkit.getPluginManager().callEvent(replaceVanillaTreasureEvent); + + //Replace + replacementCatch = replaceVanillaTreasureEvent.getReplacementItemStack(); + fishingCatch.setItemStack(replacementCatch); } if (Permissions.vanillaXpBoost(player, PrimarySkillType.FISHING)) { diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index 7d2841c6a..c85f36c8e 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -615,7 +615,11 @@ public class mcMMO extends JavaPlugin { private void scheduleTasks() { // Periodic save timer (Saves every 10 minutes by default) - long saveIntervalTicks = Config.getInstance().getSaveInterval() * 1200; + long second = 20; + long minute = second * 60; + + long saveIntervalTicks = Math.max(minute, Config.getInstance().getSaveInterval() * minute); + new SaveTimerTask().runTaskTimer(this, saveIntervalTicks, saveIntervalTicks); // Cleanup the backups folder diff --git a/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java b/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java index 566e7966c..4b0b7b002 100644 --- a/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java @@ -31,7 +31,7 @@ public class FormulaConversionTask extends BukkitRunnable { // If the mmoPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process. if (mmoPlayer == null) { - profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(playerName, false); + profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(playerName); if (!profile.isLoaded()) { mcMMO.p.debug("Profile not loaded."); diff --git a/src/main/java/com/gmail/nossr50/runnables/database/UUIDUpdateAsyncTask.java b/src/main/java/com/gmail/nossr50/runnables/database/UUIDUpdateAsyncTask.java index fe87185aa..fe7a029a7 100644 --- a/src/main/java/com/gmail/nossr50/runnables/database/UUIDUpdateAsyncTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/database/UUIDUpdateAsyncTask.java @@ -99,7 +99,7 @@ public class UUIDUpdateAsyncTask implements Runnable { position += batch.size(); plugin.getLogger().info(String.format("Conversion progress: %d/%d users", position, userNames.size())); - if (position == userNames.size()) { + if (position +1 >= userNames.size()) { mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_UUIDS); awaiter.countDown(); plugin.getLogger().info("UUID checks completed"); diff --git a/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java b/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java index 0beb85755..8944fb043 100644 --- a/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java @@ -2,12 +2,13 @@ package com.gmail.nossr50.runnables.player; import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.player.McMMOPlayer; -import com.neetgames.mcmmo.player.MMOPlayerData; +import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.commands.McScoreboardKeepTask; import com.gmail.nossr50.util.EventUtils; import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import org.bukkit.Server; import org.bukkit.entity.Player; @@ -41,40 +42,46 @@ public class PlayerProfileLoadingTask extends BukkitRunnable { return; } - try { - MMOPlayerData mmoPlayerData = mcMMO.getDatabaseManager().queryPlayerDataByPlayer(player); - McMMOPlayer mmoPlayer = new McMMOPlayer(player, player.getUniqueId(), player.getName()); - new ApplySuccessfulProfile(new McMMOPlayer(player, )).runTask(mcMMO.p); + PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(player.getUniqueId(), player.getName()); + + if(!profile.isLoaded()) { + mcMMO.p.getLogger().info("Creating new data for player: "+player.getName()); + //Profile isn't loaded so add as new user + profile = mcMMO.getDatabaseManager().newUser(player); + } + + // If successful, schedule the apply + if (profile.isLoaded()) { + new ApplySuccessfulProfile(new McMMOPlayer(player, profile)).runTask(mcMMO.p); EventUtils.callPlayerProfileLoadEvent(player, profile); return; - - } catch () { - // Print errors to console/logs if we're failing at least 2 times in a row to load the profile - if (attempt >= 3) - { - //Log the error - mcMMO.p.getLogger().severe(LocaleLoader.getString("Profile.Loading.FailureNotice", - player.getName(), String.valueOf(attempt))); - - //Notify the admins - mcMMO.p.getServer().broadcast(LocaleLoader.getString("Profile.Loading.FailureNotice", player.getName()), Server.BROADCAST_CHANNEL_ADMINISTRATIVE); - - //Notify the player - player.sendMessage(LocaleLoader.getString("Profile.Loading.FailurePlayer", String.valueOf(attempt)).split("\n")); - } - - // Increment attempt counter and try - attempt++; - - new PlayerProfileLoadingTask(player, attempt).runTaskLaterAsynchronously(mcMMO.p, (100 + (attempt * 100))); } + + // Print errors to console/logs if we're failing at least 2 times in a row to load the profile + if (attempt >= 3) + { + //Log the error + mcMMO.p.getLogger().severe(LocaleLoader.getString("Profile.Loading.FailureNotice", + player.getName(), String.valueOf(attempt))); + + //Notify the admins + mcMMO.p.getServer().broadcast(LocaleLoader.getString("Profile.Loading.FailureNotice", player.getName()), Server.BROADCAST_CHANNEL_ADMINISTRATIVE); + + //Notify the player + player.sendMessage(LocaleLoader.getString("Profile.Loading.FailurePlayer", String.valueOf(attempt)).split("\n")); + } + + // Increment attempt counter and try + attempt++; + + new PlayerProfileLoadingTask(player, attempt).runTaskLaterAsynchronously(mcMMO.p, (100 + (attempt * 100))); } private class ApplySuccessfulProfile extends BukkitRunnable { - private final McMMOPlayer mmoPlayer; + private final McMMOPlayer mcMMOPlayer; - private ApplySuccessfulProfile(McMMOPlayer mmoPlayer) { - this.mmoPlayer = mmoPlayer; + private ApplySuccessfulProfile(McMMOPlayer mcMMOPlayer) { + this.mcMMOPlayer = mcMMOPlayer; } // Synchronized task @@ -86,8 +93,9 @@ public class PlayerProfileLoadingTask extends BukkitRunnable { return; } - mcMMO.getUserManager().track(mmoPlayer); - mmoPlayer.actualizeRespawnATS(); + mcMMOPlayer.setupPartyData(); + UserManager.track(mcMMOPlayer); + mcMMOPlayer.actualizeRespawnATS(); if (Config.getInstance().getScoreboardsEnabled()) { ScoreboardManager.setupPlayer(player); diff --git a/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java b/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java index e70f0fe51..d97aac15a 100644 --- a/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java @@ -138,7 +138,7 @@ public class SmeltingManager extends SkillManager { ItemStack furnaceResult = furnaceInventory.getResult(); if(furnaceResult == null) - return false; + return true; //This actually means there is nothing yet in the resulting item slot, which means it should always be okay to double smelt int resultAmount = furnaceResult.getAmount(); //Amount before double smelt int itemLimit = furnaceResult.getMaxStackSize(); diff --git a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java index 139a8a10f..70b4e7b8e 100644 --- a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java +++ b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java @@ -344,6 +344,22 @@ public class ScoreboardManager { } } + public static void enablePlayerInspectScoreboard(@NotNull Player player, @NotNull McMMOPlayer targetMcMMOPlayer) { + ScoreboardWrapper wrapper = getWrapper(player); + + if(wrapper == null) { + setupPlayer(player); + wrapper = getWrapper(player); + } + + if(wrapper != null) { + wrapper.setOldScoreboard(); + wrapper.setTypeInspectStats(targetMcMMOPlayer); + + changeScoreboard(wrapper, Config.getInstance().getInspectScoreboardTime()); + } + } + public static void enablePlayerCooldownScoreboard(Player player) { ScoreboardWrapper wrapper = getWrapper(player); diff --git a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java index ef6d0e75a..8cdc69e90 100644 --- a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java +++ b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java @@ -24,6 +24,7 @@ import org.bukkit.scoreboard.DisplaySlot; import org.bukkit.scoreboard.Objective; import org.bukkit.scoreboard.Score; import org.bukkit.scoreboard.Scoreboard; +import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.Map; @@ -321,6 +322,17 @@ public class ScoreboardWrapper { loadObjective(LocaleLoader.getString("Scoreboard.Header.PlayerInspect", targetPlayer)); } + public void setTypeInspectStats(@NotNull McMMOPlayer mcMMOPlayer) { + this.sidebarType = SidebarType.STATS_BOARD; + targetPlayer = mcMMOPlayer.getPlayer().getName(); + targetProfile = mcMMOPlayer.getProfile(); + + targetSkill = null; + leaderboardPage = -1; + + loadObjective(LocaleLoader.getString("Scoreboard.Header.PlayerInspect", targetPlayer)); + } + public void setTypeCooldowns() { this.sidebarType = SidebarType.COOLDOWNS_BOARD; diff --git a/src/main/java/com/gmail/nossr50/util/text/TextUtils.java b/src/main/java/com/gmail/nossr50/util/text/TextUtils.java index b8d71500e..1d3c001d5 100644 --- a/src/main/java/com/gmail/nossr50/util/text/TextUtils.java +++ b/src/main/java/com/gmail/nossr50/util/text/TextUtils.java @@ -16,9 +16,12 @@ import org.jetbrains.annotations.Nullable; import java.util.List; public class TextUtils { - private static @Nullable LegacyComponentSerializer customLegacySerializer; + private TextUtils() { + // We don't want any instances of this class. + } + /** * Makes a single component from an array of components, can optionally add prefixes and suffixes to come before and after each component * @param componentsArray target array diff --git a/src/main/java/com/gmail/nossr50/util/upgrade/UpgradeManager.java b/src/main/java/com/gmail/nossr50/util/upgrade/UpgradeManager.java index 082376c0e..55c747ffd 100644 --- a/src/main/java/com/gmail/nossr50/util/upgrade/UpgradeManager.java +++ b/src/main/java/com/gmail/nossr50/util/upgrade/UpgradeManager.java @@ -11,7 +11,7 @@ public class UpgradeManager extends ConfigLoader { private final Set setNeededUpgrades; public UpgradeManager() { - super("upgrades.yml"); + super("upgrades_overhaul.yml"); //overhaul is added so we don't have any issues with classic setNeededUpgrades = EnumSet.allOf(UpgradeType.class); diff --git a/src/main/resources/locale/locale_de.properties b/src/main/resources/locale/locale_de.properties index 7b6b534b5..87cfc4240 100644 --- a/src/main/resources/locale/locale_de.properties +++ b/src/main/resources/locale/locale_de.properties @@ -17,7 +17,7 @@ Acrobatics.SubSkill.GracefulRoll.Name = Anmutiges Abrollen Acrobatics.SubSkill.Roll.Chance = Chance abzurollen: &e{0} Acrobatics.SubSkill.Roll.Description = Lande gezielt, um deinen Fallschaden zu reduzieren. Acrobatics.SubSkill.Roll.GraceChance = Chance anmutig abzurollen: &e{0} -Acrobatics.SubSkill.Roll.Mechanics = &7Abrollen ist eine aktive F\u00E4higkeit mit einem passiven Teil. Immer, wenn du Fallschaden nimmst, gibt es eine Chance, dass der Schaden reduziert wird, je nachdem wie hoch dein Akrobatik-Level ist. Auf Level 50 hast du eine &e{0}%&7 Chance, den Schaden zu reduzieren bzw. &e{1}%&7 wenn Anmutiges Abrollen aktiviert wird. Die Erfolgschance steigt linear bis Level &e{2}&7, auf welchem es seinen maximalen Wert erreicht. Jedes Akrobatik-Level gibt dir eine &e{3}%&7 Chance zum erfolgreichen Abrollen. H\u00E4ltst du im Fall die Duck-Taste (standardm\u00E4\u00DFig Shift), aktivierst du Anmutiges Abrollen, welches den Fallschaden um noch mehr Schaden reduzieren oder sogar komplett verhindern kann. Normales Abrollen wird maximal &c{4}&7 Schaden verhindern, Anmutiges Abrollen bis zu &a{5}&7. +Acrobatics.SubSkill.Roll.Mechanics = &7Abrollen ist eine aktive F\u00E4higkeit mit einem passiven Teil. Immer, wenn du Fallschaden nimmst, gibt es eine Chance, dass der Schaden reduziert wird, je nachdem wie hoch dein Akrobatik-Level ist. Auf Level 50 hast du eine &e{0}%&7 Chance, den Schaden zu reduzieren bzw. &e{1}%&7 wenn Anmutiges Abrollen aktiviert wird. Die Erfolgschance steigt linear bis Level &e{2}&7, auf welchem es seinen maximalen Wert erreicht. Jedes Akrobatik-Level gibt dir eine &e{3}%&7 Chance zum erfolgreichen Abrollen. H\u00E4ltst du im Fall die Duck-Taste (standardm\u00E4\u00DFig Shift), aktivierst du Anmutiges Abrollen, welches den Fallschaden auf noch weniger Schaden reduzieren oder sogar komplett verhindern kann. Normales Abrollen wird maximal &c{4}&7 Schaden verhindern, Anmutiges Abrollen bis zu &a{5}&7. Acrobatics.SubSkill.Roll.Name = Abrollen Acrobatics.SubSkill.Roll.Stat = Chance abzurollen Acrobatics.SubSkill.Roll.Stat.Extra = Chance anmutig abzurollen @@ -62,7 +62,7 @@ Axes.Ability.Lower = &7&o**Du senkst deine Axt.** Axes.Ability.Ready = &a&o**Du hebst deine Axt...** Axes.Ability.Ready.Extra = &3Du &6hebst&3 deine Axt. &7({0} ist f\u00FCr {1}s pausiert) Axes.Combat.CritStruck = &cDu wurdest &4schwer &cverwundet! -Axes.Combat.CriticalHit = &4&Kritischer Treffer! +Axes.Combat.CriticalHit = &4Kritischer Treffer! Axes.Combat.GI.Proc = &a**Du landest einen &2gewaltigen &aSchlag** Axes.Combat.GI.Struck = &a&o**Von einem Wuchtschlag getroffen** Axes.Combat.SS.Struck = &a&o**Von einem Sch\u00E4delspalter getroffen** @@ -233,7 +233,7 @@ Commands.Party.PartyFull.InviteAccept = Du kannst der Party &a{0}&c nicht beitre Commands.Party.Quit = &a- Verlasse deine aktuelle Party. Commands.Party.Rename = &7Party Name wurde zu &f{0} &7ver\u00E4ndert Commands.Party.SetSharing = &7Party {0} teilen: &3{1} -Commands.Party.ShareMode = &8Teilen Modus: +Commands.Party.ShareMode = &8Teilen-Modus: Commands.Party.Status = &8Name: &f{0} {1} &8Level: &3{2} Commands.Party.Status.Alliance = &8Verb\u00FCndeter: &f{0} Commands.Party.Teleport = &a- Teleportiere dich zu Partymitgliedern. @@ -242,7 +242,7 @@ Commands.Party.ToggleShareCategory = &7Party Item teilen f\u00FCr&6{0} &7wurde & Commands.Party.UnlockedFeatures = &8Freigeschaltete Features: &7&o{0} Commands.Party1 = &a- Erstelle eine neue Party. Commands.Party2 = &a- Tritt der Party eines Spielers bei. -Commands.PowerLevel = &4GESAMT LEVEL: &a{0} +Commands.PowerLevel = &4Gesamtlevel: &a{0} Commands.PowerLevel.Capped = &4Gesamtlevel: &a{0} &4H\u00F6chstlevel: &e{1} Commands.PowerLevel.Leaderboard = --mcMMO&9 Power-Level &eBestenliste-- Commands.Reset = &a- Setze ein Skilllevel auf 0 @@ -262,14 +262,14 @@ Commands.Skill.ChildSkill = Unterskills sind f\u00FCr diesen Befehl nicht benutz Commands.Skill.Invalid = Das ist kein g\u00FCltiger Skillname! Commands.Skill.Leaderboard = --mcMMO &9{0}&e Bestenliste-- Commands.SkillInfo = &a- Detaillierte Informationen zu einem Skill. -Commands.Stats = &a- Zeige deine Skill Statistiken. +Commands.Stats = &a- Zeige deine Skill-Statistiken. Commands.Stats.Self.Overhaul = Statistiken Commands.ToggleAbility = &a- Schalte F\u00E4higkeiten-Aktivierung mit Rechtsklick an oder aus. Commands.Usage.0 = &cDie korrekte Verwendung ist /{0} Commands.Usage.1 = &cDie korrekte Verwendung ist /{0} {1} Commands.Usage.2 = &cDie korrekte Verwendung ist /{0} {1} {2} Commands.Usage.3 = &cDie korrekte Verwendung ist /{0} {1} {2} {3} -Commands.Usage.3.XP = &cDie korrekte Verwendung ist /{0} {1} {2} {3}&7 (Du kannst auch -s an das Ende des Befehls hinzuf\u00FC"gen, damit der Spieler nicht benachrichtigt wird.) +Commands.Usage.3.XP = &cDie korrekte Verwendung ist /{0} {1} {2} {3}&7 (Du kannst auch -s an das Ende des Befehls hinzuf\u00FCgen, damit der Spieler nicht benachrichtigt wird.) Commands.Usage.FullClassName = Klassenname Commands.Usage.Level = Level Commands.Usage.Message = Nachricht @@ -285,7 +285,7 @@ Commands.XPBar.DisableAll = &6Alle mcMMO Erfahrungsleisten wurden deaktiviert, b Commands.XPBar.Reset = &6Die Erfahrungsleisten-Einstellungen f\u00FCr mcMMO wurden zur\u00FCckgesetzt. Commands.XPBar.SettingChanged = &6Die Erfahrungsleisten-Einstellungen f\u00FCr &a{0}&6 wurden gesetzt auf: &a{1} Commands.XPBar.Usage = Die korrekte Verwendung ist /mmoxpbar -Commands.XPGain = &8XP ZUWACHS: &f{0} +Commands.XPGain = &8XP-Zuwachs: &f{0} Commands.XPGain.Acrobatics = Fallen Commands.XPGain.Alchemy = Tr\u00E4nke brauen Commands.XPGain.Archery = Monster angreifen @@ -379,12 +379,12 @@ Excavation.SubSkill.GigaDrillBreaker.Description = Dreifache Droprate, dreifache Excavation.SubSkill.GigaDrillBreaker.Name = Gigabohrer Excavation.SubSkill.GigaDrillBreaker.Stat = Gigabohrer-Dauer -Fishing.Ability.Info = Zauberj\u00E4ger: &7 **Verbessert sich mit Schatzj\u00E4ger-Rang** +Fishing.Ability.Info = Zauberj\u00E4ger: &7**Verbessert sich mit Schatzj\u00E4ger-Rang** Fishing.Ability.Locked.0 = Gesperrt bis Level {0}! Fishing.Ability.Locked.1 = Gesperrt bis Level {0}! Fishing.Ability.Locked.2 = Gesperrt bis Level {0}! Fishing.Ability.TH.Boom = &c&lDeine Angelschnur hat sich in einer &4&lSeemine &c&lverfangen! -Fishing.Ability.TH.MagicFound = &bDu f\u00FChlst etwas Magisches in diesem Fang... +Fishing.Ability.TH.MagicFound = &bDu f\u00FChlst etwas Magisches an diesem Fang... Fishing.Ability.TH.Poison = &7Irgendetwas stinkt hier... Fishing.Chance.Raining = &9Regen-Bonus Fishing.Exhausting = &c&oUnsachgem\u00E4\u00DFe Nutzung der Angelrute f\u00FChrt zu Erm\u00FCdung und Abnutzen der Rute. @@ -557,7 +557,7 @@ Inspect.OfflineStats = mcMMO Stats f\u00FCr Offline-Spieler &e{0} Inspect.Stats = &amcMMO Stats f\u00FCr &e{0} Inspect.TooFar = Du bist zu weit entfernt um den Spieler zu inspizieren! -Item.ChimaeraWing.Fail = &c**CHIMAERA FL\u00DCGEL GESCHEITERT!** +Item.ChimaeraWing.Fail = &c**Chimaera Fl\u00FCgel gescheitert!** Item.ChimaeraWing.Lore = &7Teleportiert dich zu deinem Bett. Item.ChimaeraWing.Name = Chimaera Fl\u00FCgel Item.ChimaeraWing.NotEnough = Du ben\u00F6tigst &e{0}&c weitere &6{1}&c! @@ -595,7 +595,7 @@ JSON.JWrapper.Perks.Lucky = {0}% Bessere Chancen JSON.JWrapper.Target.Block = Block JSON.JWrapper.Target.Player = Spieler JSON.JWrapper.Target.Type = Zieltyp: -JSON.LevelRequirement = Level Voraussetzung +JSON.LevelRequirement = Level-Voraussetzung JSON.Locked = -=[NICHT VERF\u00DCGBAR]=- JSON.Mining = Bergbau JSON.Notification.SuperAbility = {0} @@ -610,7 +610,7 @@ JSON.Type.Passive = Passiv JSON.Type.SuperAbility = Superf\u00E4higkeit JSON.URL.Discord = Der offizielle (englische) mcMMO Discord Server! JSON.URL.Patreon = Unterst\u00FCtze die Entwicklung von mcMMO \u00FCber nossr50's Patreon! -JSON.URL.Spigot = Die offizielle mcmmo Spigot Seite +JSON.URL.Spigot = Die offizielle mcMMO Spigot-Seite. JSON.URL.Translation = \u00DCbersetze mcMMO in andere Sprachen! JSON.URL.Website = Die offizielle mcMMO Website! JSON.URL.Wiki = Das offizielle mcMMO Wiki! @@ -666,7 +666,7 @@ Mining.SubSkill.SuperBreaker.Stat = Superbrecher L\u00E4nge Notifications.Admin.Format.Others = &6(&amcMMO &3Admin&6) &7{0} Notifications.Admin.Format.Self = &6(&amcMMO&6) &7{0} -Notifications.Admin.XPRate.End.Others = {0} &7hat das Bonuserfahrungs-Event beendet +Notifications.Admin.XPRate.End.Others = {0} &7hat das Bonuserfahrungs-Event beendet. Notifications.Admin.XPRate.End.Self = &7Du hast das Bonuserfahrungs-Event beendet. Notifications.Admin.XPRate.Start.Others = {0} &7hat ein Bonuserfahrungs-Event mit einem Faktor von {1}x gestartet. Notifications.Admin.XPRate.Start.Self = &7Du hast den globalen Erfahrungsraten-Multiplikator auf &6{0}x&7 gesetzt. @@ -715,7 +715,7 @@ Party.Help.0 = &cDie korrekte Benutzung ist &3{0} [passwort]. Party.Help.1 = &cUm eine Gruppe zu erstellen, nutze &3{0} [gruppenpasswort]. Party.Help.10 = &cNutze &3{0} &cum Erfahrungsteilung mit Mitgliedern zu aktivieren. Party.Help.2 = &cNutze &3{0} &cf\u00FCr mehr Informationen. -Party.Help.3 = &cNutze &3{0} [passwort] &czum beitreten oder &3{1} &czum verlassen. +Party.Help.3 = &cNutze &3{0} [passwort] &czum Beitreten oder &3{1} &czum Verlassen. Party.Help.4 = &cUm deine Gruppe zu sperren oder entsperren, nutze &3{0}. Party.Help.5 = &cUm deine Gruppe per Passwort zu sch\u00FCtzen, nutze &3{0} . Party.Help.6 = &cUm einen Spieler aus deiner Gruppe zu entfernen, nutze &3{0} . @@ -823,7 +823,7 @@ Repair.SubSkill.StoneRepair.Description = Repariere Stein-Werkzeuge. Repair.SubSkill.StoneRepair.Name = Stein-Reparatur ({0}+ SKILL) Repair.SubSkill.SuperRepair.Description = Doppelte Effektivit\u00E4t. Repair.SubSkill.SuperRepair.Name = Super-Reparatur -Repair.SubSkill.SuperRepair.Stat = Chance auf Superreparatur +Repair.SubSkill.SuperRepair.Stat = Chance auf Super-Reparatur Salvage.Ability.Bonus.0 = Fortgeschrittenes Verwerten Salvage.Ability.Bonus.1 = Max Ertrag {0} Item zerst\u00F6rt @@ -845,7 +845,7 @@ Salvage.Skills.Success = &aItem verwertet! Salvage.Skills.TooDamaged = &4Das Item ist zu besch\u00E4digt um verwertet zu werden. Salvage.SubSkill.ArcaneSalvage.Description = Extrahiere Verzauberungen aus Items. Salvage.SubSkill.ArcaneSalvage.Name = Magische Bergung -Salvage.SubSkill.ArcaneSalvage.Stat = Magische Bergung: &eRank {0}/{1} +Salvage.SubSkill.ArcaneSalvage.Stat = Magische Bergung: &eRang {0}/{1} Salvage.SubSkill.ScrapCollector.Description = Verschrotte einen Gegenstand, um Materialien zur\u00FCckzugewinnen; eine perfekte Verschrottung erfordert Gl\u00FCck und Geschick. Salvage.SubSkill.ScrapCollector.Name = Schrottsammler Salvage.SubSkill.ScrapCollector.Stat = Schrottsammler: &aVerschrotte bis zu &e{0}&a Gegenst\u00E4nde. Hierbei spielt Gl\u00FCck eine gewisse Rolle. @@ -856,13 +856,13 @@ Scoreboard.Header.PlayerCooldowns = mcMMO Abklingzeiten Scoreboard.Header.PlayerInspect = mcMMO Stats: {0} Scoreboard.Header.PlayerRank = mcMMO Bestenlisten Scoreboard.Header.PlayerStats = mcMMO Stats -Scoreboard.Header.PowerLevel = Gesamt Level +Scoreboard.Header.PowerLevel = Gesamt-Level Scoreboard.Misc.Ability = F\u00E4higkeit Scoreboard.Misc.Cooldown = &dAbklingzeit Scoreboard.Misc.CurrentXP = &aAktuelle XP Scoreboard.Misc.Level = &3Level Scoreboard.Misc.Overall = &6Insgesamt -Scoreboard.Misc.PowerLevel = &6Gesamt Level +Scoreboard.Misc.PowerLevel = &6Gesamt-Level Scoreboard.Misc.RemainingXP = Verbliebene XP Server.ConsoleName = &e[Server] @@ -884,9 +884,9 @@ Skills.TooTired = Du bist zu m\u00FCde um diese F\u00E4higkeit zu verwenden. &e( Skills.TooTired.Extra = &6{0} &eSuperf\u00E4higkeit CDs - {1} Skills.TooTired.Named = &7(&6{0}&e {1}s&7) -Smelting.Ability.Locked.0 = Gesperrt bis {0}+ Skill (XP BOOST) -Smelting.Ability.Locked.1 = Gesperrt bis {0}+ Skill (SCHMELZTIEGEL) -Smelting.Effect.4 = Vanilla XP Boost +Smelting.Ability.Locked.0 = Gesperrt bis {0}+ Skill (XP-Boost) +Smelting.Ability.Locked.1 = Gesperrt bis {0}+ Skill (Schmelztiegel) +Smelting.Effect.4 = Vanilla XP-Boost Smelting.Effect.5 = Erh\u00F6ht die erhaltene Erfahrung beim Schmelzen. Smelting.Listener = Schmelzen: Smelting.SkillName = Schmelzen @@ -895,7 +895,7 @@ Smelting.SubSkill.FluxMining.Name = Schmelztiegel Smelting.SubSkill.FluxMining.Stat = Schmelztiegel Chance Smelting.SubSkill.FuelEfficiency.Description = Erh\u00F6he die Brenndauer des Brennstoffes in \u00D6fen. Smelting.SubSkill.FuelEfficiency.Name = Brennstoff Effizienz -Smelting.SubSkill.FuelEfficiency.Stat = Brennstoff Effizienz Multiplikator: &e{0}x +Smelting.SubSkill.FuelEfficiency.Stat = Brennstoff Effizienz-Multiplikator: &e{0}x Smelting.SubSkill.SecondSmelt.Description = Verdoppelt den Ertrag beim Schmelzen. Smelting.SubSkill.SecondSmelt.Name = Extra Schmelzung Smelting.SubSkill.SecondSmelt.Stat = Extra Schmelzung Chance @@ -906,12 +906,12 @@ Smelting.SubSkill.UnderstandingTheArt.Stat = Vanilla Erfahrungsmultiplikator: &e Stats.Header.Combat = &6-=Kampfskills=- Stats.Header.Gathering = &6-=Sammelskills=- Stats.Header.Misc = &6-=Weitere Skills=- -Stats.Own.Stats = &aSkill Statistik +Stats.Own.Stats = &aSkill-Statistik -Swords.Ability.Lower = &7&o**Du senkst dein Sschwert.** +Swords.Ability.Lower = &7&o**Du senkst dein Schwert.** Swords.Ability.Ready = &a&o**Du hebst dein Schwert...** Swords.Combat.Bleeding = &a**Gegner blutet** -Swords.Combat.Bleeding.Started = &4 Du blutest! +Swords.Combat.Bleeding.Started = &4Du blutest! Swords.Combat.Bleeding.Stopped = &7Das Bluten hat &aaufgeh\u00F6rt&7! Swords.Combat.Counter.Hit = &4Treffer durch Gegenangriff! Swords.Combat.Countered = &a**Gegenangriff** @@ -920,7 +920,7 @@ Swords.Combat.SS.Struck = &4Getroffen von S\u00E4gezahnschlag! Swords.Effect.4 = S\u00E4gezahnschlag, Blutung+ Swords.Effect.5 = {0} Ticks Blutung Swords.Listener = Schwert: -Swords.SkillName = Sschwert +Swords.SkillName = Schwert Swords.Skills.SS.Off = &a&o**S\u00E4gezahnschlag abgenutzt** Swords.Skills.SS.On = &a&o**S\u00E4gezahnschlag aktiviert** Swords.Skills.SS.Other.Off = {0}s &cS\u00E4gezahnschlag&a ist &aabgenutzt. @@ -983,7 +983,7 @@ Taming.SubSkill.Pummel.Name = Pummel Taming.SubSkill.Pummel.TargetMessage = Du wurdest von einem Wolf zur\u00FCckgeschlagen! Taming.SubSkill.SharpenedClaws.Description = Schadens-Bonus Taming.SubSkill.SharpenedClaws.Name = Gesch\u00E4rfte Krallen -Taming.SubSkill.ShockProof.Description = Reduktion von Explosions-Schaden. +Taming.SubSkill.ShockProof.Description = Reduktion von Explosionsschaden. Taming.SubSkill.ShockProof.Name = Schock-Sicher Taming.SubSkill.ThickFur.Description = Verminderter Schaden, Feuer-Resistenz Taming.SubSkill.ThickFur.Name = Dicker Pelz @@ -1030,7 +1030,7 @@ Unarmed.SubSkill.SteelArmStyle.Description = Verst\u00E4rkt deinen Arm mit der Z Unarmed.SubSkill.SteelArmStyle.Name = St\u00E4hlerner Arm Unarmed.SubSkill.UnarmedLimitBreak.Description = Durchbreche deine Grenzen! Unarmed.SubSkill.UnarmedLimitBreak.Name = \u00DCberwindung -Unarmed.SubSkill.UnarmedLimitBreak.Stat = Bonus Schaden durch \u00DCberwindung +Unarmed.SubSkill.UnarmedLimitBreak.Stat = Bonus-Schaden durch \u00DCberwindung UpdateChecker.NewAvailable = Eine neue Version von mcMMO ist auf Spigot erh\u00E4ltlich! UpdateChecker.Outdated = Du verwendest eine veraltete mcMMO Version! @@ -1088,9 +1088,9 @@ XPBar.Woodcutting = Holzf\u00E4llen Level: &6{0} XPRate.Event = &6Es findet derzeit ein Skill-Event statt! Du bekommst aktuell &c{0} &6mal so viel Erfahrung f\u00FCr deine Skills wie normal! -mcMMO.Description = &3\u00DCber das &emcMMO&3 Projekt:,&6mcMMO ist ein &copen source&6 RPG mod erstellt in Februar 2011&6von &9nossr50&6. Das Ziel ist es ein qualitatives RPG Erlebnis zu liefern.,&3Tips:,&6 - &aNutze &c/mcmmo help&a um Befehle zu sehen &6,- &aNutze &c/skillname&a f\u00FCr detaillierte Skill Infos,&3Entwickler:,&6 - &anossr50 &9(Erfinder & Projektleitung),&6 - &aGJ &9(Fr\u00FChere Projektleitung),&6 - &aNuclearW &9(Entwickler),&6 - &abm01 &9(Entwickler),&6 - &aTfT_02 &9(Entwickler),&6 - &aGlitchfinder &9(Entwickler),&6 - &at00thpick1 &9(Entwickler),&6 - &alumis31 &9 (Urspr\u00FCngliche Deutsche \u00DCbersetzung),&6 - &aOverCrave &9 (Neue Deutsche \u00DCbersetzung & \u00DCberarbeitung),&3N\u00FCtzliche Links:,&6 - &ahttps://github.com/mcMMO-Dev/mcMMO/issues&6 Bug Reporting,&6 - &ahttps://discord.gg/EJGVanb &6 Offizieller Discord (Englisch) +mcMMO.Description = &3\u00DCber das &emcMMO&3 Projekt: &6mcMMO ist ein &copen source&6 RPG-Mod erstellt im Februar 2011 &6von &9nossr50&6. Das Ziel ist es ein qualitatives RPG Erlebnis zu liefern. &3Tipps:&6 - &aNutze &c/mcmmo help&a um Befehle zu sehen, &6 - &aNutze &c/skillname&a f\u00FCr detaillierte Skill Infos, &3Entwickler:&6 - &anossr50 &9(Erfinder & Projektleitung),&6 - &aGJ &9(Fr\u00FChere Projektleitung),&6 - &aNuclearW &9(Entwickler),&6 - &abm01 &9(Entwickler),&6 - &aTfT_02 &9(Entwickler),&6 - &aGlitchfinder &9(Entwickler),&6 - &at00thpick1 &9(Entwickler),&6 - &alumis31 &9(Urspr\u00FCngliche Deutsche \u00DCbersetzung),&6 - &aOverCrave &9(Neue Deutsche \u00DCbersetzung & \u00DCberarbeitung),&6 - &aAnseba &9(\u00DCberarbeitung Deutsche \u00DCbersetzung), &3N\u00FCtzliche Links:&6 - &ahttps://github.com/mcMMO-Dev/mcMMO/issues&6 Bug Reporting,&6 - &ahttps://discord.gg/EJGVanb &6 Offizieller Discord (Englisch) mcMMO.Description.FormerDevs = &3Ehemalige Entwickler: &aGJ, NuclearW, bm01, TfT_02, Glitchfinder -mcMMO.NoInvites = &cDu hast zurzeit keine Einladungen +mcMMO.NoInvites = &cDu hast zurzeit keine Einladungen. mcMMO.NoPermission = &4Unzureichende Berechtigungen. mcMMO.NoSkillNote = &8Wenn du keinen Zugriff auf einen Skill hast wird er hier nicht angezeigt. mcMMO.Template.Prefix = &6(&amcMMO&6) &7{0} diff --git a/src/main/resources/upgrades.yml b/src/main/resources/upgrades_overhaul.yml similarity index 93% rename from src/main/resources/upgrades.yml rename to src/main/resources/upgrades_overhaul.yml index ff54726c4..4443960a9 100644 --- a/src/main/resources/upgrades.yml +++ b/src/main/resources/upgrades_overhaul.yml @@ -12,3 +12,4 @@ Upgrades_Finished: FIX_NETHERITE_SALVAGE_QUANTITIES: false ADD_SQL_2_2: false ADD_UUIDS: false + SQL_CHARSET_UTF8MB4: false diff --git a/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java b/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java new file mode 100644 index 000000000..fee41b9b3 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java @@ -0,0 +1,32 @@ +package com.gmail.nossr50.util.text; + +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.format.NamedTextColor; +import org.junit.Assert; +import org.junit.Test; + +/** + * This Unit Test checks if Adventure was set up correctly and works as expected. + * Normally we can rely on this to be the case. However sometimes our dependencies + * lack so far behind that things stop working correctly. + * This test ensures that basic functionality is guaranteed to work as we would expect. + * + * See https://github.com/mcMMO-Dev/mcMMO/pull/4446 + * + */ +public class TextUtilsTest { + + @Test + public void testColorizeText() { + String inputText = "&4This text should be red."; + + /* + * If this method raises an exception, we know Adventure is not set up correctly. + * This will also make the test fail and warn us about it. + */ + TextComponent component = TextUtils.colorizeText(inputText); + + Assert.assertEquals("Looks like Adventure is not working correctly.", + NamedTextColor.DARK_RED, component.color()); + } +}