diff --git a/Changelog.txt b/Changelog.txt index 5c1381faa..d841d68cb 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -103,21 +103,88 @@ 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.189 - Removed UP warning - Updated pl locale (Thanks Mich3l3k) +Version 2.1.196 + Crossbows can now be fished up with enchantments NOTES: - Ultra Permissions is SAFE to use with mcMMO + Crossbows is not in the default fishing loot list, you'd have to add it yourself. + +Version 2.1.195 + Fixed a null connection error which affected some SQL users + +Version 2.1.194 + Fixed an XP exploit + Updated SQL to not throw errors if upgrades.yml was reset for any reason + Updated SQL to use the newest driver path (and fall back to the old one if the new one doesn't exist on the server) + Locale override files are now named locale_override.properties (converted automatically/generated automatically) + Existing in use locale override files will be renamed to locale_override.properties and have some useful text put in them + mcMMO will now generate a locale override file with some detailed instructions if one doesn't exist (will be found in /plugins/mcMMO/locales/locale_override.properties) + + NOTES: + If you were overriding locale before this update mcMMO will just rename the existing override file to locale_override.properties add some useful text and then load it + Remember you can use /mcreloadlocale to swap the edits in without restarting the server + +Version 2.1.193 + Fixed another bug where mcrank/mctop/leaderboards weren't loading + Fixed a bug where override locales weren't being loaded (but worked after a reloadlocale command) + (Unit Tests) Added a test to make sure leaderboards for FlatFile were working + Fixed blocks being dropped from blast mining even if yield was set to 0 (thanks Warriorrrr) + Fixed Tree feller not working entirely if one fake block break event is cancelled. (thanks Warriorrrr) + Fixes no woodcutting xp being rewarded if a tree is too big while using tree feller. (thanks Warriorrrr) + Updated pl locale (thanks Mich3l3k) + +Version 2.1.192 + Removed some debug messages from FlatFileDatabaseManager + Fixed another bug where player names could be saved as null for FlatFileDB (they will update on the players next login at the next save interval) + (API) Removed deprecation from com.gmail.nossr50.api.ExperienceAPI.getOfflineProfile(java.lang.String) + (API) Added com.gmail.nossr50.api.DatabaseAPI.doesPlayerExistInDB(org.bukkit.OfflinePlayer) + (API) Added com.gmail.nossr50.api.ExperienceAPI.getOfflineProfile(org.bukkit.OfflinePlayer) + (API) Added com.gmail.nossr50.api.ExperienceAPI.getOfflineXP(org.bukkit.OfflinePlayer, java.lang.String) + (API) Added com.gmail.nossr50.api.ExperienceAPI.getOfflineXPRaw(org.bukkit.OfflinePlayer, com.gmail.nossr50.datatypes.skills.PrimarySkillType) + (API) Added com.gmail.nossr50.api.ExperienceAPI.getOfflineXPRaw(org.bukkit.OfflinePlayer, java.lang.String) + (API) Added com.gmail.nossr50.api.ExperienceAPI.getOfflineXPToNextLevel(org.bukkit.OfflinePlayer, java.lang.String) + (API) Added com.gmail.nossr50.api.DatabaseAPI.doesPlayerExistInDB(java.lang.String) + (Unit Tests) Added some more unit tests to FlatFileDB + +Version 2.1.191 + Fixed a bug related to our blocktracker + Fixed a bug that prevented the leaderboards from working on FlatFile in some circumstances + Some minor optimizations to our Block events + (Unit Tests) Added a test for initializing the leaderboard on FlatFile +Version 2.1.190 + Fixed a null error in BitSetChunkStore +Version 2.1.189 + Fixed a bug that would remove components from death messages when players were killed by mobs (thanks lexikiq) + Rewrote how FlatFileDatabase verifies data integrity + FlatFileDatabase has much better data validation and will repair broken/invalid data much better + Fixed a bug where FlatFileDatabase users could have their names saved as "null" (names will be fixed the next time the player logs in) + Added 20~ unit tests for FlatFileDatabaseManager (see notes) + FlatFileDB now stores the last login of users again (was completely non functional for a while) + Newly created flat file databases (mcmmo.users file) will have a comment line at the top noting the date the database was created + Minor performance optimizations to FlatFile database + mcMMO will once again purge old users if the config option is on (see notes) + Fixed a bug where FlatFileDatabaseManager didn't properly upgrade older database entries to the newest schema + The setting to disable the mcMMO user block tracker has been moved from our "hidden config" to persistent_data.yml + Added 'mcMMO_Region_System.Enabled' to persistent_data.yml (don't touch this setting unless you know what you are doing) + Removed MHD command (it didn't do anything for a while now) + Removed UltraPermissions warning + Updated pl locale (Thanks Mich3l3k) + Fixed an IllegalPluginAccessException error that could happen during server shutdown + Minor performance optimizations to misc parts of the codebase + (API) Added com.gmail.nossr50.database.DatabaseManager.loadPlayerProfile(org.bukkit.OfflinePlayer) + (API) Deprecated com.gmail.nossr50.database.DatabaseManager.loadPlayerProfile(java.util.UUID, java.lang.String) + (API) Removed com.gmail.nossr50.database.DatabaseManager.newUser(java.lang.String, java.util.UUID) + (API) PrimarySkillType will soon be just an enum with nothing special going on + (API) Deprecated the members of PrimarySkillType use mcMMO::getSkillTools instead, deprecated members will be removed in Tridents & Crossbows (due soon) + (API) Some members of PrimarySkillType were removed and not deprecated (such as the field constants) + + NOTES: + I spent over 26 hours refactoring FlatFileDB and writing unit tests for it, this will ensure that any changes in the code that could break the database are caught at compile time (so long as we have enough tests, could probably use more) + Regarding purging old users on the FlatFileDB, since this wasn't functioning for a while, the last login of users has been reset and if mcMMO hasn't seen that user since this update, it won't purge them as it has no way to know if they are truly an old user + I'm likely going to add SQLite DB as an option in the future, I spent time to fix up the FlatFileDB as some Unit Testing practice. + Ultra Permissions is SAFE to use with mcMMO, disregard previous messages stating otherwise After getting in contact with the UltraPermissions devs and exhaustive testing, I have concluded that using UltraPermissions is completely safe with mcMMO. The users who had an issue with performance currently have an unknown cause, potentially it is from a plugin using the UltraPermissions API I really can't say without more data. My apologies to the UltraPermissions team for reporting an issue between our two plugins directly, as that is not the case. I would have tested it myself sooner but UltraPermissions was closed source and premium so I wasn't particularly motivated to do so, however I have been given access to the binaries so now I can do all the testing I want if future issues ever arise which I have zero expectations that they will. - UltraPermissions is as efficient as LuckPerms - I have done a lot of profiling of UltraPermissions via Spark in the last few hours, I also compared it to LuckPerms. I wasn't expecting it, but UltraPermissions runs just as fast as LuckPerms if not faster. So it has no performance issues whatsoever from my point of view. - - Use whatever permission plugin you like, there will be no difference between using LuckPerms or UltraPermissions with mcMMO. - - If you had issues with UltraPermissions please contact the UP devs - If you experience lag with mcMMO and UltraPermissions, we are trying to determine the culprit. It is likely the culprit is from another plugin doing bad things with the UltraPermissions API. Please get in contact with the UltraPermission devs if you run into issues ( @MATRIX | Timo K. & @Liz3 ). Neither I nor they can replicate it so we need you guys to provide more data. Version 2.1.188 Updated default entries in treasures.yml to use "Level_Requirement" instead of "Drop_Level" Fixed a bug where excavation treasures only required level 0 instead of loading the value from the config diff --git a/pom.xml b/pom.xml index 21a354350..d2869cbb7 100755 --- a/pom.xml +++ b/pom.xml @@ -11,6 +11,11 @@ scm:git:git@github.com:mcMMO-Dev/mcMMO.git HEAD + + + UTF-8 + + https://github.com/mcMMO-Dev/mcMMO/issues GitHub @@ -65,6 +70,15 @@ + + maven-surefire-plugin + 2.22.2 + + + maven-failsafe-plugin + 2.22.2 + + org.apache.maven.plugins maven-release-plugin @@ -209,7 +223,10 @@ sk89q-repo https://maven.sk89q.com/repo/ - + + sonatype-oss + https://oss.sonatype.org/content/repositories/snapshots/ + aikar https://repo.aikar.co/content/groups/aikar/ @@ -218,8 +235,18 @@ sonatype-oss https://oss.sonatype.org/content/repositories/snapshots/ - + + + + + + + + + + + com.neetgames @@ -241,6 +268,12 @@ NEET-lib 1.0-SNAPSHOT + + com.github.seeseemelk + MockBukkit-v1.16 + 0.25.0 + test + co.aikar acf-bukkit @@ -286,6 +319,12 @@ net.kyori adventure-platform-common 4.0.0-SNAPSHOT + + + net.kyori + adventure-nbt + + org.apache.maven.scm @@ -329,9 +368,21 @@ - junit - junit-dep - 4.11 + org.junit.jupiter + junit-jupiter-api + 5.7.1 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.7.1 + test + + + org.junit.vintage + junit-vintage-engine + 5.6.2 test @@ -364,7 +415,4 @@ 19.0.0 - - UTF-8 - diff --git a/src/main/java/com/gmail/nossr50/api/DatabaseAPI.java b/src/main/java/com/gmail/nossr50/api/DatabaseAPI.java index 7299f93d1..55f682377 100644 --- a/src/main/java/com/gmail/nossr50/api/DatabaseAPI.java +++ b/src/main/java/com/gmail/nossr50/api/DatabaseAPI.java @@ -1,30 +1,50 @@ -//package com.gmail.nossr50.api; -// -//import com.gmail.nossr50.datatypes.player.PlayerProfile; -//import com.gmail.nossr50.mcMMO; -// -//import java.util.UUID; -// -//public class DatabaseAPI { -// -// /** -// * Checks if a player exists in the mcMMO Database -// * @param uuid player UUID -// * @return true if the player exists in the DB, false if they do not -// */ -// public boolean doesPlayerExistInDB(String uuid) { -// return doesPlayerExistInDB(UUID.fromString(uuid)); -// } -// -// /** -// * Checks if a player exists in the mcMMO Database -// * @param uuid player UUID -// * @return true if the player exists in the DB, false if they do not -// */ -// public boolean doesPlayerExistInDB(UUID uuid) { -// PlayerProfile playerProfile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid, null); -// -// return playerProfile.isLoaded(); -// } -// -//} +package com.gmail.nossr50.api; + +import com.gmail.nossr50.datatypes.player.PlayerProfile; +import com.gmail.nossr50.mcMMO; +import org.bukkit.OfflinePlayer; +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public class DatabaseAPI { + + /** + * Checks if a player exists in the mcMMO Database + * @param offlinePlayer target player + * @return true if the player exists in the DB, false if they do not + */ + public boolean doesPlayerExistInDB(@NotNull OfflinePlayer offlinePlayer) { + PlayerProfile playerProfile = mcMMO.getDatabaseManager().loadPlayerProfile(offlinePlayer); + + return playerProfile.isLoaded(); + } + + /** + * Checks if a player exists in the mcMMO Database + * @param uuid target player + * @return true if the player exists in the DB, false if they do not + */ + public boolean doesPlayerExistInDB(@NotNull UUID uuid) { + PlayerProfile playerProfile = null; + try { + playerProfile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid); + } catch (Exception e) { + return false; + } + + return playerProfile.isLoaded(); + } + + /** + * Checks if a player exists in the mcMMO Database + * @param playerName target player + * @return true if the player exists in the DB, false if they do not + */ + public boolean doesPlayerExistInDB(@NotNull String playerName) { + PlayerProfile playerProfile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName); + + 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 4979acd1d..678f1346b 100644 --- a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java +++ b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java @@ -1,1226 +1,1308 @@ -//package com.gmail.nossr50.api; -// -//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.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 com.neetgames.mcmmo.exceptions.InvalidPlayerException; -//import com.neetgames.mcmmo.exceptions.InvalidSkillException; -//import com.neetgames.mcmmo.exceptions.InvalidXPGainReasonException; -//import com.neetgames.mcmmo.experience.XPGainSource; -//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); -// } -//} +package com.gmail.nossr50.api; + +import com.gmail.nossr50.api.exceptions.*; +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 com.gmail.nossr50.util.skills.SkillTools; +import org.bukkit.OfflinePlayer; +import org.bukkit.block.BlockState; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +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.getSkillTools().matchSkill(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 = mcMMO.p.getSkillTools().matchSkill(skillType); + + return skill != null && !SkillTools.isChildSkill(skill); + } + + @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 / ExperienceConfig.getInstance().getFormulaSkillModifier(skill) * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()), getXPGainReason(xpGainReason), XPGainSource.CUSTOM); + return; + } + + getPlayer(player).applyXpGain(skill, (int) (XP / ExperienceConfig.getInstance().getFormulaSkillModifier(skill) * 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 / ExperienceConfig.getInstance().getFormulaSkillModifier(skill) * 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 amount of XP an offline player has in a specific skill. + *
+ * This function is designed for API usage. + * + * @param offlinePlayer 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(@NotNull OfflinePlayer offlinePlayer, @NotNull String skillType) throws InvalidPlayerException { + return getOfflineProfile(offlinePlayer).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 raw amount of XP an offline player has in a specific skill. + *
+ * This function is designed for API usage. + * + * @param offlinePlayer 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(@NotNull OfflinePlayer offlinePlayer, @NotNull String skillType) throws InvalidPlayerException, UnsupportedOperationException, InvalidSkillException { + return getOfflineProfile(offlinePlayer).getSkillXpLevelRaw(getNonChildSkillType(skillType)); + } + + public static float getOfflineXPRaw(@NotNull OfflinePlayer offlinePlayer, @NotNull PrimarySkillType skillType) throws InvalidPlayerException, UnsupportedOperationException { + if(SkillTools.isChildSkill(skillType)) + throw new UnsupportedOperationException(); + + return getOfflineProfile(offlinePlayer).getSkillXpLevelRaw(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(@NotNull UUID uuid, @NotNull String skillType) { + return getOfflineProfile(uuid).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 offlinePlayer 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(@NotNull OfflinePlayer offlinePlayer, @NotNull String skillType) throws UnsupportedOperationException, InvalidSkillException, InvalidPlayerException { + return getOfflineProfile(offlinePlayer).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); + } + + /** + * Get the amount of XP an offline player has left before leveling up. + *
+ * This function is designed for API usage. + * + * @param offlinePlayer 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(OfflinePlayer offlinePlayer, String skillType) throws InvalidSkillException, InvalidPlayerException, UnsupportedOperationException { + PrimarySkillType skill = getNonChildSkillType(skillType); + PlayerProfile profile = getOfflineProfile(offlinePlayer); + + 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 (SkillTools.isChildSkill(skill)) { + 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 (SkillTools.isChildSkill(skill)) { + 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 : SkillTools.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 : SkillTools.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 mcMMO.p.getSkillTools().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 mcMMO.p.getGeneralConfig().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(@NotNull UUID playerUniqueId, @NotNull PrimarySkillType skill, int XP) { + PlayerProfile profile = getOfflineProfile(playerUniqueId); + + profile.addXp(skill, XP); + profile.save(true); + } + + private static void addOfflineXP(@NotNull String playerName, @NotNull PrimarySkillType skill, int XP) { + PlayerProfile profile = getOfflineProfile(playerName); + + profile.addXp(skill, XP); + profile.scheduleAsyncSave(); + } + + private static @NotNull PlayerProfile getOfflineProfile(@NotNull UUID uuid) throws InvalidPlayerException { + PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid); + + if (!profile.isLoaded()) { + throw new InvalidPlayerException(); + } + + return profile; + } + + private static @NotNull PlayerProfile getOfflineProfile(@NotNull OfflinePlayer offlinePlayer) throws InvalidPlayerException { + PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(offlinePlayer); + + if (!profile.isLoaded()) { + throw new InvalidPlayerException(); + } + + return profile; + } + + private static @NotNull PlayerProfile getOfflineProfile(@NotNull String playerName) throws InvalidPlayerException { + PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName); + + if (!profile.isLoaded()) { + throw new InvalidPlayerException(); + } + + return profile; + } + + private static PrimarySkillType getSkillType(String skillType) throws InvalidSkillException { + PrimarySkillType skill = mcMMO.p.getSkillTools().matchSkill(skillType); + + if (skill == null) { + throw new InvalidSkillException(); + } + + return skill; + } + + private static PrimarySkillType getNonChildSkillType(String skillType) throws InvalidSkillException, UnsupportedOperationException { + PrimarySkillType skill = getSkillType(skillType); + + if (SkillTools.isChildSkill(skill)) { + 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/api/PartyAPI.java b/src/main/java/com/gmail/nossr50/api/PartyAPI.java index 66aa4feb7..7592df5e6 100644 --- a/src/main/java/com/gmail/nossr50/api/PartyAPI.java +++ b/src/main/java/com/gmail/nossr50/api/PartyAPI.java @@ -1,258 +1,257 @@ -//package com.gmail.nossr50.api; -// -//import com.gmail.nossr50.config.Config; -//import com.gmail.nossr50.datatypes.interactions.NotificationType; -//import com.gmail.nossr50.datatypes.party.Party; -//import com.gmail.nossr50.datatypes.party.PartyLeader; -//import com.gmail.nossr50.mcMMO; -//import com.gmail.nossr50.party.PartyManager; -//import com.gmail.nossr50.util.player.NotificationManager; -//import com.gmail.nossr50.util.player.UserManager; -//import org.bukkit.OfflinePlayer; -//import org.bukkit.entity.Player; -// -//import java.util.*; -// -//public final class PartyAPI { -// private PartyAPI() {} -// -// /** -// * Get the name of the party a player is in. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to check the party name of -// * @return the name of the player's party, or null if not in a party -// */ -// public static String getPartyName(Player player) { -// if (!inParty(player)) { -// return null; -// } -// -// return UserManager.getPlayer(player).getParty().getName(); -// } -// -// /** -// * Checks if a player is in a party. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to check -// * @return true if the player is in a party, false otherwise -// */ -// public static boolean inParty(Player player) { -// if(UserManager.getPlayer(player) == null) -// return false; -// -// return UserManager.getPlayer(player).inParty(); -// } -// -// /** -// * Check if two players are in the same party. -// *
-// * This function is designed for API usage. -// * -// * @param playera The first player to check -// * @param playerb The second player to check -// * @return true if the two players are in the same party, false otherwise -// */ -// public static boolean inSameParty(Player playera, Player playerb) { -// return PartyManager.inSameParty(playera, playerb); -// } -// -// /** -// * Get a list of all current parties. -// *
-// * This function is designed for API usage. -// * -// * @return the list of parties. -// */ -// public static List getParties() { -// return PartyManager.getParties(); -// } -// -// /** -// * Add a player to a party. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to add to the party -// * @param partyName The party to add the player to -// * @deprecated parties can have limits, use the other method -// */ -// @Deprecated -// public static void addToParty(Player player, String partyName) { -// //Check if player profile is loaded -// if(UserManager.getPlayer(player) == null) -// return; -// -// Party party = PartyManager.getParty(partyName); -// -// if (party == null) { -// party = new Party(new PartyLeader(player.getUniqueId(), player.getName()), partyName); -// } else { -// if(PartyManager.isPartyFull(player, party)) -// { -// NotificationManager.sendPlayerInformation(player, NotificationType.PARTY_MESSAGE, "Commands.Party.PartyFull", party.toString()); -// return; -// } -// } -// -// PartyManager.addToParty(UserManager.getPlayer(player), party); -// } -// -// /** -// * The max party size of the server -// * 0 or less for no size limit -// * @return the max party size on this server -// */ -// public static int getMaxPartySize() -// { -// return Config.getInstance().getPartyMaxSize(); -// } -// -// /** -// * Add a player to a party. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to add to the party -// * @param partyName The party to add the player to -// * @param bypassLimit if true bypasses party size limits -// */ -// //TODO: bypasslimit not used? -// public static void addToParty(Player player, String partyName, boolean bypassLimit) { -// //Check if player profile is loaded -// if(UserManager.getPlayer(player) == null) -// return; -// -// Party party = PartyManager.getParty(partyName); -// -// if (party == null) { -// party = new Party(new PartyLeader(player.getUniqueId(), player.getName()), partyName); -// } -// -// PartyManager.addToParty(UserManager.getPlayer(player), party); -// } -// -// /** -// * Remove a player from a party. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to remove -// */ -// public static void removeFromParty(Player player) { -// //Check if player profile is loaded -// if(UserManager.getPlayer(player) == null) -// return; -// -// PartyManager.removeFromParty(UserManager.getPlayer(player)); -// } -// -// /** -// * Get the leader of a party. -// *
-// * This function is designed for API usage. -// * -// * @param partyName The party name -// * @return the leader of the party -// */ -// public static String getPartyLeader(String partyName) { -// return PartyManager.getPartyLeaderName(partyName); -// } -// -// /** -// * Set the leader of a party. -// *
-// * This function is designed for API usage. -// * -// * @param partyName The name of the party to set the leader of -// * @param playerName The playerName to set as leader -// */ -// @Deprecated -// public static void setPartyLeader(String partyName, String playerName) { -// PartyManager.setPartyLeader(mcMMO.p.getServer().getOfflinePlayer(playerName).getUniqueId(), PartyManager.getParty(partyName)); -// } -// -// /** -// * Get a list of all players in this player's party. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to check -// * @return all the players in the player's party -// */ -// @Deprecated -// public static List getOnlineAndOfflineMembers(Player player) { -// List members = new ArrayList<>(); -// -// for (UUID memberUniqueId : PartyManager.getAllMembers(player).keySet()) { -// OfflinePlayer member = mcMMO.p.getServer().getOfflinePlayer(memberUniqueId); -// members.add(member); -// } -// return members; -// } -// -// /** -// * Get a list of all player names in this player's party. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to check -// * @return all the player names in the player's party -// */ -// @Deprecated -// public static LinkedHashSet getMembers(Player player) { -// return (LinkedHashSet) PartyManager.getAllMembers(player).values(); -// } -// -// /** -// * Get a list of all player names and uuids in this player's party. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to check -// * @return all the player names and uuids in the player's party -// */ -// public static LinkedHashMap getMembersMap(Player player) { -// return PartyManager.getAllMembers(player); -// } -// -// /** -// * Get a list of all online players in this party. -// *
-// * This function is designed for API usage. -// * -// * @param partyName The party to check -// * @return all online players in this party -// */ -// public static List getOnlineMembers(String partyName) { -// return PartyManager.getOnlineMembers(partyName); -// } -// -// /** -// * Get a list of all online players in this player's party. -// *
-// * This function is designed for API usage. -// * -// * @param player The player to check -// * @return all online players in the player's party -// */ -// public static List getOnlineMembers(Player player) { -// return PartyManager.getOnlineMembers(player); -// } -// -// public static boolean hasAlly(String partyName) { -// return getAllyName(partyName) != null; -// } -// -// public static String getAllyName(String partyName) { -// Party ally = PartyManager.getParty(partyName).getAlly(); -// if (ally != null) { -// return ally.getName(); -// } -// -// return null; -// } -//} +package com.gmail.nossr50.api; + +import com.gmail.nossr50.datatypes.interactions.NotificationType; +import com.gmail.nossr50.datatypes.party.Party; +import com.gmail.nossr50.datatypes.party.PartyLeader; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.party.PartyManager; +import com.gmail.nossr50.util.player.NotificationManager; +import com.gmail.nossr50.util.player.UserManager; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; + +import java.util.*; + +public final class PartyAPI { + private PartyAPI() {} + + /** + * Get the name of the party a player is in. + *
+ * This function is designed for API usage. + * + * @param player The player to check the party name of + * @return the name of the player's party, or null if not in a party + */ + public static String getPartyName(Player player) { + if (!inParty(player)) { + return null; + } + + return UserManager.getPlayer(player).getParty().getName(); + } + + /** + * Checks if a player is in a party. + *
+ * This function is designed for API usage. + * + * @param player The player to check + * @return true if the player is in a party, false otherwise + */ + public static boolean inParty(Player player) { + if(UserManager.getPlayer(player) == null) + return false; + + return UserManager.getPlayer(player).inParty(); + } + + /** + * Check if two players are in the same party. + *
+ * This function is designed for API usage. + * + * @param playera The first player to check + * @param playerb The second player to check + * @return true if the two players are in the same party, false otherwise + */ + public static boolean inSameParty(Player playera, Player playerb) { + return PartyManager.inSameParty(playera, playerb); + } + + /** + * Get a list of all current parties. + *
+ * This function is designed for API usage. + * + * @return the list of parties. + */ + public static List getParties() { + return PartyManager.getParties(); + } + + /** + * Add a player to a party. + *
+ * This function is designed for API usage. + * + * @param player The player to add to the party + * @param partyName The party to add the player to + * @deprecated parties can have limits, use the other method + */ + @Deprecated + public static void addToParty(Player player, String partyName) { + //Check if player profile is loaded + if(UserManager.getPlayer(player) == null) + return; + + Party party = PartyManager.getParty(partyName); + + if (party == null) { + party = new Party(new PartyLeader(player.getUniqueId(), player.getName()), partyName); + } else { + if(PartyManager.isPartyFull(player, party)) + { + NotificationManager.sendPlayerInformation(player, NotificationType.PARTY_MESSAGE, "Commands.Party.PartyFull", party.toString()); + return; + } + } + + PartyManager.addToParty(UserManager.getPlayer(player), party); + } + + /** + * The max party size of the server + * 0 or less for no size limit + * @return the max party size on this server + */ + public static int getMaxPartySize() + { + return mcMMO.p.getGeneralConfig().getPartyMaxSize(); + } + + /** + * Add a player to a party. + *
+ * This function is designed for API usage. + * + * @param player The player to add to the party + * @param partyName The party to add the player to + * @param bypassLimit if true bypasses party size limits + */ + //TODO: bypasslimit not used? + public static void addToParty(Player player, String partyName, boolean bypassLimit) { + //Check if player profile is loaded + if(UserManager.getPlayer(player) == null) + return; + + Party party = PartyManager.getParty(partyName); + + if (party == null) { + party = new Party(new PartyLeader(player.getUniqueId(), player.getName()), partyName); + } + + PartyManager.addToParty(UserManager.getPlayer(player), party); + } + + /** + * Remove a player from a party. + *
+ * This function is designed for API usage. + * + * @param player The player to remove + */ + public static void removeFromParty(Player player) { + //Check if player profile is loaded + if(UserManager.getPlayer(player) == null) + return; + + PartyManager.removeFromParty(UserManager.getPlayer(player)); + } + + /** + * Get the leader of a party. + *
+ * This function is designed for API usage. + * + * @param partyName The party name + * @return the leader of the party + */ + public static String getPartyLeader(String partyName) { + return PartyManager.getPartyLeaderName(partyName); + } + + /** + * Set the leader of a party. + *
+ * This function is designed for API usage. + * + * @param partyName The name of the party to set the leader of + * @param playerName The playerName to set as leader + */ + @Deprecated + public static void setPartyLeader(String partyName, String playerName) { + PartyManager.setPartyLeader(mcMMO.p.getServer().getOfflinePlayer(playerName).getUniqueId(), PartyManager.getParty(partyName)); + } + + /** + * Get a list of all players in this player's party. + *
+ * This function is designed for API usage. + * + * @param player The player to check + * @return all the players in the player's party + */ + @Deprecated + public static List getOnlineAndOfflineMembers(Player player) { + List members = new ArrayList<>(); + + for (UUID memberUniqueId : PartyManager.getAllMembers(player).keySet()) { + OfflinePlayer member = mcMMO.p.getServer().getOfflinePlayer(memberUniqueId); + members.add(member); + } + return members; + } + + /** + * Get a list of all player names in this player's party. + *
+ * This function is designed for API usage. + * + * @param player The player to check + * @return all the player names in the player's party + */ + @Deprecated + public static LinkedHashSet getMembers(Player player) { + return (LinkedHashSet) PartyManager.getAllMembers(player).values(); + } + + /** + * Get a list of all player names and uuids in this player's party. + *
+ * This function is designed for API usage. + * + * @param player The player to check + * @return all the player names and uuids in the player's party + */ + public static LinkedHashMap getMembersMap(Player player) { + return PartyManager.getAllMembers(player); + } + + /** + * Get a list of all online players in this party. + *
+ * This function is designed for API usage. + * + * @param partyName The party to check + * @return all online players in this party + */ + public static List getOnlineMembers(String partyName) { + return PartyManager.getOnlineMembers(partyName); + } + + /** + * Get a list of all online players in this player's party. + *
+ * This function is designed for API usage. + * + * @param player The player to check + * @return all online players in the player's party + */ + public static List getOnlineMembers(Player player) { + return PartyManager.getOnlineMembers(player); + } + + public static boolean hasAlly(String partyName) { + return getAllyName(partyName) != null; + } + + public static String getAllyName(String partyName) { + Party ally = PartyManager.getParty(partyName).getAlly(); + if (ally != null) { + return ally.getName(); + } + + return null; + } +} diff --git a/src/main/java/com/gmail/nossr50/api/SkillAPI.java b/src/main/java/com/gmail/nossr50/api/SkillAPI.java index 460a97c60..be8315a28 100644 --- a/src/main/java/com/gmail/nossr50/api/SkillAPI.java +++ b/src/main/java/com/gmail/nossr50/api/SkillAPI.java @@ -1,93 +1,95 @@ -//package com.gmail.nossr50.api; -// -//import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -// -//import java.util.ArrayList; -//import java.util.Arrays; -//import java.util.List; -// -//public final class SkillAPI { -// private SkillAPI() {} -// -// /** -// * Returns a list of strings with mcMMO's skills -// * This includes parent and child skills -// *
-// * This function is designed for API usage. -// * -// * @return a list of strings with valid skill names -// */ -// public static List getSkills() { -// return getListFromEnum(Arrays.asList(PrimarySkillType.values())); -// } -// -// /** -// * Returns a list of strings with mcMMO's skills -// * This only includes parent skills -// *
-// * This function is designed for API usage. -// * -// * @return a list of strings with valid skill names -// */ -// public static List getNonChildSkills() { -// return getListFromEnum(PrimarySkillType.NON_CHILD_SKILLS); -// } -// -// /** -// * Returns a list of strings with mcMMO's skills -// * This only includes child skills -// *
-// * This function is designed for API usage. -// * -// * @return a list of strings with valid skill names -// */ -// public static List getChildSkills() { -// return getListFromEnum(PrimarySkillType.CHILD_SKILLS); -// } -// -// /** -// * Returns a list of strings with mcMMO's skills -// * This only includes combat skills -// *
-// * This function is designed for API usage. -// * -// * @return a list of strings with valid skill names -// */ -// public static List getCombatSkills() { -// return getListFromEnum(PrimarySkillType.COMBAT_SKILLS); -// } -// -// /** -// * Returns a list of strings with mcMMO's skills -// * This only includes gathering skills -// *
-// * This function is designed for API usage. -// * -// * @return a list of strings with valid skill names -// */ -// public static List getGatheringSkills() { -// return getListFromEnum(PrimarySkillType.GATHERING_SKILLS); -// } -// -// /** -// * Returns a list of strings with mcMMO's skills -// * This only includes misc skills -// *
-// * This function is designed for API usage. -// * -// * @return a list of strings with valid skill names -// */ -// public static List getMiscSkills() { -// return getListFromEnum(PrimarySkillType.MISC_SKILLS); -// } -// -// private static List getListFromEnum(List skillsTypes) { -// List skills = new ArrayList<>(); -// -// for (PrimarySkillType primarySkillType : skillsTypes) { -// skills.add(primarySkillType.name()); -// } -// -// return skills; -// } -//} +package com.gmail.nossr50.api; + +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.skills.SkillTools; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public final class SkillAPI { + private SkillAPI() {} + + /** + * Returns a list of strings with mcMMO's skills + * This includes parent and child skills + *
+ * This function is designed for API usage. + * + * @return a list of strings with valid skill names + */ + public static List getSkills() { + return getListFromEnum(Arrays.asList(PrimarySkillType.values())); + } + + /** + * Returns a list of strings with mcMMO's skills + * This only includes parent skills + *
+ * This function is designed for API usage. + * + * @return a list of strings with valid skill names + */ + public static List getNonChildSkills() { + return getListFromEnum(SkillTools.NON_CHILD_SKILLS); + } + + /** + * Returns a list of strings with mcMMO's skills + * This only includes child skills + *
+ * This function is designed for API usage. + * + * @return a list of strings with valid skill names + */ + public static List getChildSkills() { + return getListFromEnum(mcMMO.p.getSkillTools().CHILD_SKILLS); + } + + /** + * Returns a list of strings with mcMMO's skills + * This only includes combat skills + *
+ * This function is designed for API usage. + * + * @return a list of strings with valid skill names + */ + public static List getCombatSkills() { + return getListFromEnum(mcMMO.p.getSkillTools().COMBAT_SKILLS); + } + + /** + * Returns a list of strings with mcMMO's skills + * This only includes gathering skills + *
+ * This function is designed for API usage. + * + * @return a list of strings with valid skill names + */ + public static List getGatheringSkills() { + return getListFromEnum(mcMMO.p.getSkillTools().GATHERING_SKILLS); + } + + /** + * Returns a list of strings with mcMMO's skills + * This only includes misc skills + *
+ * This function is designed for API usage. + * + * @return a list of strings with valid skill names + */ + public static List getMiscSkills() { + return getListFromEnum(mcMMO.p.getSkillTools().MISC_SKILLS); + } + + private static List getListFromEnum(List skillsTypes) { + List skills = new ArrayList<>(); + + for (PrimarySkillType primarySkillType : skillsTypes) { + skills.add(primarySkillType.name()); + } + + return skills; + } +} diff --git a/src/main/java/com/gmail/nossr50/commands/MHDCommand.java b/src/main/java/com/gmail/nossr50/commands/MHDCommand.java deleted file mode 100644 index d3b547acc..000000000 --- a/src/main/java/com/gmail/nossr50/commands/MHDCommand.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.gmail.nossr50.commands; - -import com.gmail.nossr50.config.Config; -import com.gmail.nossr50.database.FlatFileDatabaseManager; -import com.gmail.nossr50.database.SQLDatabaseManager; -import com.gmail.nossr50.datatypes.player.McMMOPlayer; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.player.UserManager; -import com.google.common.collect.ImmutableList; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.command.TabExecutor; -import org.jetbrains.annotations.NotNull; - -import java.util.List; - -public class MHDCommand implements TabExecutor { - - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { - if (mcMMO.getDatabaseManager() instanceof SQLDatabaseManager) { - SQLDatabaseManager m = (SQLDatabaseManager) mcMMO.getDatabaseManager(); - m.resetMobHealthSettings(); - for (McMMOPlayer player : UserManager.getPlayers()) { - player.getProfile().setMobHealthbarType(Config.getInstance().getMobHealthbarDefault()); - } - sender.sendMessage("Mob health reset"); - return true; - } - if (mcMMO.getDatabaseManager() instanceof FlatFileDatabaseManager) { - FlatFileDatabaseManager m = (FlatFileDatabaseManager) mcMMO.getDatabaseManager(); - m.resetMobHealthSettings(); - for (McMMOPlayer player : UserManager.getPlayers()) { - player.getProfile().setMobHealthbarType(Config.getInstance().getMobHealthbarDefault()); - } - sender.sendMessage("Mob health reset"); - return true; - } - return false; - } - - @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { - return ImmutableList.of(); - } -} diff --git a/src/main/java/com/gmail/nossr50/commands/McmmoCommand.java b/src/main/java/com/gmail/nossr50/commands/McmmoCommand.java index 4a71e6b51..a100b98ce 100644 --- a/src/main/java/com/gmail/nossr50/commands/McmmoCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/McmmoCommand.java @@ -1,6 +1,7 @@ package com.gmail.nossr50.commands; import com.gmail.nossr50.config.Config; +import com.gmail.nossr50.commands.party.PartySubcommandType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; @@ -25,7 +26,7 @@ public class McmmoCommand implements CommandExecutor { sender.sendMessage(mcSplit); sender.sendMessage(LocaleLoader.getString("mcMMO.Description.FormerDevs")); - if (Config.getInstance().getDonateMessageEnabled()) { + if (mcMMO.p.getGeneralConfig().getDonateMessageEnabled()) { sender.sendMessage(LocaleLoader.getString("MOTD.Donate")); sender.sendMessage(ChatColor.GOLD + " - " + ChatColor.GREEN + "nossr50@gmail.com" + ChatColor.GOLD + " Paypal"); } diff --git a/src/main/java/com/gmail/nossr50/commands/McscoreboardCommand.java b/src/main/java/com/gmail/nossr50/commands/McscoreboardCommand.java index 1afaa110e..4748a5708 100644 --- a/src/main/java/com/gmail/nossr50/commands/McscoreboardCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/McscoreboardCommand.java @@ -1,7 +1,7 @@ package com.gmail.nossr50.commands; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.google.common.collect.ImmutableList; @@ -32,7 +32,7 @@ public class McscoreboardCommand implements TabExecutor { } if (args[0].equalsIgnoreCase("keep")) { - if (!Config.getInstance().getAllowKeepBoard() || !Config.getInstance().getScoreboardsEnabled()) { + if (!mcMMO.p.getGeneralConfig().getAllowKeepBoard() || !mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { sender.sendMessage(LocaleLoader.getString("Commands.Disabled")); return true; } diff --git a/src/main/java/com/gmail/nossr50/commands/XprateCommand.java b/src/main/java/com/gmail/nossr50/commands/XprateCommand.java index 150b97590..f5ad2641c 100644 --- a/src/main/java/com/gmail/nossr50/commands/XprateCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/XprateCommand.java @@ -1,7 +1,5 @@ package com.gmail.nossr50.commands; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.notifications.SensitiveCommandType; import com.gmail.nossr50.locale.LocaleLoader; @@ -39,7 +37,7 @@ public class XprateCommand implements TabExecutor { if (mcMMO.p.isXPEventEnabled()) { - if(AdvancedConfig.getInstance().useTitlesForXPEvent()) + if(mcMMO.p.getAdvancedConfig().useTitlesForXPEvent()) { NotificationManager.broadcastTitle(mcMMO.p.getServer(), LocaleLoader.getString("Commands.Event.Stop"), @@ -47,7 +45,7 @@ public class XprateCommand implements TabExecutor { 10, 10*20, 20); } - if(Config.getInstance().broadcastEventMessages()) + if(mcMMO.p.getGeneralConfig().broadcastEventMessages()) { mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Commands.Event.Stop")); mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Commands.Event.Stop.Subtitle")); @@ -92,7 +90,7 @@ public class XprateCommand implements TabExecutor { ExperienceConfig.getInstance().setExperienceGainsGlobalMultiplier(newXpRate); - if(AdvancedConfig.getInstance().useTitlesForXPEvent()) + if(mcMMO.p.getAdvancedConfig().useTitlesForXPEvent()) { NotificationManager.broadcastTitle(mcMMO.p.getServer(), LocaleLoader.getString("Commands.Event.Start"), @@ -100,7 +98,7 @@ public class XprateCommand implements TabExecutor { 10, 10*20, 20); } - if(Config.getInstance().broadcastEventMessages()) + if(mcMMO.p.getGeneralConfig().broadcastEventMessages()) { mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Commands.Event.Start")); mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Commands.Event.XP", newXpRate)); 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 0c3df662a..c6dbb73ba 100644 --- a/src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java @@ -27,7 +27,11 @@ public class ConvertDatabaseCommand implements CommandExecutor { return true; } - DatabaseManager oldDatabase = DatabaseManagerFactory.createDatabaseManager(previousType); + DatabaseManager oldDatabase = DatabaseManagerFactory.createDatabaseManager(previousType, mcMMO.getUsersFilePath(), mcMMO.p.getLogger(), mcMMO.p.getPurgeTime(), mcMMO.p.getAdvancedConfig().getStartingLevel()); + if(oldDatabase == null) { + sender.sendMessage("Unable to load the old database! Check your log for errors."); + return true; + } if (previousType == DatabaseType.CUSTOM) { Class clazz; @@ -54,7 +58,7 @@ public class ConvertDatabaseCommand implements CommandExecutor { UserManager.clearAll(); for (Player player : mcMMO.p.getServer().getOnlinePlayers()) { - PlayerProfile profile = oldDatabase.loadPlayerProfile(player.getUniqueId(), null); + PlayerProfile profile = oldDatabase.loadPlayerProfile(player); if (profile.isLoaded()) { mcMMO.getDatabaseManager().saveUser(profile.getPlayerData()); diff --git a/src/main/java/com/gmail/nossr50/commands/database/McpurgeCommand.java b/src/main/java/com/gmail/nossr50/commands/database/McpurgeCommand.java index 9bc472875..6f192510f 100644 --- a/src/main/java/com/gmail/nossr50/commands/database/McpurgeCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/database/McpurgeCommand.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.commands.database; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.google.common.collect.ImmutableList; @@ -17,7 +16,7 @@ public class McpurgeCommand implements TabExecutor { if (args.length == 0) { mcMMO.getDatabaseManager().purgePowerlessUsers(); - if (Config.getInstance().getOldUsersCutoff() != -1) { + if (mcMMO.p.getGeneralConfig().getOldUsersCutoff() != -1) { mcMMO.getDatabaseManager().purgeOldUsers(); } diff --git a/src/main/java/com/gmail/nossr50/commands/database/MmoshowdbCommand.java b/src/main/java/com/gmail/nossr50/commands/database/MmoshowdbCommand.java index aafae253e..bcb07312d 100644 --- a/src/main/java/com/gmail/nossr50/commands/database/MmoshowdbCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/database/MmoshowdbCommand.java @@ -1,8 +1,8 @@ package com.gmail.nossr50.commands.database; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.database.DatabaseManagerFactory; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.google.common.collect.ImmutableList; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -22,7 +22,7 @@ public class MmoshowdbCommand implements TabExecutor { return true; } - sender.sendMessage(LocaleLoader.getString("Commands.mmoshowdb", (Config.getInstance().getUseMySQL() ? "sql" : "flatfile"))); + sender.sendMessage(LocaleLoader.getString("Commands.mmoshowdb", (mcMMO.p.getGeneralConfig().getUseMySQL() ? "sql" : "flatfile"))); return true; } return false; diff --git a/src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java index 7b1c34e80..8f7213a05 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java @@ -4,6 +4,7 @@ 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.player.UserManager; @@ -55,6 +56,6 @@ public class AddlevelsCommand extends ExperienceCommand { if(isSilent) return; - player.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.1", value, skill.getName())); + player.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.1", value, mcMMO.p.getSkillTools().getLocalizedSkillName(skill))); } } diff --git a/src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java index 5110accd9..4d19b7a13 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java @@ -5,6 +5,7 @@ import com.gmail.nossr50.datatypes.experience.XPGainSource; 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.player.UserManager; import org.bukkit.command.CommandSender; @@ -49,6 +50,6 @@ public class AddxpCommand extends ExperienceCommand { if(isSilent) return; - player.sendMessage(LocaleLoader.getString("Commands.addxp.AwardSkill", value, skill.getName())); + player.sendMessage(LocaleLoader.getString("Commands.addxp.AwardSkill", value, mcMMO.p.getSkillTools().getLocalizedSkillName(skill))); } } 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 11684ebf8..4bd6b4eeb 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java @@ -7,8 +7,8 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.skills.SkillTools; import com.google.common.collect.ImmutableList; -import org.bukkit.OfflinePlayer; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; @@ -18,7 +18,6 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; -import java.util.UUID; public abstract class ExperienceCommand implements TabExecutor { @Override @@ -44,13 +43,13 @@ public abstract class ExperienceCommand implements TabExecutor { return true; } - skill = PrimarySkillType.getSkill(args[0]); + skill = mcMMO.p.getSkillTools().matchSkill(args[0]); if (args[1].equalsIgnoreCase("all")) { skill = null; } - if (skill != null && skill.isChildSkill()) + if (skill != null && SkillTools.isChildSkill(skill)) { sender.sendMessage(LocaleLoader.getString("Commands.Skill.ChildSkill")); return true; @@ -77,13 +76,13 @@ public abstract class ExperienceCommand implements TabExecutor { return true; } - skill = PrimarySkillType.getSkill(args[1]); + skill = mcMMO.p.getSkillTools().matchSkill(args[1]); if (args[1].equalsIgnoreCase("all")) { skill = null; } - if (skill != null && skill.isChildSkill()) + if (skill != null && SkillTools.isChildSkill(skill)) { sender.sendMessage(LocaleLoader.getString("Commands.Skill.ChildSkill")); return true; @@ -96,12 +95,9 @@ public abstract class ExperienceCommand implements TabExecutor { // 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 offlinePlayer = mcMMO.p.getServer().getOfflinePlayer(playerName); PlayerProfile profile; - uuid = offlinePlayer.getUniqueId(); - profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid, null); + profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName); //Check loading by UUID if (CommandUtils.unloadedProfile(sender, profile)) { @@ -144,7 +140,7 @@ public abstract class ExperienceCommand implements TabExecutor { List playerNames = CommandUtils.getOnlinePlayerNames(sender); return StringUtil.copyPartialMatches(args[0], playerNames, new ArrayList<>(playerNames.size())); case 2: - return StringUtil.copyPartialMatches(args[1], PrimarySkillType.SKILL_NAMES, new ArrayList<>(PrimarySkillType.SKILL_NAMES.size())); + return StringUtil.copyPartialMatches(args[1], mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES, new ArrayList<>(mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES.size())); default: return ImmutableList.of(); } @@ -165,13 +161,13 @@ public abstract class ExperienceCommand implements TabExecutor { sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardAll.2", playerName)); } else { - sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", skill.getName(), playerName)); + sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", mcMMO.p.getSkillTools().getLocalizedSkillName(skill), playerName)); } } protected void editValues(Player player, PlayerProfile profile, PrimarySkillType skill, int value, boolean isSilent) { if (skill == null) { - for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { handleCommand(player, profile, primarySkillType, value); } diff --git a/src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java index f65baac39..3b84a77ee 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java @@ -5,6 +5,7 @@ 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.player.UserManager; @@ -62,6 +63,6 @@ public class MmoeditCommand extends ExperienceCommand { if(isSilent) return; - player.sendMessage(LocaleLoader.getString("Commands.mmoedit.Modified.1", skill.getName(), value)); + player.sendMessage(LocaleLoader.getString("Commands.mmoedit.Modified.1", mcMMO.p.getSkillTools().getLocalizedSkillName(skill), value)); } } 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 890982735..94df154b0 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/SkillResetCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/SkillResetCommand.java @@ -9,6 +9,7 @@ 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.gmail.nossr50.util.skills.SkillTools; import com.google.common.collect.ImmutableList; import org.bukkit.OfflinePlayer; import org.bukkit.command.Command; @@ -20,7 +21,6 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; -import java.util.UUID; /** * This class mirrors the structure of ExperienceCommand, except the @@ -49,7 +49,7 @@ public class SkillResetCommand implements TabExecutor { skill = null; } else { - skill = PrimarySkillType.getSkill(args[0]); + skill = mcMMO.p.getSkillTools().matchSkill(args[0]); } editValues((Player) sender, UserManager.getPlayer(sender.getName()).getProfile(), skill); @@ -69,7 +69,7 @@ public class SkillResetCommand implements TabExecutor { skill = null; } else { - skill = PrimarySkillType.getSkill(args[1]); + skill = mcMMO.p.getSkillTools().matchSkill(args[1]); } String playerName = CommandUtils.getMatchedPlayerName(args[0]); @@ -77,11 +77,8 @@ public class SkillResetCommand implements TabExecutor { // 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); - uuid = player.getUniqueId(); - - PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid, playerName); + OfflinePlayer offlinePlayer = mcMMO.p.getServer().getOfflinePlayer(playerName); + PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(offlinePlayer); //Check loading by UUID if (CommandUtils.unloadedProfile(sender, profile)) { @@ -115,7 +112,7 @@ public class SkillResetCommand implements TabExecutor { List playerNames = CommandUtils.getOnlinePlayerNames(sender); return StringUtil.copyPartialMatches(args[0], playerNames, new ArrayList<>(playerNames.size())); case 2: - return StringUtil.copyPartialMatches(args[1], PrimarySkillType.SKILL_NAMES, new ArrayList<>(PrimarySkillType.SKILL_NAMES.size())); + return StringUtil.copyPartialMatches(args[1], mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES, new ArrayList<>(mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES.size())); default: return ImmutableList.of(); } @@ -148,7 +145,7 @@ public class SkillResetCommand implements TabExecutor { } protected void handlePlayerMessageSkill(Player player, PrimarySkillType skill) { - player.sendMessage(LocaleLoader.getString("Commands.Reset.Single", skill.getName())); + player.sendMessage(LocaleLoader.getString("Commands.Reset.Single", mcMMO.p.getSkillTools().getLocalizedSkillName(skill))); } private boolean validateArguments(CommandSender sender, String skillName) { @@ -160,13 +157,13 @@ public class SkillResetCommand implements TabExecutor { sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardAll.2", playerName)); } else { - sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", skill.getName(), playerName)); + sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", mcMMO.p.getSkillTools().getLocalizedSkillName(skill), playerName)); } } protected void editValues(Player player, PlayerProfile profile, PrimarySkillType skill) { if (skill == null) { - for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { handleCommand(player, profile, primarySkillType); } diff --git a/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreCommand.java b/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreCommand.java index e3697be36..4a8656e37 100644 --- a/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreCommand.java @@ -51,7 +51,7 @@ // // private void toggle(boolean enable, PrimarySkillType skill) { // if (skill == null) { -// for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { +// for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { // primarySkillType.setHardcoreStatLossEnabled(enable); // } // } @@ -59,6 +59,6 @@ // skill.setHardcoreStatLossEnabled(enable); // } // -// mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Hardcore.Mode." + (enable ? "Enabled" : "Disabled"), LocaleLoader.getString("Hardcore.DeathStatLoss.Name"), (skill == null ? "all skills" : skill.getName()))); +// mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Hardcore.Mode." + (enable ? "Enabled" : "Disabled"), LocaleLoader.getString("Hardcore.DeathStatLoss.Name"), (skill == null ? "all skills" : mcMMO.p.getSkillTools().getLocalizedSkillName(skill)))); // } //} \ No newline at end of file diff --git a/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreModeCommand.java b/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreModeCommand.java index 62206566a..1bffa7a65 100644 --- a/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreModeCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreModeCommand.java @@ -1,129 +1,129 @@ -package com.gmail.nossr50.commands.hardcore; - -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -import com.gmail.nossr50.util.Permissions; -import com.gmail.nossr50.util.commands.CommandUtils; -import com.gmail.nossr50.util.text.StringUtils; -import com.google.common.collect.ImmutableList; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.command.TabExecutor; -import org.bukkit.util.StringUtil; -import org.jetbrains.annotations.NotNull; - -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.List; - -public abstract class HardcoreModeCommand implements TabExecutor { - protected final DecimalFormat percent = new DecimalFormat("##0.00%"); - - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { - switch (args.length) { - case 0: - if (!checkTogglePermissions(sender)) { - sender.sendMessage(command.getPermissionMessage()); - return true; - } - - if (checkEnabled(null)) { - disable(null); - } - else { - enable(null); - } - - return true; - - case 1: - if (CommandUtils.shouldEnableToggle(args[0])) { - if (!Permissions.hardcoreToggle(sender)) { - sender.sendMessage(command.getPermissionMessage()); - return true; - } - - enable(null); - return true; - } - - if (CommandUtils.shouldDisableToggle(args[0])) { - if (!Permissions.hardcoreToggle(sender)) { - sender.sendMessage(command.getPermissionMessage()); - return true; - } - - disable(null); - return true; - } - - if (CommandUtils.isInvalidDouble(sender, args[0])) { - return true; - } - - if (!Permissions.hardcoreModify(sender)) { - sender.sendMessage(command.getPermissionMessage()); - return true; - } - - modify(sender, Double.parseDouble(args[0])); - return true; - - - case 2: - if (CommandUtils.isInvalidSkill(sender, args[0])) { - return true; - } - - PrimarySkillType skill = PrimarySkillType.getSkill(args[0]); - - if (!CommandUtils.isChildSkill(sender, skill)) { - return true; - } - - if (CommandUtils.shouldEnableToggle(args[1])) { - if (!Permissions.hardcoreToggle(sender)) { - sender.sendMessage(command.getPermissionMessage()); - return true; - } - - enable(skill); - return true; - } - - if (CommandUtils.shouldDisableToggle(args[1])) { - if (!Permissions.hardcoreToggle(sender)) { - sender.sendMessage(command.getPermissionMessage()); - return true; - } - - enable(skill); - return true; - } - - return true; - - default: - return false; - } - } - - @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { - if (args.length == 1) { - if (StringUtils.isDouble(args[0])) { - return ImmutableList.of(); - } - - return StringUtil.copyPartialMatches(args[0], CommandUtils.TRUE_FALSE_OPTIONS, new ArrayList<>(CommandUtils.TRUE_FALSE_OPTIONS.size())); - } - return ImmutableList.of(); - } - - protected abstract boolean checkTogglePermissions(CommandSender sender); - protected abstract boolean checkModifyPermissions(CommandSender sender); - protected abstract boolean checkEnabled(PrimarySkillType skill); - protected abstract void enable(PrimarySkillType skill); - protected abstract void disable(PrimarySkillType skill); - protected abstract void modify(CommandSender sender, double newPercentage); -} +//package com.gmail.nossr50.commands.hardcore; +// +//import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +//import com.gmail.nossr50.util.Permissions; +//import com.gmail.nossr50.util.commands.CommandUtils; +//import com.gmail.nossr50.util.text.StringUtils; +//import com.google.common.collect.ImmutableList; +//import org.bukkit.command.Command; +//import org.bukkit.command.CommandSender; +//import org.bukkit.command.TabExecutor; +//import org.bukkit.util.StringUtil; +//import org.jetbrains.annotations.NotNull; +// +//import java.text.DecimalFormat; +//import java.util.ArrayList; +//import java.util.List; +// +//public abstract class HardcoreModeCommand implements TabExecutor { +// protected final DecimalFormat percent = new DecimalFormat("##0.00%"); +// +// @Override +// public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { +// switch (args.length) { +// case 0: +// if (!checkTogglePermissions(sender)) { +// sender.sendMessage(command.getPermissionMessage()); +// return true; +// } +// +// if (checkEnabled(null)) { +// disable(null); +// } +// else { +// enable(null); +// } +// +// return true; +// +// case 1: +// if (CommandUtils.shouldEnableToggle(args[0])) { +// if (!Permissions.hardcoreToggle(sender)) { +// sender.sendMessage(command.getPermissionMessage()); +// return true; +// } +// +// enable(null); +// return true; +// } +// +// if (CommandUtils.shouldDisableToggle(args[0])) { +// if (!Permissions.hardcoreToggle(sender)) { +// sender.sendMessage(command.getPermissionMessage()); +// return true; +// } +// +// disable(null); +// return true; +// } +// +// if (CommandUtils.isInvalidDouble(sender, args[0])) { +// return true; +// } +// +// if (!Permissions.hardcoreModify(sender)) { +// sender.sendMessage(command.getPermissionMessage()); +// return true; +// } +// +// modify(sender, Double.parseDouble(args[0])); +// return true; +// +// +// case 2: +// if (CommandUtils.isInvalidSkill(sender, args[0])) { +// return true; +// } +// +// PrimarySkillType skill = PrimarySkillType.getSkill(args[0]); +// +// if (!CommandUtils.isChildSkill(sender, skill)) { +// return true; +// } +// +// if (CommandUtils.shouldEnableToggle(args[1])) { +// if (!Permissions.hardcoreToggle(sender)) { +// sender.sendMessage(command.getPermissionMessage()); +// return true; +// } +// +// enable(skill); +// return true; +// } +// +// if (CommandUtils.shouldDisableToggle(args[1])) { +// if (!Permissions.hardcoreToggle(sender)) { +// sender.sendMessage(command.getPermissionMessage()); +// return true; +// } +// +// enable(skill); +// return true; +// } +// +// return true; +// +// default: +// return false; +// } +// } +// +// @Override +// public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { +// if (args.length == 1) { +// if (StringUtils.isDouble(args[0])) { +// return ImmutableList.of(); +// } +// +// return StringUtil.copyPartialMatches(args[0], CommandUtils.TRUE_FALSE_OPTIONS, new ArrayList<>(CommandUtils.TRUE_FALSE_OPTIONS.size())); +// } +// return ImmutableList.of(); +// } +// +// protected abstract boolean checkTogglePermissions(CommandSender sender); +// protected abstract boolean checkModifyPermissions(CommandSender sender); +// protected abstract boolean checkEnabled(PrimarySkillType skill); +// protected abstract void enable(PrimarySkillType skill); +// protected abstract void disable(PrimarySkillType skill); +// protected abstract void modify(CommandSender sender, double newPercentage); +//} diff --git a/src/main/java/com/gmail/nossr50/commands/hardcore/VampirismCommand.java b/src/main/java/com/gmail/nossr50/commands/hardcore/VampirismCommand.java index 8bdfa83f9..037c34e11 100644 --- a/src/main/java/com/gmail/nossr50/commands/hardcore/VampirismCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/hardcore/VampirismCommand.java @@ -51,7 +51,7 @@ // // private void toggle(boolean enable, PrimarySkillType skill) { // if (skill == null) { -// for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { +// for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { // primarySkillType.setHardcoreVampirismEnabled(enable); // } // } diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyInfoCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyInfoCommand.java index ec28ac529..ab46f14de 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyInfoCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyInfoCommand.java @@ -1,11 +1,11 @@ package com.gmail.nossr50.commands.party; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.party.PartyFeature; import com.gmail.nossr50.datatypes.party.ShareMode; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.ChatColor; @@ -85,7 +85,7 @@ public class PartyInfoCommand implements CommandExecutor { } private boolean isUnlockedFeature(Party party, PartyFeature partyFeature) { - return party.getLevel() >= Config.getInstance().getPartyFeatureUnlockLevel(partyFeature); + return party.getLevel() >= mcMMO.p.getGeneralConfig().getPartyFeatureUnlockLevel(partyFeature); } private void displayShareModeInfo(Player player, Party party) { diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyInviteCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyInviteCommand.java index 7d6c6a8ca..7a24a4936 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyInviteCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyInviteCommand.java @@ -1,9 +1,9 @@ package com.gmail.nossr50.commands.party; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; @@ -53,7 +53,7 @@ public class PartyInviteCommand implements CommandExecutor { Party playerParty = mcMMOPlayer.getParty(); if (PartyManager.isPartyFull(target, playerParty)) { - player.sendMessage(LocaleLoader.getString("Commands.Party.PartyFull.Invite", target.getName(), playerParty.toString(), Config.getInstance().getPartyMaxSize())); + player.sendMessage(LocaleLoader.getString("Commands.Party.PartyFull.Invite", target.getName(), playerParty.toString(), mcMMO.p.getGeneralConfig().getPartyMaxSize())); return true; } diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyXpShareCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyXpShareCommand.java index a8354914e..8322beecf 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyXpShareCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyXpShareCommand.java @@ -1,10 +1,10 @@ package com.gmail.nossr50.commands.party; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.party.PartyFeature; import com.gmail.nossr50.datatypes.party.ShareMode; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.text.StringUtils; @@ -25,7 +25,7 @@ public class PartyXpShareCommand implements CommandExecutor { Party party = UserManager.getPlayer((Player) sender).getParty(); - if (party.getLevel() < Config.getInstance().getPartyFeatureUnlockLevel(PartyFeature.XP_SHARE)) { + if (party.getLevel() < mcMMO.p.getGeneralConfig().getPartyFeatureUnlockLevel(PartyFeature.XP_SHARE)) { sender.sendMessage(LocaleLoader.getString("Party.Feature.Disabled.5")); return true; } diff --git a/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpAcceptCommand.java b/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpAcceptCommand.java index 86728e272..19c98ad6a 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpAcceptCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpAcceptCommand.java @@ -1,8 +1,8 @@ package com.gmail.nossr50.commands.party.teleport; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.party.PartyTeleportRecord; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.SkillUtils; @@ -35,7 +35,7 @@ public class PtpAcceptCommand implements CommandExecutor { return true; } - if (SkillUtils.cooldownExpired(ptpRecord.getTimeout(), Config.getInstance().getPTPCommandTimeout())) { + if (SkillUtils.cooldownExpired(ptpRecord.getTimeout(), mcMMO.p.getGeneralConfig().getPTPCommandTimeout())) { ptpRecord.removeRequest(); player.sendMessage(LocaleLoader.getString("Commands.ptp.RequestExpired")); return true; @@ -48,7 +48,7 @@ public class PtpAcceptCommand implements CommandExecutor { return true; } - if (Config.getInstance().getPTPCommandWorldPermissions()) { + if (mcMMO.p.getGeneralConfig().getPTPCommandWorldPermissions()) { World targetWorld = target.getWorld(); World playerWorld = player.getWorld(); diff --git a/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpCommand.java b/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpCommand.java index 893164435..c892fa7e0 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpCommand.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.commands.party.teleport; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.WorldBlacklist; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.party.PartyFeature; @@ -76,7 +75,7 @@ public class PtpCommand implements TabExecutor { Party party = mcMMOPlayer.getParty(); - if (party.getLevel() < Config.getInstance().getPartyFeatureUnlockLevel(PartyFeature.TELEPORT)) { + if (party.getLevel() < mcMMO.p.getGeneralConfig().getPartyFeatureUnlockLevel(PartyFeature.TELEPORT)) { sender.sendMessage(LocaleLoader.getString("Party.Feature.Disabled.2")); return true; } @@ -91,7 +90,7 @@ public class PtpCommand implements TabExecutor { } long recentlyHurt = mcMMOPlayer.getRecentlyHurt(); - int hurtCooldown = Config.getInstance().getPTPCommandRecentlyHurtCooldown(); + int hurtCooldown = mcMMO.p.getGeneralConfig().getPTPCommandRecentlyHurtCooldown(); if (hurtCooldown > 0) { int timeRemaining = SkillUtils.calculateTimeLeft(recentlyHurt * Misc.TIME_CONVERSION_FACTOR, hurtCooldown, player); @@ -111,7 +110,7 @@ public class PtpCommand implements TabExecutor { return true; } - int ptpCooldown = Config.getInstance().getPTPCommandCooldown(); + int ptpCooldown = mcMMO.p.getGeneralConfig().getPTPCommandCooldown(); long ptpLastUse = mcMMOPlayer.getPartyTeleportRecord().getLastUse(); if (ptpCooldown > 0) { @@ -165,7 +164,7 @@ public class PtpCommand implements TabExecutor { Player target = mcMMOTarget.getPlayer(); - if (Config.getInstance().getPTPCommandWorldPermissions()) { + if (mcMMO.p.getGeneralConfig().getPTPCommandWorldPermissions()) { World targetWorld = target.getWorld(); World playerWorld = player.getWorld(); @@ -194,7 +193,7 @@ public class PtpCommand implements TabExecutor { player.sendMessage(LocaleLoader.getString("Commands.Invite.Success")); target.sendMessage(LocaleLoader.getString("Commands.ptp.Request1", player.getName())); - target.sendMessage(LocaleLoader.getString("Commands.ptp.Request2", Config.getInstance().getPTPCommandTimeout())); + target.sendMessage(LocaleLoader.getString("Commands.ptp.Request2", mcMMO.p.getGeneralConfig().getPTPCommandTimeout())); } protected static boolean canTeleport(CommandSender sender, Player player, String targetName) { @@ -245,7 +244,7 @@ public class PtpCommand implements TabExecutor { McMMOPlayer mcMMOPlayer = UserManager.getPlayer(teleportingPlayer); McMMOPlayer mcMMOTarget = UserManager.getPlayer(targetPlayer); - long warmup = Config.getInstance().getPTPCommandWarmup(); + long warmup = mcMMO.p.getGeneralConfig().getPTPCommandWarmup(); mcMMOPlayer.actualizeTeleportCommenceLocation(teleportingPlayer); 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 a65004417..5779147ea 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java @@ -1,6 +1,5 @@ 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; @@ -36,12 +35,12 @@ public class InspectCommand implements TabExecutor { return true; } - if (Config.getInstance().getScoreboardsEnabled() + if (mcMMO.p.getGeneralConfig().getScoreboardsEnabled() && sender instanceof Player - && Config.getInstance().getInspectUseBoard()) { + && mcMMO.p.getGeneralConfig().getInspectUseBoard()) { ScoreboardManager.enablePlayerInspectScoreboard((Player) sender, profile); - if (!Config.getInstance().getInspectUseChat()) { + if (!mcMMO.p.getGeneralConfig().getInspectUseChat()) { return true; } } @@ -49,17 +48,17 @@ public class InspectCommand implements TabExecutor { sender.sendMessage(LocaleLoader.getString("Inspect.OfflineStats", playerName)); sender.sendMessage(LocaleLoader.getString("Stats.Header.Gathering")); - for (PrimarySkillType skill : PrimarySkillType.GATHERING_SKILLS) { + for (PrimarySkillType skill : mcMMO.p.getSkillTools().GATHERING_SKILLS) { sender.sendMessage(CommandUtils.displaySkill(profile, skill)); } sender.sendMessage(LocaleLoader.getString("Stats.Header.Combat")); - for (PrimarySkillType skill : PrimarySkillType.COMBAT_SKILLS) { + for (PrimarySkillType skill : mcMMO.p.getSkillTools().COMBAT_SKILLS) { sender.sendMessage(CommandUtils.displaySkill(profile, skill)); } sender.sendMessage(LocaleLoader.getString("Stats.Header.Misc")); - for (PrimarySkillType skill : PrimarySkillType.MISC_SKILLS) { + for (PrimarySkillType skill : mcMMO.p.getSkillTools().MISC_SKILLS) { sender.sendMessage(CommandUtils.displaySkill(profile, skill)); } @@ -76,12 +75,12 @@ public class InspectCommand implements TabExecutor { return true; } - if (Config.getInstance().getScoreboardsEnabled() + if (mcMMO.p.getGeneralConfig().getScoreboardsEnabled() && sender instanceof Player - && Config.getInstance().getInspectUseBoard()) { + && mcMMO.p.getGeneralConfig().getInspectUseBoard()) { ScoreboardManager.enablePlayerInspectScoreboard((Player) sender, mcMMOPlayer); - if (!Config.getInstance().getInspectUseChat()) { + if (!mcMMO.p.getGeneralConfig().getInspectUseChat()) { return true; } } diff --git a/src/main/java/com/gmail/nossr50/commands/player/MccooldownCommand.java b/src/main/java/com/gmail/nossr50/commands/player/MccooldownCommand.java index 74011a39c..4475c984a 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/MccooldownCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/MccooldownCommand.java @@ -1,9 +1,9 @@ package com.gmail.nossr50.commands.player; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; @@ -30,10 +30,10 @@ public class MccooldownCommand implements TabExecutor { if (args.length == 0) { Player player = (Player) sender; - if (Config.getInstance().getScoreboardsEnabled() && Config.getInstance().getCooldownUseBoard()) { + if (mcMMO.p.getGeneralConfig().getScoreboardsEnabled() && mcMMO.p.getGeneralConfig().getCooldownUseBoard()) { ScoreboardManager.enablePlayerCooldownScoreboard(player); - if (!Config.getInstance().getCooldownUseChat()) { + if (!mcMMO.p.getGeneralConfig().getCooldownUseChat()) { return true; } } diff --git a/src/main/java/com/gmail/nossr50/commands/player/McrankCommand.java b/src/main/java/com/gmail/nossr50/commands/player/McrankCommand.java index 5a781cdfb..4958cbc54 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/McrankCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/McrankCommand.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.commands.player; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; @@ -91,7 +90,7 @@ public class McrankCommand implements TabExecutor { return; } - long cooldownMillis = Math.min(Config.getInstance().getDatabasePlayerCooldown(), 1750); + long cooldownMillis = Math.min(mcMMO.p.getGeneralConfig().getDatabasePlayerCooldown(), 1750); if (mcMMOPlayer.getDatabaseATS() + cooldownMillis > System.currentTimeMillis()) { sender.sendMessage(LocaleLoader.getString("Commands.Database.CooldownMS", getCDSeconds(mcMMOPlayer, cooldownMillis))); @@ -108,8 +107,8 @@ public class McrankCommand implements TabExecutor { mcMMOPlayer.actualizeDatabaseATS(); } - boolean useBoard = Config.getInstance().getScoreboardsEnabled() && (sender instanceof Player) && (Config.getInstance().getRankUseBoard()); - boolean useChat = !useBoard || Config.getInstance().getRankUseChat(); + boolean useBoard = mcMMO.p.getGeneralConfig().getScoreboardsEnabled() && (sender instanceof Player) && (mcMMO.p.getGeneralConfig().getRankUseBoard()); + boolean useChat = !useBoard || mcMMO.p.getGeneralConfig().getRankUseChat(); new McrankCommandAsyncTask(playerName, sender, useBoard, useChat).runTaskAsynchronously(mcMMO.p); } diff --git a/src/main/java/com/gmail/nossr50/commands/player/McstatsCommand.java b/src/main/java/com/gmail/nossr50/commands/player/McstatsCommand.java index 87025fac5..a9e8cf6e1 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/McstatsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/McstatsCommand.java @@ -1,7 +1,7 @@ package com.gmail.nossr50.commands.player; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; @@ -33,10 +33,10 @@ public class McstatsCommand implements TabExecutor { Player player = (Player) sender; - if (Config.getInstance().getStatsUseBoard() && Config.getInstance().getScoreboardsEnabled()) { + if (mcMMO.p.getGeneralConfig().getStatsUseBoard() && mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { ScoreboardManager.enablePlayerStatsScoreboard(player); - if (!Config.getInstance().getStatsUseChat()) { + if (!mcMMO.p.getGeneralConfig().getStatsUseChat()) { return true; } } @@ -48,7 +48,7 @@ public class McstatsCommand implements TabExecutor { CommandUtils.printCombatSkills(player); CommandUtils.printMiscSkills(player); - int powerLevelCap = Config.getInstance().getPowerLevelCap(); + int powerLevelCap = mcMMO.p.getGeneralConfig().getPowerLevelCap(); if (powerLevelCap != Integer.MAX_VALUE) { player.sendMessage(LocaleLoader.getString("Commands.PowerLevel.Capped", UserManager.getPlayer(player).getPowerLevel(), powerLevelCap)); diff --git a/src/main/java/com/gmail/nossr50/commands/player/MctopCommand.java b/src/main/java/com/gmail/nossr50/commands/player/MctopCommand.java index 63ed2726e..04f0f82e1 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/MctopCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/MctopCommand.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.commands.player; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; @@ -69,7 +68,7 @@ public class MctopCommand implements TabExecutor { @Override public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { if (args.length == 1) { - return StringUtil.copyPartialMatches(args[0], PrimarySkillType.SKILL_NAMES, new ArrayList<>(PrimarySkillType.SKILL_NAMES.size())); + return StringUtil.copyPartialMatches(args[0], mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES, new ArrayList<>(mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES.size())); } return ImmutableList.of(); } @@ -86,7 +85,7 @@ public class MctopCommand implements TabExecutor { } McMMOPlayer mcMMOPlayer = UserManager.getPlayer(sender.getName()); - long cooldownMillis = Math.max(Config.getInstance().getDatabasePlayerCooldown(), 1750); + long cooldownMillis = Math.max(mcMMO.p.getGeneralConfig().getDatabasePlayerCooldown(), 1750); if (mcMMOPlayer.getDatabaseATS() + cooldownMillis > System.currentTimeMillis()) { double seconds = ((mcMMOPlayer.getDatabaseATS() + cooldownMillis) - System.currentTimeMillis()) / 1000.0D; @@ -112,8 +111,8 @@ public class MctopCommand implements TabExecutor { } private void display(int page, PrimarySkillType skill, CommandSender sender) { - boolean useBoard = (sender instanceof Player) && (Config.getInstance().getTopUseBoard()); - boolean useChat = !useBoard || Config.getInstance().getTopUseChat(); + boolean useBoard = (sender instanceof Player) && (mcMMO.p.getGeneralConfig().getTopUseBoard()); + boolean useChat = !useBoard || mcMMO.p.getGeneralConfig().getTopUseChat(); new MctopCommandAsyncTask(page, skill, sender, useBoard, useChat).runTaskAsynchronously(mcMMO.p); } @@ -123,7 +122,7 @@ public class MctopCommand implements TabExecutor { return null; } - PrimarySkillType skill = PrimarySkillType.getSkill(skillName); + PrimarySkillType skill = mcMMO.p.getSkillTools().matchSkill(skillName); if (CommandUtils.isChildSkill(sender, skill)) { return null; diff --git a/src/main/java/com/gmail/nossr50/commands/player/XPBarCommand.java b/src/main/java/com/gmail/nossr50/commands/player/XPBarCommand.java index ad24c60da..e780fa19d 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/XPBarCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/XPBarCommand.java @@ -2,6 +2,7 @@ package com.gmail.nossr50.commands.player; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.experience.ExperienceBarManager; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; @@ -51,7 +52,7 @@ public class XPBarCommand implements TabExecutor { if(SkillUtils.isSkill(skillName)) { - PrimarySkillType targetSkill = PrimarySkillType.getSkill(skillName); + PrimarySkillType targetSkill = mcMMO.p.getSkillTools().matchSkill(skillName); //Target setting String option = args[0].toLowerCase(); @@ -103,7 +104,7 @@ public class XPBarCommand implements TabExecutor { return StringUtil.copyPartialMatches(args[0], options, new ArrayList<>(ExperienceBarManager.XPBarSettingTarget.values().length)); case 2: if(!args[0].equalsIgnoreCase(ExperienceBarManager.XPBarSettingTarget.RESET.toString())) - return StringUtil.copyPartialMatches(args[1], PrimarySkillType.SKILL_NAMES, new ArrayList<>(PrimarySkillType.SKILL_NAMES.size())); + return StringUtil.copyPartialMatches(args[1], mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES, new ArrayList<>(mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES.size())); default: return ImmutableList.of(); } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java index 9b6e8ea2f..bb963168f 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java @@ -69,7 +69,7 @@ public class AcrobaticsCommand extends SkillCommand { //Chance Stat Calculations rollChance = RandomChanceUtil.getRandomChanceExecutionChance(roll_rcs); graceChance = RandomChanceUtil.getRandomChanceExecutionChance(grace_rcs); - //damageThreshold = AdvancedConfig.getInstance().getRollDamageThreshold(); + //damageThreshold = mcMMO.p.getAdvancedConfig().getRollDamageThreshold(); String[] rollStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.ACROBATICS_ROLL); diff --git a/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java index 3d4693b77..871d0066f 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java @@ -3,6 +3,7 @@ package com.gmail.nossr50.commands.skills; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillActivationType; @@ -93,7 +94,7 @@ public class HerbalismCommand extends SkillCommand { canGreenThumbPlants = RankUtils.hasUnlockedSubskill(player, SubSkillType.HERBALISM_GREEN_THUMB) && (Permissions.greenThumbPlant(player, Material.WHEAT) || Permissions.greenThumbPlant(player, Material.CARROT) || Permissions.greenThumbPlant(player, Material.POTATO) || Permissions.greenThumbPlant(player, Material.BEETROOT) || Permissions.greenThumbPlant(player, Material.NETHER_WART) || Permissions.greenThumbPlant(player, Material.COCOA)); canGreenThumbBlocks = RankUtils.hasUnlockedSubskill(player, SubSkillType.HERBALISM_GREEN_THUMB) && (Permissions.greenThumbBlock(player, Material.DIRT) || Permissions.greenThumbBlock(player, Material.COBBLESTONE) || Permissions.greenThumbBlock(player, Material.COBBLESTONE_WALL) || Permissions.greenThumbBlock(player, Material.STONE_BRICKS)); canFarmersDiet = canUseSubskill(player, SubSkillType.HERBALISM_FARMERS_DIET); - canDoubleDrop = canUseSubskill(player, SubSkillType.HERBALISM_DOUBLE_DROPS) && !skill.getDoubleDropsDisabled(); + canDoubleDrop = canUseSubskill(player, SubSkillType.HERBALISM_DOUBLE_DROPS) && !mcMMO.p.getGeneralConfig().getDoubleDropsDisabled(skill); canShroomThumb = canUseSubskill(player, SubSkillType.HERBALISM_SHROOM_THUMB); } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java index e724ee8cd..d3090f46b 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java @@ -1,9 +1,9 @@ package com.gmail.nossr50.commands.skills; -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.listeners.InteractionManager; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.text.TextComponentFactory; import com.google.common.collect.ImmutableList; @@ -45,7 +45,7 @@ public class MmoInfoCommand implements TabExecutor { player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.DetailsHeader")); player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.Mystery")); return true; - } else if(InteractionManager.getAbstractByName(args[0]) != null || PrimarySkillType.SUBSKILL_NAMES.contains(args[0])) + } else if(InteractionManager.getAbstractByName(args[0]) != null || mcMMO.p.getSkillTools().EXACT_SUBSKILL_NAMES.contains(args[0])) { displayInfo(player, args[0]); return true; @@ -63,7 +63,7 @@ public class MmoInfoCommand implements TabExecutor { @Override public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { if (args.length == 1) { - return StringUtil.copyPartialMatches(args[0], PrimarySkillType.SUBSKILL_NAMES, new ArrayList<>(PrimarySkillType.SUBSKILL_NAMES.size())); + return StringUtil.copyPartialMatches(args[0], mcMMO.p.getSkillTools().EXACT_SUBSKILL_NAMES, new ArrayList<>(mcMMO.p.getSkillTools().EXACT_SUBSKILL_NAMES.size())); } return ImmutableList.of(); } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java index e550913fa..6e2926062 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java @@ -1,11 +1,10 @@ package com.gmail.nossr50.commands.skills; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.child.FamilyTree; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.commands.CommandUtils; @@ -16,6 +15,7 @@ import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.gmail.nossr50.util.skills.PerksUtils; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillActivationType; +import com.gmail.nossr50.util.skills.SkillTools; import com.gmail.nossr50.util.text.StringUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import com.google.common.collect.ImmutableList; @@ -45,7 +45,7 @@ public abstract class SkillCommand implements TabExecutor { public SkillCommand(PrimarySkillType skill) { this.skill = skill; - skillName = skill.getName(); + skillName = mcMMO.p.getSkillTools().getLocalizedSkillName(skill); skillGuideCommand = new SkillGuideCommand(skill); } @@ -74,7 +74,7 @@ public abstract class SkillCommand implements TabExecutor { float skillValue = mcMMOPlayer.getSkillLevel(skill); //Send the players a few blank lines to make finding the top of the skill command easier - if (AdvancedConfig.getInstance().doesSkillCommandSendBlankLines()) + if (mcMMO.p.getAdvancedConfig().doesSkillCommandSendBlankLines()) for (int i = 0; i < 2; i++) { player.sendMessage(""); } @@ -106,13 +106,13 @@ public abstract class SkillCommand implements TabExecutor { //Link Header - if (Config.getInstance().getUrlLinksEnabled()) { + if (mcMMO.p.getGeneralConfig().getUrlLinksEnabled()) { player.sendMessage(LocaleLoader.getString("Overhaul.mcMMO.Header")); TextComponentFactory.sendPlayerUrlHeader(player); } - if (Config.getInstance().getScoreboardsEnabled() && Config.getInstance().getSkillUseBoard()) { + if (mcMMO.p.getGeneralConfig().getScoreboardsEnabled() && mcMMO.p.getGeneralConfig().getSkillUseBoard()) { ScoreboardManager.enablePlayerSkillScoreboard(player, skill); } @@ -143,7 +143,7 @@ public abstract class SkillCommand implements TabExecutor { player.sendMessage(LocaleLoader.getString("Skills.Overhaul.Header", skillName)); - if(!skill.isChildSkill()) + if(!SkillTools.isChildSkill(skill)) { /* * NON-CHILD SKILLS @@ -173,10 +173,10 @@ public abstract class SkillCommand implements TabExecutor { { if(i+1 < parentList.size()) { - parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", parentList.get(i).getName(), mcMMOPlayer.getSkillLevel(parentList.get(i)))); + parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", mcMMO.p.getSkillTools().getLocalizedSkillName(parentList.get(i)), mcMMOPlayer.getSkillLevel(parentList.get(i)))); parentMessage.append(ChatColor.GRAY).append(", "); } else { - parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", parentList.get(i).getName(), mcMMOPlayer.getSkillLevel(parentList.get(i)))); + parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", mcMMO.p.getSkillTools().getLocalizedSkillName(parentList.get(i)), mcMMOPlayer.getSkillLevel(parentList.get(i)))); } } @@ -189,7 +189,7 @@ public abstract class SkillCommand implements TabExecutor { } /* - if (!skill.isChildSkill()) { + if (!SkillTools.isChildSkill(skill)) { player.sendMessage(LocaleLoader.getString("Skills.Header", skillName)); player.sendMessage(LocaleLoader.getString("Commands.XPGain", LocaleLoader.getString("Commands.XPGain." + StringUtils.getCapitalized(skill.toString())))); player.sendMessage(LocaleLoader.getString("Effects.Level", skillValue, mcMMOPlayer.getSkillXpLevel(skill), mcMMOPlayer.getXpToLevel(skill))); @@ -225,9 +225,9 @@ public abstract class SkillCommand implements TabExecutor { } protected String[] calculateLengthDisplayValues(Player player, float skillValue) { - int maxLength = skill.getAbility().getMaxLength(); - int abilityLengthVar = AdvancedConfig.getInstance().getAbilityLength(); - int abilityLengthCap = AdvancedConfig.getInstance().getAbilityLengthCap(); + int maxLength = mcMMO.p.getSkillTools().getSuperAbilityMaxLength(mcMMO.p.getSkillTools().getSuperAbility(skill)); + int abilityLengthVar = mcMMO.p.getAdvancedConfig().getAbilityLength(); + int abilityLengthCap = mcMMO.p.getAdvancedConfig().getAbilityLengthCap(); int length; @@ -268,7 +268,7 @@ public abstract class SkillCommand implements TabExecutor { } protected String getLimitBreakDescriptionParameter() { - if(AdvancedConfig.getInstance().canApplyLimitBreakPVE()) { + if(mcMMO.p.getAdvancedConfig().canApplyLimitBreakPVE()) { return "(PVP/PVE)"; } else { return "(PVP)"; diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SkillGuideCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SkillGuideCommand.java index a7879bb8d..ed471f188 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillGuideCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SkillGuideCommand.java @@ -2,6 +2,7 @@ package com.gmail.nossr50.commands.skills; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.text.StringUtils; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -18,7 +19,7 @@ public class SkillGuideCommand implements CommandExecutor { private final String invalidPage = LocaleLoader.getString("Guides.Page.Invalid"); public SkillGuideCommand(PrimarySkillType skill) { - header = LocaleLoader.getString("Guides.Header", skill.getName()); + header = LocaleLoader.getString("Guides.Header", mcMMO.p.getSkillTools().getLocalizedSkillName(skill)); guide = getGuide(skill); } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java index 69a5e86ec..83e0264c0 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java @@ -1,9 +1,9 @@ package com.gmail.nossr50.commands.skills; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.CombatUtils; @@ -46,17 +46,17 @@ public class SwordsCommand extends SkillCommand { // SWORDS_RUPTURE if (canRupture) { int ruptureRank = RankUtils.getRank(player, SubSkillType.SWORDS_RUPTURE); - ruptureLengthSecondsAgainstPlayers = String.valueOf(AdvancedConfig.getInstance().getRuptureDurationSeconds(true)); - ruptureLengthSecondsAgainstMobs = String.valueOf(AdvancedConfig.getInstance().getRuptureDurationSeconds(false)); + ruptureLengthSecondsAgainstPlayers = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureDurationSeconds(true)); + ruptureLengthSecondsAgainstMobs = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureDurationSeconds(false)); - rupturePureTickDamageAgainstPlayers = String.valueOf(AdvancedConfig.getInstance().getRuptureTickDamage(true, ruptureRank)); - rupturePureTickDamageAgainstMobs = String.valueOf(AdvancedConfig.getInstance().getRuptureTickDamage(false, ruptureRank)); + rupturePureTickDamageAgainstPlayers = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureTickDamage(true, ruptureRank)); + rupturePureTickDamageAgainstMobs = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureTickDamage(false, ruptureRank)); - ruptureExplosionDamageAgainstPlayers = String.valueOf(AdvancedConfig.getInstance().getRuptureExplosionDamage(true, ruptureRank)); - ruptureExplosionDamageAgainstMobs = String.valueOf(AdvancedConfig.getInstance().getRuptureExplosionDamage(false, ruptureRank)); + ruptureExplosionDamageAgainstPlayers = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureExplosionDamage(true, ruptureRank)); + ruptureExplosionDamageAgainstMobs = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureExplosionDamage(false, ruptureRank)); - ruptureChanceToApply = String.valueOf(AdvancedConfig.getInstance().getRuptureChanceToApplyOnHit(ruptureRank) + "%"); - ruptureChanceToApplyLucky = String.valueOf(AdvancedConfig.getInstance().getRuptureChanceToApplyOnHit(ruptureRank) * 1.33); + ruptureChanceToApply = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(ruptureRank) + "%"); + ruptureChanceToApplyLucky = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(ruptureRank) * 1.33); } // SERRATED STRIKES diff --git a/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java index a817a312d..08639c27b 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java @@ -3,6 +3,7 @@ package com.gmail.nossr50.commands.skills; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillActivationType; @@ -55,7 +56,9 @@ public class WoodcuttingCommand extends SkillCommand { @Override protected void permissionsCheck(Player player) { canTreeFell = RankUtils.hasUnlockedSubskill(player, SubSkillType.WOODCUTTING_TREE_FELLER) && Permissions.treeFeller(player); - canDoubleDrop = canUseSubskill(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) && !skill.getDoubleDropsDisabled() && RankUtils.getRank(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) >= 1; + canDoubleDrop = canUseSubskill(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) + && !mcMMO.p.getGeneralConfig().getDoubleDropsDisabled(skill) + && RankUtils.getRank(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) >= 1; canLeafBlow = canUseSubskill(player, SubSkillType.WOODCUTTING_LEAF_BLOWER); canKnockOnWood = canTreeFell && canUseSubskill(player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD); /*canSplinter = canUseSubskill(player, SubSkillType.WOODCUTTING_SPLINTER); diff --git a/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java b/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java index 7781ade98..fd0cd85e8 100644 --- a/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java +++ b/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java @@ -6,25 +6,17 @@ import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.mcMMO; import net.md_5.bungee.api.ChatColor; +import java.io.File; import java.util.ArrayList; import java.util.List; public class AdvancedConfig extends AutoUpdateConfigLoader { - private static AdvancedConfig instance; - private AdvancedConfig() { - super("advanced.yml"); + public AdvancedConfig(File dataFolder) { + super("advanced.yml", dataFolder); validate(); } - public static AdvancedConfig getInstance() { - if (instance == null) { - instance = new AdvancedConfig(); - } - - return instance; - } - @Override protected boolean validateKeys() { // Validate all the settings! @@ -68,15 +60,6 @@ public class AdvancedConfig extends AutoUpdateConfigLoader { reason.add("Skills.Acrobatics.GracefulRoll.DamageThreshold should be at least 0!"); } - /* ALCHEMY */ - /*if (getCatalysisUnlockLevel() < 0) { - reason.add("Skills.Alchemy.Catalysis.UnlockLevel should be at least 0!"); - } - - if (getCatalysisMaxBonusLevel() <= getCatalysisUnlockLevel()) { - reason.add("Skills.Alchemy.Catalysis.MaxBonusLevel should be greater than Skills.Alchemy.Catalysis.UnlockLevel!"); - }*/ - if (getCatalysisMinSpeed() <= 0) { reason.add("Skills.Alchemy.Catalysis.MinSpeed must be greater than 0!"); } @@ -85,21 +68,6 @@ public class AdvancedConfig extends AutoUpdateConfigLoader { reason.add("Skills.Alchemy.Catalysis.MaxSpeed should be at least Skills.Alchemy.Catalysis.MinSpeed!"); } - /*List alchemyTierList = Arrays.asList(Alchemy.Tier.values()); - for (Alchemy.Tier tier : alchemyTierList) { - if (getConcoctionsTierLevel(tier) < 0) { - reason.add("Skills.Alchemy.Rank_Levels.Rank_" + rank + " should be at least 0!"); - } - - if (tier != Alchemy.Tier.fromNumerical(Alchemy.Tier.values().length)) { - Alchemy.Tier nextTier = alchemyTierList.get(alchemyTierList.indexOf(tier) - 1); - - if (getConcoctionsTierLevel(tier) > getConcoctionsTierLevel(nextTier)) { - reason.add("Skills.Alchemy.Rank_Levels.Rank_" + rank + " should be less than or equal to Skills.Alchemy.Rank_Levels.Rank_" + nextrank + "!"); - } - } - }*/ - /* ARCHERY */ if (getSkillShotRankDamageMultiplier() <= 0) { diff --git a/src/main/java/com/gmail/nossr50/config/AutoUpdateConfigLoader.java b/src/main/java/com/gmail/nossr50/config/AutoUpdateConfigLoader.java index 831dcf144..f2c936a56 100644 --- a/src/main/java/com/gmail/nossr50/config/AutoUpdateConfigLoader.java +++ b/src/main/java/com/gmail/nossr50/config/AutoUpdateConfigLoader.java @@ -1,5 +1,6 @@ package com.gmail.nossr50.config; +import com.gmail.nossr50.mcMMO; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.jetbrains.annotations.NotNull; @@ -11,17 +12,27 @@ import java.util.LinkedHashMap; import java.util.Set; public abstract class AutoUpdateConfigLoader extends ConfigLoader { + public AutoUpdateConfigLoader(String relativePath, String fileName, File dataFolder) { + super(relativePath, fileName, dataFolder); + } + + public AutoUpdateConfigLoader(String fileName, File dataFolder) { + super(fileName, dataFolder); + } + + @Deprecated public AutoUpdateConfigLoader(String relativePath, String fileName) { super(relativePath, fileName); } + @Deprecated public AutoUpdateConfigLoader(String fileName) { super(fileName); } protected void saveConfig() { try { - plugin.getLogger().info("Saving changes to config file - "+fileName); + mcMMO.p.getLogger().info("Saving changes to config file - "+fileName); config.save(configFile); } catch (IOException e) { e.printStackTrace(); @@ -29,13 +40,13 @@ public abstract class AutoUpdateConfigLoader extends ConfigLoader { } protected @NotNull FileConfiguration getInternalConfig() { - return YamlConfiguration.loadConfiguration(plugin.getResourceAsReader(fileName)); + return YamlConfiguration.loadConfiguration(mcMMO.p.getResourceAsReader(fileName)); } @Override protected void loadFile() { super.loadFile(); - FileConfiguration internalConfig = YamlConfiguration.loadConfiguration(plugin.getResourceAsReader(fileName)); + FileConfiguration internalConfig = YamlConfiguration.loadConfiguration(mcMMO.p.getResourceAsReader(fileName)); Set configKeys = config.getKeys(true); Set internalConfigKeys = internalConfig.getKeys(true); @@ -55,12 +66,12 @@ public abstract class AutoUpdateConfigLoader extends ConfigLoader { } // // for (String key : oldKeys) { -// plugin.debug("Detected potentially unused key: " + key); +// mcMMO.p.debug("Detected potentially unused key: " + key); // //config.set(key, null); // } for (String key : newKeys) { - plugin.debug("Adding new key: " + key + " = " + internalConfig.get(key)); + mcMMO.p.debug("Adding new key: " + key + " = " + internalConfig.get(key)); config.set(key, internalConfig.get(key)); } @@ -79,7 +90,7 @@ public abstract class AutoUpdateConfigLoader extends ConfigLoader { // Read the internal config to get comments, then put them in the new one try { // Read internal - BufferedReader reader = new BufferedReader(new InputStreamReader(plugin.getResource(fileName))); + BufferedReader reader = new BufferedReader(new InputStreamReader(mcMMO.p.getResource(fileName))); LinkedHashMap comments = new LinkedHashMap<>(); StringBuilder temp = new StringBuilder(); @@ -129,14 +140,21 @@ public abstract class AutoUpdateConfigLoader extends ConfigLoader { } // Save it + if(dataFolder == null) { + mcMMO.p.getLogger().severe("Data folder should never be null!"); + return; + } + try { String saveName = fileName; // At this stage we cannot guarantee that Config has been loaded, so we do the check directly here - if (!plugin.getConfig().getBoolean("General.Config_Update_Overwrite", true)) { + if (!mcMMO.p.getConfig().getBoolean("General.Config_Update_Overwrite", true)) { saveName += ".new"; } - BufferedWriter writer = new BufferedWriter(new FileWriter(new File(plugin.getDataFolder(), saveName))); + File newSaveFile = new File(dataFolder, saveName); + FileWriter fileWriter = new FileWriter(newSaveFile.getAbsolutePath()); + BufferedWriter writer = new BufferedWriter(fileWriter); writer.write(output); writer.flush(); writer.close(); diff --git a/src/main/java/com/gmail/nossr50/config/ConfigLoader.java b/src/main/java/com/gmail/nossr50/config/ConfigLoader.java index 7fb7f19d1..a1c75058d 100644 --- a/src/main/java/com/gmail/nossr50/config/ConfigLoader.java +++ b/src/main/java/com/gmail/nossr50/config/ConfigLoader.java @@ -3,41 +3,60 @@ package com.gmail.nossr50.config; import com.gmail.nossr50.mcMMO; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; +import org.jetbrains.annotations.NotNull; import java.io.File; import java.util.List; public abstract class ConfigLoader { - protected static final mcMMO plugin = mcMMO.p; protected String fileName; protected final File configFile; protected FileConfiguration config; + protected @NotNull final File dataFolder; - public ConfigLoader(String relativePath, String fileName) { + public ConfigLoader(String relativePath, String fileName, @NotNull File dataFolder) { this.fileName = fileName; - configFile = new File(plugin.getDataFolder(), relativePath + File.separator + fileName); + this.dataFolder = dataFolder; + configFile = new File(dataFolder, relativePath + File.separator + fileName); loadFile(); } + public ConfigLoader(String fileName, @NotNull File dataFolder) { + this.fileName = fileName; + this.dataFolder = dataFolder; + configFile = new File(dataFolder, fileName); + loadFile(); + } + + @Deprecated + public ConfigLoader(String relativePath, String fileName) { + this.fileName = fileName; + configFile = new File(mcMMO.p.getDataFolder(), relativePath + File.separator + fileName); + this.dataFolder = mcMMO.p.getDataFolder(); + loadFile(); + } + + @Deprecated public ConfigLoader(String fileName) { this.fileName = fileName; - configFile = new File(plugin.getDataFolder(), fileName); + configFile = new File(mcMMO.p.getDataFolder(), fileName); + this.dataFolder = mcMMO.p.getDataFolder(); loadFile(); } protected void loadFile() { if (!configFile.exists()) { - plugin.debug("Creating mcMMO " + fileName + " File..."); + mcMMO.p.debug("Creating mcMMO " + fileName + " File..."); try { - plugin.saveResource(fileName, false); // Normal files + mcMMO.p.saveResource(fileName, false); // Normal files } catch (IllegalArgumentException ex) { - plugin.saveResource(configFile.getParentFile().getName() + File.separator + fileName, false); // Mod files + mcMMO.p.saveResource(configFile.getParentFile().getName() + File.separator + fileName, false); // Mod files } } else { - plugin.debug("Loading mcMMO " + fileName + " File..."); + mcMMO.p.debug("Loading mcMMO " + fileName + " File..."); } config = YamlConfiguration.loadConfiguration(configFile); @@ -51,7 +70,7 @@ public abstract class ConfigLoader { protected boolean noErrorsInConfig(List issues) { for (String issue : issues) { - plugin.getLogger().warning(issue); + mcMMO.p.getLogger().warning(issue); } return issues.isEmpty(); @@ -59,12 +78,12 @@ public abstract class ConfigLoader { protected void validate() { if (validateKeys()) { - plugin.debug("No errors found in " + fileName + "!"); + mcMMO.p.debug("No errors found in " + fileName + "!"); } else { - plugin.getLogger().warning("Errors were found in " + fileName + "! mcMMO was disabled!"); - plugin.getServer().getPluginManager().disablePlugin(plugin); - plugin.noErrorsInConfigFiles = false; + mcMMO.p.getLogger().warning("Errors were found in " + fileName + "! mcMMO was disabled!"); + mcMMO.p.getServer().getPluginManager().disablePlugin(mcMMO.p); + mcMMO.p.noErrorsInConfigFiles = false; } } @@ -73,16 +92,16 @@ public abstract class ConfigLoader { } public void backup() { - plugin.getLogger().warning("You are using an old version of the " + fileName + " file."); - plugin.getLogger().warning("Your old file has been renamed to " + fileName + ".old and has been replaced by an updated version."); + mcMMO.p.getLogger().warning("You are using an old version of the " + fileName + " file."); + mcMMO.p.getLogger().warning("Your old file has been renamed to " + fileName + ".old and has been replaced by an updated version."); configFile.renameTo(new File(configFile.getPath() + ".old")); - if (plugin.getResource(fileName) != null) { - plugin.saveResource(fileName, true); + if (mcMMO.p.getResource(fileName) != null) { + mcMMO.p.saveResource(fileName, true); } - plugin.getLogger().warning("Reloading " + fileName + " with new values..."); + mcMMO.p.getLogger().warning("Reloading " + fileName + " with new values..."); loadFile(); loadKeys(); } diff --git a/src/main/java/com/gmail/nossr50/config/Config.java b/src/main/java/com/gmail/nossr50/config/GeneralConfig.java similarity index 89% rename from src/main/java/com/gmail/nossr50/config/Config.java rename to src/main/java/com/gmail/nossr50/config/GeneralConfig.java index 581fb4a82..fa68fe5b2 100644 --- a/src/main/java/com/gmail/nossr50/config/Config.java +++ b/src/main/java/com/gmail/nossr50/config/GeneralConfig.java @@ -12,27 +12,19 @@ import org.bukkit.configuration.ConfigurationSection; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Set; -public class Config extends AutoUpdateConfigLoader { - private static Config instance; +public class GeneralConfig extends AutoUpdateConfigLoader { - private Config() { - super("config.yml"); + public GeneralConfig(@NotNull File dataFolder) { + super("config.yml", dataFolder); validate(); } - public static Config getInstance() { - if (instance == null) { - instance = new Config(); - } - - return instance; - } - @Override protected void loadKeys() { @@ -63,47 +55,6 @@ public class Config extends AutoUpdateConfigLoader { reason.add("Mob_Healthbar.Display_Time cannot be 0! Set to -1 to disable or set a valid value."); } - /* Scoreboards */ - /*if (getRankScoreboardTime() != -1 && getRankScoreboardTime() <= 0) { - reason.add("Scoreboard.Types.Rank.Display_Time should be greater than 0, or -1!"); - } - - if (getStatsScoreboardTime() != -1 && getStatsScoreboardTime() <= 0) { - reason.add("Scoreboard.Types.Stats.Display_Time should be greater than 0, or -1!"); - } - - if (getTopScoreboardTime() != -1 && getTopScoreboardTime() <= 0) { - reason.add("Scoreboard.Types.Top.Display_Time should be greater than 0, or -1!"); - } - - if (getInspectScoreboardTime() != -1 && getInspectScoreboardTime() <= 0) { - reason.add("Scoreboard.Types.Inspect.Display_Time should be greater than 0, or -1!"); - } - - if (getSkillScoreboardTime() != -1 && getSkillScoreboardTime() <= 0) { - reason.add("Scoreboard.Types.Skill.Display_Time should be greater than 0, or -1!"); - } - - if (getSkillLevelUpTime() != -1 && getSkillScoreboardTime() <= 0) { - reason.add("Scoreboard.Types.Skill.Display_Time should be greater than 0, or -1!"); - } - - if (!(getRankUseChat() || getRankUseBoard())) { - reason.add("Either Board or Print in Scoreboard.Types.Rank must be true!"); - } - - if (!(getTopUseChat() || getTopUseBoard())) { - reason.add("Either Board or Print in Scoreboard.Types.Top must be true!"); - } - - if (!(getStatsUseChat() || getStatsUseBoard())) { - reason.add("Either Board or Print in Scoreboard.Types.Stats must be true!"); - } - - if (!(getInspectUseChat() || getInspectUseBoard())) { - reason.add("Either Board or Print in Scoreboard.Types.Inspect must be true!"); - }*/ - /* Database Purging */ if (getPurgeInterval() < -1) { reason.add("Database_Purging.Purge_Interval should be greater than, or equal to -1!"); @@ -200,42 +151,6 @@ public class Config extends AutoUpdateConfigLoader { reason.add("Cannot use the same item for Repair and Salvage anvils!"); } -// if (getTamingCOTWMaterial(EntityType.WOLF) == null) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Item_Material is invalid!!"); -// } -// -// if (getTamingCOTWMaterial(EntityType.OCELOT) == null) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Item_Material is invalid!!"); -// } -// -// if (getTamingCOTWMaterial(EntityType.HORSE) == null) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Item_Material is invalid!!"); -// } -// -// if (getTamingCOTWCost(EntityType.WOLF) <= 0) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Item_Amount should be greater than 0!"); -// } -// -// if (getTamingCOTWCost(EntityType.OCELOT) <= 0) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Item_Amount should be greater than 0!"); -// } -// -// if (getTamingCOTWCost(EntityType.HORSE) <= 0) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Item_Amount should be greater than 0!"); -// } -// -// if (getTamingCOTWAmount(EntityType.WOLF) <= 0) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Summon_Amount should be greater than 0!"); -// } -// -// if (getTamingCOTWAmount(EntityType.OCELOT) <= 0) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Summon_Amount should be greater than 0!"); -// } -// -// if (getTamingCOTWAmount(EntityType.HORSE) <= 0) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Summon_Amount should be greater than 0!"); -// } - return noErrorsInConfig(reason); } @@ -249,7 +164,7 @@ public class Config extends AutoUpdateConfigLoader { //Retro mode will default the value to true if the config file doesn't contain the entry (server is from a previous mcMMO install) public boolean getIsRetroMode() { return config.getBoolean("General.RetroMode.Enabled", true); } - public String getLocale() { return config.getString("General.Locale", "en_us"); } + public String getLocale() { return config.getString("General.Locale", "en_US"); } public boolean getMOTDEnabled() { return config.getBoolean("General.MOTD_Enabled", true); } public boolean getShowProfileLoadedMessage() { return config.getBoolean("General.Show_Profile_Loaded", true); } public boolean getDonateMessageEnabled() { return config.getBoolean("Commands.mcmmo.Donate_Message", true); } diff --git a/src/main/java/com/gmail/nossr50/config/HiddenConfig.java b/src/main/java/com/gmail/nossr50/config/HiddenConfig.java index d4b646fd3..54cdf0ff0 100644 --- a/src/main/java/com/gmail/nossr50/config/HiddenConfig.java +++ b/src/main/java/com/gmail/nossr50/config/HiddenConfig.java @@ -9,7 +9,6 @@ public class HiddenConfig { private static HiddenConfig instance; private final String fileName; private YamlConfiguration config; - private boolean chunkletsEnabled; private int conversionRate; private boolean useEnchantmentBuffs; @@ -30,15 +29,11 @@ public class HiddenConfig { InputStreamReader reader = mcMMO.p.getResourceAsReader(fileName); if (reader != null) { config = YamlConfiguration.loadConfiguration(reader); - chunkletsEnabled = config.getBoolean("Options.Chunklets", true); conversionRate = config.getInt("Options.ConversionRate", 1); useEnchantmentBuffs = config.getBoolean("Options.EnchantmentBuffs", true); } } - public boolean getChunkletsEnabled() { - return chunkletsEnabled; - } public int getConversionRate() { return conversionRate; diff --git a/src/main/java/com/gmail/nossr50/config/PersistentDataConfig.java b/src/main/java/com/gmail/nossr50/config/PersistentDataConfig.java index 10a7adcfc..2f9a23066 100644 --- a/src/main/java/com/gmail/nossr50/config/PersistentDataConfig.java +++ b/src/main/java/com/gmail/nossr50/config/PersistentDataConfig.java @@ -34,4 +34,9 @@ public class PersistentDataConfig extends AutoUpdateConfigLoader { return config.getBoolean(key, false); } + public boolean useBlockTracker() { + return config.getBoolean("mcMMO_Region_System.Enabled", true); + } + + } \ No newline at end of file diff --git a/src/main/java/com/gmail/nossr50/config/RankConfig.java b/src/main/java/com/gmail/nossr50/config/RankConfig.java index 2fa1a353e..d164d64ca 100644 --- a/src/main/java/com/gmail/nossr50/config/RankConfig.java +++ b/src/main/java/com/gmail/nossr50/config/RankConfig.java @@ -2,6 +2,7 @@ package com.gmail.nossr50.config; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; +import com.gmail.nossr50.mcMMO; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -88,7 +89,7 @@ public class RankConfig extends AutoUpdateConfigLoader { * @return the level requirement for a subskill at this particular rank */ private int findRankByRootAddress(int rank, String key) { - String scalingKey = Config.getInstance().getIsRetroMode() ? ".RetroMode." : ".Standard."; + String scalingKey = mcMMO.p.getGeneralConfig().getIsRetroMode() ? ".RetroMode." : ".Standard."; String targetRank = "Rank_" + rank; @@ -126,7 +127,7 @@ public class RankConfig extends AutoUpdateConfigLoader { String key = getRankAddressKey(subSkillType, rank, retroMode); int defaultValue = getInternalConfig().getInt(key); config.set(key, defaultValue); - plugin.getLogger().info(key +" SET -> " + defaultValue); + mcMMO.p.getLogger().info(key +" SET -> " + defaultValue); } /** @@ -144,10 +145,10 @@ public class RankConfig extends AutoUpdateConfigLoader { if(badSkillSetup.isEmpty()) return; - plugin.getLogger().info("(FIXING CONFIG) mcMMO is correcting a few mistakes found in your skill rank config setup"); + mcMMO.p.getLogger().info("(FIXING CONFIG) mcMMO is correcting a few mistakes found in your skill rank config setup"); for(SubSkillType subSkillType : badSkillSetup) { - plugin.getLogger().info("(FIXING CONFIG) Resetting rank config settings for skill named - "+subSkillType.toString()); + mcMMO.p.getLogger().info("(FIXING CONFIG) Resetting rank config settings for skill named - "+subSkillType.toString()); fixBadEntries(subSkillType); } } @@ -179,7 +180,7 @@ public class RankConfig extends AutoUpdateConfigLoader { if(prevRank > curRank) { //We're going to allow this but we're going to warn them - plugin.getLogger().info("(CONFIG ISSUE) You have the ranks for the subskill "+ subSkillType.toString()+" set up poorly, sequential ranks should have ascending requirements"); + mcMMO.p.getLogger().info("(CONFIG ISSUE) You have the ranks for the subskill "+ subSkillType.toString()+" set up poorly, sequential ranks should have ascending requirements"); badSkillSetup.add(subSkillType); } } diff --git a/src/main/java/com/gmail/nossr50/config/SoundConfig.java b/src/main/java/com/gmail/nossr50/config/SoundConfig.java index 734e770aa..61960803d 100644 --- a/src/main/java/com/gmail/nossr50/config/SoundConfig.java +++ b/src/main/java/com/gmail/nossr50/config/SoundConfig.java @@ -1,5 +1,6 @@ package com.gmail.nossr50.config; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.sounds.SoundType; public class SoundConfig extends AutoUpdateConfigLoader { @@ -31,7 +32,7 @@ public class SoundConfig extends AutoUpdateConfigLoader { { if(config.getDouble("Sounds."+soundType.toString()+".Volume") < 0) { - plugin.getLogger().info("[mcMMO] Sound volume cannot be below 0 for "+soundType.toString()); + mcMMO.p.getLogger().info("[mcMMO] Sound volume cannot be below 0 for "+soundType.toString()); return false; } @@ -40,7 +41,7 @@ public class SoundConfig extends AutoUpdateConfigLoader { { if(config.getDouble("Sounds."+soundType.toString()+".Pitch") < 0) { - plugin.getLogger().info("[mcMMO] Sound pitch cannot be below 0 for "+soundType.toString()); + mcMMO.p.getLogger().info("[mcMMO] Sound pitch cannot be below 0 for "+soundType.toString()); return false; } } diff --git a/src/main/java/com/gmail/nossr50/config/mods/CustomArmorConfig.java b/src/main/java/com/gmail/nossr50/config/mods/CustomArmorConfig.java index 76686f82d..94c30580a 100644 --- a/src/main/java/com/gmail/nossr50/config/mods/CustomArmorConfig.java +++ b/src/main/java/com/gmail/nossr50/config/mods/CustomArmorConfig.java @@ -3,6 +3,7 @@ package com.gmail.nossr50.config.mods; import com.gmail.nossr50.config.ConfigLoader; import com.gmail.nossr50.datatypes.skills.ItemType; import com.gmail.nossr50.datatypes.skills.MaterialType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.repair.repairables.Repairable; import com.gmail.nossr50.skills.repair.repairables.RepairableFactory; import org.bukkit.Material; @@ -62,7 +63,7 @@ public class CustomArmorConfig extends ConfigLoader { Material armorMaterial = Material.matchMaterial(armorName); if (armorMaterial == null) { - plugin.getLogger().warning("Invalid material name. This item will be skipped. - " + armorName); + mcMMO.p.getLogger().warning("Invalid material name. This item will be skipped. - " + armorName); continue; } @@ -70,7 +71,7 @@ public class CustomArmorConfig extends ConfigLoader { Material repairMaterial = Material.matchMaterial(config.getString(armorType + "." + armorName + ".Repair_Material", "")); if (repairable && (repairMaterial == null)) { - plugin.getLogger().warning("Incomplete repair information. This item will be unrepairable. - " + armorName); + mcMMO.p.getLogger().warning("Incomplete repair information. This item will be unrepairable. - " + armorName); repairable = false; } diff --git a/src/main/java/com/gmail/nossr50/config/mods/CustomBlockConfig.java b/src/main/java/com/gmail/nossr50/config/mods/CustomBlockConfig.java index 2b30ec0cf..881b483fe 100644 --- a/src/main/java/com/gmail/nossr50/config/mods/CustomBlockConfig.java +++ b/src/main/java/com/gmail/nossr50/config/mods/CustomBlockConfig.java @@ -2,6 +2,7 @@ package com.gmail.nossr50.config.mods; import com.gmail.nossr50.config.ConfigLoader; import com.gmail.nossr50.datatypes.mods.CustomBlock; +import com.gmail.nossr50.mcMMO; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; @@ -66,7 +67,7 @@ public class CustomBlockConfig extends ConfigLoader { Material blockMaterial = Material.matchMaterial(blockInfo[0]); if (blockMaterial == null) { - plugin.getLogger().warning("Invalid material name. This item will be skipped. - " + blockInfo[0]); + mcMMO.p.getLogger().warning("Invalid material name. This item will be skipped. - " + blockInfo[0]); continue; } diff --git a/src/main/java/com/gmail/nossr50/config/mods/CustomEntityConfig.java b/src/main/java/com/gmail/nossr50/config/mods/CustomEntityConfig.java index 549836152..64155043d 100644 --- a/src/main/java/com/gmail/nossr50/config/mods/CustomEntityConfig.java +++ b/src/main/java/com/gmail/nossr50/config/mods/CustomEntityConfig.java @@ -2,6 +2,7 @@ package com.gmail.nossr50.config.mods; import com.gmail.nossr50.config.ConfigLoader; import com.gmail.nossr50.datatypes.mods.CustomEntity; +import com.gmail.nossr50.mcMMO; import org.apache.commons.lang.ClassUtils; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -32,8 +33,8 @@ public class CustomEntityConfig extends ConfigLoader { clazz = ClassUtils.getClass(className); } catch (ClassNotFoundException e) { - plugin.getLogger().warning("Invalid class (" + className + ") detected for " + entityName + "."); - plugin.getLogger().warning("This custom entity may not function properly."); + mcMMO.p.getLogger().warning("Invalid class (" + className + ") detected for " + entityName + "."); + mcMMO.p.getLogger().warning("This custom entity may not function properly."); } String entityTypeName = entityName.replace("_", "."); @@ -48,7 +49,7 @@ public class CustomEntityConfig extends ConfigLoader { int callOfTheWildAmount = config.getInt(entityName + ".COTW_Material_Amount"); if (canBeSummoned && (callOfTheWildMaterial == null || callOfTheWildAmount == 0)) { - plugin.getLogger().warning("Incomplete Call of the Wild information. This entity will not be able to be summoned by Call of the Wild."); + mcMMO.p.getLogger().warning("Incomplete Call of the Wild information. This entity will not be able to be summoned by Call of the Wild."); canBeSummoned = false; } diff --git a/src/main/java/com/gmail/nossr50/config/mods/CustomToolConfig.java b/src/main/java/com/gmail/nossr50/config/mods/CustomToolConfig.java index 104fb3726..28dd85b58 100644 --- a/src/main/java/com/gmail/nossr50/config/mods/CustomToolConfig.java +++ b/src/main/java/com/gmail/nossr50/config/mods/CustomToolConfig.java @@ -4,6 +4,7 @@ import com.gmail.nossr50.config.ConfigLoader; import com.gmail.nossr50.datatypes.mods.CustomTool; import com.gmail.nossr50.datatypes.skills.ItemType; import com.gmail.nossr50.datatypes.skills.MaterialType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.repair.repairables.Repairable; import com.gmail.nossr50.skills.repair.repairables.RepairableFactory; import org.bukkit.Material; @@ -70,7 +71,7 @@ public class CustomToolConfig extends ConfigLoader { Material toolMaterial = Material.matchMaterial(toolName); if (toolMaterial == null) { - plugin.getLogger().warning("Invalid material name. This item will be skipped. - " + toolName); + mcMMO.p.getLogger().warning("Invalid material name. This item will be skipped. - " + toolName); continue; } @@ -78,7 +79,7 @@ public class CustomToolConfig extends ConfigLoader { Material repairMaterial = Material.matchMaterial(config.getString(toolType + "." + toolName + ".Repair_Material", "")); if (repairable && (repairMaterial == null)) { - plugin.getLogger().warning("Incomplete repair information. This item will be unrepairable. - " + toolName); + mcMMO.p.getLogger().warning("Incomplete repair information. This item will be unrepairable. - " + toolName); repairable = false; } diff --git a/src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfig.java b/src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfig.java index c5ff8846c..02066fc98 100644 --- a/src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfig.java +++ b/src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfig.java @@ -182,7 +182,7 @@ public class RepairConfig extends ConfigLoader { private boolean noErrorsInRepairable(List issues) { for (String issue : issues) { - plugin.getLogger().warning(issue); + mcMMO.p.getLogger().warning(issue); } return issues.isEmpty(); diff --git a/src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfig.java b/src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfig.java index 66e107d09..47bc7acea 100644 --- a/src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfig.java +++ b/src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfig.java @@ -200,12 +200,12 @@ public class SalvageConfig extends ConfigLoader { private boolean noErrorsInSalvageable(List issues) { if (!issues.isEmpty()) { - plugin.getLogger().warning("Errors have been found in: " + fileName); - plugin.getLogger().warning("The following issues were found:"); + mcMMO.p.getLogger().warning("Errors have been found in: " + fileName); + mcMMO.p.getLogger().warning("The following issues were found:"); } for (String issue : issues) { - plugin.getLogger().warning(issue); + mcMMO.p.getLogger().warning(issue); } return issues.isEmpty(); diff --git a/src/main/java/com/gmail/nossr50/config/treasure/FishingTreasureConfig.java b/src/main/java/com/gmail/nossr50/config/treasure/FishingTreasureConfig.java index bfd814889..dc129344d 100755 --- a/src/main/java/com/gmail/nossr50/config/treasure/FishingTreasureConfig.java +++ b/src/main/java/com/gmail/nossr50/config/treasure/FishingTreasureConfig.java @@ -348,7 +348,7 @@ public class FishingTreasureConfig extends ConfigLoader { Enchantment enchantment = EnchantmentUtils.getByName(enchantmentName); if (enchantment == null) { - plugin.getLogger().warning("Skipping invalid enchantment in " + FILENAME + ": " + enchantmentName); + mcMMO.p.getLogger().warning("Skipping invalid enchantment in " + FILENAME + ": " + enchantmentName); continue; } diff --git a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java index 72253d658..6242c571d 100644 --- a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java @@ -1,13 +1,13 @@ 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.PlayerData; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -17,15 +17,13 @@ import java.util.Map; import java.util.UUID; public interface DatabaseManager { - // One month in milliseconds - long PURGE_TIME = 2630000000L * Config.getInstance().getOldUsersCutoff(); // During convertUsers, how often to output a status int progressInterval = 200; /** * Purge users with 0 power level from the database. */ - void purgePowerlessUsers(); + int purgePowerlessUsers(); /** * Purge users who haven't logged on in over a certain time frame from the database. @@ -87,11 +85,11 @@ public interface DatabaseManager { /** * 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 + * @return */ - void newUser(String playerName, UUID uuid); + @NotNull PlayerProfile newUser(String playerName, UUID uuid); @NotNull PlayerProfile newUser(@NotNull Player player); @@ -104,13 +102,9 @@ public interface DatabaseManager { */ @NotNull PlayerProfile loadPlayerProfile(@NotNull String playerName); - /** - * Load a player from the database. - * - * @param uuid The uuid of the player to load from the database - * @return The player's data, or an unloaded PlayerProfile if not found - */ - @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid, @Nullable String playerName); + @NotNull PlayerProfile loadPlayerProfile(@NotNull OfflinePlayer offlinePlayer); + + @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid); /** * Get all users currently stored in the database. diff --git a/src/main/java/com/gmail/nossr50/database/DatabaseManagerFactory.java b/src/main/java/com/gmail/nossr50/database/DatabaseManagerFactory.java index c781d4428..91403d0b2 100644 --- a/src/main/java/com/gmail/nossr50/database/DatabaseManagerFactory.java +++ b/src/main/java/com/gmail/nossr50/database/DatabaseManagerFactory.java @@ -1,13 +1,16 @@ package com.gmail.nossr50.database; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.database.DatabaseType; import com.gmail.nossr50.mcMMO; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.logging.Logger; public class DatabaseManagerFactory { private static Class customManager = null; - public static DatabaseManager getDatabaseManager() { + public static DatabaseManager getDatabaseManager(@NotNull String userFilePath, @NotNull Logger logger, long purgeTime, int startingLevel) { if (customManager != null) { try { return createDefaultCustomDatabaseManager(); @@ -20,10 +23,10 @@ public class DatabaseManagerFactory { mcMMO.p.getLogger().info("Failed to create custom database manager"); e.printStackTrace(); } - mcMMO.p.getLogger().info("Falling back on " + (Config.getInstance().getUseMySQL() ? "SQL" : "Flatfile") + " database"); + mcMMO.p.getLogger().info("Falling back on " + (mcMMO.p.getGeneralConfig().getUseMySQL() ? "SQL" : "Flatfile") + " database"); } - return Config.getInstance().getUseMySQL() ? new SQLDatabaseManager() : new FlatFileDatabaseManager(); + return mcMMO.p.getGeneralConfig().getUseMySQL() ? new SQLDatabaseManager() : new FlatFileDatabaseManager(userFilePath, logger, purgeTime, startingLevel); } /** @@ -56,11 +59,11 @@ public class DatabaseManagerFactory { return customManager; } - public static DatabaseManager createDatabaseManager(DatabaseType type) { + public static @Nullable DatabaseManager createDatabaseManager(@NotNull DatabaseType type, @NotNull String userFilePath, @NotNull Logger logger, long purgeTime, int startingLevel) { switch (type) { case FLATFILE: mcMMO.p.getLogger().info("Using FlatFile Database"); - return new FlatFileDatabaseManager(); + return new FlatFileDatabaseManager(userFilePath, logger, purgeTime, startingLevel); case SQL: mcMMO.p.getLogger().info("Using SQL Database"); @@ -80,7 +83,7 @@ public class DatabaseManagerFactory { } } - public static DatabaseManager createDefaultCustomDatabaseManager() throws Throwable { + private static DatabaseManager createDefaultCustomDatabaseManager() throws Throwable { return customManager.getConstructor().newInstance(); } diff --git a/src/main/java/com/gmail/nossr50/database/ExpectedType.java b/src/main/java/com/gmail/nossr50/database/ExpectedType.java new file mode 100644 index 000000000..ab3ad7c9c --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/ExpectedType.java @@ -0,0 +1,13 @@ +package com.gmail.nossr50.database; + +public enum ExpectedType { + STRING, + INTEGER, + LONG, + BOOLEAN, + FLOAT, + DOUBLE, + UUID, + IGNORED, + OUT_OF_RANGE +} diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java b/src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java new file mode 100644 index 000000000..b80c39e15 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java @@ -0,0 +1,13 @@ +package com.gmail.nossr50.database; + +public enum FlatFileDataFlag { + INCOMPLETE, + BAD_VALUES, + LAST_LOGIN_SCHEMA_UPGRADE, + MISSING_NAME, + DUPLICATE_NAME, + DUPLICATE_UUID, + BAD_UUID_DATA, //Can be because it is missing, null, or corrupted or some other reason + TOO_INCOMPLETE, + CORRUPTED_OR_UNRECOGNIZABLE, +} diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java new file mode 100644 index 000000000..a232d86cd --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java @@ -0,0 +1,345 @@ +package com.gmail.nossr50.database; + +import com.gmail.nossr50.database.flatfile.FlatFileDataBuilder; +import com.gmail.nossr50.database.flatfile.FlatFileDataContainer; +import com.gmail.nossr50.database.flatfile.FlatFileDataUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.logging.Logger; + +import static com.gmail.nossr50.database.FlatFileDatabaseManager.*; + +public class FlatFileDataProcessor { + private final @NotNull List flatFileDataContainers; + private final @NotNull List flatFileDataFlags; + private final @NotNull Logger logger; + private final HashSet names; + private final HashSet uuids; + private int uniqueProcessingID; //TODO: Not being used, should we use it? + boolean corruptDataFound; + + public FlatFileDataProcessor(@NotNull Logger logger) { + this.logger = logger; + flatFileDataContainers = new ArrayList<>(); + flatFileDataFlags = new ArrayList<>(); + names = new HashSet<>(); + uuids = new HashSet<>(); + uniqueProcessingID = 0; + } + + public void processData(@NotNull String lineData) { + assert !lineData.isEmpty(); + + //Make sure the data line is "correct" + if(lineData.charAt(lineData.length() - 1) != ':') { + // Length checks depend on last rawSplitData being ':' + // We add it here if it is missing + lineData = lineData.concat(":"); + } + + //Split the data into an array + String[] splitDataLine = lineData.split(":"); + + FlatFileDataBuilder builder = new FlatFileDataBuilder(splitDataLine, uniqueProcessingID); + uniqueProcessingID++; + boolean[] badDataValues = new boolean[DATA_ENTRY_COUNT]; + boolean anyBadData = false; + + //This is the minimum size of the split array needed to be considered proper data + if(splitDataLine.length < getMinimumSplitDataLength()) { + //Data is considered junk + if(!corruptDataFound) { + logger.severe("Some corrupt data was found in mcmmo.users and has been repaired, it is possible that some player data has been lost in this process."); + corruptDataFound = true; + } + + //Flag as junk (corrupt) + builder.appendFlag(FlatFileDataFlag.CORRUPTED_OR_UNRECOGNIZABLE); + + //TODO: This block here is probably pointless + if(splitDataLine.length >= 10 //The value here is kind of arbitrary, it shouldn't be too low to avoid false positives, but also we aren't really going to correctly identify when player data has been corrupted or not with 100% accuracy ever + && splitDataLine[0] != null && !splitDataLine[0].isEmpty()) { + if(splitDataLine[0].length() <= 16 && splitDataLine[0].length() >= 3) { + logger.severe("Not enough data found to recover corrupted player data for user: "+splitDataLine[0]); + registerData(builder.appendFlag(FlatFileDataFlag.TOO_INCOMPLETE)); + return; + } + } + + registerData(builder.appendFlag(FlatFileDataFlag.CORRUPTED_OR_UNRECOGNIZABLE)); + return; + } + + /* + * Check for duplicate names + */ + + boolean invalidUUID = false; + + String name = splitDataLine[USERNAME_INDEX]; + String strOfUUID = splitDataLine[UUID_INDEX]; + + if(name.isEmpty()) { + reportBadDataLine("No name found for data", "[MISSING NAME]", lineData); + builder.appendFlag(FlatFileDataFlag.MISSING_NAME); + anyBadData = true; + badDataValues[USERNAME_INDEX] = true; + } + + if(strOfUUID.isEmpty() || strOfUUID.equalsIgnoreCase("NULL")) { + invalidUUID = true; + badDataValues[UUID_INDEX] = true; + reportBadDataLine("Empty/null UUID for user", "Empty/null", lineData); + builder.appendFlag(FlatFileDataFlag.BAD_UUID_DATA); + + anyBadData = true; + } + + UUID uuid = null; + + try { + uuid = UUID.fromString(strOfUUID); + } catch (IllegalArgumentException e) { + //UUID does not conform + invalidUUID = true; + badDataValues[UUID_INDEX] = true; + reportBadDataLine("Invalid UUID data found for user", strOfUUID, lineData); + builder.appendFlag(FlatFileDataFlag.BAD_UUID_DATA); + } + + //Duplicate UUID is no good, reject them + if(!invalidUUID && uuid != null && uuids.contains(uuid)) { + registerData(builder.appendFlag(FlatFileDataFlag.DUPLICATE_UUID)); + return; + } + + uuids.add(uuid); + + if(names.contains(name)) { + builder.appendFlag(FlatFileDataFlag.DUPLICATE_NAME); + anyBadData = true; + badDataValues[USERNAME_INDEX] = true; + } + + if(!name.isEmpty()) + names.add(name); + + //Make sure the data is up to date schema wise, if it isn't we adjust it to the correct size and flag it for repair + splitDataLine = isDataSchemaUpToDate(splitDataLine, builder, badDataValues); + + /* + * After establishing this data has at least an identity we check for bad data + * Bad Value checks + */ + + //Check each data for bad values + for(int i = 0; i < DATA_ENTRY_COUNT; i++) { + if(shouldNotBeEmpty(splitDataLine[i], i)) { + + if(i == OVERHAUL_LAST_LOGIN) { + builder.appendFlag(FlatFileDataFlag.LAST_LOGIN_SCHEMA_UPGRADE); + } + + badDataValues[i] = true; + anyBadData = true; + continue; + } + + boolean isCorrectType = isOfExpectedType(splitDataLine[i], getExpectedValueType(i)); + + if(!isCorrectType) { + anyBadData = true; + badDataValues[i] = true; + } + } + + if(anyBadData) { + builder.appendFlag(FlatFileDataFlag.BAD_VALUES); + builder.appendBadDataValues(badDataValues); + } + + registerData(builder); + } + + public @NotNull String[] isDataSchemaUpToDate(@NotNull String[] splitDataLine, @NotNull FlatFileDataBuilder builder, boolean[] badDataValues) { + assert splitDataLine.length <= DATA_ENTRY_COUNT; //should NEVER be higher + + if(splitDataLine.length < DATA_ENTRY_COUNT) { + int oldLength = splitDataLine.length; + splitDataLine = Arrays.copyOf(splitDataLine, DATA_ENTRY_COUNT); + int newLength = splitDataLine.length; + + //TODO: Test this + for(int i = oldLength; i < (newLength - 1); i++){ + badDataValues[i] = true; + } + + builder.appendFlag(FlatFileDataFlag.INCOMPLETE); + builder.setSplitStringData(splitDataLine); + } + return splitDataLine; + } + + + public boolean shouldNotBeEmpty(@Nullable String data, int index) { + if(getExpectedValueType(index) == ExpectedType.IGNORED) { + return false; + } else { + return data == null || data.isEmpty(); + } + } + + public boolean isOfExpectedType(@NotNull String data, @NotNull ExpectedType expectedType) { + switch(expectedType) { + case STRING: + return true; + case INTEGER: + try { + Integer.valueOf(data); + return true; + } catch (Exception e) { + return false; + } + case BOOLEAN: + return data.equalsIgnoreCase("true") || data.equalsIgnoreCase("false"); + case FLOAT: + try { + Float.valueOf(data); + return true; + } catch (NumberFormatException e) { + return false; + } + case DOUBLE: + try { + Double.valueOf(data); + return true; + } catch (NumberFormatException e) { + return false; + } + case UUID: + try { + UUID.fromString(data); + return true; + } catch (IllegalArgumentException e) { + return false; + } + case OUT_OF_RANGE: + throw new ArrayIndexOutOfBoundsException("Value matched type OUT_OF_RANGE, this should never happen."); + case IGNORED: + default: + return true; + } + + } + + private void reportBadDataLine(String warning, String context, String dataLine) { + logger.warning("FlatFileDatabaseBuilder Warning: " + warning + " - " + context); + logger.warning("FlatFileDatabaseBuilder: (Line Data) - " + dataLine); + logger.warning("mcMMO will repair this data if automatically (if it is possible)."); + } + + private int getMinimumSplitDataLength() { + return UUID_INDEX + 1; + } + + private void registerData(@NotNull FlatFileDataBuilder builder) { + FlatFileDataContainer flatFileDataContainer = builder.build(); + flatFileDataContainers.add(flatFileDataContainer); + + if(flatFileDataContainer.getDataFlags() != null) + flatFileDataFlags.addAll(flatFileDataContainer.getDataFlags()); + } + + public static @NotNull ExpectedType getExpectedValueType(int dataIndex) throws IndexOutOfBoundsException { + switch(dataIndex) { + case USERNAME_INDEX: + return ExpectedType.STRING; + case 2: //Assumption: Used to be for something, no longer used + case 3: //Assumption: Used to be for something, no longer used + case 23: //Assumption: Used to be used for something, no longer used + case 33: //Assumption: Used to be used for something, no longer used + case HEALTHBAR: + case LEGACY_LAST_LOGIN: + return ExpectedType.IGNORED; + case SKILLS_MINING: + case SKILLS_REPAIR: + case SKILLS_UNARMED: + case SKILLS_HERBALISM: + case SKILLS_EXCAVATION: + case SKILLS_ARCHERY: + case SKILLS_SWORDS: + case SKILLS_AXES: + case SKILLS_WOODCUTTING: + case SKILLS_ACROBATICS: + case SKILLS_TAMING: + case SKILLS_FISHING: + case SKILLS_ALCHEMY: + case COOLDOWN_BERSERK: + case COOLDOWN_GIGA_DRILL_BREAKER: + case COOLDOWN_TREE_FELLER: + case COOLDOWN_GREEN_TERRA: + case COOLDOWN_SERRATED_STRIKES: + case COOLDOWN_SKULL_SPLITTER: + case COOLDOWN_SUPER_BREAKER: + case COOLDOWN_BLAST_MINING: + case SCOREBOARD_TIPS: + case COOLDOWN_CHIMAERA_WING: + return ExpectedType.INTEGER; + case EXP_MINING: + case EXP_WOODCUTTING: + case EXP_REPAIR: + case EXP_UNARMED: + case EXP_HERBALISM: + case EXP_EXCAVATION: + case EXP_ARCHERY: + case EXP_SWORDS: + case EXP_AXES: + case EXP_ACROBATICS: + case EXP_TAMING: + case EXP_FISHING: + case EXP_ALCHEMY: + return ExpectedType.FLOAT; + case UUID_INDEX: + return ExpectedType.UUID; + case OVERHAUL_LAST_LOGIN: + return ExpectedType.LONG; + } + + throw new IndexOutOfBoundsException(); + } + + public @NotNull List getFlatFileDataContainers() { + return flatFileDataContainers; + } + + public @NotNull List getFlatFileDataFlags() { + return flatFileDataFlags; + } + + public int getDataFlagCount() { + return flatFileDataFlags.size(); + } + + public @NotNull StringBuilder processDataForSave() { + StringBuilder stringBuilder = new StringBuilder(); + + //Fix our data if needed and prepare it to be saved + + for(FlatFileDataContainer dataContainer : flatFileDataContainers) { + String[] splitData = FlatFileDataUtil.getPreparedSaveDataLine(dataContainer); + + if(splitData == null) + continue; + + //We add a trailing : as it is needed for some reason (is it?) + //TODO: Is the trailing ":" actually necessary? + String fromSplit = org.apache.commons.lang.StringUtils.join(splitData, ":") + ":"; + stringBuilder.append(fromSplit).append("\r\n"); + } + + return stringBuilder; + } + +} diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index b60108495..dc1b40855 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -1,62 +1,124 @@ package com.gmail.nossr50.database; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; +import com.gmail.nossr50.api.exceptions.InvalidSkillException; +import com.gmail.nossr50.database.flatfile.LeaderboardStatus; 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.MMODataBuilder; -import com.gmail.nossr50.datatypes.player.MMODataSnapshot; -import com.gmail.nossr50.datatypes.player.PlayerData; import com.gmail.nossr50.datatypes.player.PlayerProfile; +import com.gmail.nossr50.datatypes.player.UniqueDataType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; -import com.gmail.nossr50.util.experience.MMOExperienceBarManager; -import com.gmail.nossr50.util.skills.SkillUtils; -import com.google.common.collect.ImmutableMap; -import com.neetgames.mcmmo.UniqueDataType; -import com.neetgames.mcmmo.exceptions.InvalidSkillException; -import com.neetgames.mcmmo.skill.SkillBossBarState; -import org.apache.commons.lang.NullArgumentException; +import com.gmail.nossr50.util.skills.SkillTools; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.*; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.*; +import java.util.logging.Logger; public final class FlatFileDatabaseManager implements DatabaseManager { - public static final String FLATFILE_SPLIT_CHARACTER_REGEX = ":"; - public static final String NULL_VALUE = "NULL"; - private final HashMap> playerStatHash = new HashMap<>(); - private final List powerLevels = new ArrayList<>(); + public static final String IGNORED = "IGNORED"; + public static final String LEGACY_INVALID_OLD_USERNAME = "_INVALID_OLD_USERNAME_'"; + private final @NotNull EnumMap> playerStatHash = new EnumMap>(PrimarySkillType.class); + private final @NotNull List powerLevels = new ArrayList<>(); private long lastUpdate = 0; + private final @NotNull String usersFilePath; + private final @NotNull Logger logger; + private final long purgeTime; + private final int startingLevel; + private final boolean testing; private final long UPDATE_WAIT_TIME = 600000L; // 10 minutes - private final File usersFile; + private final @NotNull File usersFile; private static final Object fileWritingLock = new Object(); - protected FlatFileDatabaseManager() { - usersFile = new File(mcMMO.getUsersFilePath()); - checkStructure(); - updateLeaderboards(); + public static final int USERNAME_INDEX = 0; + public static final int SKILLS_MINING = 1; + public static final int EXP_MINING = 4; + public static final int SKILLS_WOODCUTTING = 5; + public static final int EXP_WOODCUTTING = 6; + public static final int SKILLS_REPAIR = 7; + public static final int SKILLS_UNARMED = 8; + public static final int SKILLS_HERBALISM = 9; + public static final int SKILLS_EXCAVATION = 10; + public static final int SKILLS_ARCHERY = 11; + public static final int SKILLS_SWORDS = 12; + public static final int SKILLS_AXES = 13; + public static final int SKILLS_ACROBATICS = 14; + public static final int EXP_REPAIR = 15; + public static final int EXP_UNARMED = 16; + public static final int EXP_HERBALISM = 17; + public static final int EXP_EXCAVATION = 18; + public static final int EXP_ARCHERY = 19; + public static final int EXP_SWORDS = 20; + public static final int EXP_AXES = 21; + public static final int EXP_ACROBATICS = 22; + public static final int SKILLS_TAMING = 24; + public static final int EXP_TAMING = 25; + public static final int COOLDOWN_BERSERK = 26; + public static final int COOLDOWN_GIGA_DRILL_BREAKER = 27; + public static final int COOLDOWN_TREE_FELLER = 28; + public static final int COOLDOWN_GREEN_TERRA = 29; + public static final int COOLDOWN_SERRATED_STRIKES = 30; + public static final int COOLDOWN_SKULL_SPLITTER = 31; + public static final int COOLDOWN_SUPER_BREAKER = 32; + public static final int SKILLS_FISHING = 34; + public static final int EXP_FISHING = 35; + public static final int COOLDOWN_BLAST_MINING = 36; + public static final int LEGACY_LAST_LOGIN = 37; + public static final int HEALTHBAR = 38; + public static final int SKILLS_ALCHEMY = 39; + public static final int EXP_ALCHEMY = 40; + public static final int UUID_INDEX = 41; + public static final int SCOREBOARD_TIPS = 42; + public static final int COOLDOWN_CHIMAERA_WING = 43; + public static final int OVERHAUL_LAST_LOGIN = 44; - if (mcMMO.getUpgradeManager().shouldUpgrade(UpgradeType.ADD_UUIDS)) { - new UUIDUpdateAsyncTask(mcMMO.p, getStoredUsers()).start(); + public static final int DATA_ENTRY_COUNT = OVERHAUL_LAST_LOGIN + 1; //Update this everytime new data is added + + protected FlatFileDatabaseManager(@NotNull File usersFile, @NotNull Logger logger, long purgeTime, int startingLevel, boolean testing) { + this.usersFile = usersFile; + this.usersFilePath = usersFile.getPath(); + this.logger = logger; + this.purgeTime = purgeTime; + this.startingLevel = startingLevel; + this.testing = testing; + + if(!usersFile.exists()) { + initEmptyDB(); + } + + if(!testing) { + List flatFileDataFlags = checkFileHealthAndStructure(); + + if(flatFileDataFlags != null) { + if(flatFileDataFlags.size() > 0) { + logger.info("Detected "+flatFileDataFlags.size() + " data entries which need correction."); + } + } + + updateLeaderboards(); } } - public void purgePowerlessUsers() { + protected FlatFileDatabaseManager(@NotNull String usersFilePath, @NotNull Logger logger, long purgeTime, int startingLevel) { + this(new File(usersFilePath), logger, purgeTime, startingLevel, false); + } + + + public int purgePowerlessUsers() { int purgedUsers = 0; - mcMMO.p.getLogger().info("Purging powerless users..."); + logger.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) { @@ -91,7 +153,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { out.write(writer.toString()); } catch (IOException e) { - mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString()); + logger.severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e); } finally { if (in != null) { @@ -113,18 +175,19 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - mcMMO.p.getLogger().info("Purged " + purgedUsers + " users from the database."); + logger.info("Purged " + purgedUsers + " users from the database."); + return purgedUsers; } + //TODO: Test this public void purgeOldUsers() { int removedPlayers = 0; long currentTime = System.currentTimeMillis(); - mcMMO.p.getLogger().info("Purging old users..."); + logger.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) { @@ -135,32 +198,34 @@ public final class FlatFileDatabaseManager implements DatabaseManager { while ((line = in.readLine()) != null) { String[] character = line.split(":"); - String name = character[FlatFileMappings.USERNAME]; + String name = character[USERNAME_INDEX]; long lastPlayed = 0; boolean rewrite = false; + try { - lastPlayed = Long.parseLong(character[37]) * Misc.TIME_CONVERSION_FACTOR; - } - catch (NumberFormatException e) { + lastPlayed = Long.parseLong(character[OVERHAUL_LAST_LOGIN]); + } catch (NumberFormatException e) { e.printStackTrace(); } - if (lastPlayed == 0) { + + if (lastPlayed == -1) { OfflinePlayer player = mcMMO.p.getServer().getOfflinePlayer(name); - lastPlayed = player.getLastPlayed(); - rewrite = true; + + if(player.getLastPlayed() != 0) { + lastPlayed = player.getLastPlayed(); + rewrite = true; + } } - if (currentTime - lastPlayed > PURGE_TIME) { + if (lastPlayed != -1 && lastPlayed != 0 && currentTime - lastPlayed > purgeTime) { removedPlayers++; - } - else { + } else { if (rewrite) { // Rewrite their data with a valid time - character[37] = Long.toString(lastPlayed); + character[OVERHAUL_LAST_LOGIN] = Long.toString(lastPlayed); String newLine = org.apache.commons.lang.StringUtils.join(character, ":"); writer.append(newLine).append("\r\n"); - } - else { + } else { writer.append(line).append("\r\n"); } } @@ -169,9 +234,13 @@ public final class FlatFileDatabaseManager implements DatabaseManager { // Write the new file out = new FileWriter(usersFilePath); out.write(writer.toString()); + + if(testing) { + System.out.println(writer.toString()); + } } catch (IOException e) { - mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString()); + logger.severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e); } finally { if (in != null) { @@ -193,16 +262,15 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - mcMMO.p.getLogger().info("Purged " + removedPlayers + " users from the database."); + logger.info("Purged " + removedPlayers + " users from the database."); } - public boolean removeUser(@NotNull String playerName, @Nullable UUID uuid) { + public boolean removeUser(String playerName, 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 { @@ -212,8 +280,8 @@ public final class FlatFileDatabaseManager implements DatabaseManager { 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..."); + if (!worked && line.split(":")[USERNAME_INDEX].equalsIgnoreCase(playerName)) { + logger.info("User found, removing..."); worked = true; continue; // Skip the player } @@ -225,7 +293,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { out.write(writer.toString()); } catch (Exception e) { - mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString()); + logger.severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e); } finally { if (in != null) { @@ -257,18 +325,12 @@ public final class FlatFileDatabaseManager implements DatabaseManager { //Not used in FlatFile } - public boolean saveUser(@NotNull PlayerData playerData) { - MMODataSnapshot mmoDataSnapshot = new MMODataSnapshot(playerData); - return saveUser(mmoDataSnapshot); //Clone data into Immutable data - } - - public boolean saveUser(@NotNull MMODataSnapshot mmoDataSnapshot) { - String playerName = mmoDataSnapshot.getPlayerName(); - UUID uuid = mmoDataSnapshot.getPlayerUUID(); + public boolean saveUser(@NotNull PlayerProfile profile) { + String playerName = profile.getPlayerName(); + UUID uuid = profile.getUniqueId(); BufferedReader in = null; FileWriter out = null; - String usersFilePath = mcMMO.getUsersFilePath(); boolean corruptDataFound = false; synchronized (fileWritingLock) { @@ -281,11 +343,16 @@ public final class FlatFileDatabaseManager implements DatabaseManager { boolean wroteUser = false; // While not at the end of the file while ((line = in.readLine()) != null) { + if(line.startsWith("#")) { + writer.append(line).append("\r\n"); + continue; + } + //Check for incomplete or corrupted data if(!line.contains(":")) { if(!corruptDataFound) { - mcMMO.p.getLogger().severe("mcMMO found some unexpected or corrupted data in mcmmo.users and is removing it, it is possible some data has been lost."); + logger.severe("mcMMO found some unexpected or corrupted data in mcmmo.users and is removing it, it is possible some data has been lost."); corruptDataFound = true; } @@ -294,12 +361,11 @@ public final class FlatFileDatabaseManager implements DatabaseManager { String[] splitData = line.split(":"); - //This would be rare, but check the splitData for having enough entries to contain a username - if(splitData.length < FlatFileMappings.USERNAME) { //UUID have been in mcMMO DB for a very long time so any user without - //Something is wrong if we don't have enough split data to have an entry for a username + //This would be rare, but check the splitData for having enough entries to contain a UUID + if(splitData.length < UUID_INDEX) { //UUID have been in mcMMO DB for a very long time so any user without if(!corruptDataFound) { - mcMMO.p.getLogger().severe("mcMMO found some unexpected or corrupted data in mcmmo.users and is removing it, it is possible some data has been lost."); + logger.severe("mcMMO found some unexpected or corrupted data in mcmmo.users and is removing it, it is possible some data has been lost."); corruptDataFound = true; } @@ -307,12 +373,12 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } if (!(uuid != null - && splitData[FlatFileMappings.UUID_INDEX].equalsIgnoreCase(uuid.toString())) - && !splitData[FlatFileMappings.USERNAME].equalsIgnoreCase(playerName)) { + && splitData[UUID_INDEX].equalsIgnoreCase(uuid.toString())) + && !splitData[USERNAME_INDEX].equalsIgnoreCase(playerName)) { writer.append(line).append("\r\n"); //Not the user so write it to file and move on } else { //User found - writeUserToLine(mmoDataSnapshot, playerName, uuid, writer); + writeUserToLine(profile, writer); wroteUser = true; } } @@ -321,7 +387,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { * If we couldn't find the user in the DB we need to add him */ if(!wroteUser) { - writeUserToLine(mmoDataSnapshot, playerName, uuid, writer); + writeUserToLine(profile, writer); } // Write the new file @@ -354,270 +420,218 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - private void writeUserToLine(@NotNull MMODataSnapshot mmoDataSnapshot, @NotNull String playerName, @Nullable UUID uuid, @NotNull StringBuilder writer) { - ImmutableMap primarySkillLevelMap = mmoDataSnapshot.getSkillLevelValues(); - ImmutableMap primarySkillExperienceValueMap = mmoDataSnapshot.getSkillExperienceValues(); - - writer.append(playerName).append(":"); - writer.append(primarySkillLevelMap.get(PrimarySkillType.MINING)).append(":"); - writer.append(":"); - writer.append(":"); - writer.append(primarySkillExperienceValueMap.get(PrimarySkillType.MINING)).append(":"); - writer.append(primarySkillLevelMap.get(PrimarySkillType.WOODCUTTING)).append(":"); - writer.append(primarySkillExperienceValueMap.get(PrimarySkillType.WOODCUTTING)).append(":"); - writer.append(primarySkillLevelMap.get(PrimarySkillType.REPAIR)).append(":"); - writer.append(primarySkillLevelMap.get(PrimarySkillType.UNARMED)).append(":"); - writer.append(primarySkillLevelMap.get(PrimarySkillType.HERBALISM)).append(":"); - writer.append(primarySkillLevelMap.get(PrimarySkillType.EXCAVATION)).append(":"); - writer.append(primarySkillLevelMap.get(PrimarySkillType.ARCHERY)).append(":"); - writer.append(primarySkillLevelMap.get(PrimarySkillType.SWORDS)).append(":"); - writer.append(primarySkillLevelMap.get(PrimarySkillType.AXES)).append(":"); - writer.append(primarySkillLevelMap.get(PrimarySkillType.ACROBATICS)).append(":"); - writer.append(primarySkillExperienceValueMap.get(PrimarySkillType.REPAIR)).append(":"); - writer.append(primarySkillExperienceValueMap.get(PrimarySkillType.UNARMED)).append(":"); - writer.append(primarySkillExperienceValueMap.get(PrimarySkillType.HERBALISM)).append(":"); - writer.append(primarySkillExperienceValueMap.get(PrimarySkillType.EXCAVATION)).append(":"); - writer.append(primarySkillExperienceValueMap.get(PrimarySkillType.ARCHERY)).append(":"); - writer.append(primarySkillExperienceValueMap.get(PrimarySkillType.SWORDS)).append(":"); - writer.append(primarySkillExperienceValueMap.get(PrimarySkillType.AXES)).append(":"); - writer.append(primarySkillExperienceValueMap.get(PrimarySkillType.ACROBATICS)).append(":"); - writer.append(":"); - writer.append(primarySkillLevelMap.get(PrimarySkillType.TAMING)).append(":"); - writer.append(primarySkillExperienceValueMap.get(PrimarySkillType.TAMING)).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(PrimarySkillType.FISHING)).append(":"); - writer.append(primarySkillExperienceValueMap.get(PrimarySkillType.FISHING)).append(":"); - writer.append((int) mmoDataSnapshot.getAbilityDATS(SuperAbilityType.BLAST_MINING)).append(":"); - writer.append(System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR).append(":"); - - writer.append(NULL_VALUE).append(":"); //Mob Health Bars are no longer based on player data - - writer.append(primarySkillLevelMap.get(PrimarySkillType.ALCHEMY)).append(":"); - writer.append(primarySkillExperienceValueMap.get(PrimarySkillType.ALCHEMY)).append(":"); - writer.append(uuid != null ? uuid.toString() : NULL_VALUE).append(":"); //Can be NULL - 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(PrimarySkillType.TRIDENTS)).append(":"); - writer.append(primarySkillExperienceValueMap.get(PrimarySkillType.TRIDENTS)).append(":"); - writer.append(primarySkillLevelMap.get(PrimarySkillType.CROSSBOWS)).append(":"); - writer.append(primarySkillExperienceValueMap.get(PrimarySkillType.CROSSBOWS)).append(":"); - - //XPBar States - writer.append(mmoDataSnapshot.getBarStateMap().get(PrimarySkillType.ACROBATICS).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(PrimarySkillType.ALCHEMY).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(PrimarySkillType.ARCHERY).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(PrimarySkillType.AXES).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(PrimarySkillType.EXCAVATION).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(PrimarySkillType.FISHING).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(PrimarySkillType.HERBALISM).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(PrimarySkillType.MINING).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(PrimarySkillType.REPAIR).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(PrimarySkillType.SALVAGE).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(PrimarySkillType.SMELTING).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(PrimarySkillType.SWORDS).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(PrimarySkillType.TAMING).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(PrimarySkillType.UNARMED).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(PrimarySkillType.WOODCUTTING).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(PrimarySkillType.TRIDENTS).toString()).append(":"); - writer.append(mmoDataSnapshot.getBarStateMap().get(PrimarySkillType.CROSSBOWS).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"); + public void writeUserToLine(@NotNull PlayerProfile profile, @NotNull Appendable appendable) throws IOException { + appendable.append(profile.getPlayerName()).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.MINING))).append(":"); + appendable.append(IGNORED).append(":"); + appendable.append(IGNORED).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.MINING))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.WOODCUTTING))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.WOODCUTTING))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.REPAIR))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.UNARMED))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.HERBALISM))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.EXCAVATION))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ARCHERY))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.SWORDS))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.AXES))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ACROBATICS))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.REPAIR))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.UNARMED))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.HERBALISM))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.EXCAVATION))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ARCHERY))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.SWORDS))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.AXES))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ACROBATICS))).append(":"); + appendable.append(IGNORED).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.TAMING))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.TAMING))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.BERSERK))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.GIGA_DRILL_BREAKER))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.TREE_FELLER))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.GREEN_TERRA))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SERRATED_STRIKES))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SKULL_SPLITTER))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SUPER_BREAKER))).append(":"); + appendable.append(IGNORED).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.FISHING))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.FISHING))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.BLAST_MINING))).append(":"); + appendable.append(IGNORED).append(":"); //Legacy last login + appendable.append(IGNORED).append(":"); //mob health bar + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ALCHEMY))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ALCHEMY))).append(":"); + appendable.append(profile.getUniqueId() != null ? profile.getUniqueId().toString() : "NULL").append(":"); + appendable.append(String.valueOf(profile.getScoreboardTipsShown())).append(":"); + appendable.append(String.valueOf(profile.getUniqueData(UniqueDataType.CHIMAERA_WING_DATS))).append(":"); + appendable.append(String.valueOf(profile.getLastLogin())).append(":"); //overhaul last login + appendable.append("\r\n"); } - public @NotNull List readLeaderboard(@NotNull PrimarySkillType skill, int pageNumber, int statsPerPage) { + public @NotNull List readLeaderboard(@Nullable PrimarySkillType primarySkillType, int pageNumber, int statsPerPage) throws InvalidSkillException { //Fix for a plugin that people are using that is throwing SQL errors - if(skill != null && skill.isChildSkill()) { - mcMMO.p.getLogger().severe("A plugin hooking into mcMMO is being naughty with our database commands, update all plugins that hook into mcMMO and contact their devs!"); + if(primarySkillType != null && SkillTools.isChildSkill(primarySkillType)) { + logger.severe("A plugin hooking into mcMMO is being naughty with our database commands, update all plugins that hook into mcMMO and contact their devs!"); throw new InvalidSkillException("A plugin hooking into mcMMO that you are using is attempting to read leaderboard skills for child skills, child skills do not have leaderboards! This is NOT an mcMMO error!"); } updateLeaderboards(); - List statsList = skill == null ? powerLevels : playerStatHash.get(skill); + List statsList = primarySkillType == null ? powerLevels : playerStatHash.get(primarySkillType); int fromIndex = (Math.max(pageNumber, 1) - 1) * statsPerPage; return statsList.subList(Math.min(fromIndex, statsList.size()), Math.min(fromIndex + statsPerPage, statsList.size())); } - public Map readRank(String playerName) { + public @NotNull HashMap readRank(String playerName) { updateLeaderboards(); - Map skills = new HashMap<>(); + HashMap skills = new HashMap<>(); - for (PrimarySkillType skill : PrimarySkillType.NON_CHILD_SKILLS) { + for (PrimarySkillType skill : SkillTools.NON_CHILD_SKILLS) { skills.put(skill, getPlayerRank(playerName, playerStatHash.get(skill))); } + //TODO: Gross skills.put(null, getPlayerRank(playerName, powerLevels)); return skills; } public @NotNull PlayerProfile newUser(@NotNull Player player) { - newUser(player.getName(), player.getUniqueId()); - MMODataBuilder mmoDataBuilder = new MMODataBuilder(); - PlayerData newPlayerData = mmoDataBuilder.buildNewPlayerData(player); - - return new PlayerProfile(newPlayerData, true); + return new PlayerProfile(player.getName(), player.getUniqueId(), true, startingLevel); } - public void newUser(String playerName, UUID uuid) { - BufferedWriter out = null; + public @NotNull PlayerProfile newUser(@NotNull String playerName, @NotNull UUID uuid) { + PlayerProfile playerProfile = new PlayerProfile(playerName, uuid, true, startingLevel); + synchronized (fileWritingLock) { - try { - // Open the file to write the player - out = new BufferedWriter(new FileWriter(mcMMO.getUsersFilePath(), true)); + try(BufferedReader bufferedReader = new BufferedReader(new FileReader(usersFilePath))) { + StringBuilder stringBuilder = new StringBuilder(); - String startingLevel = AdvancedConfig.getInstance().getStartingLevel() + ":"; + String line; - // 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_VALUE).append(":"); // UUID - out.append("0:"); // Scoreboard tips shown - out.append("0:"); // Chimaera Wing Dats + //Build up the file + while((line = bufferedReader.readLine()) != null) { + stringBuilder.append(line).append("\r\n"); + } - 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) { + try (FileWriter fileWriter = new FileWriter(usersFile)) { + writeUserToLine(playerProfile, stringBuilder); + fileWriter.write(stringBuilder.toString()); + } catch (Exception e) { + e.printStackTrace(); + } + } catch (IOException e) { e.printStackTrace(); } - finally { - if (out != null) { - try { - out.close(); + } + + return playerProfile; + } + + public @NotNull PlayerProfile loadPlayerProfile(@NotNull OfflinePlayer offlinePlayer) { + return processUserQuery(getUserQuery(offlinePlayer.getUniqueId(), offlinePlayer.getName())); + } + + public @NotNull PlayerProfile loadPlayerProfile(@NotNull String playerName) { + return processUserQuery(getUserQuery(null, playerName)); + } + + public @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid) { + return processUserQuery(getUserQuery(uuid, null)); + } + + private @NotNull UserQuery getUserQuery(@Nullable UUID uuid, @Nullable String playerName) throws NullPointerException { + boolean hasName = playerName != null && !playerName.equalsIgnoreCase("null"); + + if(hasName && uuid != null) { + return new UserQueryFull(playerName, uuid); + } else if (uuid != null) { + return new UserQueryUUIDImpl(uuid); + } else if(hasName) { + return new UserQueryNameImpl(playerName); + } else { + throw new NullPointerException("Both name and UUID cannot be null, at least one must be non-null!"); + } + } + + /** + * Find and load a player by UUID/Name + * If the name isn't null and doesn't match the name in the DB, the players name is then replaced/updated + * + * @param userQuery the query + * @return a profile with the targets data or an unloaded profile if no data was found + */ + private @NotNull PlayerProfile processUserQuery(@NotNull UserQuery userQuery) throws RuntimeException { + switch(userQuery.getType()) { + case UUID_AND_NAME: + return queryByUUIDAndName((UserQueryFull) userQuery); + case UUID: + return queryByUUID((UserQueryUUID) userQuery); + case NAME: + return queryByName((UserQueryNameImpl) userQuery); + default: + throw new RuntimeException("No case for this UserQueryType!"); + } + } + + private @NotNull PlayerProfile queryByName(@NotNull UserQueryName userQuery) { + String playerName = userQuery.getName(); + BufferedReader in = null; + + synchronized (fileWritingLock) { + try { + // Open the user file + in = new BufferedReader(new FileReader(usersFilePath)); + String line; + + + while ((line = in.readLine()) != null) { + if(line.startsWith("#")) { + continue; } - catch (IOException e) { + + + // Find if the line contains the player we want. + String[] rawSplitData = line.split(":"); + + + /* Don't read corrupt data */ + if(rawSplitData.length < (USERNAME_INDEX + 1)) { + continue; + } + + + //If we couldn't find anyone + if(playerName.equalsIgnoreCase(rawSplitData[USERNAME_INDEX])) { + return loadFromLine(rawSplitData); + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + // I have no idea why it's necessary to inline tryClose() here, but it removes + // a resource leak warning, and I'm trusting the compiler on this one. + if (in != null) { + try { + in.close(); + } catch (IOException e) { // Ignore } } } } + + + //Return a new blank profile + return new PlayerProfile(playerName, new UUID(0, 0), startingLevel); } - public @NotNull PlayerProfile loadPlayerProfile(@NotNull String playerName) { - return loadPlayerByName(playerName); - } - - public @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid, @Nullable String playerName) { - return loadPlayerByUUID(uuid, playerName); - } - - private @NotNull PlayerProfile loadPlayerByUUID(@NotNull UUID uuid, @Nullable String playerName) { + private @NotNull PlayerProfile queryByUUID(@NotNull UserQueryUUID userQuery) { BufferedReader in = null; - String usersFilePath = mcMMO.getUsersFilePath(); + UUID uuid = userQuery.getUUID(); - //Retrieve player synchronized (fileWritingLock) { try { // Open the user file @@ -625,46 +639,95 @@ public final class FlatFileDatabaseManager implements DatabaseManager { String line; while ((line = in.readLine()) != null) { + if(line.startsWith("#")) { + continue; + } // Find if the line contains the player we want. String[] rawSplitData = line.split(":"); /* Don't read corrupt data */ - if(rawSplitData.length < (FlatFileMappings.UUID_INDEX + 1)) { + if(rawSplitData.length < (UUID_INDEX + 1)) { continue; } - /* Does this entry have a UUID? */ - if (rawSplitData[FlatFileMappings.UUID_INDEX].equalsIgnoreCase("NULL") - || rawSplitData[FlatFileMappings.UUID_INDEX].isEmpty() - || rawSplitData[FlatFileMappings.UUID_INDEX].equalsIgnoreCase("")) { - continue; //No UUID entry found for this data in the DB, go to next entry + try { + UUID fromDataUUID = UUID.fromString(rawSplitData[UUID_INDEX]); + if(fromDataUUID.equals(uuid)) { + return loadFromLine(rawSplitData); + } + } catch (Exception e) { + if(testing) { + e.printStackTrace(); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + // I have no idea why it's necessary to inline tryClose() here, but it removes + // a resource leak warning, and I'm trusting the compiler on this one. + if (in != null) { + try { + in.close(); + } catch (IOException e) { + // Ignore + } + } + } + } + + /* + * No match was found in the file + */ + + return grabUnloadedProfile(uuid, "Player-Not-Found="+uuid.toString()); + } + + private @NotNull PlayerProfile queryByUUIDAndName(@NotNull UserQueryFull userQuery) { + BufferedReader in = null; + String playerName = userQuery.getName(); + UUID uuid = userQuery.getUUID(); + + synchronized (fileWritingLock) { + try { + // Open the user file + in = new BufferedReader(new FileReader(usersFilePath)); + String line; + + while ((line = in.readLine()) != null) { + if(line.startsWith("#")) { + continue; + } + // Find if the line contains the player we want. + String[] rawSplitData = line.split(":"); + + /* Don't read corrupt data */ + if(rawSplitData.length < (UUID_INDEX + 1)) { + continue; } - // Compare provided UUID to DB - if (!rawSplitData[FlatFileMappings.UUID_INDEX].equalsIgnoreCase(uuid.toString())) { - continue; //Doesn't match, go to the next entry - } + try { + UUID fromDataUUID = UUID.fromString(rawSplitData[UUID_INDEX]); + if(fromDataUUID.equals(uuid)) { + //Matched UUID, now check if name matches + String dbPlayerName = rawSplitData[USERNAME_INDEX]; - /* - * UUID Matched! - * Making it this far means the current data line is considered a match - */ + boolean matchingName = dbPlayerName.equalsIgnoreCase(playerName); + if (!matchingName) { + logger.info("When loading user: "+playerName +" with UUID of (" + uuid.toString() + +") we found a mismatched name, the name in the DB will be replaced (DB name: "+dbPlayerName+")"); + //logger.info("Name updated for player: " + rawSplitData[USERNAME_INDEX] + " => " + playerName); + rawSplitData[USERNAME_INDEX] = playerName; + } - /* Check for nickname changes and update since we are here anyways */ - if (!rawSplitData[FlatFileMappings.USERNAME].equalsIgnoreCase(playerName)) { - //mcMMO.p.getLogger().info("Name updated for player: " + rawSplitData[FlatFileMappings.USERNAME] + " => " + playerName); - rawSplitData[FlatFileMappings.USERNAME] = playerName; - } - - PlayerData playerData = loadFromLine(rawSplitData); - if(playerData == null) { - mcMMO.p.getLogger().severe("Could not load player data from line"); - mcMMO.p.getLogger().severe("Data: "+line); - - return grabUnloadedProfile(uuid, playerName); - } else { - return new PlayerProfile(playerData, true); + //TODO: Logic to replace name here + return loadFromLine(rawSplitData); + } + } catch (Exception e) { + if(testing) { + e.printStackTrace(); + } } } } catch (Exception e) { @@ -689,69 +752,16 @@ public final class FlatFileDatabaseManager implements DatabaseManager { return grabUnloadedProfile(uuid, playerName); //Create an empty new profile and return } - private @NotNull PlayerProfile loadPlayerByName(@NotNull String playerName) { - 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) { - // Find if the line contains the player we want. - String[] rawSplitData = line.split(":"); - - /* Don't read corrupt data */ - if(rawSplitData.length < (FlatFileMappings.USERNAME + 1)) { - continue; - } - - //If we couldn't find anyone - if(playerName.equalsIgnoreCase(rawSplitData[FlatFileMappings.USERNAME])) { - PlayerData playerData = loadFromLine(rawSplitData); - if(playerData != null) { - //Data loaded - return new PlayerProfile(playerData, true); - } else { - //Data was unable to be loaded, return "unloaded" profile - return grabUnloadedProfile(null, playerName); - } - } - } - } catch (Exception e) { - e.printStackTrace(); - } finally { - // I have no idea why it's necessary to inline tryClose() here, but it removes - // a resource leak warning, and I'm trusting the compiler on this one. - if (in != null) { - try { - in.close(); - } catch (IOException e) { - // Ignore - } - } - } - } - - //Return a new blank profile - return grabUnloadedProfile(null, playerName); - } - - private @NotNull PlayerProfile grabUnloadedProfile(@Nullable UUID uuid, @Nullable String playerName) { + private @NotNull PlayerProfile grabUnloadedProfile(@NotNull UUID uuid, @Nullable String playerName) { if(playerName == null) { playerName = ""; //No name for you boy! } - MMODataBuilder mmoDataBuilder = new MMODataBuilder(); - PlayerData newPlayerData = mmoDataBuilder.buildNewPlayerData(uuid, playerName); - return new PlayerProfile(newPlayerData, false); + return new PlayerProfile(playerName, uuid, 0); } - public void convertUsers(@NotNull DatabaseManager destination) { + public void convertUsers(DatabaseManager destination) { BufferedReader in = null; - String usersFilePath = mcMMO.getUsersFilePath(); int convertedUsers = 0; long startMillis = System.currentTimeMillis(); @@ -762,20 +772,15 @@ public final class FlatFileDatabaseManager implements DatabaseManager { String line; while ((line = in.readLine()) != null) { + if(line.startsWith("#")) { + continue; + } + String[] character = line.split(":"); try { - PlayerData processedLineData = loadFromLine(character); - - if(processedLineData == null) { - mcMMO.p.getLogger().severe("Unable to convert data from line in FlatFile DB"); - mcMMO.p.getLogger().info("Data: "+line); - continue; - } - - destination.saveUser(processedLineData); - } - catch (Exception e) { + destination.saveUser(loadFromLine(character)); + } catch (Exception e) { e.printStackTrace(); } convertedUsers++; @@ -804,7 +809,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { int i = 0; BufferedReader in = null; FileWriter out = null; - String usersFilePath = mcMMO.getUsersFilePath(); synchronized (fileWritingLock) { try { @@ -814,14 +818,14 @@ public final class FlatFileDatabaseManager implements DatabaseManager { while ((line = in.readLine()) != null) { String[] character = line.split(":"); - if (!worked && character[FlatFileMappings.USERNAME].equalsIgnoreCase(userName)) { + if (!worked && character[USERNAME_INDEX].equalsIgnoreCase(userName)) { if (character.length < 42) { - mcMMO.p.getLogger().severe("Could not update UUID for " + userName + "!"); - mcMMO.p.getLogger().severe("Database entry is invalid."); + logger.severe("Could not update UUID for " + userName + "!"); + logger.severe("Database entry is invalid."); continue; } - line = line.replace(character[FlatFileMappings.UUID_INDEX], uuid.toString()); + line = line.replace(character[UUID_INDEX], uuid.toString()); worked = true; } @@ -833,10 +837,10 @@ public final class FlatFileDatabaseManager implements DatabaseManager { out.write(writer.toString()); } catch (Exception e) { - mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString()); + logger.severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e); } finally { - mcMMO.p.getLogger().info(i + " entries written while saving UUID for " + userName); + logger.info(i + " entries written while saving UUID for " + userName); if (in != null) { try { in.close(); @@ -862,7 +866,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { public boolean saveUserUUIDs(Map fetchedUUIDs) { BufferedReader in = null; FileWriter out = null; - String usersFilePath = mcMMO.getUsersFilePath(); int i = 0; synchronized (fileWritingLock) { @@ -873,14 +876,14 @@ public final class FlatFileDatabaseManager implements DatabaseManager { while (((line = in.readLine()) != null)) { String[] character = line.split(":"); - if (!fetchedUUIDs.isEmpty() && fetchedUUIDs.containsKey(character[FlatFileMappings.USERNAME])) { + if (!fetchedUUIDs.isEmpty() && fetchedUUIDs.containsKey(character[USERNAME_INDEX])) { if (character.length < 42) { - mcMMO.p.getLogger().severe("Could not update UUID for " + character[FlatFileMappings.USERNAME] + "!"); - mcMMO.p.getLogger().severe("Database entry is invalid."); + logger.severe("Could not update UUID for " + character[USERNAME_INDEX] + "!"); + logger.severe("Database entry is invalid."); continue; } - character[FlatFileMappings.UUID_INDEX] = fetchedUUIDs.remove(character[FlatFileMappings.USERNAME]).toString(); + character[UUID_INDEX] = fetchedUUIDs.remove(character[USERNAME_INDEX]).toString(); line = org.apache.commons.lang.StringUtils.join(character, ":") + ":"; } @@ -892,10 +895,10 @@ public final class FlatFileDatabaseManager implements DatabaseManager { out.write(writer.toString()); } catch (Exception e) { - mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString()); + logger.severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e); } finally { - mcMMO.p.getLogger().info(i + " entries written while saving UUID batch"); + logger.info(i + " entries written while saving UUID batch"); if (in != null) { try { in.close(); @@ -921,7 +924,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { public List getStoredUsers() { ArrayList users = new ArrayList<>(); BufferedReader in = null; - String usersFilePath = mcMMO.getUsersFilePath(); synchronized (fileWritingLock) { try { @@ -931,7 +933,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { while ((line = in.readLine()) != null) { String[] character = line.split(":"); - users.add(character[FlatFileMappings.USERNAME]); + users.add(character[USERNAME_INDEX]); } } catch (Exception e) { @@ -954,13 +956,12 @@ public final class FlatFileDatabaseManager implements DatabaseManager { /** * Update the leader boards. */ - private void updateLeaderboards() { + public @NotNull LeaderboardStatus 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; + return LeaderboardStatus.TOO_SOON_TO_UPDATE; } - String usersFilePath = mcMMO.getUsersFilePath(); lastUpdate = System.currentTimeMillis(); // Log when the last update was run powerLevels.clear(); // Clear old values from the power levels @@ -988,8 +989,12 @@ public final class FlatFileDatabaseManager implements DatabaseManager { String line; while ((line = in.readLine()) != null) { + + if(line.startsWith("#")) + continue; + String[] data = line.split(":"); - playerName = data[FlatFileMappings.USERNAME]; + playerName = data[USERNAME_INDEX]; int powerLevel = 0; Map skills = getSkillMapFromLine(data); @@ -1007,16 +1012,14 @@ public final class FlatFileDatabaseManager implements DatabaseManager { powerLevel += putStat(taming, playerName, skills.get(PrimarySkillType.TAMING)); powerLevel += putStat(unarmed, playerName, skills.get(PrimarySkillType.UNARMED)); powerLevel += putStat(woodcutting, playerName, skills.get(PrimarySkillType.WOODCUTTING)); - powerLevel += putStat(woodcutting, playerName, skills.get(PrimarySkillType.CROSSBOWS)); - powerLevel += putStat(woodcutting, playerName, skills.get(PrimarySkillType.TRIDENTS)); 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 { + logger.severe("Exception while reading " + usersFilePath + " during user " + playerName + " (Are you sure you formatted it correctly?) " + e); + return LeaderboardStatus.FAILED; + } finally { if (in != null) { try { in.close(); @@ -1026,6 +1029,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } } + } SkillComparator c = new SkillComparator(); @@ -1058,142 +1062,111 @@ public final class FlatFileDatabaseManager implements DatabaseManager { playerStatHash.put(PrimarySkillType.TAMING, taming); playerStatHash.put(PrimarySkillType.FISHING, fishing); playerStatHash.put(PrimarySkillType.ALCHEMY, alchemy); - playerStatHash.put(PrimarySkillType.TRIDENTS, alchemy); - playerStatHash.put(PrimarySkillType.CROSSBOWS, alchemy); + + return LeaderboardStatus.UPDATED; } - /** - * Checks that the file is present and valid - */ - private void checkStructure() { - boolean corruptDataFound = false; - - 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 rawSplitData being ':' - if (line.charAt(line.length() - 1) != ':') { - line = line.concat(":"); - } - - String[] rawSplitData = line.split(":"); - - //Not enough data found to be considered a user reliably (NOTE: not foolproof) - if(rawSplitData.length < (FlatFileMappings.UUID_INDEX + 1)) { - if(!corruptDataFound) { - mcMMO.p.getLogger().severe("Some corrupt data was found in mcmmo.users and has been repaired, it is possible that some player data has been lost in this process."); - corruptDataFound = true; - } - - if(rawSplitData.length >= 10 //The value here is kind of arbitrary, it shouldn't be too low to avoid false positives, but also we aren't really going to correctly identify when player data has been corrupted or not with 100% accuracy ever - && rawSplitData[0] != null && !rawSplitData[0].isEmpty()) { - if(rawSplitData[0].length() <= 16 && rawSplitData[0].length() >= 3) { - mcMMO.p.getLogger().severe("Not enough data found to recover corrupted player data for user: "+rawSplitData[0]); - } - } - //This user may have had a name so declare it - - continue; - } - - // Prevent the same username from being present multiple times - if (!usernames.add(rawSplitData[FlatFileMappings.USERNAME])) { - //TODO: Check if the commented out code was even necessary - rawSplitData[FlatFileMappings.USERNAME] = "_INVALID_OLD_USERNAME_'"; - if (rawSplitData.length < FlatFileMappings.UUID_INDEX + 1 || rawSplitData[FlatFileMappings.UUID_INDEX].equals("NULL")) { - mcMMO.p.getLogger().severe("Fixing duplicate player names found in mcmmo.users"); - continue; - } - } - - // Prevent the same player from being present multiple times - if (rawSplitData.length >= (FlatFileMappings.UUID_INDEX + 1) //TODO: Test this condition - && (!rawSplitData[FlatFileMappings.UUID_INDEX].isEmpty() - && !rawSplitData[FlatFileMappings.UUID_INDEX].equals("NULL") && !players.add(rawSplitData[FlatFileMappings.UUID_INDEX]))) { - - mcMMO.p.getLogger().severe("Removing duplicate player data from mcmmo.users"); - mcMMO.p.getLogger().info("Duplicate Data: "+line); - continue; - } - - //Correctly size the data (null entries for missing values) - if(line.length() < FlatFileMappings.LENGTH_OF_SPLIT_DATA_ARRAY) { //TODO: Test this condition - String[] correctSizeSplitData = Arrays.copyOf(rawSplitData, FlatFileMappings.LENGTH_OF_SPLIT_DATA_ARRAY); - line = org.apache.commons.lang.StringUtils.join(correctSizeSplitData, ":") + ":"; - rawSplitData = line.split(":"); - PlayerData dataFromLine = loadFromLine(rawSplitData); - - if(dataFromLine == null) - continue; - - - PlayerProfile temporaryProfile = new PlayerProfile(dataFromLine, true); - //TODO: MMODataSnapshot is an unnecessary creation of resources for this operation - writeUserToLine(new MMODataSnapshot(temporaryProfile.getPlayerData()), rawSplitData[FlatFileMappings.USERNAME], temporaryProfile.getUUID(), writer); - } else { - writer.append(line).append("\r\n"); - } - + private void initEmptyDB() { + BufferedWriter bufferedWriter = null; + synchronized (fileWritingLock) { + try { + // Open the file to write the player + bufferedWriter = new BufferedWriter(new FileWriter(usersFilePath, true)); + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm"); + LocalDateTime localDateTime = LocalDateTime.now(); + bufferedWriter.append("# mcMMO Database created on ").append(localDateTime.format(dateTimeFormatter)).append("\r\n"); //Empty file + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (bufferedWriter != null) { + try { + bufferedWriter.close(); } - - // 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) { - e.printStackTrace(); - } - } - if (out != null) { - try { - out.close(); - } - catch (IOException e) { - e.printStackTrace(); - } + catch (IOException e) { + // Ignore } } } + } + } - if(corruptDataFound) - mcMMO.p.getLogger().info("Corrupt data was found and removed, everything should be working fine. It is possible some player data was lost."); + public @Nullable List checkFileHealthAndStructure() { + ArrayList flagsFound = null; + logger.info("(" + usersFile.getPath() + ") Validating database file.."); + FlatFileDataProcessor dataProcessor = null; - return; + if (usersFile.exists()) { + BufferedReader bufferedReader = null; + FileWriter fileWriter = null; + + synchronized (fileWritingLock) { + + dataProcessor = new FlatFileDataProcessor(logger); + + try { + String currentLine; + String dbCommentDate = null; + + bufferedReader = new BufferedReader(new FileReader(usersFilePath)); + + //Analyze the data + while ((currentLine = bufferedReader.readLine()) != null) { + //Commented lines + if(currentLine.startsWith("#") && dbCommentDate == null) { //The first commented line in the file is likely to be our note about when the file was created + dbCommentDate = currentLine; + continue; + } + + if(currentLine.isEmpty()) + continue; + + //TODO: We are never passing empty lines, should we remove the flag for them? + dataProcessor.processData(currentLine); + } + + //Only update the file if needed + if(dataProcessor.getFlatFileDataFlags().size() > 0) { + flagsFound = new ArrayList<>(dataProcessor.getFlatFileDataFlags()); + logger.info("Saving the updated and or repaired FlatFile Database..."); + fileWriter = new FileWriter(usersFilePath); + //Write data to file + if(dbCommentDate != null) + fileWriter.write(dbCommentDate + "\r\n"); + + fileWriter.write(dataProcessor.processDataForSave().toString()); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + closeResources(bufferedReader, fileWriter); + } + } } - usersFile.getParentFile().mkdir(); - - try { - mcMMO.p.debug("Creating mcmmo.users file..."); - new File(mcMMO.getUsersFilePath()).createNewFile(); + if(flagsFound == null || flagsFound.size() == 0) { + return null; + } else { + return flagsFound; } - catch (IOException e) { - e.printStackTrace(); + } + + private void closeResources(BufferedReader bufferedReader, FileWriter fileWriter) { + if(bufferedReader != null) { + try { + bufferedReader.close(); + } + catch (IOException e) { + e.printStackTrace(); + } + } + + if (fileWriter != null) { + try { + fileWriter.close(); + } + catch (IOException e) { + e.printStackTrace(); + } } } @@ -1227,221 +1200,132 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - private @Nullable PlayerData loadFromLine(@NotNull String[] dataStrSplit) { - MMODataBuilder playerDataBuilder = new MMODataBuilder(); - String username = dataStrSplit[FlatFileMappings.USERNAME]; - - 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<>(); + private PlayerProfile loadFromLine(@NotNull String[] character) { + Map skills = getSkillMapFromLine(character); // Skill levels + Map skillsXp = new EnumMap<>(PrimarySkillType.class); // Skill & XP + Map skillsDATS = new EnumMap<>(SuperAbilityType.class); // Ability & Cooldown + Map uniquePlayerDataMap = new EnumMap<>(UniqueDataType.class); int scoreboardTipsShown; + long lastLogin; - //XP Values - tryLoadSkillFloatValuesFromRawData(skillExperienceValueMap, dataStrSplit, PrimarySkillType.TAMING, FlatFileMappings.EXP_TAMING, username); - tryLoadSkillFloatValuesFromRawData(skillExperienceValueMap, dataStrSplit, PrimarySkillType.MINING, FlatFileMappings.EXP_MINING, username); - tryLoadSkillFloatValuesFromRawData(skillExperienceValueMap, dataStrSplit, PrimarySkillType.REPAIR, FlatFileMappings.EXP_REPAIR, username); - tryLoadSkillFloatValuesFromRawData(skillExperienceValueMap, dataStrSplit, PrimarySkillType.WOODCUTTING, FlatFileMappings.EXP_WOODCUTTING, username); - tryLoadSkillFloatValuesFromRawData(skillExperienceValueMap, dataStrSplit, PrimarySkillType.UNARMED, FlatFileMappings.EXP_UNARMED, username); - tryLoadSkillFloatValuesFromRawData(skillExperienceValueMap, dataStrSplit, PrimarySkillType.HERBALISM, FlatFileMappings.EXP_HERBALISM, username); - tryLoadSkillFloatValuesFromRawData(skillExperienceValueMap, dataStrSplit, PrimarySkillType.EXCAVATION, FlatFileMappings.EXP_EXCAVATION, username); - tryLoadSkillFloatValuesFromRawData(skillExperienceValueMap, dataStrSplit, PrimarySkillType.ARCHERY, FlatFileMappings.EXP_ARCHERY, username); - tryLoadSkillFloatValuesFromRawData(skillExperienceValueMap, dataStrSplit, PrimarySkillType.SWORDS, FlatFileMappings.EXP_SWORDS, username); - tryLoadSkillFloatValuesFromRawData(skillExperienceValueMap, dataStrSplit, PrimarySkillType.AXES, FlatFileMappings.EXP_AXES, username); - tryLoadSkillFloatValuesFromRawData(skillExperienceValueMap, dataStrSplit, PrimarySkillType.ACROBATICS, FlatFileMappings.EXP_ACROBATICS, username); - tryLoadSkillFloatValuesFromRawData(skillExperienceValueMap, dataStrSplit, PrimarySkillType.FISHING, FlatFileMappings.EXP_FISHING, username); - tryLoadSkillFloatValuesFromRawData(skillExperienceValueMap, dataStrSplit, PrimarySkillType.ALCHEMY, FlatFileMappings.EXP_ALCHEMY, username); - tryLoadSkillFloatValuesFromRawData(skillExperienceValueMap, dataStrSplit, PrimarySkillType.TRIDENTS, FlatFileMappings.EXP_TRIDENTS, username); - tryLoadSkillFloatValuesFromRawData(skillExperienceValueMap, dataStrSplit, PrimarySkillType.CROSSBOWS, FlatFileMappings.EXP_CROSSBOWS, username); + String username = character[USERNAME_INDEX]; - //Set Skill XP + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.TAMING, EXP_TAMING, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.MINING, EXP_MINING, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.REPAIR, EXP_REPAIR, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.WOODCUTTING, EXP_WOODCUTTING, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.UNARMED, EXP_UNARMED, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.HERBALISM, EXP_HERBALISM, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.EXCAVATION, EXP_EXCAVATION, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.ARCHERY, EXP_ARCHERY, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.SWORDS, EXP_SWORDS, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.AXES, EXP_AXES, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.ACROBATICS, EXP_ACROBATICS, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.FISHING, EXP_FISHING, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.ALCHEMY, EXP_ALCHEMY, username); // Taming - Unused - skillAbilityDeactivationTimeStamp.put(SuperAbilityType.SUPER_BREAKER, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_SUPER_BREAKER])); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SUPER_BREAKER, COOLDOWN_SUPER_BREAKER, username); // 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])); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.TREE_FELLER, COOLDOWN_TREE_FELLER, username); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.BERSERK, COOLDOWN_BERSERK, username); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.GREEN_TERRA, COOLDOWN_GREEN_TERRA, username); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.GIGA_DRILL_BREAKER, COOLDOWN_GIGA_DRILL_BREAKER, username); + // Archery - Unused + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SERRATED_STRIKES, COOLDOWN_SERRATED_STRIKES, username); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SKULL_SPLITTER, COOLDOWN_SKULL_SPLITTER, username); // 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])); - - /* - * Mob Health Bars are no longer saved per player and are ignored from the data - */ - - //Sometimes players are retrieved by name - UUID playerUUID; + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.BLAST_MINING, COOLDOWN_BLAST_MINING, username); + UUID uuid; try { - playerUUID = UUID.fromString(dataStrSplit[FlatFileMappings.UUID_INDEX]); + uuid = UUID.fromString(character[UUID_INDEX]); } catch (Exception e) { - playerUUID = null; + uuid = null; } try { - scoreboardTipsShown = Integer.parseInt(dataStrSplit[FlatFileMappings.SCOREBOARD_TIPS]); + scoreboardTipsShown = Integer.parseInt(character[SCOREBOARD_TIPS]); } catch (Exception e) { scoreboardTipsShown = 0; } try { - uniquePlayerDataMap.put(UniqueDataType.CHIMAERA_WING_DATS, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_CHIMAERA_WING])); + uniquePlayerDataMap.put(UniqueDataType.CHIMAERA_WING_DATS, Integer.valueOf(character[COOLDOWN_CHIMAERA_WING])); } catch (Exception e) { uniquePlayerDataMap.put(UniqueDataType.CHIMAERA_WING_DATS, 0); } try { - xpBarStateMap.put(PrimarySkillType.ACROBATICS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_ACROBATICS])); - xpBarStateMap.put(PrimarySkillType.ALCHEMY, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_ALCHEMY])); - xpBarStateMap.put(PrimarySkillType.ARCHERY, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_ARCHERY])); - xpBarStateMap.put(PrimarySkillType.AXES, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_AXES])); - xpBarStateMap.put(PrimarySkillType.EXCAVATION, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_EXCAVATION])); - xpBarStateMap.put(PrimarySkillType.FISHING, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_FISHING])); - xpBarStateMap.put(PrimarySkillType.HERBALISM, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_HERBALISM])); - xpBarStateMap.put(PrimarySkillType.MINING, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_MINING])); - xpBarStateMap.put(PrimarySkillType.REPAIR, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_REPAIR])); - xpBarStateMap.put(PrimarySkillType.SALVAGE, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_SALVAGE])); - xpBarStateMap.put(PrimarySkillType.SMELTING, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_SMELTING])); - xpBarStateMap.put(PrimarySkillType.SWORDS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_SWORDS])); - xpBarStateMap.put(PrimarySkillType.TAMING, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_TAMING])); - xpBarStateMap.put(PrimarySkillType.UNARMED, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_UNARMED])); - xpBarStateMap.put(PrimarySkillType.WOODCUTTING, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_WOODCUTTING])); - xpBarStateMap.put(PrimarySkillType.TRIDENTS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_TRIDENTS])); - xpBarStateMap.put(PrimarySkillType.CROSSBOWS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_CROSSBOWS])); - + lastLogin = Long.parseLong(character[OVERHAUL_LAST_LOGIN]); } catch (Exception e) { - xpBarStateMap = MMOExperienceBarManager.generateDefaultBarStateMap(); + lastLogin = -1; } - PlayerData 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; - } - } - - private @NotNull Map getSkillMapFromLine(@NotNull String[] splitDataArray) { - Map skills = new EnumMap<>(PrimarySkillType.class); // Skill & Level - String username = splitDataArray[FlatFileMappings.USERNAME]; - - tryLoadSkillIntValuesFromRawData(skills, splitDataArray, PrimarySkillType.TAMING, FlatFileMappings.SKILLS_TAMING, username); - tryLoadSkillIntValuesFromRawData(skills, splitDataArray, PrimarySkillType.MINING, FlatFileMappings.SKILLS_MINING, username); - tryLoadSkillIntValuesFromRawData(skills, splitDataArray, PrimarySkillType.REPAIR, FlatFileMappings.SKILLS_REPAIR, username); - tryLoadSkillIntValuesFromRawData(skills, splitDataArray, PrimarySkillType.WOODCUTTING, FlatFileMappings.SKILLS_WOODCUTTING, username); - tryLoadSkillIntValuesFromRawData(skills, splitDataArray, PrimarySkillType.UNARMED, FlatFileMappings.SKILLS_UNARMED, username); - tryLoadSkillIntValuesFromRawData(skills, splitDataArray, PrimarySkillType.HERBALISM, FlatFileMappings.SKILLS_HERBALISM, username); - tryLoadSkillIntValuesFromRawData(skills, splitDataArray, PrimarySkillType.EXCAVATION, FlatFileMappings.SKILLS_EXCAVATION, username); - tryLoadSkillIntValuesFromRawData(skills, splitDataArray, PrimarySkillType.ARCHERY, FlatFileMappings.SKILLS_ARCHERY, username); - tryLoadSkillIntValuesFromRawData(skills, splitDataArray, PrimarySkillType.SWORDS, FlatFileMappings.SKILLS_SWORDS, username); - tryLoadSkillIntValuesFromRawData(skills, splitDataArray, PrimarySkillType.AXES, FlatFileMappings.SKILLS_AXES, username); - tryLoadSkillIntValuesFromRawData(skills, splitDataArray, PrimarySkillType.ACROBATICS, FlatFileMappings.SKILLS_ACROBATICS, username); - tryLoadSkillIntValuesFromRawData(skills, splitDataArray, PrimarySkillType.FISHING, FlatFileMappings.SKILLS_FISHING, username); - tryLoadSkillIntValuesFromRawData(skills, splitDataArray, PrimarySkillType.ALCHEMY, FlatFileMappings.SKILLS_ALCHEMY, username); - tryLoadSkillIntValuesFromRawData(skills, splitDataArray, PrimarySkillType.TRIDENTS, FlatFileMappings.SKILLS_TRIDENTS, username); - tryLoadSkillIntValuesFromRawData(skills, splitDataArray, PrimarySkillType.CROSSBOWS, FlatFileMappings.SKILLS_CROSSBOWS, username); - - return skills; + return new PlayerProfile(username, uuid, skills, skillsXp, skillsDATS, scoreboardTipsShown, uniquePlayerDataMap, lastLogin); } private void tryLoadSkillCooldownFromRawData(@NotNull Map cooldownMap, @NotNull String[] character, @NotNull SuperAbilityType superAbilityType, int cooldownSuperBreaker, @NotNull String userName) { try { cooldownMap.put(superAbilityType, Integer.valueOf(character[cooldownSuperBreaker])); } catch (NumberFormatException e) { - mcMMO.p.getLogger().severe("Data corruption when trying to load the value for skill "+superAbilityType.toString()+" for player named " + userName+ " setting value to zero"); + logger.severe("Data corruption when trying to load the value for skill "+superAbilityType+" for player named " + userName+ " setting value to zero"); e.printStackTrace(); } } - private void tryLoadSkillFloatValuesFromRawData(@NotNull Map skillMap, @NotNull String[] character, @NotNull PrimarySkillType primarySkillType, int index, @NotNull String userName) { try { float valueFromString = Integer.parseInt(character[index]); skillMap.put(primarySkillType, valueFromString); } catch (NumberFormatException e) { skillMap.put(primarySkillType, 0F); - mcMMO.p.getLogger().severe("Data corruption when trying to load the value for skill "+primarySkillType.toString()+" for player named " + userName+ " setting value to zero"); + logger.severe("Data corruption when trying to load the value for skill "+primarySkillType+" for player named " + userName+ " setting value to zero"); e.printStackTrace(); } } - private void tryLoadSkillIntValuesFromRawData(@NotNull Map skillMap, @NotNull String[] character, @NotNull PrimarySkillType primarySkillType, int index, @NotNull String userName) { try { int valueFromString = Integer.parseInt(character[index]); skillMap.put(primarySkillType, valueFromString); } catch (NumberFormatException e) { skillMap.put(primarySkillType, 0); - mcMMO.p.getLogger().severe("Data corruption when trying to load the value for skill "+primarySkillType.toString()+" for player named " + userName+ " setting value to zero"); + logger.severe("Data corruption when trying to load the value for skill "+primarySkillType+" for player named " + userName+ " setting value to zero"); e.printStackTrace(); } } + private @NotNull Map getSkillMapFromLine(@NotNull String[] character) { + EnumMap skills = new EnumMap<>(PrimarySkillType.class); // Skill & Level + String username = character[USERNAME_INDEX]; - public @NotNull DatabaseType getDatabaseType() { + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.ACROBATICS, SKILLS_ACROBATICS, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.TAMING, SKILLS_TAMING, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.MINING, SKILLS_MINING, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.REPAIR, SKILLS_REPAIR, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.WOODCUTTING, SKILLS_WOODCUTTING, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.UNARMED, SKILLS_UNARMED, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.HERBALISM, SKILLS_HERBALISM, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.EXCAVATION, SKILLS_EXCAVATION, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.ARCHERY, SKILLS_ARCHERY, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.SWORDS, SKILLS_SWORDS, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.AXES, SKILLS_AXES, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.FISHING, SKILLS_FISHING, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.ALCHEMY, SKILLS_ALCHEMY, username); + + return skills; + } + + public DatabaseType getDatabaseType() { return DatabaseType.FLATFILE; } - private int getSkillIndex(@NotNull PrimarySkillType primarySkillType) { - 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"); - - } + public @NotNull File getUsersFile() { + return usersFile; } @Override diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index 16d1588dc..65b492648 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -13,6 +13,7 @@ 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.skills.SkillTools; import com.gmail.nossr50.util.skills.SkillUtils; import com.neetgames.mcmmo.MobHealthBarType; import com.neetgames.mcmmo.UniqueDataType; @@ -21,6 +22,7 @@ import com.neetgames.mcmmo.exceptions.InvalidSkillException; import com.neetgames.mcmmo.skill.SkillBossBarState; import org.apache.tomcat.jdbc.pool.DataSource; import org.apache.tomcat.jdbc.pool.PoolProperties; +import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; import org.jetbrains.annotations.NotNull; @@ -35,7 +37,9 @@ public final class SQLDatabaseManager implements DatabaseManager { 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(); + public static final int CHILD_SKILLS_SIZE = 2; + public static final String LEGACY_DRIVER_PATH = "com.mysql.jdbc.Driver"; + private final String tablePrefix = mcMMO.p.getGeneralConfig().getMySQLTablePrefix(); private final Map cachedUserIDs = new HashMap<>(); @@ -48,12 +52,13 @@ public final class SQLDatabaseManager implements DatabaseManager { 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. + private String driverPath = "com.mysql.cj.jdbc.Driver"; //modern driver protected SQLDatabaseManager() { - String connectionString = "jdbc:mysql://" + Config.getInstance().getMySQLServerName() - + ":" + Config.getInstance().getMySQLServerPort() + "/" + Config.getInstance().getMySQLDatabaseName(); + String connectionString = "jdbc:mysql://" + mcMMO.p.getGeneralConfig().getMySQLServerName() + + ":" + mcMMO.p.getGeneralConfig().getMySQLServerPort() + "/" + mcMMO.p.getGeneralConfig().getMySQLDatabaseName(); - if(Config.getInstance().getMySQLSSL()) + if(mcMMO.p.getGeneralConfig().getMySQLSSL()) connectionString += "?verifyServerCertificate=false"+ "&useSSL=true"+ @@ -64,24 +69,29 @@ public final class SQLDatabaseManager implements DatabaseManager { try { // Force driver to load if not yet loaded - Class.forName("com.mysql.jdbc.Driver"); - } - catch (ClassNotFoundException e) { - e.printStackTrace(); - return; + Class.forName(driverPath); + } catch (ClassNotFoundException e) { + try { + driverPath = LEGACY_DRIVER_PATH; //fall on deprecated path if new path isn't found + Class.forName(driverPath); + } catch (ClassNotFoundException ex) { + e.printStackTrace(); + ex.printStackTrace(); + mcMMO.p.getLogger().severe("Neither driver found"); + return; + } //throw e; // aborts onEnable() Riking if you want to do this, fully implement it. } - debug = Config.getInstance().getMySQLDebug(); - + debug = mcMMO.p.getGeneralConfig().getMySQLDebug(); PoolProperties poolProperties = new PoolProperties(); - poolProperties.setDriverClassName("com.mysql.jdbc.Driver"); + poolProperties.setDriverClassName(driverPath); poolProperties.setUrl(connectionString); - poolProperties.setUsername(Config.getInstance().getMySQLUserName()); - poolProperties.setPassword(Config.getInstance().getMySQLUserPassword()); - poolProperties.setMaxIdle(Config.getInstance().getMySQLMaxPoolSize(PoolIdentifier.MISC)); - poolProperties.setMaxActive(Config.getInstance().getMySQLMaxConnections(PoolIdentifier.MISC)); + poolProperties.setUsername(mcMMO.p.getGeneralConfig().getMySQLUserName()); + poolProperties.setPassword(mcMMO.p.getGeneralConfig().getMySQLUserPassword()); + poolProperties.setMaxIdle(mcMMO.p.getGeneralConfig().getMySQLMaxPoolSize(PoolIdentifier.MISC)); + poolProperties.setMaxActive(mcMMO.p.getGeneralConfig().getMySQLMaxConnections(PoolIdentifier.MISC)); poolProperties.setInitialSize(0); poolProperties.setMaxWait(-1); poolProperties.setRemoveAbandoned(true); @@ -91,13 +101,13 @@ public final class SQLDatabaseManager implements DatabaseManager { poolProperties.setValidationInterval(30000); miscPool = new DataSource(poolProperties); poolProperties = new PoolProperties(); - poolProperties.setDriverClassName("com.mysql.jdbc.Driver"); + poolProperties.setDriverClassName(driverPath); poolProperties.setUrl(connectionString); - poolProperties.setUsername(Config.getInstance().getMySQLUserName()); - poolProperties.setPassword(Config.getInstance().getMySQLUserPassword()); + poolProperties.setUsername(mcMMO.p.getGeneralConfig().getMySQLUserName()); + poolProperties.setPassword(mcMMO.p.getGeneralConfig().getMySQLUserPassword()); poolProperties.setInitialSize(0); - poolProperties.setMaxIdle(Config.getInstance().getMySQLMaxPoolSize(PoolIdentifier.SAVE)); - poolProperties.setMaxActive(Config.getInstance().getMySQLMaxConnections(PoolIdentifier.SAVE)); + poolProperties.setMaxIdle(mcMMO.p.getGeneralConfig().getMySQLMaxPoolSize(PoolIdentifier.SAVE)); + poolProperties.setMaxActive(mcMMO.p.getGeneralConfig().getMySQLMaxConnections(PoolIdentifier.SAVE)); poolProperties.setMaxWait(-1); poolProperties.setRemoveAbandoned(true); poolProperties.setRemoveAbandonedTimeout(60); @@ -106,13 +116,13 @@ public final class SQLDatabaseManager implements DatabaseManager { poolProperties.setValidationInterval(30000); savePool = new DataSource(poolProperties); poolProperties = new PoolProperties(); - poolProperties.setDriverClassName("com.mysql.jdbc.Driver"); + poolProperties.setDriverClassName(driverPath); poolProperties.setUrl(connectionString); - poolProperties.setUsername(Config.getInstance().getMySQLUserName()); - poolProperties.setPassword(Config.getInstance().getMySQLUserPassword()); + poolProperties.setUsername(mcMMO.p.getGeneralConfig().getMySQLUserName()); + poolProperties.setPassword(mcMMO.p.getGeneralConfig().getMySQLUserPassword()); poolProperties.setInitialSize(0); - poolProperties.setMaxIdle(Config.getInstance().getMySQLMaxPoolSize(PoolIdentifier.LOAD)); - poolProperties.setMaxActive(Config.getInstance().getMySQLMaxConnections(PoolIdentifier.LOAD)); + poolProperties.setMaxIdle(mcMMO.p.getGeneralConfig().getMySQLMaxPoolSize(PoolIdentifier.LOAD)); + poolProperties.setMaxActive(mcMMO.p.getGeneralConfig().getMySQLMaxConnections(PoolIdentifier.LOAD)); poolProperties.setMaxWait(-1); poolProperties.setRemoveAbandoned(true); poolProperties.setRemoveAbandonedTimeout(60); @@ -124,7 +134,7 @@ public final class SQLDatabaseManager implements DatabaseManager { checkStructure(); } - public void purgePowerlessUsers() { + public int purgePowerlessUsers() { massUpdateLock.lock(); mcMMO.p.getLogger().info("Purging powerless users..."); @@ -157,11 +167,12 @@ public final class SQLDatabaseManager implements DatabaseManager { } mcMMO.p.getLogger().info("Purged " + purged + " users from the database."); + return purged; } public void purgeOldUsers() { massUpdateLock.lock(); - mcMMO.p.getLogger().info("Purging inactive users older than " + (PURGE_TIME / 2630000000L) + " months..."); + mcMMO.p.getLogger().info("Purging inactive users older than " + (mcMMO.p.getPurgeTime() / 2630000000L) + " months..."); Connection connection = null; Statement statement = null; @@ -176,12 +187,11 @@ public final class SQLDatabaseManager implements DatabaseManager { "JOIN " + tablePrefix + "huds h ON (u.id = h.user_id) " + "JOIN " + tablePrefix + "skills s ON (u.id = s.user_id) " + "JOIN " + tablePrefix + "cooldowns c ON (u.id = c.user_id) " + - "WHERE ((UNIX_TIMESTAMP() - lastlogin) > " + PURGE_TIME + ")"); + "WHERE ((UNIX_TIMESTAMP() - lastlogin) > " + mcMMO.p.getPurgeTime() + ")"); } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { tryClose(statement); tryClose(connection); massUpdateLock.unlock(); @@ -279,7 +289,7 @@ public final class SQLDatabaseManager implements DatabaseManager { statement.setInt(14, dataSnapshot.getSkillLevel(PrimarySkillType.TRIDENTS)); statement.setInt(15, dataSnapshot.getSkillLevel(PrimarySkillType.CROSSBOWS)); int total = 0; - for (PrimarySkillType primarySkillType : PrimarySkillType.getNonChildSkills()) + for (PrimarySkillType primarySkillType : SkillTools.getNonChildSkills()) total += dataSnapshot.getSkillLevel(primarySkillType); statement.setInt(16, total); statement.setInt(17, id); @@ -343,7 +353,7 @@ public final class SQLDatabaseManager implements DatabaseManager { } statement = connection.prepareStatement("UPDATE " + tablePrefix + "huds SET mobhealthbar = ?, scoreboardtips = ? WHERE user_id = ?"); - statement.setString(1, Config.getInstance().getMobHealthbarDefault().name()); + statement.setString(1, MobHealthbarType.HEARTS.name()); statement.setInt(2, dataSnapshot.getScoreboardTipsShown()); statement.setInt(3, id); success = (statement.executeUpdate() != 0); @@ -416,7 +426,7 @@ public final class SQLDatabaseManager implements DatabaseManager { List stats = new ArrayList<>(); //Fix for a plugin that people are using that is throwing SQL errors - if(primarySkillType != null && PrimarySkillType.isChildSkill(primarySkillType)) { + if(primarySkillType != null && SkillTools.isChildSkill(primarySkillType)) { mcMMO.p.getLogger().severe("A plugin hooking into mcMMO is being naughty with our database commands, update all plugins that hook into mcMMO and contact their devs!"); throw new InvalidSkillException("A plugin hooking into mcMMO that you are using is attempting to read leaderboard skills for child skills, child skills do not have leaderboards! This is NOT an mcMMO error!"); } @@ -467,7 +477,7 @@ public final class SQLDatabaseManager implements DatabaseManager { try { connection = getConnection(PoolIdentifier.MISC); - for (PrimarySkillType primarySkillType : PrimarySkillType.getNonChildSkills()) { + for (PrimarySkillType primarySkillType : SkillTools.getNonChildSkills()) { String skillName = primarySkillType.getRawSkillName().toLowerCase(Locale.ENGLISH); // Get count of all users with higher skill level than player String sql = "SELECT COUNT(*) AS 'rank' FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE " + skillName + " > 0 " + @@ -554,19 +564,19 @@ public final class SQLDatabaseManager implements DatabaseManager { return skills; } - public void insertNewUser(@NotNull String playerName, @NotNull UUID uuid) { + public @NotNull PlayerProfile newUser(String playerName, UUID uuid) { Connection connection = null; try { connection = getConnection(PoolIdentifier.MISC); newUser(connection, playerName, uuid); - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { tryClose(connection); } + + return new PlayerProfile(playerName, uuid, true, mcMMO.p.getAdvancedConfig().getStartingLevel()); } @Override @@ -576,15 +586,15 @@ public final class SQLDatabaseManager implements DatabaseManager { int id = newUser(connection, player.getName(), player.getUniqueId()); if (id == -1) { - return new PlayerProfile(player.getName(), player.getUniqueId(), false); + return new PlayerProfile(player.getName(), player.getUniqueId(), false, mcMMO.p.getAdvancedConfig().getStartingLevel()); } else { - return loadPlayerProfile(player.getUniqueId(), player.getName()); + return loadPlayerProfile(player); } } catch (SQLException e) { e.printStackTrace(); } - return new PlayerProfile(player.getName(), player.getUniqueId(), false); + return new PlayerProfile(player.getName(), player.getUniqueId(), false, mcMMO.p.getAdvancedConfig().getStartingLevel()); } private int newUser(Connection connection, String playerName, UUID uuid) { @@ -630,14 +640,25 @@ public final class SQLDatabaseManager implements DatabaseManager { return loadPlayerFromDB(null, playerName); } catch (RuntimeException e) { e.printStackTrace(); - return new PlayerProfile(playerName, false); + return new PlayerProfile(playerName, false, mcMMO.p.getAdvancedConfig().getStartingLevel()); } } - public @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid, @Nullable String playerName) { + @Override + public @NotNull PlayerProfile loadPlayerProfile(@NotNull OfflinePlayer offlinePlayer) { + return loadPlayerFromDB(offlinePlayer.getUniqueId(), offlinePlayer.getName()); + } + + public @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid, @Nullable String playerName) { return loadPlayerFromDB(uuid, playerName); } + @Override + public @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid) { + return loadPlayerFromDB(uuid, null); + } + + 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."); @@ -657,7 +678,7 @@ public final class SQLDatabaseManager implements DatabaseManager { if (id == -1) { // There is no such user - return new PlayerProfile(playerName, false); + return new PlayerProfile(playerName, mcMMO.p.getAdvancedConfig().getStartingLevel()); } // There is such a user writeMissingRows(connection, id); @@ -715,7 +736,7 @@ public final class SQLDatabaseManager implements DatabaseManager { } //Return empty profile - return new PlayerProfile(playerName, false); + return new PlayerProfile(playerName, mcMMO.p.getAdvancedConfig().getStartingLevel()); } public void convertUsers(DatabaseManager destination) { @@ -885,7 +906,7 @@ public final class SQLDatabaseManager implements DatabaseManager { statement = connection.prepareStatement("SELECT table_name FROM INFORMATION_SCHEMA.TABLES" + " WHERE table_schema = ?" + " AND table_name = ?"); - statement.setString(1, Config.getInstance().getMySQLDatabaseName()); + statement.setString(1, mcMMO.p.getGeneralConfig().getMySQLDatabaseName()); statement.setString(2, tablePrefix + "users"); resultSet = statement.executeQuery(); if (!resultSet.next()) { @@ -901,21 +922,21 @@ public final class SQLDatabaseManager implements DatabaseManager { tryClose(createStatement); } tryClose(resultSet); - statement.setString(1, Config.getInstance().getMySQLDatabaseName()); + statement.setString(1, mcMMO.p.getGeneralConfig().getMySQLDatabaseName()); statement.setString(2, tablePrefix + "huds"); resultSet = statement.executeQuery(); if (!resultSet.next()) { createStatement = connection.createStatement(); createStatement.executeUpdate("CREATE TABLE IF NOT EXISTS `" + tablePrefix + "huds` (" + "`user_id` int(10) unsigned NOT NULL," - + "`mobhealthbar` varchar(50) NOT NULL DEFAULT '" + Config.getInstance().getMobHealthbarDefault() + "'," + + "`mobhealthbar` varchar(50) NOT NULL DEFAULT '" + mcMMO.p.getGeneralConfig().getMobHealthbarDefault() + "'," + "`scoreboardtips` int(10) NOT NULL DEFAULT '0'," + "PRIMARY KEY (`user_id`)) " + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); tryClose(createStatement); } tryClose(resultSet); - statement.setString(1, Config.getInstance().getMySQLDatabaseName()); + statement.setString(1, mcMMO.p.getGeneralConfig().getMySQLDatabaseName()); statement.setString(2, tablePrefix + "cooldowns"); resultSet = statement.executeQuery(); if (!resultSet.next()) { @@ -942,10 +963,12 @@ public final class SQLDatabaseManager implements DatabaseManager { tryClose(createStatement); } tryClose(resultSet); - statement.setString(1, Config.getInstance().getMySQLDatabaseName()); + statement.setString(1, mcMMO.p.getGeneralConfig().getMySQLDatabaseName()); statement.setString(2, tablePrefix + "skills"); resultSet = statement.executeQuery(); if (!resultSet.next()) { + String startingLevel = "'" + mcMMO.p.getAdvancedConfig().getStartingLevel() + "'"; + String totalLevel = "'" + (mcMMO.p.getAdvancedConfig().getStartingLevel() * (PrimarySkillType.values().length - CHILD_SKILLS_SIZE)) + "'"; createStatement = connection.createStatement(); createStatement.executeUpdate("CREATE TABLE IF NOT EXISTS `" + tablePrefix + "skills` (" + "`user_id` int(10) unsigned NOT NULL," @@ -970,7 +993,7 @@ public final class SQLDatabaseManager implements DatabaseManager { tryClose(createStatement); } tryClose(resultSet); - statement.setString(1, Config.getInstance().getMySQLDatabaseName()); + statement.setString(1, mcMMO.p.getGeneralConfig().getMySQLDatabaseName()); statement.setString(2, tablePrefix + "experience"); resultSet = statement.executeQuery(); if (!resultSet.next()) { @@ -1050,9 +1073,9 @@ public final class SQLDatabaseManager implements DatabaseManager { checkDatabaseStructure(connection, updateType); } - if (Config.getInstance().getTruncateSkills()) { - for (PrimarySkillType primarySkillType : PrimarySkillType.getNonChildSkills()) { - int cap = Config.getInstance().getLevelCap(primarySkillType); + if (mcMMO.p.getGeneralConfig().getTruncateSkills()) { + for (PrimarySkillType primarySkillType : SkillTools.getNonChildSkills()) { + int cap = mcMMO.p.getSkillTools().getLevelCap(primarySkillType); if (cap != Integer.MAX_VALUE) { statement = connection.prepareStatement("UPDATE `" + tablePrefix + "skills` SET `" + primarySkillType.getRawSkillName().toLowerCase(Locale.ENGLISH) + "` = " + cap + " WHERE `" @@ -1129,7 +1152,7 @@ public final class SQLDatabaseManager implements DatabaseManager { break; case ADD_SQL_INDEXES: - checkUpgradeAddSQLIndexes(statement); +// checkUpgradeAddSQLIndexes(statement); break; case ADD_MOB_HEALTHBARS: @@ -1207,7 +1230,7 @@ public final class SQLDatabaseManager implements DatabaseManager { statement = connection.prepareStatement("INSERT IGNORE INTO " + tablePrefix + "huds (user_id, mobhealthbar, scoreboardtips) VALUES (?, ?, ?)"); statement.setInt(1, id); - statement.setString(2, Config.getInstance().getMobHealthbarDefault().name()); + statement.setString(2, mcMMO.p.getGeneralConfig().getMobHealthbarDefault().name()); statement.setInt(3, 0); statement.execute(); statement.close(); @@ -1220,15 +1243,12 @@ public final class SQLDatabaseManager implements DatabaseManager { } } - private @Nullable PlayerData loadFromResult(@NotNull String playerName, @NotNull ResultSet result) throws SQLException { - MMODataBuilder MMODataBuilder = new MMODataBuilder(); - Map skills = new HashMap<>(); // Skill & Level - Map skillsXp = new HashMap<>(); // Skill & XP - Map skillsDATS = new HashMap<>(); // Ability & Cooldown - Map uniqueData = new EnumMap(UniqueDataType.class); //Chimaera wing cooldown and other misc info - Map xpBarStateMap = new HashMap(); - - MobHealthBarType mobHealthbarType; + private PlayerProfile loadFromResult(String playerName, ResultSet result) throws SQLException { + Map skills = new EnumMap(PrimarySkillType.class); // Skill & Level + Map skillsXp = new EnumMap(PrimarySkillType.class); // Skill & XP + Map skillsDATS = new EnumMap<>(SuperAbilityType.class); // Ability & Cooldown + Map uniqueData = new EnumMap<>(UniqueDataType.class); //Chimaera wing cooldown and other misc info + MobHealthbarType mobHealthbarType; UUID uuid; int scoreboardTipsShown; @@ -1291,14 +1311,6 @@ public final class SQLDatabaseManager implements DatabaseManager { // - - try { - mobHealthbarType = MobHealthBarType.valueOf(result.getString(OFFSET_OTHER + 1)); - } - catch (Exception e) { - mobHealthbarType = Config.getInstance().getMobHealthbarDefault(); - } - try { scoreboardTipsShown = result.getInt(OFFSET_OTHER + 2); } @@ -1358,6 +1370,7 @@ public final class SQLDatabaseManager implements DatabaseManager { return null; } + return new PlayerProfile(playerName, uuid, skills, skillsXp, skillsDATS, scoreboardTipsShown, uniqueData, null); } private void printErrors(SQLException ex) { @@ -1469,7 +1482,7 @@ public final class SQLDatabaseManager implements DatabaseManager { } catch (SQLException ex) { mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for mob healthbars..."); - statement.executeUpdate("ALTER TABLE `" + tablePrefix + "huds` ADD `mobhealthbar` varchar(50) NOT NULL DEFAULT '" + Config.getInstance().getMobHealthbarDefault() + "'"); + statement.executeUpdate("ALTER TABLE `" + tablePrefix + "huds` ADD `mobhealthbar` varchar(50) NOT NULL DEFAULT '" + mcMMO.p.getGeneralConfig().getMobHealthbarDefault() + "'"); } } @@ -1491,10 +1504,10 @@ public final class SQLDatabaseManager implements DatabaseManager { resultSet = statement.executeQuery("SHOW INDEX FROM `" + tablePrefix + "skills` WHERE `Key_name` LIKE 'idx\\_%'"); resultSet.last(); - if (resultSet.getRow() != PrimarySkillType.getNonChildSkills().size()) { + if (resultSet.getRow() != SkillTools.getNonChildSkills().size()) { mcMMO.p.getLogger().info("Indexing tables, this may take a while on larger databases"); - for (PrimarySkillType primarySkillType : PrimarySkillType.getNonChildSkills()) { + for (PrimarySkillType primarySkillType : SkillTools.getNonChildSkills()) { String skill_name = primarySkillType.getRawSkillName().toLowerCase(Locale.ENGLISH); try { @@ -1778,7 +1791,7 @@ public final class SQLDatabaseManager implements DatabaseManager { try { connection = getConnection(PoolIdentifier.MISC); statement = connection.prepareStatement("UPDATE " + tablePrefix + "huds SET mobhealthbar = ?"); - statement.setString(1, Config.getInstance().getMobHealthbarDefault().toString()); + statement.setString(1, mcMMO.p.getGeneralConfig().getMobHealthbarDefault().toString()); statement.executeUpdate(); } catch (SQLException ex) { diff --git a/src/main/java/com/gmail/nossr50/database/UserQuery.java b/src/main/java/com/gmail/nossr50/database/UserQuery.java new file mode 100644 index 000000000..4c6b5e730 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/UserQuery.java @@ -0,0 +1,7 @@ +package com.gmail.nossr50.database; + +import org.jetbrains.annotations.NotNull; + +public interface UserQuery { + @NotNull UserQueryType getType(); +} diff --git a/src/main/java/com/gmail/nossr50/database/UserQueryFull.java b/src/main/java/com/gmail/nossr50/database/UserQueryFull.java new file mode 100644 index 000000000..47a3e965a --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/UserQueryFull.java @@ -0,0 +1,31 @@ +package com.gmail.nossr50.database; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public class UserQueryFull implements UserQueryUUID, UserQueryName { + + private final @NotNull String name; + private final @NotNull UUID uuid; + + public UserQueryFull(@NotNull String name, @NotNull UUID uuid) { + this.name = name; + this.uuid = uuid; + } + + @Override + public @NotNull UserQueryType getType() { + return UserQueryType.UUID_AND_NAME; + } + + @Override + public @NotNull String getName() { + return name; + } + + @Override + public @NotNull UUID getUUID() { + return uuid; + } +} diff --git a/src/main/java/com/gmail/nossr50/database/UserQueryName.java b/src/main/java/com/gmail/nossr50/database/UserQueryName.java new file mode 100644 index 000000000..60604101c --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/UserQueryName.java @@ -0,0 +1,7 @@ +package com.gmail.nossr50.database; + +import org.jetbrains.annotations.NotNull; + +public interface UserQueryName extends UserQuery { + @NotNull String getName(); +} diff --git a/src/main/java/com/gmail/nossr50/database/UserQueryNameImpl.java b/src/main/java/com/gmail/nossr50/database/UserQueryNameImpl.java new file mode 100644 index 000000000..fe7abf910 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/UserQueryNameImpl.java @@ -0,0 +1,20 @@ +package com.gmail.nossr50.database; + +import org.jetbrains.annotations.NotNull; + +public class UserQueryNameImpl implements UserQueryName { + private final @NotNull String name; + + public UserQueryNameImpl(@NotNull String name) { + this.name = name; + } + + @Override + public @NotNull UserQueryType getType() { + return UserQueryType.NAME; + } + + public @NotNull String getName() { + return name; + } +} diff --git a/src/main/java/com/gmail/nossr50/database/UserQueryType.java b/src/main/java/com/gmail/nossr50/database/UserQueryType.java new file mode 100644 index 000000000..588dd76b0 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/UserQueryType.java @@ -0,0 +1,7 @@ +package com.gmail.nossr50.database; + +public enum UserQueryType { + UUID_AND_NAME, + UUID, + NAME +} diff --git a/src/main/java/com/gmail/nossr50/database/UserQueryUUID.java b/src/main/java/com/gmail/nossr50/database/UserQueryUUID.java new file mode 100644 index 000000000..192997f90 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/UserQueryUUID.java @@ -0,0 +1,11 @@ +package com.gmail.nossr50.database; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public interface UserQueryUUID extends UserQuery { + + @NotNull UUID getUUID(); + +} diff --git a/src/main/java/com/gmail/nossr50/database/UserQueryUUIDImpl.java b/src/main/java/com/gmail/nossr50/database/UserQueryUUIDImpl.java new file mode 100644 index 000000000..49ad038f5 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/UserQueryUUIDImpl.java @@ -0,0 +1,23 @@ +package com.gmail.nossr50.database; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public class UserQueryUUIDImpl implements UserQueryUUID { + private final @NotNull UUID uuid; + + public UserQueryUUIDImpl(@NotNull UUID uuid) { + this.uuid = uuid; + } + + @Override + public @NotNull UserQueryType getType() { + return UserQueryType.UUID; + } + + @Override + public @NotNull UUID getUUID() { + return uuid; + } +} diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/BadCategorizedFlatFileData.java b/src/main/java/com/gmail/nossr50/database/flatfile/BadCategorizedFlatFileData.java new file mode 100644 index 000000000..fbeaf9c2d --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/flatfile/BadCategorizedFlatFileData.java @@ -0,0 +1,42 @@ +package com.gmail.nossr50.database.flatfile; + +import com.gmail.nossr50.database.FlatFileDataFlag; +import com.google.common.base.Objects; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.HashSet; + +public class BadCategorizedFlatFileData extends CategorizedFlatFileData { + private final boolean[] badDataIndexes; + + protected BadCategorizedFlatFileData(int uniqueProcessingId, @NotNull HashSet dataFlags, @NotNull String[] splitData, boolean[] badDataIndexes) { + super(uniqueProcessingId, dataFlags, splitData); + this.badDataIndexes = badDataIndexes; + } + + public boolean[] getBadDataIndexes() { + return badDataIndexes; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + BadCategorizedFlatFileData that = (BadCategorizedFlatFileData) o; + return Objects.equal(badDataIndexes, that.badDataIndexes); + } + + @Override + public int hashCode() { + return Objects.hashCode(super.hashCode(), badDataIndexes); + } + + @Override + public String toString() { + return "BadCategorizedFlatFileData{" + + "badDataIndexes=" + Arrays.toString(badDataIndexes) + + '}'; + } +} diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileData.java b/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileData.java new file mode 100644 index 000000000..500be9c4f --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileData.java @@ -0,0 +1,58 @@ +package com.gmail.nossr50.database.flatfile; + +import com.gmail.nossr50.database.FlatFileDataFlag; +import com.google.common.base.Objects; +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; +import java.util.Set; + +public class CategorizedFlatFileData implements FlatFileDataContainer { + private final @NotNull Set dataFlags; + private final @NotNull String[] splitData; + private final int uniqueProcessingId; + + public CategorizedFlatFileData(int uniqueProcessingId, @NotNull HashSet dataFlags, @NotNull String[] splitData) { + this.uniqueProcessingId = uniqueProcessingId; + this.dataFlags = dataFlags; + this.splitData = splitData; + } + + public @NotNull Set getDataFlags() { + return dataFlags; + } + + public @NotNull String[] getSplitData() { + return splitData; + } + + public int getUniqueProcessingId() { + return uniqueProcessingId; + } + + public boolean isHealthyData() { + return dataFlags.size() == 0; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CategorizedFlatFileData that = (CategorizedFlatFileData) o; + return uniqueProcessingId == that.uniqueProcessingId && Objects.equal(dataFlags, that.dataFlags) && Objects.equal(splitData, that.splitData); + } + + @Override + public int hashCode() { + return Objects.hashCode(dataFlags, splitData, uniqueProcessingId); + } + + @Override + public String toString() { + return "CategorizedFlatFileData{" + + "dataFlags=" + dataFlags + + ", stringDataRepresentation='" + splitData + '\'' + + ", uniqueProcessingId=" + uniqueProcessingId + + '}'; + } +} diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataBuilder.java b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataBuilder.java new file mode 100644 index 000000000..ed048d5e1 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataBuilder.java @@ -0,0 +1,42 @@ +package com.gmail.nossr50.database.flatfile; + +import com.gmail.nossr50.database.FlatFileDataFlag; +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; + +public class FlatFileDataBuilder { + private final @NotNull HashSet dataFlags; + private @NotNull String[] splitStringData; + private final int uniqueProcessingId; + private boolean[] badDataValues; + + public FlatFileDataBuilder(@NotNull String[] splitStringData, int uniqueProcessingId) { + this.uniqueProcessingId = uniqueProcessingId; + this.splitStringData = splitStringData; + dataFlags = new HashSet<>(); + } + + public @NotNull FlatFileDataBuilder appendFlag(@NotNull FlatFileDataFlag dataFlag) { + dataFlags.add(dataFlag); + return this; + } + + public @NotNull FlatFileDataBuilder appendBadDataValues(boolean[] badDataValues) { + this.badDataValues = badDataValues; + return this; + } + + public @NotNull FlatFileDataContainer build() { + if(dataFlags.contains(FlatFileDataFlag.BAD_VALUES)) { + return new BadCategorizedFlatFileData(uniqueProcessingId, dataFlags, splitStringData, badDataValues); + } + + return new CategorizedFlatFileData(uniqueProcessingId, dataFlags, splitStringData); + } + + public @NotNull FlatFileDataBuilder setSplitStringData(@NotNull String[] splitStringData) { + this.splitStringData = splitStringData; + return this; + } +} diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataContainer.java b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataContainer.java new file mode 100644 index 000000000..e2fb2336c --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataContainer.java @@ -0,0 +1,21 @@ +package com.gmail.nossr50.database.flatfile; + +import com.gmail.nossr50.database.FlatFileDataFlag; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Set; + +public interface FlatFileDataContainer { + default @Nullable Set getDataFlags() { + return null; + } + + @NotNull String[] getSplitData(); + + int getUniqueProcessingId(); + + default boolean isHealthyData() { + return getDataFlags() == null || getDataFlags().size() == 0; + } +} diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtil.java b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtil.java new file mode 100644 index 000000000..e4048cdf0 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtil.java @@ -0,0 +1,116 @@ +package com.gmail.nossr50.database.flatfile; + +import com.gmail.nossr50.database.FlatFileDataFlag; +import com.gmail.nossr50.database.FlatFileDatabaseManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import static com.gmail.nossr50.database.FlatFileDatabaseManager.*; + +public class FlatFileDataUtil { + + public static @Nullable String[] getPreparedSaveDataLine(@NotNull FlatFileDataContainer dataContainer) { + if(dataContainer.getDataFlags() == null) { + return dataContainer.getSplitData(); + } + + //Data of this type is not salvageable + //TODO: Test that we ignore the things we are supposed to ignore + //TODO: Should we even keep track of the bad data or just not even build data containers for it? Making containers for it is only really useful for debugging.. well I suppose operations are typically async so it shouldn't matter + if(dataContainer.getDataFlags().contains(FlatFileDataFlag.CORRUPTED_OR_UNRECOGNIZABLE) + || dataContainer.getDataFlags().contains(FlatFileDataFlag.DUPLICATE_UUID) //For now we will not try to fix any issues with UUIDs + || dataContainer.getDataFlags().contains(FlatFileDataFlag.BAD_UUID_DATA) //For now we will not try to fix any issues with UUIDs + || dataContainer.getDataFlags().contains(FlatFileDataFlag.TOO_INCOMPLETE)) { + return null; + } + + String[] splitData; + + /* + * First fix the bad data values if they exist + */ + if(dataContainer instanceof BadCategorizedFlatFileData) { + BadCategorizedFlatFileData badData = (BadCategorizedFlatFileData) dataContainer; + splitData = repairBadData(dataContainer.getSplitData(), badData.getBadDataIndexes()); + } else { + splitData = dataContainer.getSplitData(); + } + + //Make sure we have as many values as we are supposed to + assert splitData.length == FlatFileDatabaseManager.DATA_ENTRY_COUNT; + return splitData; + } + + public static @NotNull String[] repairBadData(@NotNull String[] splitData, boolean[] badDataValues) { + for(int i = 0; i < FlatFileDatabaseManager.DATA_ENTRY_COUNT; i++) { + if(badDataValues[i]) { + //This data value was marked as bad so we zero initialize it + splitData[i] = getZeroInitialisedData(i, 0); + } + } + + return splitData; + } + + /** + * @param index "zero" Initialization will depend on what the index is for + * @return the "zero" initialized data corresponding to the index + */ + public static @NotNull String getZeroInitialisedData(int index, int startingLevel) throws IndexOutOfBoundsException { + switch(index) { + case USERNAME_INDEX: + return LEGACY_INVALID_OLD_USERNAME; //We'll keep using this value for legacy compatibility reasons (not sure if needed but don't care) + case 2: //Assumption: Used to be for something, no longer used + case 3: //Assumption: Used to be for something, no longer used + case 23: //Assumption: Used to be used for something, no longer used + case 33: //Assumption: Used to be used for something, no longer used + case LEGACY_LAST_LOGIN: + case HEALTHBAR: + return "IGNORED"; + case SKILLS_MINING: + case SKILLS_REPAIR: + case SKILLS_UNARMED: + case SKILLS_HERBALISM: + case SKILLS_EXCAVATION: + case SKILLS_ARCHERY: + case SKILLS_SWORDS: + case SKILLS_AXES: + case SKILLS_WOODCUTTING: + case SKILLS_ACROBATICS: + case SKILLS_TAMING: + case SKILLS_FISHING: + case SKILLS_ALCHEMY: + return String.valueOf(startingLevel); + case OVERHAUL_LAST_LOGIN: + return String.valueOf(-1L); + case COOLDOWN_BERSERK: + case COOLDOWN_GIGA_DRILL_BREAKER: + case COOLDOWN_TREE_FELLER: + case COOLDOWN_GREEN_TERRA: + case COOLDOWN_SERRATED_STRIKES: + case COOLDOWN_SKULL_SPLITTER: + case COOLDOWN_SUPER_BREAKER: + case COOLDOWN_BLAST_MINING: + case SCOREBOARD_TIPS: + case COOLDOWN_CHIMAERA_WING: + case EXP_MINING: + case EXP_WOODCUTTING: + case EXP_REPAIR: + case EXP_UNARMED: + case EXP_HERBALISM: + case EXP_EXCAVATION: + case EXP_ARCHERY: + case EXP_SWORDS: + case EXP_AXES: + case EXP_ACROBATICS: + case EXP_TAMING: + case EXP_FISHING: + case EXP_ALCHEMY: + return "0"; + case UUID_INDEX: + throw new IndexOutOfBoundsException(); //TODO: Add UUID recovery? Might not even be worth it. + } + + throw new IndexOutOfBoundsException(); + } +} diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/LeaderboardStatus.java b/src/main/java/com/gmail/nossr50/database/flatfile/LeaderboardStatus.java new file mode 100644 index 000000000..9b3313d99 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/flatfile/LeaderboardStatus.java @@ -0,0 +1,7 @@ +package com.gmail.nossr50.database.flatfile; + +public enum LeaderboardStatus { + TOO_SOON_TO_UPDATE, + UPDATED, + FAILED +} diff --git a/src/main/java/com/gmail/nossr50/datatypes/LevelUpBroadcastPredicate.java b/src/main/java/com/gmail/nossr50/datatypes/LevelUpBroadcastPredicate.java index 8820f7742..51ab29a14 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/LevelUpBroadcastPredicate.java +++ b/src/main/java/com/gmail/nossr50/datatypes/LevelUpBroadcastPredicate.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.datatypes; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.mcMMO; @@ -42,7 +41,7 @@ public class LevelUpBroadcastPredicate implements Predi Player listeningPlayer = (Player) t; //Party Member Check - if(Config.getInstance().isLevelUpBroadcastsPartyMembersOnly()) { + if(mcMMO.p.getGeneralConfig().isLevelUpBroadcastsPartyMembersOnly()) { McMMOPlayer mmoListeningPlayer = UserManager.getPlayer(listeningPlayer); if(mmoListeningPlayer == null) { @@ -68,8 +67,8 @@ public class LevelUpBroadcastPredicate implements Predi } //Distance checks - if(Config.getInstance().shouldLevelUpBroadcastsRestrictDistance()) { - if(!Misc.isNear(mmoBroadcastingPlayer.getPlayer().getLocation(), listeningPlayer.getLocation(), Config.getInstance().getLevelUpBroadcastRadius())) { + if(mcMMO.p.getGeneralConfig().shouldLevelUpBroadcastsRestrictDistance()) { + if(!Misc.isNear(mmoBroadcastingPlayer.getPlayer().getLocation(), listeningPlayer.getLocation(), mcMMO.p.getGeneralConfig().getLevelUpBroadcastRadius())) { return false; } } @@ -83,12 +82,12 @@ public class LevelUpBroadcastPredicate implements Predi return true; } else { //Send out to console - return Config.getInstance().shouldLevelUpBroadcastToConsole(); + return mcMMO.p.getGeneralConfig().shouldLevelUpBroadcastToConsole(); } } private static boolean isLevelUpBroadcastsSameWorldOnly() { - return Config.getInstance().isLevelUpBroadcastsSameWorldOnly(); + return mcMMO.p.getGeneralConfig().isLevelUpBroadcastsSameWorldOnly(); } @Override diff --git a/src/main/java/com/gmail/nossr50/datatypes/PowerLevelUpBroadcastPredicate.java b/src/main/java/com/gmail/nossr50/datatypes/PowerLevelUpBroadcastPredicate.java index 549255006..b50d731eb 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/PowerLevelUpBroadcastPredicate.java +++ b/src/main/java/com/gmail/nossr50/datatypes/PowerLevelUpBroadcastPredicate.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.datatypes; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.mcMMO; @@ -42,7 +41,7 @@ public class PowerLevelUpBroadcastPredicate implements Player listeningPlayer = (Player) t; //Party Member Check - if(Config.getInstance().isPowerLevelUpBroadcastsPartyMembersOnly()) { + if(mcMMO.p.getGeneralConfig().isPowerLevelUpBroadcastsPartyMembersOnly()) { McMMOPlayer mmoListeningPlayer = UserManager.getPlayer(listeningPlayer); if(mmoListeningPlayer == null) { @@ -68,8 +67,8 @@ public class PowerLevelUpBroadcastPredicate implements } //Distance checks - if(Config.getInstance().shouldPowerLevelUpBroadcastsRestrictDistance()) { - if(!Misc.isNear(mmoBroadcastingPlayer.getPlayer().getLocation(), listeningPlayer.getLocation(), Config.getInstance().getPowerLevelUpBroadcastRadius())) { + if(mcMMO.p.getGeneralConfig().shouldPowerLevelUpBroadcastsRestrictDistance()) { + if(!Misc.isNear(mmoBroadcastingPlayer.getPlayer().getLocation(), listeningPlayer.getLocation(), mcMMO.p.getGeneralConfig().getPowerLevelUpBroadcastRadius())) { return false; } } @@ -83,12 +82,12 @@ public class PowerLevelUpBroadcastPredicate implements return true; } else { //Send out to console - return Config.getInstance().shouldPowerLevelUpBroadcastToConsole(); + return mcMMO.p.getGeneralConfig().shouldPowerLevelUpBroadcastToConsole(); } } private static boolean isPowerLevelUpBroadcastsSameWorldOnly() { - return Config.getInstance().isPowerLevelUpBroadcastsSameWorldOnly(); + return mcMMO.p.getGeneralConfig().isPowerLevelUpBroadcastsSameWorldOnly(); } @Override diff --git a/src/main/java/com/gmail/nossr50/datatypes/party/Party.java b/src/main/java/com/gmail/nossr50/datatypes/party/Party.java new file mode 100644 index 000000000..fe7b9cb91 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/datatypes/party/Party.java @@ -0,0 +1,422 @@ +package com.gmail.nossr50.datatypes.party; + +import com.gmail.nossr50.chat.SamePartyPredicate; +import com.gmail.nossr50.config.experience.ExperienceConfig; +import com.gmail.nossr50.datatypes.experience.FormulaType; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.party.PartyManager; +import com.gmail.nossr50.util.EventUtils; +import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.sounds.SoundManager; +import com.gmail.nossr50.util.sounds.SoundType; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.UUID; +import java.util.function.Predicate; + +public class Party { + private final @NotNull Predicate samePartyPredicate; + private final LinkedHashMap members = new LinkedHashMap<>(); + private final List onlineMembers = new ArrayList<>(); + + private PartyLeader leader; + private String name; + private String password; + private boolean locked; + private Party ally; + private int level; + private float xp; + + private ShareMode xpShareMode = ShareMode.NONE; + private ShareMode itemShareMode = ShareMode.NONE; + + private boolean shareLootDrops = true; + private boolean shareMiningDrops = true; + private boolean shareHerbalismDrops = true; + private boolean shareWoodcuttingDrops = true; + private boolean shareMiscDrops = true; + + public Party(String name) { + this.name = name; + samePartyPredicate = new SamePartyPredicate<>(this); + } + + public Party(PartyLeader leader, String name) { + this.leader = leader; + this.name = name; + this.locked = true; + this.level = 0; + samePartyPredicate = new SamePartyPredicate<>(this); + } + + public Party(PartyLeader leader, String name, String password) { + this.leader = leader; + this.name = name; + this.password = password; + this.locked = true; + this.level = 0; + samePartyPredicate = new SamePartyPredicate<>(this); + } + + public Party(PartyLeader leader, String name, String password, boolean locked) { + this.leader = leader; + this.name = name; + this.password = password; + this.locked = locked; + this.level = 0; + samePartyPredicate = new SamePartyPredicate<>(this); + } + + public LinkedHashMap getMembers() { + return members; + } + + public List getOnlineMembers() { + return onlineMembers; + } + + public List getVisibleMembers(Player player) + { + ArrayList visibleMembers = new ArrayList<>(); + + for(Player p : onlineMembers) + { + if(player.canSee(p)) + visibleMembers.add(p); + } + + return visibleMembers; + } + + public List getOnlinePlayerNames(CommandSender sender) { + Player player = sender instanceof Player ? (Player) sender : null; + List onlinePlayerNames = new ArrayList<>(); + + for (Player onlinePlayer : getOnlineMembers()) { + if (player != null && player.canSee(onlinePlayer)) { + onlinePlayerNames.add(onlinePlayer.getName()); + } + } + + return onlinePlayerNames; + } + + public boolean addOnlineMember(Player player) { + return onlineMembers.add(player); + } + + public boolean removeOnlineMember(Player player) { + return onlineMembers.remove(player); + } + + public String getName() { + return name; + } + + public PartyLeader getLeader() { + return leader; + } + + public String getPassword() { + return password; + } + + public boolean isLocked() { + return locked; + } + + public Party getAlly() { + return ally; + } + + public List getItemShareCategories() { + List shareCategories = new ArrayList<>(); + + for (ItemShareType shareType : ItemShareType.values()) { + if (sharingDrops(shareType)) { + shareCategories.add(shareType.getLocaleString()); + } + } + + return shareCategories; + } + + public void setName(String name) { + this.name = name; + } + + public void setLeader(PartyLeader leader) { + this.leader = leader; + } + + public void setPassword(String password) { + this.password = password; + } + + public void setLocked(boolean locked) { + this.locked = locked; + } + + public void setAlly(Party ally) { + this.ally = ally; + } + + public int getLevel() { + return level; + } + + public void setLevel(int level) { + this.level = level; + } + + public float getXp() { + return xp; + } + + public void setXp(float xp) { + this.xp = xp; + } + + public void addXp(float xp) { + setXp(getXp() + xp); + } + + protected float levelUp() { + float xpRemoved = getXpToLevel(); + + setLevel(getLevel() + 1); + setXp(getXp() - xpRemoved); + + return xpRemoved; + } + + public int getXpToLevel() { + FormulaType formulaType = ExperienceConfig.getInstance().getFormulaType(); + return (mcMMO.getFormulaManager().getXPtoNextLevel(level, formulaType)) * (getOnlineMembers().size() + mcMMO.p.getGeneralConfig().getPartyXpCurveMultiplier()); + } + + public String getXpToLevelPercentage() { + DecimalFormat percent = new DecimalFormat("##0.00%"); + return percent.format(this.getXp() / getXpToLevel()); + } + + /** + * Applies an experience gain + * + * @param xp Experience amount to add + */ + public void applyXpGain(float xp) { + if (!EventUtils.handlePartyXpGainEvent(this, xp)) { + return; + } + + if (getXp() < getXpToLevel()) { + return; + } + + int levelsGained = 0; + float xpRemoved = 0; + + while (getXp() >= getXpToLevel()) { + if (hasReachedLevelCap()) { + setXp(0); + return; + } + + xpRemoved += levelUp(); + levelsGained++; + } + + if (!EventUtils.handlePartyLevelChangeEvent(this, levelsGained, xpRemoved)) { + return; + } + + if (!mcMMO.p.getGeneralConfig().getPartyInformAllMembers()) { + Player leader = mcMMO.p.getServer().getPlayer(this.leader.getUniqueId()); + + if (leader != null) { + leader.sendMessage(LocaleLoader.getString("Party.LevelUp", levelsGained, getLevel())); + + if (mcMMO.p.getGeneralConfig().getLevelUpSoundsEnabled()) { + SoundManager.sendSound(leader, leader.getLocation(), SoundType.LEVEL_UP); + } + } + return; + } + + PartyManager.informPartyMembersLevelUp(this, levelsGained, getLevel()); + } + + public boolean hasReachedLevelCap() { + return mcMMO.p.getGeneralConfig().getPartyLevelCap() < getLevel() + 1; + } + + public void setXpShareMode(ShareMode xpShareMode) { + this.xpShareMode = xpShareMode; + } + + public ShareMode getXpShareMode() { + return xpShareMode; + } + + public void setItemShareMode(ShareMode itemShareMode) { + this.itemShareMode = itemShareMode; + } + + public ShareMode getItemShareMode() { + return itemShareMode; + } + + public boolean sharingDrops(ItemShareType shareType) { + switch (shareType) { + case HERBALISM: + return shareHerbalismDrops; + + case LOOT: + return shareLootDrops; + + case MINING: + return shareMiningDrops; + + case MISC: + return shareMiscDrops; + + case WOODCUTTING: + return shareWoodcuttingDrops; + + default: + return false; + } + } + + public void setSharingDrops(ItemShareType shareType, boolean enabled) { + switch (shareType) { + case HERBALISM: + shareHerbalismDrops = enabled; + break; + + case LOOT: + shareLootDrops = enabled; + break; + + case MINING: + shareMiningDrops = enabled; + break; + + case MISC: + shareMiscDrops = enabled; + break; + + case WOODCUTTING: + shareWoodcuttingDrops = enabled; + break; + + default: + } + } + + public boolean hasMember(String memberName) { + return this.getMembers().containsValue(memberName); + } + + public boolean hasMember(UUID uuid) { + return this.getMembers().containsKey(uuid); + } + + /** + * Makes a formatted list of party members based on the perspective of a target player + * Players that are hidden will be shown as offline (formatted in the same way) + * Party leader will be formatted a specific way as well + * @param player target player to use as POV + * @return formatted list of party members from the POV of a player + */ + public String createMembersList(Player player) { + StringBuilder memberList = new StringBuilder(); + List coloredNames = new ArrayList<>(); + + for(UUID playerUUID : members.keySet()) { + OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(playerUUID); + + if(offlinePlayer.isOnline() && player.canSee((Player) offlinePlayer)) { + ChatColor onlineColor = leader.getUniqueId().equals(playerUUID) ? ChatColor.GOLD : ChatColor.GREEN; + coloredNames.add(onlineColor + offlinePlayer.getName()); + } else { + coloredNames.add(ChatColor.DARK_GRAY + members.get(playerUUID)); + } + } + + buildChatMessage(memberList, coloredNames.toArray(new String[0])); + return memberList.toString(); + } + + private void buildChatMessage(@NotNull StringBuilder stringBuilder, String @NotNull [] names) { + for(int i = 0; i < names.length; i++) { + if(i + 1 >= names.length) { + stringBuilder + .append(names[i]); + } else { + stringBuilder + .append(names[i]) + .append(" "); + } + } + } + + /** + * Get the near party members. + * + * @param mcMMOPlayer The player to check + * @return the near party members + */ + public List getNearMembers(McMMOPlayer mcMMOPlayer) { + List nearMembers = new ArrayList<>(); + Party party = mcMMOPlayer.getParty(); + + if (party != null) { + Player player = mcMMOPlayer.getPlayer(); + double range = mcMMO.p.getGeneralConfig().getPartyShareRange(); + + for (Player member : party.getOnlineMembers()) { + if (!player.equals(member) && member.isValid() && Misc.isNear(player.getLocation(), member.getLocation(), range)) { + nearMembers.add(member); + } + } + } + + return nearMembers; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + + if (!(obj instanceof Party)) { + return false; + } + + Party other = (Party) obj; + + if ((this.getName() == null) || (other.getName() == null)) { + return false; + } + + return this.getName().equals(other.getName()); + } + + public @NotNull Predicate getSamePartyPredicate() { + return samePartyPredicate; + } +} diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java index 4868a8533..22ab7f4a6 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java @@ -1,257 +1,251 @@ package com.gmail.nossr50.datatypes.skills; -import com.gmail.nossr50.config.Config; -import com.gmail.nossr50.config.experience.ExperienceConfig; -import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.config.GeneralConfig; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.skills.SkillManager; -import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager; -import com.gmail.nossr50.skills.alchemy.AlchemyManager; -import com.gmail.nossr50.skills.archery.ArcheryManager; -import com.gmail.nossr50.skills.axes.AxesManager; -import com.gmail.nossr50.skills.crossbows.CrossbowsManager; -import com.gmail.nossr50.skills.excavation.ExcavationManager; -import com.gmail.nossr50.skills.fishing.FishingManager; -import com.gmail.nossr50.skills.herbalism.HerbalismManager; -import com.gmail.nossr50.skills.mining.MiningManager; -import com.gmail.nossr50.skills.repair.RepairManager; -import com.gmail.nossr50.skills.salvage.SalvageManager; -import com.gmail.nossr50.skills.smelting.SmeltingManager; -import com.gmail.nossr50.skills.swords.SwordsManager; -import com.gmail.nossr50.skills.taming.TamingManager; -import com.gmail.nossr50.skills.tridents.TridentsManager; -import com.gmail.nossr50.skills.unarmed.UnarmedManager; -import com.gmail.nossr50.skills.woodcutting.WoodcuttingManager; import com.gmail.nossr50.util.Permissions; -import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.text.StringUtils; -import com.google.common.collect.ImmutableList; -import com.neetgames.mcmmo.skill.CorePrimarySkillType; -import org.bukkit.Color; +import com.gmail.nossr50.util.skills.SkillTools; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; -import org.bukkit.entity.Tameable; -import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; -import java.util.Collections; import java.util.List; public enum PrimarySkillType { - ACROBATICS(AcrobaticsManager.class, Color.WHITE, - ImmutableList.of(SubSkillType.ACROBATICS_DODGE, SubSkillType.ACROBATICS_ROLL)), - ALCHEMY(AlchemyManager.class, Color.FUCHSIA, - ImmutableList.of(SubSkillType.ALCHEMY_CATALYSIS, SubSkillType.ALCHEMY_CONCOCTIONS)), - ARCHERY(ArcheryManager.class, Color.MAROON, - ImmutableList.of(SubSkillType.ARCHERY_DAZE, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK, SubSkillType.ARCHERY_ARROW_RETRIEVAL, SubSkillType.ARCHERY_SKILL_SHOT)), - AXES(AxesManager.class, Color.AQUA, SuperAbilityType.SKULL_SPLITTER, - ImmutableList.of(SubSkillType.AXES_SKULL_SPLITTER, SubSkillType.AXES_AXES_LIMIT_BREAK, SubSkillType.AXES_ARMOR_IMPACT, SubSkillType.AXES_AXE_MASTERY, SubSkillType.AXES_CRITICAL_STRIKES, SubSkillType.AXES_GREATER_IMPACT)), - EXCAVATION(ExcavationManager.class, Color.fromRGB(139, 69, 19), SuperAbilityType.GIGA_DRILL_BREAKER, - ImmutableList.of(SubSkillType.EXCAVATION_GIGA_DRILL_BREAKER, SubSkillType.EXCAVATION_ARCHAEOLOGY)), - FISHING(FishingManager.class, Color.NAVY, - ImmutableList.of(SubSkillType.FISHING_FISHERMANS_DIET, SubSkillType.FISHING_TREASURE_HUNTER, SubSkillType.FISHING_ICE_FISHING, SubSkillType.FISHING_MAGIC_HUNTER, SubSkillType.FISHING_MASTER_ANGLER, SubSkillType.FISHING_SHAKE)), - HERBALISM(HerbalismManager.class, Color.GREEN, SuperAbilityType.GREEN_TERRA, - ImmutableList.of(SubSkillType.HERBALISM_GREEN_TERRA, SubSkillType.HERBALISM_FARMERS_DIET, SubSkillType.HERBALISM_GREEN_THUMB, SubSkillType.HERBALISM_DOUBLE_DROPS, SubSkillType.HERBALISM_HYLIAN_LUCK, SubSkillType.HERBALISM_SHROOM_THUMB)), - MINING(MiningManager.class, Color.GRAY, SuperAbilityType.SUPER_BREAKER, - ImmutableList.of(SubSkillType.MINING_SUPER_BREAKER, SubSkillType.MINING_DEMOLITIONS_EXPERTISE, SubSkillType.MINING_BIGGER_BOMBS, SubSkillType.MINING_BLAST_MINING, SubSkillType.MINING_DOUBLE_DROPS)), - REPAIR(RepairManager.class, Color.SILVER, - ImmutableList.of(SubSkillType.REPAIR_ARCANE_FORGING, SubSkillType.REPAIR_REPAIR_MASTERY, SubSkillType.REPAIR_SUPER_REPAIR)), - SALVAGE(SalvageManager.class, Color.ORANGE, - ImmutableList.of(SubSkillType.SALVAGE_SCRAP_COLLECTOR, SubSkillType.SALVAGE_ARCANE_SALVAGE)), - SMELTING(SmeltingManager.class, Color.YELLOW, - ImmutableList.of(SubSkillType.SMELTING_UNDERSTANDING_THE_ART, /*SubSkillType.SMELTING_FLUX_MINING,*/ SubSkillType.SMELTING_FUEL_EFFICIENCY, SubSkillType.SMELTING_SECOND_SMELT)), - SWORDS(SwordsManager.class, Color.fromRGB(178, 34, 34), SuperAbilityType.SERRATED_STRIKES, - ImmutableList.of(SubSkillType.SWORDS_SERRATED_STRIKES, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK, SubSkillType.SWORDS_STAB, SubSkillType.SWORDS_RUPTURE, SubSkillType.SWORDS_COUNTER_ATTACK)), - TAMING(TamingManager.class, Color.PURPLE, - ImmutableList.of(SubSkillType.TAMING_BEAST_LORE, SubSkillType.TAMING_CALL_OF_THE_WILD, SubSkillType.TAMING_ENVIRONMENTALLY_AWARE, SubSkillType.TAMING_FAST_FOOD_SERVICE, SubSkillType.TAMING_GORE, SubSkillType.TAMING_HOLY_HOUND, SubSkillType.TAMING_SHARPENED_CLAWS, SubSkillType.TAMING_SHOCK_PROOF, SubSkillType.TAMING_THICK_FUR, SubSkillType.TAMING_PUMMEL)), - UNARMED(UnarmedManager.class, Color.BLACK, SuperAbilityType.BERSERK, - ImmutableList.of(SubSkillType.UNARMED_BERSERK, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK, SubSkillType.UNARMED_BLOCK_CRACKER, SubSkillType.UNARMED_ARROW_DEFLECT, SubSkillType.UNARMED_DISARM, SubSkillType.UNARMED_STEEL_ARM_STYLE, SubSkillType.UNARMED_IRON_GRIP)), - WOODCUTTING(WoodcuttingManager.class, Color.OLIVE, SuperAbilityType.TREE_FELLER, - ImmutableList.of(SubSkillType.WOODCUTTING_LEAF_BLOWER, SubSkillType.WOODCUTTING_TREE_FELLER, SubSkillType.WOODCUTTING_HARVEST_LUMBER, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)), - TRIDENTS(TridentsManager.class, Color.TEAL, ImmutableList.of(SubSkillType.TRIDENTS_MULTI_TASKING, SubSkillType.TRIDENTS_TRIDENTS_LIMIT_BREAK)), - CROSSBOWS(CrossbowsManager.class, Color.ORANGE, ImmutableList.of(SubSkillType.CROSSBOWS_SUPER_SHOTGUN, SubSkillType.CROSSBOWS_CROSSBOWS_LIMIT_BREAK)); + ACROBATICS, + ALCHEMY, + ARCHERY, + AXES, + EXCAVATION, + FISHING, + HERBALISM, + MINING, + REPAIR, + SALVAGE, + SMELTING, + SWORDS, + TAMING, + UNARMED, + WOODCUTTING; +// boolean issueWarning = true; - private final Class managerClass; - private final Color skillColor; - private final SuperAbilityType superAbilityType; - private final List subSkillTypes; + /* + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + */ - public static final List SKILL_NAMES; - public static final List SUBSKILL_NAMES; - public static final List CHILD_SKILLS; - public static final List NON_CHILD_SKILLS; +// private void processWarning() { +// if(issueWarning) { +// StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); +// Bukkit.getScheduler().scheduleSyncDelayedTask(mcMMO.p, () -> { +// mcMMO.p.getLogger().severe("A plugin that hooks into mcMMO via the mcMMO API is using soon to be deprecated API calls. Contact the plugin author and inform them to update their code before it breaks."); +// mcMMO.p.getLogger().severe("Deprecation Call from: " + stackTraceElements[2].toString()); +// mcMMO.p.getLogger().severe("This warning will not repeat itself. Nothing is broken for now, but in the future it will be."); +// }); +// +// issueWarning = !issueWarning; +// } +// } - public static final List COMBAT_SKILLS = ImmutableList.of(ARCHERY, AXES, SWORDS, TAMING, UNARMED, TRIDENTS, CROSSBOWS); - public static final List GATHERING_SKILLS = ImmutableList.of(EXCAVATION, FISHING, HERBALISM, MINING, WOODCUTTING); - public static final List MISC_SKILLS = ImmutableList.of(ACROBATICS, ALCHEMY, REPAIR, SALVAGE, SMELTING); - - static { - List childSkills = new ArrayList<>(); - List nonChildSkills = new ArrayList<>(); - ArrayList names = new ArrayList<>(); - ArrayList subSkillNames = new ArrayList<>(); - - for (PrimarySkillType skill : values()) { - if (skill.isChildSkill()) { - childSkills.add(skill); - } - else { - nonChildSkills.add(skill); - } - - for(SubSkillType subSkillType : skill.subSkillTypes) { - subSkillNames.add(subSkillType.getNiceNameNoSpaces(subSkillType)); - } - - names.add(skill.getName()); - } - - Collections.sort(names); - SKILL_NAMES = ImmutableList.copyOf(names); - SUBSKILL_NAMES = ImmutableList.copyOf(subSkillNames); - - CHILD_SKILLS = ImmutableList.copyOf(childSkills); - NON_CHILD_SKILLS = ImmutableList.copyOf(nonChildSkills); - } - - PrimarySkillType(Class managerClass, Color skillColor, List subSkillTypes) { - this(managerClass, skillColor, null, subSkillTypes); - } - - PrimarySkillType(Class managerClass, Color skillColor, SuperAbilityType superAbilityType, List subSkillTypes) { - this.managerClass = managerClass; - this.skillColor = skillColor; - this.superAbilityType = superAbilityType; - this.subSkillTypes = subSkillTypes; - } - - public Class getManagerClass() { - return managerClass; - } - - public SuperAbilityType getSuperAbilityType() { - return superAbilityType; + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#getLevelCap(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public int getMaxLevel() { + return mcMMO.p.getSkillTools().getLevelCap(this); } /** - * Get the max level of this skill. - * + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead * @return the max level of this skill + * @see SkillTools#isSuperAbilityUnlocked(com.gmail.nossr50.datatypes.skills.PrimarySkillType, org.bukkit.entity.Player) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead */ - public int getMaxLevel() { - return Config.getInstance().getLevelCap(this); - } - - public boolean isSuperAbilityUnlocked(Player player) { return RankUtils.getRank(player, getSuperAbilityType().getSubSkillTypeDefinition()) >= 1; } - - public boolean getPVPEnabled() { - return Config.getInstance().getPVPEnabled(this); - } - - public boolean getPVEEnabled() { - return Config.getInstance().getPVEEnabled(this); - } - - public boolean getDoubleDropsDisabled() { - return Config.getInstance().getDoubleDropsDisabled(this); - } - - public boolean getHardcoreStatLossEnabled() { - return Config.getInstance().getHardcoreStatLossEnabled(this); - } - - public void setHardcoreStatLossEnabled(boolean enable) { - Config.getInstance().setHardcoreStatLossEnabled(this, enable); - } - - public boolean getHardcoreVampirismEnabled() { - return Config.getInstance().getHardcoreVampirismEnabled(this); - } - - public void setHardcoreVampirismEnabled(boolean enable) { - Config.getInstance().setHardcoreVampirismEnabled(this, enable); - } - - public List getSkillAbilities() { - return subSkillTypes; - } - - public double getXpModifier() { - return ExperienceConfig.getInstance().getFormulaSkillModifier(this); - } - @Deprecated - public static @Nullable PrimarySkillType getSkill(String skillName) { - if (!Config.getInstance().getLocale().equalsIgnoreCase("en_US")) { - for (PrimarySkillType type : values()) { - if (skillName.equalsIgnoreCase(LocaleLoader.getString(StringUtils.getCapitalized(type.name()) + ".SkillName"))) { - return type; - } - } - } - - for (PrimarySkillType type : values()) { - if (type.name().equalsIgnoreCase(skillName)) { - return type; - } - } - - if (!skillName.equalsIgnoreCase("all")) { - mcMMO.p.getLogger().warning("Invalid mcMMO skill (" + skillName + ")"); //TODO: Localize - } - - return null; + public boolean isSuperAbilityUnlocked(@NotNull Player player) { + return mcMMO.p.getSkillTools().isSuperAbilityUnlocked(this, player); } - // TODO: This is a little "hacky", we probably need to add something to distinguish child skills in the enum, or to use another enum for them + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#getPVPEnabled(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public boolean getPVPEnabled() { + return mcMMO.p.getSkillTools().getPVPEnabled(this); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#getPVEEnabled(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public boolean getPVEEnabled() { + return mcMMO.p.getSkillTools().getPVEEnabled(this); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see GeneralConfig#getDoubleDropsDisabled(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public boolean getDoubleDropsDisabled() { + return mcMMO.p.getGeneralConfig().getDoubleDropsDisabled(this); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#getHardcoreStatLossEnabled(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public boolean getHardcoreStatLossEnabled() { + return mcMMO.p.getSkillTools().getHardcoreStatLossEnabled(this); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#getHardcoreVampirismEnabled(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public boolean getHardcoreVampirismEnabled() { + return mcMMO.p.getSkillTools().getHardcoreVampirismEnabled(this); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#getPrimarySkillToolType(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public ToolType getTool() { + return mcMMO.p.getSkillTools().getPrimarySkillToolType(this); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#getSubSkills(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public List getSkillAbilities() { + return new ArrayList<>(mcMMO.p.getSkillTools().getSubSkills(this)); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#getXpModifier(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public double getXpModifier() { + return mcMMO.p.getSkillTools().getXpModifier(this); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#matchSkill(java.lang.String) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public static PrimarySkillType getSkill(String skillName) { + return mcMMO.p.getSkillTools().matchSkill(skillName); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#isChildSkill(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated public boolean isChildSkill() { - switch (this) { - case SALVAGE: - case SMELTING: - return true; - - default: - return false; - } + return SkillTools.isChildSkill(this); } + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#getPrimarySkillBySubSkill(com.gmail.nossr50.datatypes.skills.SubSkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated public static PrimarySkillType bySecondaryAbility(SubSkillType subSkillType) { - for (PrimarySkillType type : values()) { - if (type.getSkillAbilities().contains(subSkillType)) { - return type; - } - } - return null; + return mcMMO.p.getSkillTools().getPrimarySkillBySubSkill(subSkillType); } - public static PrimarySkillType byAbility(SuperAbilityType ability) { - for (PrimarySkillType type : values()) { - if (type.getSuperAbilityType() == ability) { - return type; - } - } - - return null; + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#getPrimarySkillBySuperAbility(com.gmail.nossr50.datatypes.skills.SuperAbilityType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public static PrimarySkillType byAbility(SuperAbilityType superAbilityType) { + return mcMMO.p.getSkillTools().getPrimarySkillBySuperAbility(superAbilityType); } + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#getLocalizedSkillName(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated public String getName() { - return StringUtils.getCapitalized(LocaleLoader.getString(StringUtils.getCapitalized(this.toString()) + ".SkillName")); + return mcMMO.p.getSkillTools().getLocalizedSkillName(this); } -// public String getName() { -// return StringUtils.getCapitalized(StringUtils.getCapitalized(this.toString())); -// } - + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see Permissions#skillEnabled(org.bukkit.permissions.Permissible, com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update + */ + @Deprecated public boolean getPermissions(Player player) { - return Permissions.skillEnabled(player, this); + return mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, this); } -/* public void celebrateLevelUp(Player player) { - ParticleEffectUtils.fireworkParticleShower(player, skillColor); - }*/ - + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#canCombatSkillsTrigger(com.gmail.nossr50.datatypes.skills.PrimarySkillType, org.bukkit.entity.Entity) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated public boolean shouldProcess(Entity target) { - return (target instanceof Player || (target instanceof Tameable && ((Tameable) target).isTamed())) ? getPVPEnabled() : getPVEEnabled(); + return mcMMO.p.getSkillTools().canCombatSkillsTrigger(this, target); } -} +} \ No newline at end of file diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java index 480f8368b..f9fa5af3b 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java @@ -1,6 +1,7 @@ package com.gmail.nossr50.datatypes.skills; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.text.StringUtils; import java.util.Locale; @@ -145,7 +146,7 @@ public enum SubSkillType { * If we add skills, those immutable lists need to be updated * @return */ - public PrimarySkillType getParentSkill() { return PrimarySkillType.bySecondaryAbility(this); } + public PrimarySkillType getParentSkill() { return mcMMO.p.getSkillTools().getPrimarySkillBySubSkill(this); } /** * Returns the root address for this skill in the advanced.yml file diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java index 17755188b..7ce32a8f7 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.datatypes.skills; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.BlockUtils; @@ -137,11 +136,11 @@ public enum SuperAbilityType { } public int getCooldown() { - return Config.getInstance().getCooldown(this); + return mcMMO.p.getSkillTools().getSuperAbilityCooldown(this); } public int getMaxLength() { - return Config.getInstance().getMaxLength(this); + return mcMMO.p.getGeneralConfig().getMaxLength(this); } public String getAbilityOn() { diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java index 4b5f77c1a..68479909d 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.datatypes.skills.subskills.acrobatics; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.player.McMMOPlayer; @@ -83,7 +82,7 @@ public class Roll extends AcrobaticsSubSkill { entityDamageEvent.setCancelled(true); return true; } - } else if(Permissions.skillEnabled(player, PrimarySkillType.ACROBATICS)) { + } else if(mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.ACROBATICS)) { //Give XP Anyways SkillUtils.applyXpGain(mcMMOPlayer, getPrimarySkill(), calculateRollXP(player, ((EntityDamageEvent) event).getFinalDamage(), false), XPGainReason.PVE); } @@ -199,7 +198,7 @@ public class Roll extends AcrobaticsSubSkill { return gracefulRollCheck(player, mmoPlayer, damage, skillLevel); } - double modifiedDamage = calculateModifiedRollDamage(damage, AdvancedConfig.getInstance().getRollDamageThreshold()); + double modifiedDamage = calculateModifiedRollDamage(damage, mcMMO.p.getAdvancedConfig().getRollDamageThreshold()); if (!isFatal(player, modifiedDamage) && RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.ACROBATICS_ROLL, player)) { @@ -237,7 +236,7 @@ public class Roll extends AcrobaticsSubSkill { * @return the modified event damage if the ability was successful, the original event damage otherwise */ private double gracefulRollCheck(Player player, OnlineMMOPlayer mmoPlayer, double damage, int skillLevel) { - double modifiedDamage = calculateModifiedRollDamage(damage, AdvancedConfig.getInstance().getRollDamageThreshold() * 2); + double modifiedDamage = calculateModifiedRollDamage(damage, mcMMO.p.getAdvancedConfig().getRollDamageThreshold() * 2); RandomChanceSkill rcs = new RandomChanceSkill(player, subSkillType); rcs.setSkillLevel(rcs.getSkillLevel() * 2); //Double the effective odds @@ -380,7 +379,7 @@ public class Roll extends AcrobaticsSubSkill { // // //Chance to roll at half max skill // RandomChanceSkill rollHalfMaxSkill = new RandomChanceSkill(null, subSkillType); -// int halfMaxSkillValue = AdvancedConfig.getInstance().getMaxBonusLevel(SubSkillType.ACROBATICS_ROLL)/2; +// int halfMaxSkillValue = mcMMO.p.getAdvancedConfig().getMaxBonusLevel(SubSkillType.ACROBATICS_ROLL)/2; // rollHalfMaxSkill.setSkillLevel(halfMaxSkillValue); // // //Chance to graceful roll at full skill @@ -394,11 +393,11 @@ public class Roll extends AcrobaticsSubSkill { // //Chance Stat Calculations // rollChanceHalfMax = RandomChanceUtil.getRandomChanceExecutionChance(rollHalfMaxSkill); // graceChanceHalfMax = RandomChanceUtil.getRandomChanceExecutionChance(rollGraceHalfMaxSkill); -// damageThreshold = AdvancedConfig.getInstance().getRollDamageThreshold(); +// damageThreshold = mcMMO.p.getAdvancedConfig().getRollDamageThreshold(); // // chancePerLevel = RandomChanceUtil.getRandomChanceExecutionChance(rollOneSkillLevel); // -// double maxLevel = AdvancedConfig.getInstance().getMaxBonusLevel(SubSkillType.ACROBATICS_ROLL); +// double maxLevel = mcMMO.p.getAdvancedConfig().getMaxBonusLevel(SubSkillType.ACROBATICS_ROLL); // // return LocaleLoader.getString("Acrobatics.SubSkill.Roll.Mechanics", rollChanceHalfMax, graceChanceHalfMax, maxLevel, chancePerLevel, damageThreshold, damageThreshold * 2,halfMaxSkillValue); } @@ -435,4 +434,5 @@ public class Roll extends AcrobaticsSubSkill { { return player.getLocation().getBlock().getLocation(); } + } diff --git a/src/main/java/com/gmail/nossr50/events/skills/abilities/McMMOPlayerAbilityEvent.java b/src/main/java/com/gmail/nossr50/events/skills/abilities/McMMOPlayerAbilityEvent.java index 3c920464f..08d7dc2b2 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/abilities/McMMOPlayerAbilityEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/abilities/McMMOPlayerAbilityEvent.java @@ -3,6 +3,7 @@ package com.gmail.nossr50.events.skills.abilities; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.events.skills.McMMOPlayerSkillEvent; +import com.gmail.nossr50.mcMMO; import org.bukkit.entity.Player; public class McMMOPlayerAbilityEvent extends McMMOPlayerSkillEvent { @@ -10,7 +11,7 @@ public class McMMOPlayerAbilityEvent extends McMMOPlayerSkillEvent { protected McMMOPlayerAbilityEvent(Player player, PrimarySkillType skill) { super(player, skill); - ability = skill.getSuperAbilityType(); + ability = mcMMO.p.getSkillTools().getSuperAbility(skill); } public SuperAbilityType getAbility() { diff --git a/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java b/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java index ee4fbb873..7aefb003e 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java @@ -1,9 +1,9 @@ package com.gmail.nossr50.events.skills.secondaryabilities; -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.events.skills.McMMOPlayerSkillEvent; +import com.gmail.nossr50.mcMMO; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; @@ -20,7 +20,7 @@ public class SubSkillEvent extends McMMOPlayerSkillEvent implements Cancellable */ @Deprecated public SubSkillEvent(Player player, SubSkillType subSkillType) { - super(player, PrimarySkillType.bySecondaryAbility(subSkillType)); + super(player, mcMMO.p.getSkillTools().getPrimarySkillBySubSkill(subSkillType)); this.subSkillType = subSkillType; } @@ -33,7 +33,7 @@ public class SubSkillEvent extends McMMOPlayerSkillEvent implements Cancellable */ @Deprecated public SubSkillEvent(Player player, SubSkillType subSkillType, double resultModifier) { - super(player, PrimarySkillType.bySecondaryAbility(subSkillType)); + super(player, mcMMO.p.getSkillTools().getPrimarySkillBySubSkill(subSkillType)); this.subSkillType = subSkillType; this.resultModifier = resultModifier; } diff --git a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java index ec8302822..7fbd4043a 100644 --- a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.listeners; import com.gmail.nossr50.api.ItemSpawnReason; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.HiddenConfig; import com.gmail.nossr50.config.WorldBlacklist; import com.gmail.nossr50.config.experience.ExperienceConfig; @@ -20,6 +19,8 @@ import com.gmail.nossr50.skills.repair.Repair; import com.gmail.nossr50.skills.salvage.Salvage; import com.gmail.nossr50.skills.woodcutting.WoodcuttingManager; import com.gmail.nossr50.util.*; +import com.gmail.nossr50.util.compat.layers.world.WorldCompatibilityLayer; +import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundType; @@ -78,9 +79,9 @@ public class BlockListener implements Listener { continue; //TODO: Ignore this abomination its rewritten in 2.2 - if(!Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.MINING, is.getType()) - && !Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.HERBALISM, is.getType()) - && !Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, is.getType())) + if(!mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.MINING, is.getType()) + && !mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.HERBALISM, is.getType()) + && !mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, is.getType())) continue; //If we suspect TEs might be duped only reward block @@ -122,10 +123,14 @@ public class BlockListener implements Listener { BlockFace direction = event.getDirection(); Block movedBlock; + WorldCompatibilityLayer worldCompatibilityLayer = mcMMO.getCompatibilityManager().getWorldCompatibilityLayer(); - for (Block b : event.getBlocks()) { - movedBlock = b.getRelative(direction); - mcMMO.getPlaceStore().setTrue(movedBlock); + for (Block block : event.getBlocks()) { + movedBlock = block.getRelative(direction); + + if(BlockUtils.isWithinWorldBounds(worldCompatibilityLayer, movedBlock)) { + mcMMO.getPlaceStore().setTrue(movedBlock); + } } } @@ -147,14 +152,18 @@ public class BlockListener implements Listener { // Get opposite direction so we get correct block BlockFace direction = event.getDirection(); Block movedBlock = event.getBlock().getRelative(direction); - if (movedBlock.getY() >= Misc.getWorldMinCompat(movedBlock.getWorld())) // Very weird that the event is giving us these, they shouldn't exist + + WorldCompatibilityLayer worldCompatibilityLayer = mcMMO.getCompatibilityManager().getWorldCompatibilityLayer(); + + //Spigot makes bad things happen in its API + if(BlockUtils.isWithinWorldBounds(worldCompatibilityLayer, movedBlock)) { mcMMO.getPlaceStore().setTrue(movedBlock); + } for (Block block : event.getBlocks()) { - movedBlock = block.getRelative(direction); - if (movedBlock.getY() < Misc.getWorldMinCompat(movedBlock.getWorld())) // Very weird that the event is giving us these, they shouldn't exist - continue; - mcMMO.getPlaceStore().setTrue(movedBlock); + if(BlockUtils.isWithinWorldBounds(worldCompatibilityLayer, block)) { + mcMMO.getPlaceStore().setTrue(block.getRelative(direction)); + } } } @@ -171,11 +180,16 @@ public class BlockListener implements Listener { if(WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) return; + BlockState blockState = event.getNewState(); - if(ExperienceConfig.getInstance().isSnowExploitPrevented() && BlockUtils.shouldBeWatched(blockState)) - { - mcMMO.getPlaceStore().setTrue(blockState.getBlock()); + if(ExperienceConfig.getInstance().isSnowExploitPrevented() && BlockUtils.shouldBeWatched(blockState)) { + WorldCompatibilityLayer worldCompatibilityLayer = mcMMO.getCompatibilityManager().getWorldCompatibilityLayer(); + Block block = blockState.getBlock(); + + if(BlockUtils.isWithinWorldBounds(worldCompatibilityLayer, block)) { + mcMMO.getPlaceStore().setTrue(block); + } } } @@ -185,16 +199,20 @@ public class BlockListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockFormEvent(BlockFormEvent event) { + World world = event.getBlock().getWorld(); + /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) + if(WorldBlacklist.isWorldBlacklisted(world)) return; - BlockState newState = event.getNewState(); - if(ExperienceConfig.getInstance().preventStoneLavaFarming()) { - if(newState.getType() != Material.OBSIDIAN - && ExperienceConfig.getInstance().doesBlockGiveSkillXP(PrimarySkillType.MINING, newState.getBlockData())) { - mcMMO.getPlaceStore().setTrue(newState); + BlockState newState = event.getNewState(); + WorldCompatibilityLayer worldCompatibilityLayer = mcMMO.getCompatibilityManager().getWorldCompatibilityLayer(); + + if(newState.getType() != Material.OBSIDIAN && ExperienceConfig.getInstance().doesBlockGiveSkillXP(PrimarySkillType.MINING, newState.getBlockData())) { + if(BlockUtils.isWithinWorldBounds(worldCompatibilityLayer, newState.getBlock())) { + mcMMO.getPlaceStore().setTrue(newState); + } } } } @@ -207,16 +225,23 @@ public class BlockListener implements Listener { @EventHandler(priority = EventPriority.MONITOR) public void onBlockPlace(BlockPlaceEvent event) { BlockState blockState = event.getBlock().getState(); + Block block = blockState.getBlock(); /* Check if the blocks placed should be monitored so they do not give out XP in the future */ // if (!Tag.LOGS.isTagged(event.getBlockReplacedState().getType()) || !Tag.LOGS.isTagged(event.getBlockPlaced().getType())) - mcMMO.getPlaceStore().setTrue(blockState); /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) { + if(WorldBlacklist.isWorldBlacklisted(block.getWorld())) { return; } + WorldCompatibilityLayer worldCompatibilityLayer = mcMMO.getCompatibilityManager().getWorldCompatibilityLayer(); + + if(BlockUtils.isWithinWorldBounds(worldCompatibilityLayer, block)) { + mcMMO.getPlaceStore().setTrue(blockState); + } + + Player player = event.getPlayer(); if (!UserManager.hasPlayerDataKey(player)) { @@ -228,10 +253,10 @@ public class BlockListener implements Listener { if(mmoPlayer == null) return; - if (blockState.getType() == Repair.anvilMaterial && PrimarySkillType.REPAIR.getPermissions(player)) { + if (blockState.getType() == Repair.anvilMaterial && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.REPAIR)) { ((McMMOPlayer) (mmoPlayer)).getRepairManager().placedAnvilCheck(); } - else if (blockState.getType() == Salvage.anvilMaterial && PrimarySkillType.SALVAGE.getPermissions(player)) { + else if (blockState.getType() == Salvage.anvilMaterial && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.SALVAGE)) { ((McMMOPlayer) (mmoPlayer)).getSalvageManager().placedAnvilCheck(); } } @@ -243,18 +268,21 @@ public class BlockListener implements Listener { */ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockMultiPlace(BlockMultiPlaceEvent event) { - for (BlockState replacedBlockState : event.getReplacedBlockStates()) - { + for (BlockState replacedBlockState : event.getReplacedBlockStates()) { BlockState blockState = replacedBlockState.getBlock().getState(); + Block block = blockState.getBlock(); + + WorldCompatibilityLayer worldCompatibilityLayer = mcMMO.getCompatibilityManager().getWorldCompatibilityLayer(); /* Check if the blocks placed should be monitored so they do not give out XP in the future */ - mcMMO.getPlaceStore().setTrue(blockState); + if(BlockUtils.isWithinWorldBounds(worldCompatibilityLayer, block)) { + mcMMO.getPlaceStore().setTrue(blockState); + } } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onBlockGrow(BlockGrowEvent event) - { + public void onBlockGrow(BlockGrowEvent event) { Block block = event.getBlock(); World world = block.getWorld(); @@ -263,10 +291,11 @@ public class BlockListener implements Listener { return; // Minecraft is dumb, the events still throw when a plant "grows" higher than the max block height. Even though no new block is created - if (block.getY() >= world.getMaxHeight()) - return; + WorldCompatibilityLayer worldCompatibilityLayer = mcMMO.getCompatibilityManager().getWorldCompatibilityLayer(); - mcMMO.getPlaceStore().setFalse(block); + if(BlockUtils.isWithinWorldBounds(worldCompatibilityLayer, block)) { + mcMMO.getPlaceStore().setFalse(block); + } } /** @@ -333,7 +362,7 @@ public class BlockListener implements Listener { * We don't check the block store here because herbalism has too many unusual edge cases. * Instead, we check it inside the drops handler. */ - if (PrimarySkillType.HERBALISM.getPermissions(player)) { + if (mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.HERBALISM)) { herbalismManager.processHerbalismBlockBreakEvent(event); } /* @@ -344,13 +373,14 @@ public class BlockListener implements Listener { } /* MINING */ - else if (BlockUtils.affectedBySuperBreaker(blockState) && ItemUtils.isPickaxe(heldItem) && PrimarySkillType.MINING.getPermissions(player) && !mcMMO.getPlaceStore().isTrue(blockState)) { + else if (BlockUtils.affectedBySuperBreaker(blockState) && ItemUtils.isPickaxe(heldItem) && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.MINING) && !mcMMO.getPlaceStore().isTrue(blockState)) { MiningManager miningManager = ((McMMOPlayer) (mmoPlayer)).getMiningManager(); miningManager.miningBlockCheck(blockState); } /* WOOD CUTTING */ - else if (BlockUtils.hasWoodcuttingXP(blockState) && ItemUtils.isAxe(heldItem) && PrimarySkillType.WOODCUTTING.getPermissions(player) && !mcMMO.getPlaceStore().isTrue(blockState)) { + else if (BlockUtils.hasWoodcuttingXP(blockState) && ItemUtils.isAxe(heldItem) + && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.WOODCUTTING) && !mcMMO.getPlaceStore().isTrue(blockState)) { WoodcuttingManager woodcuttingManager = ((McMMOPlayer) (mmoPlayer)).getWoodcuttingManager(); if (woodcuttingManager.canUseTreeFeller(heldItem)) { woodcuttingManager.processTreeFeller(blockState); @@ -365,7 +395,7 @@ public class BlockListener implements Listener { } /* EXCAVATION */ - else if (BlockUtils.affectedByGigaDrillBreaker(blockState) && ItemUtils.isShovel(heldItem) && PrimarySkillType.EXCAVATION.getPermissions(player) && !mcMMO.getPlaceStore().isTrue(blockState)) { + else if (BlockUtils.affectedByGigaDrillBreaker(blockState) && ItemUtils.isShovel(heldItem) && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.EXCAVATION) && !mcMMO.getPlaceStore().isTrue(blockState)) { ExcavationManager excavationManager = ((McMMOPlayer) (mmoPlayer)).getExcavationManager(); excavationManager.excavationBlockCheck(blockState); @@ -523,7 +553,7 @@ public class BlockListener implements Listener { * * We don't need to check permissions here because they've already been checked for the ability to even activate. */ - if (mmoPlayer.getSuperAbilityManager().getAbilityMode(SuperAbilityType.TREE_FELLER) && BlockUtils.hasWoodcuttingXP(blockState) && Config.getInstance().getTreeFellerSoundsEnabled()) { + if (mmoPlayer.getSuperAbilityManager().getAbilityMode(SuperAbilityType.TREE_FELLER) && BlockUtils.hasWoodcuttingXP(blockState) && mcMMO.p.getGeneralConfig().getTreeFellerSoundsEnabled()) { SoundManager.sendSound(player, blockState.getLocation(), SoundType.FIZZ); } } @@ -578,7 +608,7 @@ public class BlockListener implements Listener { blockState.update(true); } } - else if (mmoPlayer.getSuperAbilityManager().getAbilityMode(SuperAbilityType.BERSERK) && (heldItem.getType() == Material.AIR || Config.getInstance().getUnarmedItemsAsUnarmed())) { + else if (mmoPlayer.getSuperAbilityManager().getAbilityMode(SuperAbilityType.BERSERK) && (heldItem.getType() == Material.AIR || mcMMO.p.getGeneralConfig().getUnarmedItemsAsUnarmed())) { if (((McMMOPlayer) (mmoPlayer)).getUnarmedManager().canUseBlockCracker() && BlockUtils.affectedByBlockCracker(blockState)) { if (EventUtils.simulateBlockBreak(block, player, true) && ((McMMOPlayer) (mmoPlayer)).getUnarmedManager().blockCrackerCheck(blockState)) { blockState.update(); diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index dd6e8c251..cf88b32d7 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -1,7 +1,5 @@ package com.gmail.nossr50.listeners; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.WorldBlacklist; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.meta.ProjectileOriginMeta; @@ -163,7 +161,7 @@ public class EntityListener implements Listener { projectile.setMetadata(mcMMO.infiniteArrowKey, mcMMO.metadataValue); } - projectile.setMetadata(mcMMO.bowForceKey, new FixedMetadataValue(pluginRef, Math.min(event.getForce() * AdvancedConfig.getInstance().getForceMultiplier(), 1.0))); + projectile.setMetadata(mcMMO.bowForceKey, new FixedMetadataValue(pluginRef, Math.min(event.getForce() * mcMMO.p.getAdvancedConfig().getForceMultiplier(), 1.0))); projectile.setMetadata(mcMMO.arrowDistanceKey, new FixedMetadataValue(pluginRef, projectile.getLocation())); //Cleanup metadata in 1 minute in case normal collection falls through CombatUtils.delayArrowMetaCleanup((Projectile) projectile); @@ -507,7 +505,7 @@ public class EntityListener implements Listener { } //Party Friendly Fire - if(!Config.getInstance().getPartyFriendlyFire()) + if(!mcMMO.p.getGeneralConfig().getPartyFriendlyFire()) if ((mcMMO.getPartyManager().inSameParty(defendingPlayer, attackingPlayer) || mcMMO.getPartyManager().areAllies(defendingPlayer, attackingPlayer)) && !(Permissions.friendlyFire(attackingPlayer) diff --git a/src/main/java/com/gmail/nossr50/listeners/InventoryListener.java b/src/main/java/com/gmail/nossr50/listeners/InventoryListener.java index 3540dc14f..244c55df4 100644 --- a/src/main/java/com/gmail/nossr50/listeners/InventoryListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/InventoryListener.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.listeners; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.WorldBlacklist; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; @@ -381,17 +380,17 @@ public class InventoryListener implements Listener { ItemStack item = event.getItem(); - if (Config.getInstance().getPreventHopperTransferIngredients() && item.getType() != Material.POTION && item.getType() != Material.SPLASH_POTION && item.getType() != Material.LINGERING_POTION) { + if (mcMMO.p.getGeneralConfig().getPreventHopperTransferIngredients() && item.getType() != Material.POTION && item.getType() != Material.SPLASH_POTION && item.getType() != Material.LINGERING_POTION) { event.setCancelled(true); return; } - if (Config.getInstance().getPreventHopperTransferBottles() && (item.getType() == Material.POTION || item.getType() == Material.SPLASH_POTION || item.getType() == Material.LINGERING_POTION)) { + if (mcMMO.p.getGeneralConfig().getPreventHopperTransferBottles() && (item.getType() == Material.POTION || item.getType() == Material.SPLASH_POTION || item.getType() == Material.LINGERING_POTION)) { event.setCancelled(true); return; } - if (Config.getInstance().getEnabledForHoppers() && AlchemyPotionBrewer.isValidIngredient(null, item)) { + if (mcMMO.p.getGeneralConfig().getEnabledForHoppers() && AlchemyPotionBrewer.isValidIngredient(null, item)) { AlchemyPotionBrewer.scheduleCheck(null, (BrewingStand) holder); } } diff --git a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java index 1a6b2237c..a9598e718 100644 --- a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.listeners; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.WorldBlacklist; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.chat.ChatChannel; @@ -13,6 +12,7 @@ import com.gmail.nossr50.events.fake.FakePlayerAnimationEvent; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.party.ShareHandler; +import com.gmail.nossr50.runnables.MobHealthDisplayUpdaterTask; import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask; import com.gmail.nossr50.skills.fishing.FishingManager; import com.gmail.nossr50.skills.herbalism.HerbalismManager; @@ -45,11 +45,13 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; +import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityPickupItemEvent; import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.player.*; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; import java.util.Locale; @@ -74,11 +76,11 @@ public class PlayerListener implements Listener { /* WORLD BLACKLIST CHECK */ if(WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld())) { //Remove scoreboards - if(Config.getInstance().getScoreboardsEnabled()) { + if(mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { ScoreboardManager.teardownPlayer(event.getPlayer()); } return; - } else if(WorldBlacklist.isWorldBlacklisted(event.getFrom().getWorld()) && Config.getInstance().getScoreboardsEnabled()) { + } else if(WorldBlacklist.isWorldBlacklisted(event.getFrom().getWorld()) && mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { //This only fires if they are travelling to a non-blacklisted world from a blacklisted world //Setup scoreboards @@ -94,7 +96,7 @@ public class PlayerListener implements Listener { return; } - if (!UserManager.hasPlayerDataKey(player) || Config.getInstance().getXPAfterTeleportCooldown() <= 0 || event.getFrom().equals(event.getTo())) { + if (!UserManager.hasPlayerDataKey(player) || mcMMO.p.getGeneralConfig().getXPAfterTeleportCooldown() <= 0 || event.getFrom().equals(event.getTo())) { return; } @@ -107,36 +109,56 @@ public class PlayerListener implements Listener { mmoPlayer.actualizeTeleportATS(); } + /** - * Handle PlayerDeathEvents at the lowest priority. + * Handle {@link EntityDamageByEntityEvent} at the highest priority. *

- * These events are used to modify the death message of a player when - * needed to correct issues potentially caused by the custom naming used - * for mob healthbars. + * This handler is used to clear the names of mobs with health bars to + * fix death messages showing mob health bars on death. * - * @param event The event to modify + * @param event the event to listen to */ - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - public void onPlayerDeathLowest(PlayerDeathEvent event) { - /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onEntityDamageByEntityHighest(EntityDamageByEntityEvent event) { + // we only care about players as this is for fixing player death messages + if (!(event.getEntity() instanceof Player)) + return; + Player player = (Player) event.getEntity(); + + // get the attacker + LivingEntity attacker; + if (event.getDamager() instanceof LivingEntity) + attacker = (LivingEntity) event.getDamager(); + // attempt to find creator of a projectile + else if (event.getDamager() instanceof Projectile && ((Projectile) event.getDamager()).getShooter() instanceof LivingEntity) + attacker = (LivingEntity) ((Projectile) event.getDamager()).getShooter(); + else return; - String deathMessage = event.getDeathMessage(); - - /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(event.getEntity())) - return; - } - - if (deathMessage == null) { + if (attacker instanceof HumanEntity) return; - } - Player player = event.getEntity(); - event.setDeathMessage(MobHealthbarUtils.fixDeathMessage(deathMessage, player)); + // world blacklist check + if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) + return; + // world guard main flag check + if (WorldGuardUtils.isWorldGuardLoaded() && !WorldGuardManager.getInstance().hasMainFlag((Player) event.getEntity())) + return; + + // we only want to handle player deaths + if ((player.getHealth() - event.getFinalDamage()) > 0) + return; + + // temporarily clear the mob's name + new MobHealthDisplayUpdaterTask(attacker).run(); + + // set the name back + new BukkitRunnable() { + @Override + public void run() { + MobHealthbarUtils.handleMobHealthbars(attacker, 0, mcMMO.p); + } + }.runTaskLater(mcMMO.p, 1); } /** @@ -276,7 +298,7 @@ public class PlayerListener implements Listener { return; } - if (!UserManager.hasPlayerDataKey(player) || !PrimarySkillType.FISHING.getPermissions(player)) { + if (!UserManager.hasPlayerDataKey(player) || !mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.FISHING)) { return; } @@ -295,7 +317,7 @@ public class PlayerListener implements Listener { if(event.getCaught() != null) { Item fishingCatch = (Item) event.getCaught(); - if (Config.getInstance().getFishingOverrideTreasures() && + if (mcMMO.p.getGeneralConfig().getFishingOverrideTreasures() && fishingCatch.getItemStack().getType() != Material.SALMON && fishingCatch.getItemStack().getType() != Material.COD && fishingCatch.getItemStack().getType() != Material.TROPICAL_FISH && @@ -363,7 +385,7 @@ public class PlayerListener implements Listener { return; } - if (!UserManager.hasPlayerDataKey(player) || !PrimarySkillType.FISHING.getPermissions(player)) { + if (!UserManager.hasPlayerDataKey(player) || !mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.FISHING)) { return; } @@ -570,11 +592,11 @@ public class PlayerListener implements Listener { //Delay loading for 3 seconds in case the player has a save task running, its hacky but it should do the trick new PlayerProfileLoadingTask(player).runTaskLaterAsynchronously(mcMMO.p, 60); - if (Config.getInstance().getMOTDEnabled() && Permissions.motd(player)) { + if (mcMMO.p.getGeneralConfig().getMOTDEnabled() && Permissions.motd(player)) { Motd.displayAll(player); } - if (plugin.isXPEventEnabled() && Config.getInstance().playerJoinEventInfo()) { + if (plugin.isXPEventEnabled() && mcMMO.p.getGeneralConfig().playerJoinEventInfo()) { player.sendMessage(LocaleLoader.getString("XPRate.Event", ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier())); } } @@ -657,10 +679,10 @@ public class PlayerListener implements Listener { case RIGHT_CLICK_BLOCK: Material type = clickedBlock.getType(); - if (!Config.getInstance().getAbilitiesOnlyActivateWhenSneaking() || player.isSneaking()) { + if (!mcMMO.p.getGeneralConfig().getAbilitiesOnlyActivateWhenSneaking() || player.isSneaking()) { /* REPAIR CHECKS */ if (type == Repair.anvilMaterial - && PrimarySkillType.REPAIR.getPermissions(player) + && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.REPAIR) && mcMMO.getRepairableManager().isRepairable(heldItem) && heldItem.getAmount() <= 1) { RepairManager repairManager = ((McMMOPlayer) (mmoPlayer)).getRepairManager(); @@ -674,7 +696,7 @@ public class PlayerListener implements Listener { } /* SALVAGE CHECKS */ else if (type == Salvage.anvilMaterial - && PrimarySkillType.SALVAGE.getPermissions(player) + && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.SALVAGE) && RankUtils.hasUnlockedSubskill(player, SubSkillType.SALVAGE_SCRAP_COLLECTOR) && mcMMO.getSalvageableManager().isSalvageable(heldItem) && heldItem.getAmount() <= 1) { @@ -705,9 +727,9 @@ public class PlayerListener implements Listener { case LEFT_CLICK_BLOCK: type = clickedBlock.getType(); - if (!Config.getInstance().getAbilitiesOnlyActivateWhenSneaking() || player.isSneaking()) { + if (!mcMMO.p.getGeneralConfig().getAbilitiesOnlyActivateWhenSneaking() || player.isSneaking()) { /* REPAIR CHECKS */ - if (type == Repair.anvilMaterial && PrimarySkillType.REPAIR.getPermissions(player) && mcMMO.getRepairableManager().isRepairable(heldItem)) { + if (type == Repair.anvilMaterial && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.REPAIR) && mcMMO.getRepairableManager().isRepairable(heldItem)) { RepairManager repairManager = ((McMMOPlayer) (mmoPlayer)).getRepairManager(); // Cancel repairing an enchanted item @@ -717,7 +739,7 @@ public class PlayerListener implements Listener { } } /* SALVAGE CHECKS */ - else if (type == Salvage.anvilMaterial && PrimarySkillType.SALVAGE.getPermissions(player) && mcMMO.getSalvageableManager().isSalvageable(heldItem)) { + else if (type == Salvage.anvilMaterial && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.SALVAGE) && mcMMO.getSalvageableManager().isSalvageable(heldItem)) { SalvageManager salvageManager = ((McMMOPlayer) (mmoPlayer)).getSalvageManager(); // Cancel salvaging an enchanted item @@ -799,7 +821,7 @@ public class PlayerListener implements Listener { /* ACTIVATION & ITEM CHECKS */ if (BlockUtils.canActivateTools(blockState)) { - if (Config.getInstance().getAbilitiesEnabled()) { + if (mcMMO.p.getGeneralConfig().getAbilitiesEnabled()) { if (BlockUtils.canActivateHerbalism(blockState)) { mcMMOPlayer.processAbilityActivation(PrimarySkillType.HERBALISM); } @@ -865,7 +887,7 @@ public class PlayerListener implements Listener { } /* ACTIVATION CHECKS */ - if (Config.getInstance().getAbilitiesEnabled()) { + if (mcMMO.p.getGeneralConfig().getAbilitiesEnabled()) { mcMMOPlayer.processAbilityActivation(PrimarySkillType.AXES); mcMMOPlayer.processAbilityActivation(PrimarySkillType.EXCAVATION); mcMMOPlayer.processAbilityActivation(PrimarySkillType.HERBALISM); @@ -897,13 +919,13 @@ public class PlayerListener implements Listener { Material type = heldItem.getType(); TamingManager tamingManager = mcMMOPlayer.getTamingManager(); - if (type == Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.WOLF.getConfigEntityTypeEntry())) { + if (type == mcMMO.p.getGeneralConfig().getTamingCOTWMaterial(CallOfTheWildType.WOLF.getConfigEntityTypeEntry())) { tamingManager.summonWolf(); } - else if (type == Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.CAT.getConfigEntityTypeEntry())) { + else if (type == mcMMO.p.getGeneralConfig().getTamingCOTWMaterial(CallOfTheWildType.CAT.getConfigEntityTypeEntry())) { tamingManager.summonOcelot(); } - else if (type == Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.HORSE.getConfigEntityTypeEntry())) { + else if (type == mcMMO.p.getGeneralConfig().getTamingCOTWMaterial(CallOfTheWildType.HORSE.getConfigEntityTypeEntry())) { tamingManager.summonHorse(); } @@ -956,7 +978,7 @@ public class PlayerListener implements Listener { */ @EventHandler(priority = EventPriority.LOWEST) public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { - if (!Config.getInstance().getLocale().equalsIgnoreCase("en_US")) { + if (!mcMMO.p.getGeneralConfig().getLocale().equalsIgnoreCase("en_US")) { String message = event.getMessage(); String command = message.substring(1).split(" ")[0]; String lowerCaseCommand = command.toLowerCase(Locale.ENGLISH); @@ -964,7 +986,7 @@ public class PlayerListener implements Listener { // Do these ACTUALLY have to be lower case to work properly? for (PrimarySkillType skill : PrimarySkillType.values()) { String skillName = skill.toString().toLowerCase(Locale.ENGLISH); - String localizedName = skill.getName().toLowerCase(Locale.ENGLISH); + String localizedName = mcMMO.p.getSkillTools().getLocalizedSkillName(skill).toLowerCase(Locale.ENGLISH); if (lowerCaseCommand.equals(localizedName)) { event.setMessage(message.replace(command, skillName)); diff --git a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java index cab7bba9a..d545b61bc 100644 --- a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.listeners; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.events.experience.McMMOPlayerLevelUpEvent; @@ -10,6 +9,7 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.player.PlayerLevelUtils; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.gmail.nossr50.util.skills.RankUtils; +import com.gmail.nossr50.util.skills.SkillTools; import com.gmail.nossr50.worldguard.WorldGuardManager; import com.gmail.nossr50.worldguard.WorldGuardUtils; import com.neetgames.mcmmo.player.OnlineMMOPlayer; @@ -50,7 +50,7 @@ public class SelfListener implements Listener { //Reset the delay timer RankUtils.resetUnlockDelayTimer(); - if(Config.getInstance().getScoreboardsEnabled()) + if(mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) ScoreboardManager.handleLevelUp(player, skill); if(Config.getInstance().getScoreboardsEnabled()) @@ -63,7 +63,7 @@ public class SelfListener implements Listener { Player player = event.getPlayer(); if(player.isOnline()) { - if(Config.getInstance().getScoreboardsEnabled()) + if(mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) ScoreboardManager.handleXp(player, event.getSkill()); } } @@ -72,7 +72,7 @@ public class SelfListener implements Listener { public void onAbility(McMMOPlayerAbilityActivateEvent event) { Player player = event.getPlayer(); if(player.isOnline()) { - if(Config.getInstance().getScoreboardsEnabled()) + if(mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) ScoreboardManager.cooldownUpdate(event.getPlayer(), event.getSkill()); } } @@ -141,7 +141,7 @@ public class SelfListener implements Listener { return; } - if (primarySkillType.isChildSkill()) { + if (SkillTools.isChildSkill(primarySkillType)) { return; } @@ -149,7 +149,7 @@ public class SelfListener implements Listener { float guaranteedMinimum = ExperienceConfig.getInstance().getDiminishedReturnsCap() * rawXp; - float modifiedThreshold = (float) (threshold / primarySkillType.getXpModifier() * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()); + float modifiedThreshold = (float) (threshold / ExperienceConfig.getInstance().getFormulaSkillModifier(primarySkillType) * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()); float difference = (mmoPlayer.getExperienceHandler().getRegisteredXpGain(primarySkillType) - modifiedThreshold) / modifiedThreshold; if (difference > 0) { diff --git a/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java b/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java index f4f57ceaf..0fed62f4f 100644 --- a/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java +++ b/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java @@ -1,22 +1,24 @@ package com.gmail.nossr50.locale; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.text.TextUtils; import net.kyori.adventure.text.TextComponent; import org.bukkit.ChatColor; +import org.jetbrains.annotations.NotNull; -import java.io.IOException; -import java.io.Reader; +import java.io.*; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.text.MessageFormat; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.*; import java.util.logging.Level; public final class LocaleLoader { private static final String BUNDLE_ROOT = "com.gmail.nossr50.locale.locale"; + private static final String OVERRIDE_FILE_NAME = "locale_override.properties"; private static Map bundleCache = new HashMap<>(); private static ResourceBundle bundle = null; private static ResourceBundle filesystemBundle = null; @@ -31,8 +33,9 @@ public final class LocaleLoader { /** * Gets the appropriate string from the Locale files. * - * @param key The key to look up the string with + * @param key The key to look up the string with * @param messageArguments Any arguments to be added to the string + * * @return The properly formatted locale string */ public static String getString(String key, Object... messageArguments) { @@ -45,11 +48,13 @@ public final class LocaleLoader { } //TODO: Remove this hacky crap with something better later + /** * Gets the appropriate TextComponent representation of a formatted string from the Locale files. * - * @param key The key to look up the string with + * @param key The key to look up the string with * @param messageArguments Any arguments to be added to the text component + * * @return The properly formatted text component */ public static TextComponent getTextComponent(String key, Object... messageArguments) { @@ -76,19 +81,18 @@ public final class LocaleLoader { if (filesystemBundle != null) { try { return filesystemBundle.getString(key); + } catch (MissingResourceException ignored) { } - catch (MissingResourceException ignored) {} } try { return bundle.getString(key); + } catch (MissingResourceException ignored) { } - catch (MissingResourceException ignored) {} try { return enBundle.getString(key); - } - catch (MissingResourceException ignored) { + } catch (MissingResourceException ignored) { if (!key.contains("Guides")) { mcMMO.p.getLogger().warning("Could not find locale string: " + key); } @@ -130,31 +134,169 @@ public final class LocaleLoader { if (bundle == null) { Locale.setDefault(new Locale("en", "US")); Locale locale = null; - String[] myLocale = Config.getInstance().getLocale().split("[-_ ]"); + + String[] myLocale = mcMMO.p.getGeneralConfig().getLocale().split("[-_ ]"); if (myLocale.length == 1) { locale = new Locale(myLocale[0]); - } - else if (myLocale.length >= 2) { + } else if (myLocale.length >= 2) { locale = new Locale(myLocale[0], myLocale[1]); } if (locale == null) { - throw new IllegalStateException("Failed to parse locale string '" + Config.getInstance().getLocale() + "'"); + throw new IllegalStateException("Failed to parse locale string '" + mcMMO.p.getGeneralConfig().getLocale() + "'"); } Path localePath = Paths.get(mcMMO.getLocalesDirectory() + "locale_" + locale.toString() + ".properties"); + Path overridePath = Paths.get(mcMMO.getLocalesDirectory() + OVERRIDE_FILE_NAME); + File overrideFile = overridePath.toFile(); + if (Files.exists(localePath) && Files.isRegularFile(localePath)) { - try (Reader localeReader = Files.newBufferedReader(localePath)) { - mcMMO.p.getLogger().log(Level.INFO, "Loading locale from {0}", localePath); - filesystemBundle = new PropertyResourceBundle(localeReader); + + File oldOverrideFile = localePath.toFile(); + + try { + //Copy the file + com.google.common.io.Files.copy(oldOverrideFile, overrideFile); + //Remove the old file now + oldOverrideFile.delete(); + + //Insert our helpful text + StringBuilder stringBuilder = new StringBuilder(); + + try(BufferedReader bufferedReader = new BufferedReader(new FileReader(overrideFile.getPath()))) { + // Open the file + String line; + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm"); + LocalDateTime localDateTime = LocalDateTime.now(); + stringBuilder.append("# mcMMO Locale Override File created on ").append(localDateTime.format(dateTimeFormatter)).append("\r\n"); //Empty file + stringBuilder.append(getLocaleHelpTextWithoutExamples()); //Add our helpful text + while ((line = bufferedReader.readLine()) != null) { + stringBuilder.append(line).append("\r\n"); + } + } catch (IOException e) { + e.printStackTrace(); + } + + try(FileWriter fileWriter = new FileWriter(overrideFile.getPath())) { + fileWriter.write(stringBuilder.toString()); + } catch (IOException e) { + e.printStackTrace(); + } + } catch (IOException e) { - mcMMO.p.getLogger().log(Level.WARNING, "Failed to load locale from " + localePath, e); + e.printStackTrace(); } } + + //Use the new locale file + if (Files.exists(overridePath) && Files.isRegularFile(overridePath)) { + try (Reader localeReader = Files.newBufferedReader(overridePath)) { + mcMMO.p.getLogger().log(Level.INFO, "Loading locale from {0}", overridePath); + filesystemBundle = new PropertyResourceBundle(localeReader); + } catch (IOException e) { + mcMMO.p.getLogger().log(Level.WARNING, "Failed to load locale from " + overridePath, e); + } + } else { + //Create a blank file and fill it in with some helpful text + try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(overrideFile, true))) { + // Open the file to write the player + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm"); + LocalDateTime localDateTime = LocalDateTime.now(); + bufferedWriter.append("# mcMMO Locale Override File created on ").append(localDateTime.format(dateTimeFormatter)).append("\r\n"); //Empty file + String localeExplanation = getLocaleHelpText(); + bufferedWriter.append(localeExplanation); + } catch (Exception e) { + e.printStackTrace(); + } + } + bundle = ResourceBundle.getBundle(BUNDLE_ROOT, locale); - enBundle = ResourceBundle.getBundle(BUNDLE_ROOT, Locale.US); } + + enBundle = ResourceBundle.getBundle(BUNDLE_ROOT, Locale.US); + } + + @NotNull + private static String getLocaleHelpText() { + String localeExplanation = + "# -- Are you looking to change the language of mcMMO but without editing it yourself? --\n" + + "\n" + + "# mcMMO has quite a few built in translations, you can choose which translation by editing config.yml with the appropriate locale code. The setting is `General.Locale` in config.yml\n" + + "# Odds are, if you speak a popular language on earth we already have a translation for it.\n" + + "# However our translations are done by the community, and update infrequently. (Please help us out <3)\n" + + "# We would love more people to help update our locales, submit any updated translation file to our GitHub or email it to me at business@neetgames.com\n" + + "# For a list of built in translations, view this link: https://github.com/mcMMO-Dev/mcMMO/tree/master/src/main/resources/locale\n" + + "\n" + + "\n" + + "# -- Using a built in translation -- \n" + + "# Assuming you read the above section, edit config.yml's General.Locale from en_US to the locale code that we support (see the above link), then reboot your server\n" + + "\n" + + "\n" + + "# -- Do you want to change the text in mcMMO? Including adding colors? ( Locale Override ) -- \n" + + "# First, a brief explanation.\n" + + "# Locales are the language files used by mcMMO, they also contain color codes and most of the styling used by mcMMO.\n" + + "# You can customize a locale outside of the JAR in version 2.1.51 and up.\n" + + "#\n" + + "# Locales can be overridden by editing this file\n" + + "# You can find the up to date current locale files here https://github.com/mcMMO-Dev/mcMMO/tree/master/src/main/resources/locale\n" + + "# The master file is en_US, if a translation is missing entries (as they often are) it will pull from the en_US file https://github.com/mcMMO-Dev/mcMMO/blob/master/src/main/resources/locale/locale_en_US.properties\n" + + "#\n" + + "# To override a locale, add entries to this file and copy ** only ** the strings you want to replace, otherwise you will not see any updated strings when mcMMO updates and will have to manually change them and read patch notes carefully.\n" + + "# If you wish to replace every line in some way, feel free to copy the entire contents of this file, just be advised that you will need to be on top of locale updates in mcMMO and follow our changelog closely.\n" + + "\n" + + "\n" + + "# WARNING: Locales only support ASCII and UTF16 characters at the moment, so you'll need to run special characters through a UTF16 converter (google it) to get them to work. This will be fixed in the future!\n" + + "# FIND KEYS HERE: On our github repo (en_US is our master file and has ALL the keys) -> https://github.com/mcMMO-Dev/mcMMO/tree/master/src/main/resources/locale\n" + + "# WARNING: Some keys in our master file are unused, make gratuitous use of Ctrl+F\n" + + "# HOW TO APPLY: You can either restart the server for these changes to take effect or run /mcreloadlocale.\n" + + "# -- Add Keys Below --\n" + + getExamples(); + return localeExplanation; + } + + @NotNull + private static String getExamples() { + return "This.Is.An.Example.Put.Locale.Keys.Here.One=&aExample text using hex color codes\n" + + "This.Is.An.Example.Put.Locale.Keys.Here.Two=[[DARK_AQUA]]Example text using our own color codes\n" + + "This.Is.An.Example.Put.Locale.Keys.Here.Three=Example text with no colors\n"; + } + + @NotNull + private static String getLocaleHelpTextWithoutExamples() { + String localeExplanation = + "# -- Are you looking to change the language of mcMMO but without editing it yourself? --\n" + + "\n" + + "# mcMMO has quite a few built in translations, you can choose which translation by editing config.yml with the appropriate locale code. The setting is `General.Locale` in config.yml\n" + + "# Odds are, if you speak a popular language on earth we already have a translation for it.\n" + + "# However our translations are done by the community, and update infrequently. (Please help us out <3)\n" + + "# We would love more people to help update our locales, submit any updated translation file to our GitHub or email it to me at business@neetgames.com\n" + + "# For a list of built in translations, view this link: https://github.com/mcMMO-Dev/mcMMO/tree/master/src/main/resources/locale\n" + + "\n" + + "\n" + + "# -- Using a built in translation -- \n" + + "# Assuming you read the above section, edit config.yml's General.Locale from en_US to the locale code that we support (see the above link), then reboot your server\n" + + "\n" + + "\n" + + "# -- Do you want to change the text in mcMMO? Including adding colors? ( Locale Override ) -- \n" + + "# First, a brief explanation.\n" + + "# Locales are the language files used by mcMMO, they also contain color codes and most of the styling used by mcMMO.\n" + + "# You can customize a locale outside of the JAR in version 2.1.51 and up.\n" + + "#\n" + + "# Locales can be overridden by editing this file\n" + + "# You can find the up to date current locale files here https://github.com/mcMMO-Dev/mcMMO/tree/master/src/main/resources/locale\n" + + "# The master file is en_US, if a translation is missing entries (as they often are) it will pull from the en_US file https://github.com/mcMMO-Dev/mcMMO/blob/master/src/main/resources/locale/locale_en_US.properties\n" + + "#\n" + + "# To override a locale, add entries to this file and copy ** only ** the strings you want to replace, otherwise you will not see any updated strings when mcMMO updates and will have to manually change them and read patch notes carefully.\n" + + "# If you wish to replace every line in some way, feel free to copy the entire contents of this file, just be advised that you will need to be on top of locale updates in mcMMO and follow our changelog closely.\n" + + "\n" + + "\n" + + "# WARNING: Locales only support ASCII and UTF16 characters at the moment, so you'll need to run special characters through a UTF16 converter (google it) to get them to work. This will be fixed in the future!\n" + + "# FIND KEYS HERE: On our github repo (en_US is our master file and has ALL the keys) -> https://github.com/mcMMO-Dev/mcMMO/tree/master/src/main/resources/locale\n" + + "# WARNING: Some keys in our master file are unused, make gratuitous use of Ctrl+F\n" + + "# HOW TO APPLY: You can either restart the server for these changes to take effect or run /mcreloadlocale.\n" + + "# -- Add Keys Below --\n"; + return localeExplanation; } public static String addColors(String input) { diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index c8ec55b9a..04b847791 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -43,6 +43,7 @@ import com.gmail.nossr50.util.player.PlayerLevelUtils; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.gmail.nossr50.util.skills.RankUtils; +import com.gmail.nossr50.util.skills.SkillTools; import com.gmail.nossr50.util.skills.SmeltingTracker; import com.gmail.nossr50.util.upgrade.UpgradeManager; import com.gmail.nossr50.worldguard.WorldGuardManager; @@ -55,8 +56,10 @@ import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.plugin.java.JavaPluginLoader; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -87,6 +90,9 @@ public class mcMMO extends JavaPlugin { private static ChatManager chatManager; private static CommandManager commandManager; //ACF private static TransientEntityTracker transientEntityTracker; + + private @NotNull SkillTools skillTools; + private static boolean serverShutdownExecuted = false; /* Adventure */ @@ -147,21 +153,46 @@ public class mcMMO extends JavaPlugin { public final static String PROJECTILE_ORIGIN_METAKEY = "mcMMO: Projectile Origin"; public static FixedMetadataValue metadataValue; + private long purgeTime = 2630000000L; - public static final String ULTRA_PERMISSONS = "UltraPermissons"; + private GeneralConfig generalConfig; + private AdvancedConfig advancedConfig; +// private RepairConfig repairConfig; +// private SalvageConfig salvageConfig; +// private PersistentDataConfig persistentDataConfig; +// private ChatConfig chatConfig; +// private CoreSkillsConfig coreSkillsConfig; +// private RankConfig rankConfig; +// private TreasureConfig treasureConfig; +// private FishingTreasureConfig fishingTreasureConfig; +// private SoundConfig soundConfig; public mcMMO() { p = this; } + + protected mcMMO(JavaPluginLoader loader, PluginDescriptionFile description, File dataFolder, File file) + { + super(loader, description, dataFolder, file); + } + + /** * Things to be run when the plugin is enabled. */ @Override public void onEnable() { try { + setupFilePaths(); + generalConfig = new GeneralConfig(getDataFolder()); //Load before skillTools + skillTools = new SkillTools(this); //Load after general config + + //Init configs + advancedConfig = new AdvancedConfig(getDataFolder()); + //Store this value so other plugins can check it - isRetroModeEnabled = Config.getInstance().getIsRetroMode(); + isRetroModeEnabled = generalConfig.getIsRetroMode(); //Platform Manager platformManager = new PlatformManager(); @@ -177,7 +208,6 @@ public class mcMMO extends JavaPlugin { upgradeManager = new UpgradeManager(); - setupFilePaths(); modManager = new ModManager(); @@ -203,7 +233,10 @@ public class mcMMO extends JavaPlugin { getLogger().warning("mcMMO will not work properly alongside NoCheatPlus without CompatNoCheatPlus"); } - databaseManager = DatabaseManagerFactory.getDatabaseManager(); + // One month in milliseconds + this.purgeTime = 2630000000L * generalConfig.getOldUsersCutoff(); + + databaseManager = DatabaseManagerFactory.getDatabaseManager(mcMMO.getUsersFilePath(), getLogger(), purgeTime, mcMMO.p.getAdvancedConfig().getStartingLevel()); //Check for the newer API and tell them what to do if its missing checkForOutdatedAPI(); @@ -243,7 +276,7 @@ public class mcMMO extends JavaPlugin { placeStore = ChunkManagerFactory.getChunkManager(); // Get our ChunkletManager - if (Config.getInstance().getPTPCommandWorldPermissions()) { + if (generalConfig.getPTPCommandWorldPermissions()) { Permissions.generateWorldTeleportPermissions(); } @@ -254,11 +287,11 @@ public class mcMMO extends JavaPlugin { //If anonymous statistics are enabled then use them Metrics metrics; - if(Config.getInstance().getIsMetricsEnabled()) { + if(generalConfig.getIsMetricsEnabled()) { metrics = new Metrics(this, 3894); metrics.addCustomChart(new SimplePie("version", () -> getDescription().getVersion())); - if(Config.getInstance().getIsRetroMode()) + if(generalConfig.getIsRetroMode()) metrics.addCustomChart(new SimplePie("leveling_system", () -> "Retro")); else metrics.addCustomChart(new SimplePie("leveling_system", () -> "Standard")); @@ -350,7 +383,7 @@ public class mcMMO extends JavaPlugin { mcMMO.getPartyManager().saveParties(); // Save our parties //TODO: Needed? - if(Config.getInstance().getScoreboardsEnabled()) + if(generalConfig.getScoreboardsEnabled()) ScoreboardManager.teardownAll(); formulaManager.saveFormula(); @@ -360,7 +393,7 @@ public class mcMMO extends JavaPlugin { e.printStackTrace(); } - if (Config.getInstance().getBackupsEnabled()) { + if (generalConfig.getBackupsEnabled()) { // Remove other tasks BEFORE starting the Backup, or we just cancel it straight away. try { ZipLibrary.mcMMOBackup(); @@ -532,7 +565,7 @@ public class mcMMO extends JavaPlugin { TreasureConfig.getInstance(); FishingTreasureConfig.getInstance(); HiddenConfig.getInstance(); - AdvancedConfig.getInstance(); + mcMMO.p.getAdvancedConfig(); PotionConfig.getInstance(); CoreSkillsConfig.getInstance(); SoundConfig.getInstance(); @@ -592,7 +625,7 @@ public class mcMMO extends JavaPlugin { private void registerCustomRecipes() { getServer().getScheduler().scheduleSyncDelayedTask(this, () -> { - if (Config.getInstance().getChimaeraEnabled()) { + if (generalConfig.getChimaeraEnabled()) { getServer().addRecipe(ChimaeraWing.getChimaeraWingRecipe()); } }, 40); @@ -603,7 +636,7 @@ public class mcMMO extends JavaPlugin { long second = 20; long minute = second * 60; - long saveIntervalTicks = Math.max(minute, Config.getInstance().getSaveInterval() * minute); + long saveIntervalTicks = Math.max(minute, generalConfig.getSaveInterval() * minute); new SaveTimerTask().runTaskTimer(this, saveIntervalTicks, saveIntervalTicks); @@ -611,7 +644,7 @@ public class mcMMO extends JavaPlugin { new CleanBackupsTask().runTaskAsynchronously(mcMMO.p); // Old & Powerless User remover - long purgeIntervalTicks = Config.getInstance().getPurgeInterval() * 60L * 60L * Misc.TICK_CONVERSION_FACTOR; + long purgeIntervalTicks = generalConfig.getPurgeInterval() * 60L * 60L * Misc.TICK_CONVERSION_FACTOR; if (purgeIntervalTicks == 0) { new UserPurgeTask().runTaskLaterAsynchronously(this, 2 * Misc.TICK_CONVERSION_FACTOR); // Start 2 seconds after startup. @@ -621,7 +654,7 @@ public class mcMMO extends JavaPlugin { } // Automatically remove old members from parties - long kickIntervalTicks = Config.getInstance().getAutoPartyKickInterval() * 60L * 60L * Misc.TICK_CONVERSION_FACTOR; + long kickIntervalTicks = generalConfig.getAutoPartyKickInterval() * 60L * 60L * Misc.TICK_CONVERSION_FACTOR; if (kickIntervalTicks == 0) { new PartyAutoKickTask().runTaskLater(this, 2 * Misc.TICK_CONVERSION_FACTOR); // Start 2 seconds after startup. @@ -638,7 +671,7 @@ public class mcMMO extends JavaPlugin { new ClearRegisteredXPGainTask().runTaskTimer(this, 60, 60); } - if(AdvancedConfig.getInstance().allowPlayerTips()) + if(mcMMO.p.getAdvancedConfig().allowPlayerTips()) { new NotifySquelchReminderTask().runTaskTimer(this, 60, ((20 * 60) * 60)); } @@ -710,4 +743,20 @@ public class mcMMO extends JavaPlugin { private static synchronized void setServerShutdown(boolean bool) { serverShutdownExecuted = bool; } + + public long getPurgeTime() { + return purgeTime; + } + + public @NotNull SkillTools getSkillTools() { + return skillTools; + } + + public @NotNull GeneralConfig getGeneralConfig() { + return generalConfig; + } + + public @NotNull AdvancedConfig getAdvancedConfig() { + return advancedConfig; + } } diff --git a/src/main/java/com/gmail/nossr50/party/PartyFeature.java b/src/main/java/com/gmail/nossr50/party/PartyFeature.java index 3c032ef8a..a299e2b4f 100644 --- a/src/main/java/com/gmail/nossr50/party/PartyFeature.java +++ b/src/main/java/com/gmail/nossr50/party/PartyFeature.java @@ -1,8 +1,8 @@ package com.gmail.nossr50.party; import com.gmail.nossr50.commands.party.PartySubCommandType; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.text.StringUtils; import org.bukkit.entity.Player; @@ -17,7 +17,7 @@ public enum PartyFeature { } public String getFeatureLockedLocaleString() { - return LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Party.Feature.Locked." + StringUtils.getPrettyPartyFeatureString(this).replace(" ", ""), Config.getInstance().getPartyFeatureUnlockLevel(this))); + return LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Party.Feature.Locked." + StringUtils.getPrettyPartyFeatureString(this).replace(" ", ""), mcMMO.p.getGeneralConfig().getPartyFeatureUnlockLevel(this))); } public boolean hasPermission(Player player) { diff --git a/src/main/java/com/gmail/nossr50/party/PartyManager.java b/src/main/java/com/gmail/nossr50/party/PartyManager.java new file mode 100644 index 000000000..4cd483329 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/party/PartyManager.java @@ -0,0 +1,845 @@ +package com.gmail.nossr50.party; + +import com.gmail.nossr50.datatypes.chat.ChatChannel; +import com.gmail.nossr50.datatypes.interactions.NotificationType; +import com.gmail.nossr50.datatypes.party.ItemShareType; +import com.gmail.nossr50.datatypes.party.Party; +import com.gmail.nossr50.datatypes.party.PartyLeader; +import com.gmail.nossr50.datatypes.party.ShareMode; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.events.party.McMMOPartyAllianceChangeEvent; +import com.gmail.nossr50.events.party.McMMOPartyChangeEvent; +import com.gmail.nossr50.events.party.McMMOPartyChangeEvent.EventReason; +import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.player.NotificationManager; +import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.sounds.SoundManager; +import com.gmail.nossr50.util.sounds.SoundType; +import org.bukkit.OfflinePlayer; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; + +import java.io.File; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map.Entry; +import java.util.UUID; + +public final class PartyManager { + private static final String partiesFilePath = mcMMO.getFlatFileDirectory() + "parties.yml"; + private static final List parties = new ArrayList<>(); + private static final File partyFile = new File(partiesFilePath); + + private PartyManager() {} + + /** + * Check if a party with a given name already exists. + * + * @param player The player to notify + * @param partyName The name of the party to check + * @return true if a party with that name exists, false otherwise + */ + public static boolean checkPartyExistence(Player player, String partyName) { + if (getParty(partyName) == null) { + return false; + } + + player.sendMessage(LocaleLoader.getString("Commands.Party.AlreadyExists", partyName)); + return true; + } + + /** + * Checks if the player can join a party, parties can have a size limit, although there is a permission to bypass this + * @param player player who is attempting to join the party + * @param targetParty the target party + * @return true if party is full and cannot be joined + */ + public static boolean isPartyFull(Player player, Party targetParty) + { + return !Permissions.partySizeBypass(player) && mcMMO.p.getGeneralConfig().getPartyMaxSize() >= 1 && targetParty.getOnlineMembers().size() >= mcMMO.p.getGeneralConfig().getPartyMaxSize(); + } + + /** + * Attempt to change parties or join a new party. + * + * @param mcMMOPlayer The player changing or joining parties + * @param newPartyName The name of the party being joined + * @return true if the party was joined successfully, false otherwise + */ + public static boolean changeOrJoinParty(McMMOPlayer mcMMOPlayer, String newPartyName) { + Player player = mcMMOPlayer.getPlayer(); + + if (mcMMOPlayer.inParty()) { + Party oldParty = mcMMOPlayer.getParty(); + + if (!handlePartyChangeEvent(player, oldParty.getName(), newPartyName, EventReason.CHANGED_PARTIES)) { + return false; + } + + removeFromParty(mcMMOPlayer); + } + else return handlePartyChangeEvent(player, null, newPartyName, EventReason.JOINED_PARTY); + + return true; + } + + /** + * Check if two online players are in the same party. + * + * @param firstPlayer The first player + * @param secondPlayer The second player + * @return true if they are in the same party, false otherwise + */ + public static boolean inSameParty(Player firstPlayer, Player secondPlayer) { + //Profile not loaded + if(UserManager.getPlayer(firstPlayer) == null) + { + return false; + } + + //Profile not loaded + if(UserManager.getPlayer(secondPlayer) == null) + { + return false; + } + + Party firstParty = UserManager.getPlayer(firstPlayer).getParty(); + Party secondParty = UserManager.getPlayer(secondPlayer).getParty(); + + if (firstParty == null || secondParty == null) { + return false; + } + + return firstParty.equals(secondParty); + } + + public static boolean areAllies(Player firstPlayer, Player secondPlayer) { + //Profile not loaded + if(UserManager.getPlayer(firstPlayer) == null) + { + return false; + } + + //Profile not loaded + if(UserManager.getPlayer(secondPlayer) == null) + { + return false; + } + + Party firstParty = UserManager.getPlayer(firstPlayer).getParty(); + Party secondParty = UserManager.getPlayer(secondPlayer).getParty(); + + if (firstParty == null || secondParty == null || firstParty.getAlly() == null || secondParty.getAlly() == null) { + return false; + } + + return firstParty.equals(secondParty.getAlly()) && secondParty.equals(firstParty.getAlly()); + } + + /** + * Get the near party members. + * + * @param mcMMOPlayer The player to check + * @return the near party members + */ + public static List getNearMembers(McMMOPlayer mcMMOPlayer) { + List nearMembers = new ArrayList<>(); + Party party = mcMMOPlayer.getParty(); + + if (party != null) { + Player player = mcMMOPlayer.getPlayer(); + double range = mcMMO.p.getGeneralConfig().getPartyShareRange(); + + for (Player member : party.getOnlineMembers()) { + if (!player.equals(member) && member.isValid() && Misc.isNear(player.getLocation(), member.getLocation(), range)) { + nearMembers.add(member); + } + } + } + + return nearMembers; + } + + public static List getNearVisibleMembers(McMMOPlayer mcMMOPlayer) { + List nearMembers = new ArrayList<>(); + Party party = mcMMOPlayer.getParty(); + + if (party != null) { + Player player = mcMMOPlayer.getPlayer(); + double range = mcMMO.p.getGeneralConfig().getPartyShareRange(); + + for (Player member : party.getVisibleMembers(player)) { + if (!player.equals(member) + && member.isValid() + && Misc.isNear(player.getLocation(), member.getLocation(), range)) { + nearMembers.add(member); + } + } + } + + return nearMembers; + } + + + /** + * Get a list of all players in this player's party. + * + * @param player The player to check + * @return all the players in the player's party + */ + public static LinkedHashMap getAllMembers(Player player) { + Party party = getParty(player); + + return party == null ? new LinkedHashMap<>() : party.getMembers(); + } + + /** + * Get a list of all online players in this party. + * + * @param partyName The party to check + * @return all online players in this party + */ + public static List getOnlineMembers(String partyName) { + return getOnlineMembers(getParty(partyName)); + } + + /** + * Get a list of all online players in this party. + * + * @param player The player to check + * @return all online players in this party + */ + public static List getOnlineMembers(Player player) { + return getOnlineMembers(getParty(player)); + } + + private static List getOnlineMembers(Party party) { + return party == null ? new ArrayList<>() : party.getOnlineMembers(); + } + + /** + * Retrieve a party by its name + * + * @param partyName The party name + * @return the existing party, null otherwise + */ + public static Party getParty(String partyName) { + for (Party party : parties) { + if (party.getName().equalsIgnoreCase(partyName)) { + return party; + } + } + + return null; + } + + /** + * Retrieve a party by a members name + * + * @param playerName The members name + * @return the existing party, null otherwise + */ + @Deprecated + public static Party getPlayerParty(String playerName) { + for (Party party : parties) { + if (party.getMembers().containsKey(playerName)) { + return party; + } + } + + return null; + } + + /** + * Retrieve a party by a members uuid + * + * @param uuid The members uuid + * @return the existing party, null otherwise + */ + public static Party getPlayerParty(String playerName, UUID uuid) { + for (Party party : parties) { + LinkedHashMap members = party.getMembers(); + if (members.containsKey(uuid) || members.containsValue(playerName)) { + + // Name changes + if (members.get(uuid) == null || !members.get(uuid).equals(playerName)) { + members.put(uuid, playerName); + } + + return party; + } + } + + return null; + } + + /** + * Retrieve a party by member + * + * @param player The member + * @return the existing party, null otherwise + */ + public static Party getParty(Player player) { + //Profile not loaded + if(UserManager.getPlayer(player) == null) + { + return null; + } + + McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); + + return mcMMOPlayer.getParty(); + } + + /** + * Get a list of all current parties. + * + * @return the list of parties. + */ + public static List getParties() { + return parties; + } + + /** + * Remove a player from a party. + * + * @param player The player to remove + * @param party The party + */ + public static void removeFromParty(OfflinePlayer player, Party party) { + LinkedHashMap members = party.getMembers(); + String playerName = player.getName(); + + members.remove(player.getUniqueId()); + + if (player.isOnline()) { + party.getOnlineMembers().remove(player.getPlayer()); + } + + if (members.isEmpty()) { + parties.remove(party); + } + else { + // If the leaving player was the party leader, appoint a new leader from the party members + if (party.getLeader().getUniqueId().equals(player.getUniqueId())) { + setPartyLeader(members.keySet().iterator().next(), party); + } + + informPartyMembersQuit(party, playerName); + } + } + + /** + * Remove a player from a party. + * + * @param mcMMOPlayer The player to remove + */ + public static void removeFromParty(McMMOPlayer mcMMOPlayer) { + removeFromParty(mcMMOPlayer.getPlayer(), mcMMOPlayer.getParty()); + processPartyLeaving(mcMMOPlayer); + } + + /** + * Disband a party. Kicks out all members and removes the party. + * + * @param party The party to remove + */ + public static void disbandParty(Party party) { + //TODO: Potential issues with unloaded profile? + for (Player member : party.getOnlineMembers()) { + //Profile not loaded + if(UserManager.getPlayer(member) == null) + { + continue; + } + + processPartyLeaving(UserManager.getPlayer(member)); + } + + // Disband the alliance between the disbanded party and it's ally + if (party.getAlly() != null) { + party.getAlly().setAlly(null); + } + + parties.remove(party); + } + + /** + * Create a new party + * + * @param mcMMOPlayer The player to add to the party + * @param partyName The party to add the player to + * @param password The password for this party, null if there was no password + */ + public static void createParty(McMMOPlayer mcMMOPlayer, String partyName, String password) { + Player player = mcMMOPlayer.getPlayer(); + + Party party = new Party(new PartyLeader(player.getUniqueId(), player.getName()), partyName.replace(".", ""), password); + + if (password != null) { + player.sendMessage(LocaleLoader.getString("Party.Password.Set", password)); + } + + parties.add(party); + + player.sendMessage(LocaleLoader.getString("Commands.Party.Create", party.getName())); + addToParty(mcMMOPlayer, party); + } + + /** + * Check if a player can join a party + * + * @param player The player trying to join a party + * @param party The party + * @param password The password provided by the player + * @return true if the player can join the party + */ + public static boolean checkPartyPassword(Player player, Party party, String password) { + if (party.isLocked()) { + String partyPassword = party.getPassword(); + + if (partyPassword == null) { + player.sendMessage(LocaleLoader.getString("Party.Locked")); + return false; + } + + if (password == null) { + player.sendMessage(LocaleLoader.getString("Party.Password.None")); + return false; + } + + if (!password.equals(partyPassword)) { + player.sendMessage(LocaleLoader.getString("Party.Password.Incorrect")); + return false; + } + } + + return true; + } + + /** + * Accept a party invitation + * + * @param mcMMOPlayer The player to add to the party + */ + public static void joinInvitedParty(McMMOPlayer mcMMOPlayer) { + Party invite = mcMMOPlayer.getPartyInvite(); + + // Check if the party still exists, it might have been disbanded + if (!parties.contains(invite)) { + NotificationManager.sendPlayerInformation(mcMMOPlayer.getPlayer(), NotificationType.PARTY_MESSAGE, "Party.Disband"); + return; + } + + /* + * Don't let players join a full party + */ + if(mcMMO.p.getGeneralConfig().getPartyMaxSize() > 0 && invite.getMembers().size() >= mcMMO.p.getGeneralConfig().getPartyMaxSize()) + { + NotificationManager.sendPlayerInformation(mcMMOPlayer.getPlayer(), NotificationType.PARTY_MESSAGE, "Commands.Party.PartyFull.InviteAccept", invite.getName(), String.valueOf(mcMMO.p.getGeneralConfig().getPartyMaxSize())); + return; + } + + NotificationManager.sendPlayerInformation(mcMMOPlayer.getPlayer(), NotificationType.PARTY_MESSAGE, "Commands.Party.Invite.Accepted", invite.getName()); + mcMMOPlayer.removePartyInvite(); + addToParty(mcMMOPlayer, invite); + } + + /** + * Accept a party alliance invitation + * + * @param mcMMOPlayer The player who accepts the alliance invite + */ + public static void acceptAllianceInvite(McMMOPlayer mcMMOPlayer) { + Party invite = mcMMOPlayer.getPartyAllianceInvite(); + Player player = mcMMOPlayer.getPlayer(); + + // Check if the party still exists, it might have been disbanded + if (!parties.contains(invite)) { + player.sendMessage(LocaleLoader.getString("Party.Disband")); + return; + } + + if (!handlePartyChangeAllianceEvent(player, mcMMOPlayer.getParty().getName(), invite.getName(), McMMOPartyAllianceChangeEvent.EventReason.FORMED_ALLIANCE)) { + return; + } + + player.sendMessage(LocaleLoader.getString("Commands.Party.Alliance.Invite.Accepted", invite.getName())); + mcMMOPlayer.removePartyAllianceInvite(); + + createAlliance(mcMMOPlayer.getParty(), invite); + } + + public static void createAlliance(Party firstParty, Party secondParty) { + firstParty.setAlly(secondParty); + secondParty.setAlly(firstParty); + + for (Player member : firstParty.getOnlineMembers()) { + member.sendMessage(LocaleLoader.getString("Party.Alliance.Formed", secondParty.getName())); + } + + for (Player member : secondParty.getOnlineMembers()) { + member.sendMessage(LocaleLoader.getString("Party.Alliance.Formed", firstParty.getName())); + } + } + + public static boolean disbandAlliance(Player player, Party firstParty, Party secondParty){ + if (!handlePartyChangeAllianceEvent(player, firstParty.getName(), secondParty.getName(), McMMOPartyAllianceChangeEvent.EventReason.DISBAND_ALLIANCE)) { + return false; + } + + PartyManager.disbandAlliance(firstParty, secondParty); + return true; + } + + private static void disbandAlliance(Party firstParty, Party secondParty) { + firstParty.setAlly(null); + secondParty.setAlly(null); + + for (Player member : firstParty.getOnlineMembers()) { + member.sendMessage(LocaleLoader.getString("Party.Alliance.Disband", secondParty.getName())); + } + + for (Player member : secondParty.getOnlineMembers()) { + member.sendMessage(LocaleLoader.getString("Party.Alliance.Disband", firstParty.getName())); + } + } + + /** + * Add a player to a party + * + * @param mcMMOPlayer The player to add to the party + * @param party The party + */ + public static void addToParty(McMMOPlayer mcMMOPlayer, Party party) { + Player player = mcMMOPlayer.getPlayer(); + String playerName = player.getName(); + + informPartyMembersJoin(party, playerName); + mcMMOPlayer.setParty(party); + party.getMembers().put(player.getUniqueId(), player.getName()); + party.getOnlineMembers().add(player); + } + + /** + * Get the leader of a party. + * + * @param partyName The party name + * @return the leader of the party + */ + public static String getPartyLeaderName(String partyName) { + Party party = getParty(partyName); + + return party == null ? null : party.getLeader().getPlayerName(); + } + + /** + * Set the leader of a party. + * + * @param uuid The uuid of the player to set as leader + * @param party The party + */ + public static void setPartyLeader(UUID uuid, Party party) { + OfflinePlayer player = mcMMO.p.getServer().getOfflinePlayer(uuid); + UUID leaderUniqueId = party.getLeader().getUniqueId(); + + for (Player member : party.getOnlineMembers()) { + UUID memberUniqueId = member.getUniqueId(); + + if (memberUniqueId.equals(player.getUniqueId())) { + member.sendMessage(LocaleLoader.getString("Party.Owner.Player")); + } + else if (memberUniqueId.equals(leaderUniqueId)) { + member.sendMessage(LocaleLoader.getString("Party.Owner.NotLeader")); + } + else { + member.sendMessage(LocaleLoader.getString("Party.Owner.New", player.getName())); + } + } + + party.setLeader(new PartyLeader(player.getUniqueId(), player.getName())); + } + + /** + * Check if a player can invite others to his party. + * + * @return true if the player can invite + */ + public static boolean canInvite(McMMOPlayer mcMMOPlayer) { + Party party = mcMMOPlayer.getParty(); + + return !party.isLocked() || party.getLeader().getUniqueId().equals(mcMMOPlayer.getPlayer().getUniqueId()); + } + + /** + * Load party file. + */ + public static void loadParties() { + if (!partyFile.exists()) { + return; + } + +// if (mcMMO.getUpgradeManager().shouldUpgrade(UpgradeType.ADD_UUIDS_PARTY)) { +// loadAndUpgradeParties(); +// return; +// } + + try { + YamlConfiguration partiesFile; + partiesFile = YamlConfiguration.loadConfiguration(partyFile); + + ArrayList hasAlly = new ArrayList<>(); + + for (String partyName : partiesFile.getConfigurationSection("").getKeys(false)) { + Party party = new Party(partyName); + + String[] leaderSplit = partiesFile.getString(partyName + ".Leader").split("[|]"); + party.setLeader(new PartyLeader(UUID.fromString(leaderSplit[0]), leaderSplit[1])); + party.setPassword(partiesFile.getString(partyName + ".Password")); + party.setLocked(partiesFile.getBoolean(partyName + ".Locked")); + party.setLevel(partiesFile.getInt(partyName + ".Level")); + party.setXp(partiesFile.getInt(partyName + ".Xp")); + + if (partiesFile.getString(partyName + ".Ally") != null) { + hasAlly.add(party); + } + + party.setXpShareMode(ShareMode.getShareMode(partiesFile.getString(partyName + ".ExpShareMode", "NONE"))); + party.setItemShareMode(ShareMode.getShareMode(partiesFile.getString(partyName + ".ItemShareMode", "NONE"))); + + for (ItemShareType itemShareType : ItemShareType.values()) { + party.setSharingDrops(itemShareType, partiesFile.getBoolean(partyName + ".ItemShareType." + itemShareType.toString(), true)); + } + + LinkedHashMap members = party.getMembers(); + + for (String memberEntry : partiesFile.getStringList(partyName + ".Members")) { + String[] memberSplit = memberEntry.split("[|]"); + members.put(UUID.fromString(memberSplit[0]), memberSplit[1]); + } + + parties.add(party); + } + + mcMMO.p.debug("Loaded (" + parties.size() + ") Parties..."); + + for (Party party : hasAlly) { + party.setAlly(PartyManager.getParty(partiesFile.getString(party.getName() + ".Ally"))); + } + + } catch (Exception e) { + e.printStackTrace(); + } + + } + + /** + * Save party file. + */ + public static void saveParties() { + mcMMO.p.debug("[Party Data] Saving..."); + + if (partyFile.exists()) { + if (!partyFile.delete()) { + mcMMO.p.getLogger().warning("Could not delete party file. Party saving failed!"); + return; + } + } + + YamlConfiguration partiesFile = new YamlConfiguration(); + + for (Party party : parties) { + String partyName = party.getName(); + PartyLeader leader = party.getLeader(); + + partiesFile.set(partyName + ".Leader", leader.getUniqueId().toString() + "|" + leader.getPlayerName()); + partiesFile.set(partyName + ".Password", party.getPassword()); + partiesFile.set(partyName + ".Locked", party.isLocked()); + partiesFile.set(partyName + ".Level", party.getLevel()); + partiesFile.set(partyName + ".Xp", (int) party.getXp()); + partiesFile.set(partyName + ".Ally", (party.getAlly() != null) ? party.getAlly().getName() : ""); + partiesFile.set(partyName + ".ExpShareMode", party.getXpShareMode().toString()); + partiesFile.set(partyName + ".ItemShareMode", party.getItemShareMode().toString()); + + for (ItemShareType itemShareType : ItemShareType.values()) { + partiesFile.set(partyName + ".ItemShareType." + itemShareType.toString(), party.sharingDrops(itemShareType)); + } + + List members = new ArrayList<>(); + + for (Entry memberEntry : party.getMembers().entrySet()) { + String memberUniqueId = memberEntry.getKey() == null ? "" : memberEntry.getKey().toString(); + String memberName = memberEntry.getValue(); + + if (!members.contains(memberName)) { + members.add(memberUniqueId + "|" + memberName); + } + } + + partiesFile.set(partyName + ".Members", members); + } + + try { + partiesFile.save(partyFile); + } + catch (Exception e) { + e.printStackTrace(); + } + } + +// private static void loadAndUpgradeParties() { +// YamlConfiguration partiesFile = YamlConfiguration.loadConfiguration(partyFile); +// +// if (!partyFile.renameTo(new File(mcMMO.getFlatFileDirectory() + "parties.yml.converted"))) { +// mcMMO.p.getLogger().severe("Could not rename parties.yml to parties.yml.converted!"); +// return; +// } +// +// ArrayList hasAlly = new ArrayList<>(); +// +// for (String partyName : partiesFile.getConfigurationSection("").getKeys(false)) { +// Party party = new Party(partyName); +// +// String leaderName = partiesFile.getString(partyName + ".Leader"); +// PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(leaderName, false); +// +// if (!profile.isLoaded()) { +// mcMMO.p.getLogger().warning("Could not find UUID in database for party leader " + leaderName + " in party " + partyName); +// continue; +// } +// +// UUID leaderUniqueId = profile.getUniqueId(); +// +// party.setLeader(new PartyLeader(leaderUniqueId, leaderName)); +// party.setPassword(partiesFile.getString(partyName + ".Password")); +// party.setLocked(partiesFile.getBoolean(partyName + ".Locked")); +// party.setLevel(partiesFile.getInt(partyName + ".Level")); +// party.setXp(partiesFile.getInt(partyName + ".Xp")); +// +// if (partiesFile.getString(partyName + ".Ally") != null) { +// hasAlly.add(party); +// } +// +// party.setXpShareMode(ShareMode.getShareMode(partiesFile.getString(partyName + ".ExpShareMode", "NONE"))); +// party.setItemShareMode(ShareMode.getShareMode(partiesFile.getString(partyName + ".ItemShareMode", "NONE"))); +// +// for (ItemShareType itemShareType : ItemShareType.values()) { +// party.setSharingDrops(itemShareType, partiesFile.getBoolean(partyName + ".ItemShareType." + itemShareType.toString(), true)); +// } +// +// LinkedHashMap members = party.getMembers(); +// +// for (String memberName : partiesFile.getStringList(partyName + ".Members")) { +// PlayerProfile memberProfile = mcMMO.getDatabaseManager().loadPlayerProfile(memberName, false); +// +// if (!memberProfile.isLoaded()) { +// mcMMO.p.getLogger().warning("Could not find UUID in database for party member " + memberName + " in party " + partyName); +// continue; +// } +// +// UUID memberUniqueId = memberProfile.getUniqueId(); +// +// members.put(memberUniqueId, memberName); +// } +// +// parties.add(party); +// } +// +// mcMMO.p.debug("Loaded (" + parties.size() + ") Parties..."); +// +// for (Party party : hasAlly) { +// party.setAlly(PartyManager.getParty(partiesFile.getString(party.getName() + ".Ally"))); +// } +// +// mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_UUIDS_PARTY); +// } + + /** + * Handle party change event. + * + * @param player The player changing parties + * @param oldPartyName The name of the old party + * @param newPartyName The name of the new party + * @param reason The reason for changing parties + * @return true if the change event was successful, false otherwise + */ + public static boolean handlePartyChangeEvent(Player player, String oldPartyName, String newPartyName, EventReason reason) { + McMMOPartyChangeEvent event = new McMMOPartyChangeEvent(player, oldPartyName, newPartyName, reason); + mcMMO.p.getServer().getPluginManager().callEvent(event); + + return !event.isCancelled(); + } + + /** + * Handle party alliance change event. + * + * @param player The player changing party alliances + * @param oldAllyName The name of the old ally + * @param newAllyName The name of the new ally + * @param reason The reason for changing allies + * @return true if the change event was successful, false otherwise + */ + public static boolean handlePartyChangeAllianceEvent(Player player, String oldAllyName, String newAllyName, McMMOPartyAllianceChangeEvent.EventReason reason) { + McMMOPartyAllianceChangeEvent event = new McMMOPartyAllianceChangeEvent(player, oldAllyName, newAllyName, reason); + mcMMO.p.getServer().getPluginManager().callEvent(event); + + return !event.isCancelled(); + } + + /** + * Remove party data from the mcMMOPlayer. + * + * @param mcMMOPlayer The player to remove party data from. + */ + public static void processPartyLeaving(McMMOPlayer mcMMOPlayer) { + mcMMOPlayer.removeParty(); + mcMMOPlayer.setChatMode(ChatChannel.NONE); + mcMMOPlayer.setItemShareModifier(10); + } + + /** + * Notify party members when the party levels up. + * + * @param party The concerned party + * @param levelsGained The amount of levels gained + * @param level The current party level + */ + public static void informPartyMembersLevelUp(Party party, int levelsGained, int level) { + boolean levelUpSoundsEnabled = mcMMO.p.getGeneralConfig().getLevelUpSoundsEnabled(); + for (Player member : party.getOnlineMembers()) { + member.sendMessage(LocaleLoader.getString("Party.LevelUp", levelsGained, level)); + + if (levelUpSoundsEnabled) { + SoundManager.sendSound(member, member.getLocation(), SoundType.LEVEL_UP); + } + } + } + + /** + * Notify party members when a player joins. + * + * @param party The concerned party + * @param playerName The name of the player that joined + */ + private static void informPartyMembersJoin(Party party, String playerName) { + for (Player member : party.getOnlineMembers()) { + member.sendMessage(LocaleLoader.getString("Party.InformedOnJoin", playerName)); + } + } + + /** + * Notify party members when a party member quits. + * + * @param party The concerned party + * @param playerName The name of the player that left + */ + private static void informPartyMembersQuit(Party party, String playerName) { + for (Player member : party.getOnlineMembers()) { + member.sendMessage(LocaleLoader.getString("Party.InformedOnQuit", playerName)); + } + } +} diff --git a/src/main/java/com/gmail/nossr50/party/PartyTeleportRecord.java b/src/main/java/com/gmail/nossr50/party/PartyTeleportRecord.java index c0c6f0564..2df50c937 100644 --- a/src/main/java/com/gmail/nossr50/party/PartyTeleportRecord.java +++ b/src/main/java/com/gmail/nossr50/party/PartyTeleportRecord.java @@ -1,6 +1,6 @@ package com.gmail.nossr50.party; -import com.gmail.nossr50.config.Config; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; import org.bukkit.entity.Player; @@ -12,7 +12,7 @@ public class PartyTeleportRecord { public PartyTeleportRecord() { requestor = null; enabled = true; - confirmRequired = Config.getInstance().getPTPCommandConfirmRequired(); + confirmRequired = mcMMO.p.getGeneralConfig().getPTPCommandConfirmRequired(); timeout = 0; lastUse = 0; } diff --git a/src/main/java/com/gmail/nossr50/party/ShareHandler.java b/src/main/java/com/gmail/nossr50/party/ShareHandler.java index 426e0814c..883bfbabf 100644 --- a/src/main/java/com/gmail/nossr50/party/ShareHandler.java +++ b/src/main/java/com/gmail/nossr50/party/ShareHandler.java @@ -3,6 +3,7 @@ package com.gmail.nossr50.party; import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.mcMMO; import com.neetgames.mcmmo.experience.XPGainReason; import com.neetgames.mcmmo.experience.XPGainSource; import com.neetgames.mcmmo.party.Party; @@ -38,7 +39,7 @@ public final class ShareHandler { nearMembers.add(mmoPlayer.getPlayer()); int partySize = nearMembers.size(); - double shareBonus = Math.min(Config.getInstance().getPartyShareBonusBase() + (partySize * Config.getInstance().getPartyShareBonusIncrease()), Config.getInstance().getPartyShareBonusCap()); + double shareBonus = Math.min(mcMMO.p.getGeneralConfig().getPartyShareBonusBase() + (partySize * mcMMO.p.getGeneralConfig().getPartyShareBonusIncrease()), mcMMO.p.getGeneralConfig().getPartyShareBonusCap()); float splitXp = (float) (xp / partySize * shareBonus); for (Player otherMember : nearMembers) { diff --git a/src/main/java/com/gmail/nossr50/runnables/backups/CleanBackupsTask.java b/src/main/java/com/gmail/nossr50/runnables/backups/CleanBackupsTask.java index 52b01e34f..b7630ea4f 100644 --- a/src/main/java/com/gmail/nossr50/runnables/backups/CleanBackupsTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/backups/CleanBackupsTask.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.runnables.backups; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.mcMMO; import org.bukkit.scheduler.BukkitRunnable; @@ -48,11 +47,11 @@ public class CleanBackupsTask extends BukkitRunnable { int weekOfYear = cal.get(Calendar.WEEK_OF_YEAR); int year = cal.get(Calendar.YEAR); - if (isPast24Hours(date) && Config.getInstance().getKeepLast24Hours()) { + if (isPast24Hours(date) && mcMMO.p.getGeneralConfig().getKeepLast24Hours()) { // Keep all files from the last 24 hours continue; } - else if (isLastWeek(date) && !savedDays.contains(dayOfWeek) && Config.getInstance().getKeepDailyLastWeek()) { + else if (isLastWeek(date) && !savedDays.contains(dayOfWeek) && mcMMO.p.getGeneralConfig().getKeepDailyLastWeek()) { // Keep daily backups of the past week savedDays.add(dayOfWeek); continue; @@ -60,7 +59,7 @@ public class CleanBackupsTask extends BukkitRunnable { else { List savedWeeks = savedYearsWeeks.computeIfAbsent(year, k -> new ArrayList<>()); - if (!savedWeeks.contains(weekOfYear) && Config.getInstance().getKeepWeeklyPastMonth()) { + if (!savedWeeks.contains(weekOfYear) && mcMMO.p.getGeneralConfig().getKeepWeeklyPastMonth()) { // Keep one backup of each week savedWeeks.add(weekOfYear); continue; diff --git a/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java b/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java index 353e0ea04..8b3c96dfe 100644 --- a/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java @@ -1,10 +1,10 @@ package com.gmail.nossr50.runnables.commands; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; +import com.gmail.nossr50.util.skills.SkillTools; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; @@ -30,7 +30,7 @@ public class McrankCommandDisplayTask extends BukkitRunnable { @Override public void run() { - if (useBoard && Config.getInstance().getScoreboardsEnabled()) { + if (useBoard && mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { displayBoard(); } @@ -47,13 +47,13 @@ public class McrankCommandDisplayTask extends BukkitRunnable { sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Heading")); sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Player", playerName)); - for (PrimarySkillType skill : PrimarySkillType.NON_CHILD_SKILLS) { -// if (!skill.getPermissions(player)) { + for (PrimarySkillType skill : SkillTools.NON_CHILD_SKILLS) { +// if (!mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, skill)) { // continue; // } rank = skills.get(skill); - sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Skill", skill.getName(), (rank == null ? LocaleLoader.getString("Commands.mcrank.Unranked") : rank))); + sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Skill", mcMMO.p.getSkillTools().getLocalizedSkillName(skill), (rank == null ? LocaleLoader.getString("Commands.mcrank.Unranked") : rank))); } rank = skills.get(null); diff --git a/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java b/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java index 6af50d467..8bbec1606 100644 --- a/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.runnables.commands; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.database.PlayerStat; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; @@ -36,7 +35,7 @@ public class MctopCommandDisplayTask extends BukkitRunnable { @Override public void run() { - if (useBoard && Config.getInstance().getScoreboardsEnabled()) { + if (useBoard && mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { displayBoard(); } @@ -62,10 +61,10 @@ public class MctopCommandDisplayTask extends BukkitRunnable { } else { if(sender instanceof Player) { - sender.sendMessage(LocaleLoader.getString("Commands.Skill.Leaderboard", primarySkillType.getName())); + sender.sendMessage(LocaleLoader.getString("Commands.Skill.Leaderboard", mcMMO.p.getSkillTools().getLocalizedSkillName(skill))); } else { - sender.sendMessage(ChatColor.stripColor(LocaleLoader.getString("Commands.Skill.Leaderboard", primarySkillType.getName()))); + sender.sendMessage(ChatColor.stripColor(LocaleLoader.getString("Commands.Skill.Leaderboard", mcMMO.p.getSkillTools().getLocalizedSkillName(skill)))); } } 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 337999308..4ade25c8c 100644 --- a/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java @@ -10,6 +10,7 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.skills.SkillTools; import org.bukkit.command.CommandSender; import org.bukkit.scheduler.BukkitRunnable; @@ -57,7 +58,7 @@ public class FormulaConversionTask extends BukkitRunnable { private void editValues(PlayerProfile profile) { mcMMO.p.debug("========================================================================"); mcMMO.p.debug("Conversion report for " + profile.getPlayerName() + ":"); - for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { int oldLevel = profile.getSkillLevel(primarySkillType); int oldXPLevel = profile.getSkillXpLevel(primarySkillType); int totalOldXP = mcMMO.getFormulaManager().calculateTotalExperience(oldLevel, oldXPLevel); diff --git a/src/main/java/com/gmail/nossr50/runnables/database/UserPurgeTask.java b/src/main/java/com/gmail/nossr50/runnables/database/UserPurgeTask.java index 8ce66bfa8..cf570e3f2 100644 --- a/src/main/java/com/gmail/nossr50/runnables/database/UserPurgeTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/database/UserPurgeTask.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.runnables.database; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.mcMMO; import org.bukkit.scheduler.BukkitRunnable; @@ -13,7 +12,7 @@ public class UserPurgeTask extends BukkitRunnable { lock.lock(); mcMMO.getDatabaseManager().purgePowerlessUsers(); - if (Config.getInstance().getOldUsersCutoff() != -1) { + if (mcMMO.p.getGeneralConfig().getOldUsersCutoff() != -1) { mcMMO.getDatabaseManager().purgeOldUsers(); } lock.unlock(); diff --git a/src/main/java/com/gmail/nossr50/runnables/items/ChimaeraWingWarmup.java b/src/main/java/com/gmail/nossr50/runnables/items/ChimaeraWingWarmup.java index 943aac775..7feaf8a97 100644 --- a/src/main/java/com/gmail/nossr50/runnables/items/ChimaeraWingWarmup.java +++ b/src/main/java/com/gmail/nossr50/runnables/items/ChimaeraWingWarmup.java @@ -1,8 +1,8 @@ package com.gmail.nossr50.runnables.items; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.ChimaeraWing; import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.Misc; @@ -36,13 +36,13 @@ public class ChimaeraWingWarmup extends BukkitRunnable { ItemStack inHand = player.getInventory().getItemInMainHand(); - if (!ItemUtils.isChimaeraWing(inHand) || inHand.getAmount() < Config.getInstance().getChimaeraUseCost()) { + if (!ItemUtils.isChimaeraWing(inHand) || inHand.getAmount() < mcMMO.p.getGeneralConfig().getChimaeraUseCost()) { player.sendMessage(LocaleLoader.getString("Skills.NeedMore", LocaleLoader.getString("Item.ChimaeraWing.Name"))); return; } long recentlyHurt = mmoPlayer.getRecentlyHurtTimestamp(); - int hurtCooldown = Config.getInstance().getChimaeraRecentlyHurtCooldown(); + int hurtCooldown = mcMMO.p.getGeneralConfig().getChimaeraRecentlyHurtCooldown(); if (hurtCooldown > 0) { int timeRemaining = SkillUtils.calculateTimeLeft(recentlyHurt * Misc.TIME_CONVERSION_FACTOR, hurtCooldown, player); diff --git a/src/main/java/com/gmail/nossr50/runnables/items/TeleportationWarmup.java b/src/main/java/com/gmail/nossr50/runnables/items/TeleportationWarmup.java index 904c84165..78f810231 100644 --- a/src/main/java/com/gmail/nossr50/runnables/items/TeleportationWarmup.java +++ b/src/main/java/com/gmail/nossr50/runnables/items/TeleportationWarmup.java @@ -1,9 +1,9 @@ package com.gmail.nossr50.runnables.items; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.EventUtils; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; @@ -42,7 +42,7 @@ public class TeleportationWarmup extends BukkitRunnable { return; } - int hurtCooldown = Config.getInstance().getPTPCommandRecentlyHurtCooldown(); + int hurtCooldown = mcMMO.p.getGeneralConfig().getPTPCommandRecentlyHurtCooldown(); if (hurtCooldown > 0) { int timeRemaining = SkillUtils.calculateTimeLeft(recentlyHurt * Misc.TIME_CONVERSION_FACTOR, hurtCooldown, teleportingPlayer); @@ -53,7 +53,7 @@ public class TeleportationWarmup extends BukkitRunnable { } } - if (Config.getInstance().getPTPCommandWorldPermissions()) { + if (mcMMO.p.getGeneralConfig().getPTPCommandWorldPermissions()) { World targetWorld = targetPlayer.getWorld(); World playerWorld = teleportingPlayer.getWorld(); diff --git a/src/main/java/com/gmail/nossr50/runnables/party/PartyAutoKickTask.java b/src/main/java/com/gmail/nossr50/runnables/party/PartyAutoKickTask.java index a7174da25..d5c586623 100644 --- a/src/main/java/com/gmail/nossr50/runnables/party/PartyAutoKickTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/party/PartyAutoKickTask.java @@ -13,7 +13,7 @@ import java.util.Map.Entry; import java.util.UUID; public class PartyAutoKickTask extends BukkitRunnable { - private final static long KICK_TIME = 24L * 60L * 60L * 1000L * Config.getInstance().getAutoPartyKickTime(); + private final static long KICK_TIME = 24L * 60L * 60L * 1000L * mcMMO.p.getGeneralConfig().getAutoPartyKickTime(); @Override public void run() { 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 8944fb043..5a82b43da 100644 --- a/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.runnables.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.locale.LocaleLoader; @@ -42,7 +41,7 @@ public class PlayerProfileLoadingTask extends BukkitRunnable { return; } - PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(player.getUniqueId(), player.getName()); + PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(player); if(!profile.isLoaded()) { mcMMO.p.getLogger().info("Creating new data for player: "+player.getName()); @@ -93,20 +92,22 @@ public class PlayerProfileLoadingTask extends BukkitRunnable { return; } + mcMMOPlayer.getProfile().updateLastLogin(); + mcMMOPlayer.setupPartyData(); UserManager.track(mcMMOPlayer); mcMMOPlayer.actualizeRespawnATS(); - if (Config.getInstance().getScoreboardsEnabled()) { + if (mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { ScoreboardManager.setupPlayer(player); - if (Config.getInstance().getShowStatsAfterLogin()) { + if (mcMMO.p.getGeneralConfig().getShowStatsAfterLogin()) { ScoreboardManager.enablePlayerStatsScoreboard(player); new McScoreboardKeepTask(player).runTaskLater(mcMMO.p, Misc.TICK_CONVERSION_FACTOR); } } - if (Config.getInstance().getShowProfileLoadedMessage()) { + if (mcMMO.p.getGeneralConfig().getShowProfileLoadedMessage()) { player.sendMessage(LocaleLoader.getString("Profile.Loading.Success")); } diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/AbilityDisableTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/AbilityDisableTask.java index da93d5dfc..2b31e55d2 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/AbilityDisableTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/AbilityDisableTask.java @@ -1,7 +1,5 @@ package com.gmail.nossr50.runnables.skills; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.mcMMO; @@ -41,7 +39,7 @@ public class AbilityDisableTask extends BukkitRunnable { // Fallthrough case BERSERK: - if (Config.getInstance().getRefreshChunksEnabled()) { + if (mcMMO.p.getGeneralConfig().getRefreshChunksEnabled()) { resendChunkRadiusAt(player); } // Fallthrough @@ -62,10 +60,12 @@ public class AbilityDisableTask extends BukkitRunnable { NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_OFF, ability.getAbilityOff()); } - if (AdvancedConfig.getInstance().sendAbilityNotificationToOtherPlayers()) { + if (mcMMO.p.getAdvancedConfig().sendAbilityNotificationToOtherPlayers()) { SkillUtils.sendSkillMessage(player, NotificationType.SUPER_ABILITY_ALERT_OTHERS, ability.getAbilityPlayerOff()); } - new AbilityCooldownTask(mmoPlayer, ability).runTaskLater(mcMMO.p, PerksUtils.handleCooldownPerks(player, ability.getCooldown()) * Misc.TICK_CONVERSION_FACTOR); + if(!mcMMO.isServerShutdownExecuted()) { + new AbilityCooldownTask(mmoPlayer, ability).runTaskLater(mcMMO.p, PerksUtils.handleCooldownPerks(player, ability.getCooldown()) * Misc.TICK_CONVERSION_FACTOR); + } } private void resendChunkRadiusAt(Player player) { diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/BleedTimerTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/BleedTimerTask.java index 49298c2bb..839358afd 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/BleedTimerTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/BleedTimerTask.java @@ -57,7 +57,7 @@ // double damage; // // if (target instanceof Player) { -// damage = AdvancedConfig.getInstance().getRuptureDamagePlayer(); +// damage = mcMMO.p.getAdvancedConfig().getRuptureDamagePlayer(); // // //Above Bleed Rank 3 deals 50% more damage // if (containerEntry.getValue().toolTier >= 4 && containerEntry.getValue().bleedRank >= 3) @@ -78,7 +78,7 @@ // } // // } else { -// damage = AdvancedConfig.getInstance().getRuptureDamageMobs(); +// damage = mcMMO.p.getAdvancedConfig().getRuptureDamageMobs(); // //// debugMessage+="BaseDMG=["+damage+"], "; // diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/RuptureTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/RuptureTask.java index 9e4f3ee2b..e740a3fcd 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/RuptureTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/RuptureTask.java @@ -1,9 +1,7 @@ package com.gmail.nossr50.runnables.skills; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.MobHealthbarUtils; import com.gmail.nossr50.util.skills.ParticleEffectUtils; import com.google.common.base.Objects; import org.bukkit.entity.LivingEntity; @@ -28,7 +26,7 @@ public class RuptureTask extends BukkitRunnable { public RuptureTask(@NotNull McMMOPlayer ruptureSource, @NotNull LivingEntity targetEntity, double pureTickDamage, double explosionDamage) { this.ruptureSource = ruptureSource; this.targetEntity = targetEntity; - this.expireTick = AdvancedConfig.getInstance().getRuptureDurationSeconds(targetEntity instanceof Player) * 20; + this.expireTick = mcMMO.p.getAdvancedConfig().getRuptureDurationSeconds(targetEntity instanceof Player) * 20; this.ruptureTick = 0; this.damageTickTracker = 0; diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/ToolLowerTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/ToolLowerTask.java index fc1e4e797..2dd8a8990 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/ToolLowerTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/ToolLowerTask.java @@ -1,8 +1,8 @@ package com.gmail.nossr50.runnables.skills; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.skills.AbilityToolType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.player.NotificationManager; import com.neetgames.mcmmo.player.OnlineMMOPlayer; import org.bukkit.scheduler.BukkitRunnable; @@ -24,7 +24,7 @@ public class ToolLowerTask extends BukkitRunnable { mmoPlayer.getSuperAbilityManager().setAbilityToolPrime(tool, false); - if (Config.getInstance().getAbilityMessagesEnabled()) { + if (mcMMO.p.getGeneralConfig().getAbilityMessagesEnabled()) { NotificationManager.sendPlayerInformation(Misc.adaptPlayer(mmoPlayer), NotificationType.TOOL, tool.getLowerToolLocaleKey()); } } diff --git a/src/main/java/com/gmail/nossr50/skills/acrobatics/Acrobatics.java b/src/main/java/com/gmail/nossr50/skills/acrobatics/Acrobatics.java index 1c72521f8..60f948d90 100644 --- a/src/main/java/com/gmail/nossr50/skills/acrobatics/Acrobatics.java +++ b/src/main/java/com/gmail/nossr50/skills/acrobatics/Acrobatics.java @@ -1,13 +1,12 @@ package com.gmail.nossr50.skills.acrobatics; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; +import com.gmail.nossr50.mcMMO; public final class Acrobatics { - public static double dodgeDamageModifier = AdvancedConfig.getInstance().getDodgeDamageModifier(); + public static double dodgeDamageModifier = mcMMO.p.getAdvancedConfig().getDodgeDamageModifier(); public static int dodgeXpModifier = ExperienceConfig.getInstance().getDodgeXPModifier(); - public static boolean dodgeLightningDisabled = Config.getInstance().getDodgeLightningDisabled(); + public static boolean dodgeLightningDisabled = mcMMO.p.getGeneralConfig().getDodgeLightningDisabled(); private Acrobatics() {} diff --git a/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java b/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java index 40274a31f..a62593147 100644 --- a/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java @@ -72,7 +72,7 @@ public class AcrobaticsManager extends SkillManager { return false; } - return skill.shouldProcess(damager); + return mcMMO.p.getSkillTools().canCombatSkillsTrigger(skill, damager); } return false; diff --git a/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java b/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java index 58ac14bee..387a35550 100644 --- a/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java +++ b/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java @@ -1,10 +1,7 @@ package com.gmail.nossr50.skills.alchemy; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.skills.AlchemyBrewTask; -import com.gmail.nossr50.util.skills.RankUtils; import org.bukkit.Location; import java.util.ArrayList; @@ -43,16 +40,15 @@ public final class Alchemy { } protected int getLevel() { - return AdvancedConfig.getInstance().getConcoctionsTierLevel(this); + return mcMMO.p.getAdvancedConfig().getConcoctionsTierLevel(this); } }*/ public static final int INGREDIENT_SLOT = 3; - public static int catalysisUnlockLevel = RankUtils.getUnlockLevel(SubSkillType.ALCHEMY_CATALYSIS); - public static int catalysisMaxBonusLevel = AdvancedConfig.getInstance().getCatalysisMaxBonusLevel(); - public static double catalysisMinSpeed = AdvancedConfig.getInstance().getCatalysisMinSpeed(); - public static double catalysisMaxSpeed = AdvancedConfig.getInstance().getCatalysisMaxSpeed(); + public static int catalysisMaxBonusLevel = mcMMO.p.getAdvancedConfig().getCatalysisMaxBonusLevel(); + public static double catalysisMinSpeed = mcMMO.p.getAdvancedConfig().getCatalysisMinSpeed(); + public static double catalysisMaxSpeed = mcMMO.p.getAdvancedConfig().getCatalysisMaxSpeed(); public static Map brewingStandMap = new HashMap<>(); diff --git a/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyManager.java b/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyManager.java index 08a6db83d..aacf63be8 100644 --- a/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyManager.java +++ b/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyManager.java @@ -43,11 +43,11 @@ public class AlchemyManager extends SkillManager { public double calculateBrewSpeed(boolean isLucky) { int skillLevel = getSkillLevel(); - if (skillLevel < Alchemy.catalysisUnlockLevel) { + if (skillLevel < RankUtils.getUnlockLevel(SubSkillType.ALCHEMY_CATALYSIS)) { return Alchemy.catalysisMinSpeed; } - return Math.min(Alchemy.catalysisMaxSpeed, Alchemy.catalysisMinSpeed + (Alchemy.catalysisMaxSpeed - Alchemy.catalysisMinSpeed) * (skillLevel - Alchemy.catalysisUnlockLevel) / (Alchemy.catalysisMaxBonusLevel - Alchemy.catalysisUnlockLevel)) * (isLucky ? LUCKY_MODIFIER : 1.0); + return Math.min(Alchemy.catalysisMaxSpeed, Alchemy.catalysisMinSpeed + (Alchemy.catalysisMaxSpeed - Alchemy.catalysisMinSpeed) * (skillLevel - RankUtils.getUnlockLevel(SubSkillType.ALCHEMY_CATALYSIS)) / (Alchemy.catalysisMaxBonusLevel - RankUtils.getUnlockLevel(SubSkillType.ALCHEMY_CATALYSIS))) * (isLucky ? LUCKY_MODIFIER : 1.0); } public void handlePotionBrewSuccesses(PotionStage potionStage, int amount) { diff --git a/src/main/java/com/gmail/nossr50/skills/archery/Archery.java b/src/main/java/com/gmail/nossr50/skills/archery/Archery.java index 7710a7bd3..b16456ec2 100644 --- a/src/main/java/com/gmail/nossr50/skills/archery/Archery.java +++ b/src/main/java/com/gmail/nossr50/skills/archery/Archery.java @@ -1,9 +1,9 @@ package com.gmail.nossr50.skills.archery; import com.gmail.nossr50.api.ItemSpawnReason; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.skills.RankUtils; import com.neetgames.mcmmo.player.OnlineMMOPlayer; @@ -19,9 +19,9 @@ import java.util.List; public class Archery { private static final List trackedEntities = new ArrayList<>(); - public static double skillShotMaxBonusDamage = AdvancedConfig.getInstance().getSkillShotDamageMax(); + public static double skillShotMaxBonusDamage = mcMMO.p.getAdvancedConfig().getSkillShotDamageMax(); - public static double dazeBonusDamage = AdvancedConfig.getInstance().getDazeBonusDamage(); + public static double dazeBonusDamage = mcMMO.p.getAdvancedConfig().getDazeBonusDamage(); public static final double DISTANCE_XP_MULTIPLIER = ExperienceConfig.getInstance().getArcheryDistanceMultiplier(); @@ -71,6 +71,6 @@ public class Archery { } public static double getDamageBonusPercent(@NotNull OnlineMMOPlayer mmoPlayer) { - return ((RankUtils.getRank(mmoPlayer, SubSkillType.ARCHERY_SKILL_SHOT)) * (AdvancedConfig.getInstance().getSkillShotRankDamageMultiplier()) / 100.0D); + return ((RankUtils.getRank(mmoPlayer, SubSkillType.ARCHERY_SKILL_SHOT)) * (mcMMO.p.getAdvancedConfig().getSkillShotRankDamageMultiplier()) / 100.0D); } } diff --git a/src/main/java/com/gmail/nossr50/skills/axes/Axes.java b/src/main/java/com/gmail/nossr50/skills/axes/Axes.java index 7f1ba62df..47d95be3f 100644 --- a/src/main/java/com/gmail/nossr50/skills/axes/Axes.java +++ b/src/main/java/com/gmail/nossr50/skills/axes/Axes.java @@ -1,7 +1,7 @@ package com.gmail.nossr50.skills.axes; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.skills.RankUtils; import org.bukkit.entity.LivingEntity; @@ -9,18 +9,18 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; public class Axes { - public static double axeMasteryRankDamageMultiplier = AdvancedConfig.getInstance().getAxeMasteryRankDamageMultiplier(); + public static double axeMasteryRankDamageMultiplier = mcMMO.p.getAdvancedConfig().getAxeMasteryRankDamageMultiplier(); - public static double criticalHitPVPModifier = AdvancedConfig.getInstance().getCriticalStrikesPVPModifier(); - public static double criticalHitPVEModifier = AdvancedConfig.getInstance().getCriticalStrikesPVEModifier(); + public static double criticalHitPVPModifier = mcMMO.p.getAdvancedConfig().getCriticalStrikesPVPModifier(); + public static double criticalHitPVEModifier = mcMMO.p.getAdvancedConfig().getCriticalStrikesPVEModifier(); - public static double impactChance = AdvancedConfig.getInstance().getImpactChance(); + public static double impactChance = mcMMO.p.getAdvancedConfig().getImpactChance(); - public static double greaterImpactBonusDamage = AdvancedConfig.getInstance().getGreaterImpactBonusDamage(); - public static double greaterImpactChance = AdvancedConfig.getInstance().getGreaterImpactChance(); - public static double greaterImpactKnockbackMultiplier = AdvancedConfig.getInstance().getGreaterImpactModifier(); + public static double greaterImpactBonusDamage = mcMMO.p.getAdvancedConfig().getGreaterImpactBonusDamage(); + public static double greaterImpactChance = mcMMO.p.getAdvancedConfig().getGreaterImpactChance(); + public static double greaterImpactKnockbackMultiplier = mcMMO.p.getAdvancedConfig().getGreaterImpactModifier(); - public static double skullSplitterModifier = AdvancedConfig.getInstance().getSkullSplitterModifier(); + public static double skullSplitterModifier = mcMMO.p.getAdvancedConfig().getSkullSplitterModifier(); protected static boolean hasArmor(LivingEntity target) { if(target == null || !target.isValid() || target.getEquipment() == null) diff --git a/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java b/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java index 3cfee3b39..99831c0bc 100644 --- a/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java +++ b/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java @@ -1,11 +1,12 @@ package com.gmail.nossr50.skills.axes; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.skills.AbilityToolType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; +import com.gmail.nossr50.datatypes.skills.ToolType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.Permissions; @@ -127,7 +128,7 @@ public class AxesManager extends SkillManager { } public double getImpactDurabilityDamage() { - return AdvancedConfig.getInstance().getImpactDurabilityDamageMultiplier() * RankUtils.getRank(getPlayer(), SubSkillType.AXES_ARMOR_IMPACT); + return mcMMO.p.getAdvancedConfig().getImpactDurabilityDamageMultiplier() * RankUtils.getRank(getPlayer(), SubSkillType.AXES_ARMOR_IMPACT); } /** diff --git a/src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java b/src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java index 66e3b48e6..4944fb97c 100644 --- a/src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java +++ b/src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java @@ -2,6 +2,7 @@ package com.gmail.nossr50.skills.child; import com.gmail.nossr50.config.AutoUpdateConfigLoader; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.text.StringUtils; import org.bukkit.configuration.file.YamlConfiguration; @@ -16,12 +17,12 @@ public class ChildConfig extends AutoUpdateConfigLoader { @Override protected void loadKeys() { - config.setDefaults(YamlConfiguration.loadConfiguration(plugin.getResourceAsReader("child.yml"))); + config.setDefaults(YamlConfiguration.loadConfiguration(mcMMO.p.getResourceAsReader("child.yml"))); FamilyTree.clearRegistrations(); // when reloading, need to clear statics - for (PrimarySkillType skill : PrimarySkillType.CHILD_SKILLS) { - plugin.debug("Finding parents of " + skill.name()); + for (PrimarySkillType skill : mcMMO.p.getSkillTools().CHILD_SKILLS) { + mcMMO.p.debug("Finding parents of " + skill.name()); EnumSet parentSkills = EnumSet.noneOf(PrimarySkillType.class); boolean useDefaults = false; // If we had an error we back out and use defaults @@ -33,7 +34,7 @@ public class ChildConfig extends AutoUpdateConfigLoader { parentSkills.add(parentSkill); } catch (IllegalArgumentException ex) { - plugin.getLogger().warning(name + " is not a valid skill type, or is a child skill!"); + mcMMO.p.getLogger().warning(name + " is not a valid skill type, or is a child skill!"); useDefaults = true; break; } @@ -52,7 +53,7 @@ public class ChildConfig extends AutoUpdateConfigLoader { // Register them for (PrimarySkillType parentSkill : parentSkills) { - plugin.debug("Registering " + parentSkill.name() + " as parent of " + skill.name()); + mcMMO.p.debug("Registering " + parentSkill.name() + " as parent of " + skill.name()); FamilyTree.registerParent(skill, parentSkill); } } diff --git a/src/main/java/com/gmail/nossr50/skills/child/FamilyTree.java b/src/main/java/com/gmail/nossr50/skills/child/FamilyTree.java index eb0e60d94..44e91fc41 100644 --- a/src/main/java/com/gmail/nossr50/skills/child/FamilyTree.java +++ b/src/main/java/com/gmail/nossr50/skills/child/FamilyTree.java @@ -5,6 +5,7 @@ import com.neetgames.mcmmo.exceptions.UnknownSkillException; import com.neetgames.mcmmo.skill.RootSkill; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import com.gmail.nossr50.util.skills.SkillTools; import java.util.HashSet; import java.util.Set; diff --git a/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java b/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java index 6acad4c41..b7599ac61 100644 --- a/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java +++ b/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java @@ -5,6 +5,7 @@ import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.treasure.ExcavationTreasure; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; @@ -97,6 +98,6 @@ public class ExcavationManager extends SkillManager { excavationBlockCheck(blockState); excavationBlockCheck(blockState); - SkillUtils.handleDurabilityChange(getPlayer().getInventory().getItemInMainHand(), Config.getInstance().getAbilityToolDamage()); + SkillUtils.handleDurabilityChange(getPlayer().getInventory().getItemInMainHand(), mcMMO.p.getGeneralConfig().getAbilityToolDamage()); } } diff --git a/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java b/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java index 28d8261a7..dab10cccf 100644 --- a/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java @@ -1,8 +1,6 @@ package com.gmail.nossr50.skills.fishing; import com.gmail.nossr50.api.ItemSpawnReason; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.config.treasure.FishingTreasureConfig; import com.gmail.nossr50.datatypes.experience.XPGainReason; @@ -198,11 +196,11 @@ public class FishingManager extends SkillManager { } public double getShakeChance() { - return AdvancedConfig.getInstance().getShakeChance(RankUtils.getRank(mmoPlayer.getPlayer(), SubSkillType.FISHING_SHAKE)); + return mcMMO.p.getAdvancedConfig().getShakeChance(RankUtils.getRank(mmoPlayer.getPlayer(), SubSkillType.FISHING_SHAKE)); } protected int getVanillaXPBoostModifier() { - return AdvancedConfig.getInstance().getFishingVanillaXPModifier(getLootTier()); + return mcMMO.p.getAdvancedConfig().getFishingVanillaXPModifier(getLootTier()); } /** @@ -273,8 +271,8 @@ public class FishingManager extends SkillManager { int maxWaitReduction = getMasterAnglerTickMaxWaitReduction(masterAnglerRank, boatBonus, convertedLureBonus); //Ticks for minWait and maxWait never go below this value - int bonusCapMin = AdvancedConfig.getInstance().getFishingReductionMinWaitCap(); - int bonusCapMax = AdvancedConfig.getInstance().getFishingReductionMaxWaitCap(); + int bonusCapMin = mcMMO.p.getAdvancedConfig().getFishingReductionMinWaitCap(); + int bonusCapMax = mcMMO.p.getAdvancedConfig().getFishingReductionMaxWaitCap(); int reducedMinWaitTime = getReducedTicks(minWaitTicks, minWaitReduction, bonusCapMin); int reducedMaxWaitTime = getReducedTicks(maxWaitTicks, maxWaitReduction, bonusCapMax); @@ -337,7 +335,7 @@ public class FishingManager extends SkillManager { } public int getMasterAnglerTickMaxWaitReduction(int masterAnglerRank, boolean boatBonus, int emulatedLureBonus) { - int totalBonus = AdvancedConfig.getInstance().getFishingReductionMaxWaitTicks() * masterAnglerRank; + int totalBonus = mcMMO.p.getAdvancedConfig().getFishingReductionMaxWaitTicks() * masterAnglerRank; if(boatBonus) { totalBonus += getFishingBoatMaxWaitReduction(); @@ -349,7 +347,7 @@ public class FishingManager extends SkillManager { } public int getMasterAnglerTickMinWaitReduction(int masterAnglerRank, boolean boatBonus) { - int totalBonus = AdvancedConfig.getInstance().getFishingReductionMinWaitTicks() * masterAnglerRank; + int totalBonus = mcMMO.p.getAdvancedConfig().getFishingReductionMinWaitTicks() * masterAnglerRank; if(boatBonus) { totalBonus += getFishingBoatMinWaitReduction(); @@ -359,11 +357,11 @@ public class FishingManager extends SkillManager { } public int getFishingBoatMinWaitReduction() { - return AdvancedConfig.getInstance().getFishingBoatReductionMinWaitTicks(); + return mcMMO.p.getAdvancedConfig().getFishingBoatReductionMinWaitTicks(); } public int getFishingBoatMaxWaitReduction() { - return AdvancedConfig.getInstance().getFishingBoatReductionMaxWaitTicks(); + return mcMMO.p.getAdvancedConfig().getFishingBoatReductionMaxWaitTicks(); } public boolean isMagicHunterEnabled() { @@ -386,7 +384,7 @@ public class FishingManager extends SkillManager { FishingTreasure treasure = null; boolean fishingSucceeds = false; - if (Config.getInstance().getFishingDropsEnabled() && Permissions.isSubSkillEnabled(player, SubSkillType.FISHING_TREASURE_HUNTER)) { + if (mcMMO.p.getGeneralConfig().getFishingDropsEnabled() && Permissions.isSubSkillEnabled(player, SubSkillType.FISHING_TREASURE_HUNTER)) { treasure = getFishingTreasure(); this.fishingCatch = null; } @@ -447,7 +445,7 @@ public class FishingManager extends SkillManager { } if(fishingSucceeds) { - if (Config.getInstance().getFishingExtraFish()) { + if (mcMMO.p.getGeneralConfig().getFishingExtraFish()) { Misc.spawnItem(player.getEyeLocation(), fishingCatch.getItemStack(), ItemSpawnReason.FISHING_EXTRA_FISH); } @@ -579,7 +577,7 @@ public class FishingManager extends SkillManager { } // Rather than subtracting luck (and causing a minimum 3% chance for every drop), scale by luck. - diceRoll *= (1.0 - luck * Config.getInstance().getFishingLureModifier() / 100); + diceRoll *= (1.0 - luck * mcMMO.p.getGeneralConfig().getFishingLureModifier() / 100); FishingTreasure treasure = null; diff --git a/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java b/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java index 2a688958f..d0aa99f43 100644 --- a/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java +++ b/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.skills.herbalism; import com.gmail.nossr50.api.ItemSpawnReason; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.config.treasure.TreasureConfig; import com.gmail.nossr50.datatypes.BlockSnapshot; @@ -208,7 +207,7 @@ public class HerbalismManager extends SkillManager { public void processHerbalismBlockBreakEvent(BlockBreakEvent blockBreakEvent) { Player player = getPlayer(); - if (Config.getInstance().getHerbalismPreventAFK() && player.isInsideVehicle()) { + if (mcMMO.p.getGeneralConfig().getHerbalismPreventAFK() && player.isInsideVehicle()) { return; } @@ -255,7 +254,7 @@ public class HerbalismManager extends SkillManager { //TODO: The design of Green Terra needs to change, this is a mess if(Permissions.greenThumbPlant(getPlayer(), originalBreak.getType())) { - if(Config.getInstance().isGreenThumbReplantableCrop(originalBreak.getType())) { + if(mcMMO.p.getGeneralConfig().isGreenThumbReplantableCrop(originalBreak.getType())) { if(!getPlayer().isSneaking()) { greenThumbActivated = processGreenThumbPlants(originalBreak, blockBreakEvent, isGreenTerraActive()); } diff --git a/src/main/java/com/gmail/nossr50/skills/mining/BlastMining.java b/src/main/java/com/gmail/nossr50/skills/mining/BlastMining.java index 5c14999a1..a71b99d4c 100644 --- a/src/main/java/com/gmail/nossr50/skills/mining/BlastMining.java +++ b/src/main/java/com/gmail/nossr50/skills/mining/BlastMining.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.skills.mining; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.skills.RankUtils; @@ -32,7 +31,7 @@ public class BlastMining { } protected int getLevel() { - return AdvancedConfig.getInstance().getBlastMiningRankLevel(this); + return mcMMO.p.getAdvancedConfig().getBlastMiningRankLevel(this); } @@ -41,13 +40,13 @@ public class BlastMining { public final static int MAXIMUM_REMOTE_DETONATION_DISTANCE = 100; public static double getBlastRadiusModifier(int rank) { - return AdvancedConfig.getInstance().getBlastRadiusModifier(rank); + return mcMMO.p.getAdvancedConfig().getBlastRadiusModifier(rank); } public static double getBlastDamageDecrease(int rank) { - return AdvancedConfig.getInstance().getBlastDamageDecrease(rank); + return mcMMO.p.getAdvancedConfig().getBlastDamageDecrease(rank); } diff --git a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java index c48ff47dc..424760e7d 100644 --- a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java +++ b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java @@ -1,8 +1,6 @@ package com.gmail.nossr50.skills.mining; import com.gmail.nossr50.api.ItemSpawnReason; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; @@ -47,7 +45,7 @@ public class MiningManager extends SkillManager { Player player = getPlayer(); return canUseBlastMining() && player.isSneaking() - && (ItemUtils.isPickaxe(getPlayer().getInventory().getItemInMainHand()) || player.getInventory().getItemInMainHand().getType() == Config.getInstance().getDetonatorItem()) + && (ItemUtils.isPickaxe(getPlayer().getInventory().getItemInMainHand()) || player.getInventory().getItemInMainHand().getType() == mcMMO.p.getGeneralConfig().getDetonatorItem()) && Permissions.remoteDetonation(player); } @@ -85,17 +83,17 @@ public class MiningManager extends SkillManager { SkillUtils.handleDurabilityChange(getPlayer().getInventory().getItemInMainHand(), Config.getInstance().getAbilityToolDamage()); } - if(!Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.MINING, blockState.getType()) || !canDoubleDrop()) + if(!mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.MINING, blockState.getType()) || !canDoubleDrop()) return; boolean silkTouch = player.getInventory().getItemInMainHand().containsEnchantment(Enchantment.SILK_TOUCH); - if(silkTouch && !AdvancedConfig.getInstance().getDoubleDropSilkTouchEnabled()) + if(silkTouch && !mcMMO.p.getAdvancedConfig().getDoubleDropSilkTouchEnabled()) return; //TODO: Make this readable if (RandomChanceUtil.checkRandomChanceExecutionSuccess(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS, true)) { - boolean useTriple = mmoPlayer.getAbilityMode(skill.getAbility()) && AdvancedConfig.getInstance().getAllowMiningTripleDrops(); + boolean useTriple = mmoPlayer.getAbilityMode(mcMMO.p.getSkillTools().getSuperAbility(skill)) && mcMMO.p.getAdvancedConfig().getAllowMiningTripleDrops(); BlockUtils.markDropsAsBonus(blockState, useTriple); } } @@ -158,8 +156,10 @@ public class MiningManager extends SkillManager { //TODO: Rewrite this garbage //TODO: Rewrite this garbage public void blastMiningDropProcessing(float yield, EntityExplodeEvent event) { - //Strip out only stuff that gives mining XP + if (yield == 0) + return; + //Strip out only stuff that gives mining XP List ores = new ArrayList<>(); List notOres = new ArrayList<>(); @@ -248,11 +248,11 @@ public class MiningManager extends SkillManager { } public static double getOreBonus(int rank) { - return AdvancedConfig.getInstance().getOreBonus(rank); + return mcMMO.p.getAdvancedConfig().getOreBonus(rank); } public static double getDebrisReduction(int rank) { - return AdvancedConfig.getInstance().getDebrisReduction(rank); + return mcMMO.p.getAdvancedConfig().getDebrisReduction(rank); } /** @@ -265,7 +265,7 @@ public class MiningManager extends SkillManager { } public static int getDropMultiplier(int rank) { - return AdvancedConfig.getInstance().getDropMultiplier(rank); + return mcMMO.p.getAdvancedConfig().getDropMultiplier(rank); } /** diff --git a/src/main/java/com/gmail/nossr50/skills/repair/ArcaneForging.java b/src/main/java/com/gmail/nossr50/skills/repair/ArcaneForging.java index f7ea4fd70..05bcfb160 100644 --- a/src/main/java/com/gmail/nossr50/skills/repair/ArcaneForging.java +++ b/src/main/java/com/gmail/nossr50/skills/repair/ArcaneForging.java @@ -1,9 +1,9 @@ package com.gmail.nossr50.skills.repair; -import com.gmail.nossr50.config.AdvancedConfig; +import com.gmail.nossr50.mcMMO; public class ArcaneForging { - public static boolean arcaneForgingDowngrades = AdvancedConfig.getInstance().getArcaneForgingDowngradeEnabled(); - public static boolean arcaneForgingEnchantLoss = AdvancedConfig.getInstance().getArcaneForgingEnchantLossEnabled(); + public static boolean arcaneForgingDowngrades = mcMMO.p.getAdvancedConfig().getArcaneForgingDowngradeEnabled(); + public static boolean arcaneForgingEnchantLoss = mcMMO.p.getAdvancedConfig().getArcaneForgingEnchantLossEnabled(); } diff --git a/src/main/java/com/gmail/nossr50/skills/repair/Repair.java b/src/main/java/com/gmail/nossr50/skills/repair/Repair.java index 4ee346ea1..36ba8cdc5 100644 --- a/src/main/java/com/gmail/nossr50/skills/repair/Repair.java +++ b/src/main/java/com/gmail/nossr50/skills/repair/Repair.java @@ -1,13 +1,12 @@ package com.gmail.nossr50.skills.repair; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.mcMMO; import org.bukkit.Material; public class Repair { - public static int repairMasteryMaxBonusLevel = AdvancedConfig.getInstance().getMaxBonusLevel(SubSkillType.REPAIR_REPAIR_MASTERY); - public static double repairMasteryMaxBonus = AdvancedConfig.getInstance().getRepairMasteryMaxBonus(); + public static int repairMasteryMaxBonusLevel = mcMMO.p.getAdvancedConfig().getMaxBonusLevel(SubSkillType.REPAIR_REPAIR_MASTERY); + public static double repairMasteryMaxBonus = mcMMO.p.getAdvancedConfig().getRepairMasteryMaxBonus(); - public static Material anvilMaterial = Config.getInstance().getRepairAnvilMaterial(); + public static Material anvilMaterial = mcMMO.p.getGeneralConfig().getRepairAnvilMaterial(); } diff --git a/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java b/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java index 1e8997995..88a9aa045 100644 --- a/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java +++ b/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java @@ -1,7 +1,5 @@ package com.gmail.nossr50.skills.repair; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; @@ -50,11 +48,11 @@ public class RepairManager extends SkillManager { return; } - if (Config.getInstance().getRepairAnvilMessagesEnabled()) { + if (mcMMO.p.getGeneralConfig().getRepairAnvilMessagesEnabled()) { NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Repair.Listener.Anvil"); } - if (Config.getInstance().getRepairAnvilPlaceSoundsEnabled()) { + if (mcMMO.p.getGeneralConfig().getRepairAnvilPlaceSoundsEnabled()) { SoundManager.sendSound(player, player.getLocation(), SoundType.ANVIL); } @@ -152,7 +150,7 @@ public class RepairManager extends SkillManager { * ExperienceConfig.getInstance().getRepairXP(repairable.getRepairMaterialType())), XPGainReason.PVE); // BWONG BWONG BWONG - if (Config.getInstance().getRepairAnvilUseSoundsEnabled()) { + if (mcMMO.p.getGeneralConfig().getRepairAnvilUseSoundsEnabled()) { SoundManager.sendSound(player, player.getLocation(), SoundType.ANVIL); SoundManager.sendSound(player, player.getLocation(), SoundType.ITEM_BREAK); } @@ -174,7 +172,7 @@ public class RepairManager extends SkillManager { Player player = getPlayer(); long lastUse = getLastAnvilUse(); - if (!SkillUtils.cooldownExpired(lastUse, 3) || !Config.getInstance().getRepairConfirmRequired()) { + if (!SkillUtils.cooldownExpired(lastUse, 3) || !mcMMO.p.getGeneralConfig().getRepairConfirmRequired()) { return true; } @@ -203,7 +201,7 @@ public class RepairManager extends SkillManager { * @return The chance of keeping the enchantment */ public double getKeepEnchantChance() { - return AdvancedConfig.getInstance().getArcaneForgingKeepEnchantsChance(getArcaneForgingRank()); + return mcMMO.p.getAdvancedConfig().getArcaneForgingKeepEnchantsChance(getArcaneForgingRank()); } /** @@ -212,7 +210,7 @@ public class RepairManager extends SkillManager { * @return The chance of the enchantment being downgraded */ public double getDowngradeEnchantChance() { - return AdvancedConfig.getInstance().getArcaneForgingDowngradeChance(getArcaneForgingRank()); + return mcMMO.p.getAdvancedConfig().getArcaneForgingDowngradeChance(getArcaneForgingRank()); } /* diff --git a/src/main/java/com/gmail/nossr50/skills/salvage/Salvage.java b/src/main/java/com/gmail/nossr50/skills/salvage/Salvage.java index 0e94b0589..4f510f909 100644 --- a/src/main/java/com/gmail/nossr50/skills/salvage/Salvage.java +++ b/src/main/java/com/gmail/nossr50/skills/salvage/Salvage.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.skills.salvage; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; +import com.gmail.nossr50.mcMMO; import org.bukkit.Material; public final class Salvage { @@ -12,15 +11,15 @@ public final class Salvage { */ private Salvage() {} - public static Material anvilMaterial = Config.getInstance().getSalvageAnvilMaterial(); + public static Material anvilMaterial = mcMMO.p.getGeneralConfig().getSalvageAnvilMaterial(); - /*public static int salvageMaxPercentageLevel = AdvancedConfig.getInstance().getSalvageMaxPercentageLevel(); - public static double salvageMaxPercentage = AdvancedConfig.getInstance().getSalvageMaxPercentage(); + /*public static int salvageMaxPercentageLevel = mcMMO.p.getAdvancedConfig().getSalvageMaxPercentageLevel(); + public static double salvageMaxPercentage = mcMMO.p.getAdvancedConfig().getSalvageMaxPercentage(); public static int advancedSalvageUnlockLevel = RankUtils.getRankUnlockLevel(SubSkillType.SALVAGE_SCRAP_COLLECTOR, 1);*/ - public static boolean arcaneSalvageDowngrades = AdvancedConfig.getInstance().getArcaneSalvageEnchantDowngradeEnabled(); - public static boolean arcaneSalvageEnchantLoss = AdvancedConfig.getInstance().getArcaneSalvageEnchantLossEnabled(); + public static boolean arcaneSalvageDowngrades = mcMMO.p.getAdvancedConfig().getArcaneSalvageEnchantDowngradeEnabled(); + public static boolean arcaneSalvageEnchantLoss = mcMMO.p.getAdvancedConfig().getArcaneSalvageEnchantLossEnabled(); static int calculateSalvageableAmount(int currentDurability, short maxDurability, int baseAmount) { double percentDamaged = (maxDurability <= 0) ? 1D : (double) (maxDurability - currentDurability) / maxDurability; diff --git a/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java b/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java index ff9a6de14..127880da3 100644 --- a/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java +++ b/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java @@ -1,8 +1,6 @@ package com.gmail.nossr50.skills.salvage; import com.gmail.nossr50.api.ItemSpawnReason; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; @@ -53,11 +51,11 @@ public class SalvageManager extends SkillManager { return; } - if (Config.getInstance().getSalvageAnvilMessagesEnabled()) { + if (mcMMO.p.getGeneralConfig().getSalvageAnvilMessagesEnabled()) { NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Salvage.Listener.Anvil"); } - if (Config.getInstance().getSalvageAnvilPlaceSoundsEnabled()) { + if (mcMMO.p.getGeneralConfig().getSalvageAnvilPlaceSoundsEnabled()) { SoundManager.sendSound(player, player.getLocation(), SoundType.ANVIL); } @@ -168,7 +166,7 @@ public class SalvageManager extends SkillManager { Misc.spawnItemTowardsLocation(anvilLoc.clone(), playerLoc.clone(), salvageResults, vectorSpeed, ItemSpawnReason.SALVAGE_MATERIALS); // BWONG BWONG BWONG - CLUNK! - if (Config.getInstance().getSalvageAnvilUseSoundsEnabled()) { + if (mcMMO.p.getGeneralConfig().getSalvageAnvilUseSoundsEnabled()) { SoundManager.sendSound(player, player.getLocation(), SoundType.ITEM_BREAK); } @@ -220,11 +218,11 @@ public class SalvageManager extends SkillManager { if(Permissions.hasSalvageEnchantBypassPerk(getPlayer())) return 100.0D; - return AdvancedConfig.getInstance().getArcaneSalvageExtractFullEnchantsChance(getArcaneSalvageRank()); + return mcMMO.p.getAdvancedConfig().getArcaneSalvageExtractFullEnchantsChance(getArcaneSalvageRank()); } public double getExtractPartialEnchantChance() { - return AdvancedConfig.getInstance().getArcaneSalvageExtractPartialEnchantsChance(getArcaneSalvageRank()); + return mcMMO.p.getAdvancedConfig().getArcaneSalvageExtractPartialEnchantsChance(getArcaneSalvageRank()); } private ItemStack arcaneSalvageCheck(Map enchants) { @@ -293,7 +291,7 @@ public class SalvageManager extends SkillManager { Player player = getPlayer(); long lastUse = getLastAnvilUse(); - if (!SkillUtils.cooldownExpired(lastUse, 3) || !Config.getInstance().getSalvageConfirmRequired()) { + if (!SkillUtils.cooldownExpired(lastUse, 3) || !mcMMO.p.getGeneralConfig().getSalvageConfirmRequired()) { return true; } 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 f39fee051..ab29e2212 100644 --- a/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java @@ -3,6 +3,7 @@ package com.gmail.nossr50.skills.smelting; import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.random.RandomChanceUtil; @@ -123,7 +124,7 @@ public class SmeltingManager extends SkillManager { */ //Process double smelt - if (Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.SMELTING, resultItemStack.getType()) + if (mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.SMELTING, resultItemStack.getType()) && canDoubleSmeltItemStack(furnace) //Effectively two less than max stack size && isSecondSmeltSuccessful()) { diff --git a/src/main/java/com/gmail/nossr50/skills/swords/Swords.java b/src/main/java/com/gmail/nossr50/skills/swords/Swords.java index 0c2bd8fad..7dda504ea 100644 --- a/src/main/java/com/gmail/nossr50/skills/swords/Swords.java +++ b/src/main/java/com/gmail/nossr50/skills/swords/Swords.java @@ -1,9 +1,9 @@ package com.gmail.nossr50.skills.swords; -import com.gmail.nossr50.config.AdvancedConfig; +import com.gmail.nossr50.mcMMO; public class Swords { - public static double counterAttackModifier = AdvancedConfig.getInstance().getCounterModifier(); + public static double counterAttackModifier = mcMMO.p.getAdvancedConfig().getCounterModifier(); - public static double serratedStrikesModifier = AdvancedConfig.getInstance().getSerratedStrikesModifier(); + public static double serratedStrikesModifier = mcMMO.p.getAdvancedConfig().getSerratedStrikesModifier(); } diff --git a/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java b/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java index 37255a435..d7e26073d 100644 --- a/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.skills.swords; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.meta.RuptureTaskMeta; import com.gmail.nossr50.datatypes.skills.AbilityToolType; @@ -76,7 +75,7 @@ public class SwordsManager extends SkillManager { return; //Don't apply bleed } - if (RandomChanceUtil.rollDice(AdvancedConfig.getInstance().getRuptureChanceToApplyOnHit(getRuptureRank()), 100)) { + if (RandomChanceUtil.rollDice(mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(getRuptureRank()), 100)) { if (target instanceof Player) { Player defender = (Player) target; @@ -91,8 +90,8 @@ public class SwordsManager extends SkillManager { } RuptureTask ruptureTask = new RuptureTask(mmoPlayer, target, - AdvancedConfig.getInstance().getRuptureTickDamage(target instanceof Player, getRuptureRank()), - AdvancedConfig.getInstance().getRuptureExplosionDamage(target instanceof Player, getRuptureRank())); + mcMMO.p.getAdvancedConfig().getRuptureTickDamage(target instanceof Player, getRuptureRank()), + mcMMO.p.getAdvancedConfig().getRuptureExplosionDamage(target instanceof Player, getRuptureRank())); RuptureTaskMeta ruptureTaskMeta = new RuptureTaskMeta(mcMMO.p, ruptureTask); @@ -136,7 +135,7 @@ public class SwordsManager extends SkillManager { } public int getRuptureBleedTicks(boolean isTargetPlayer) { - return AdvancedConfig.getInstance().getRuptureDurationSeconds(isTargetPlayer) / RuptureTask.DAMAGE_TICK_INTERVAL; + return mcMMO.p.getAdvancedConfig().getRuptureDurationSeconds(isTargetPlayer) / RuptureTask.DAMAGE_TICK_INTERVAL; } /** diff --git a/src/main/java/com/gmail/nossr50/skills/taming/Taming.java b/src/main/java/com/gmail/nossr50/skills/taming/Taming.java index 1313c4c46..26ee15a67 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/Taming.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/Taming.java @@ -1,20 +1,20 @@ package com.gmail.nossr50.skills.taming; -import com.gmail.nossr50.config.AdvancedConfig; +import com.gmail.nossr50.mcMMO; import org.bukkit.EntityEffect; import org.bukkit.entity.*; public class Taming { - public static double fastFoodServiceActivationChance = AdvancedConfig.getInstance().getFastFoodChance(); + public static double fastFoodServiceActivationChance = mcMMO.p.getAdvancedConfig().getFastFoodChance(); public static int goreBleedTicks = 2; //Equivalent to rank 1 in Rupture - public static double goreModifier = AdvancedConfig.getInstance().getGoreModifier(); + public static double goreModifier = mcMMO.p.getAdvancedConfig().getGoreModifier(); - public static double sharpenedClawsBonusDamage = AdvancedConfig.getInstance().getSharpenedClawsBonus(); + public static double sharpenedClawsBonusDamage = mcMMO.p.getAdvancedConfig().getSharpenedClawsBonus(); - public static double shockProofModifier = AdvancedConfig.getInstance().getShockProofModifier(); + public static double shockProofModifier = mcMMO.p.getAdvancedConfig().getShockProofModifier(); - public static double thickFurModifier = AdvancedConfig.getInstance().getThickFurModifier(); + public static double thickFurModifier = mcMMO.p.getAdvancedConfig().getThickFurModifier(); public static boolean canPreventDamage(Tameable pet, AnimalTamer owner) { return pet.isTamed() && owner instanceof Player && pet instanceof Wolf; diff --git a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java index 33bedb4c8..c009bc1f0 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java @@ -1,7 +1,5 @@ package com.gmail.nossr50.skills.taming; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; @@ -63,9 +61,9 @@ public class TamingManager extends SkillManager { if(summoningItems == null) { summoningItems = new HashMap<>(); - summoningItems.put(Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.CAT.getConfigEntityTypeEntry()), CallOfTheWildType.CAT); - summoningItems.put(Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.WOLF.getConfigEntityTypeEntry()), CallOfTheWildType.WOLF); - summoningItems.put(Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.HORSE.getConfigEntityTypeEntry()), CallOfTheWildType.HORSE); + summoningItems.put(mcMMO.p.getGeneralConfig().getTamingCOTWMaterial(CallOfTheWildType.CAT.getConfigEntityTypeEntry()), CallOfTheWildType.CAT); + summoningItems.put(mcMMO.p.getGeneralConfig().getTamingCOTWMaterial(CallOfTheWildType.WOLF.getConfigEntityTypeEntry()), CallOfTheWildType.WOLF); + summoningItems.put(mcMMO.p.getGeneralConfig().getTamingCOTWMaterial(CallOfTheWildType.HORSE.getConfigEntityTypeEntry()), CallOfTheWildType.HORSE); } //TODO: Temporary static cache, will be changed in 2.2 @@ -74,11 +72,11 @@ public class TamingManager extends SkillManager { cotwSummonDataProperties = new HashMap<>(); for(CallOfTheWildType callOfTheWildType : CallOfTheWildType.values()) { - Material itemSummonMaterial = Config.getInstance().getTamingCOTWMaterial(callOfTheWildType.getConfigEntityTypeEntry()); - int itemAmountRequired = Config.getInstance().getTamingCOTWCost(callOfTheWildType.getConfigEntityTypeEntry()); - int entitiesSummonedPerCOTW = Config.getInstance().getTamingCOTWAmount(callOfTheWildType.getConfigEntityTypeEntry()); - int summonLifespanSeconds = Config.getInstance().getTamingCOTWLength(callOfTheWildType.getConfigEntityTypeEntry()); - int perPlayerMaxAmount = Config.getInstance().getTamingCOTWMaxAmount(callOfTheWildType.getConfigEntityTypeEntry()); + Material itemSummonMaterial = mcMMO.p.getGeneralConfig().getTamingCOTWMaterial(callOfTheWildType.getConfigEntityTypeEntry()); + int itemAmountRequired = mcMMO.p.getGeneralConfig().getTamingCOTWCost(callOfTheWildType.getConfigEntityTypeEntry()); + int entitiesSummonedPerCOTW = mcMMO.p.getGeneralConfig().getTamingCOTWAmount(callOfTheWildType.getConfigEntityTypeEntry()); + int summonLifespanSeconds = mcMMO.p.getGeneralConfig().getTamingCOTWLength(callOfTheWildType.getConfigEntityTypeEntry()); + int perPlayerMaxAmount = mcMMO.p.getGeneralConfig().getTamingCOTWMaxAmount(callOfTheWildType.getConfigEntityTypeEntry()); TamingSummon tamingSummon = new TamingSummon(callOfTheWildType, itemSummonMaterial, itemAmountRequired, entitiesSummonedPerCOTW, summonLifespanSeconds, perPlayerMaxAmount); cotwSummonDataProperties.put(callOfTheWildType, tamingSummon); @@ -272,7 +270,7 @@ public class TamingManager extends SkillManager { if(!RankUtils.hasUnlockedSubskill(mmoPlayer, SubSkillType.TAMING_PUMMEL)) return; - if(!RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(AdvancedConfig.getInstance().getPummelChance(), getPlayer(), SubSkillType.TAMING_PUMMEL))) + if(!RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(mcMMO.p.getAdvancedConfig().getPummelChance(), getPlayer(), SubSkillType.TAMING_PUMMEL))) return; ParticleEffectUtils.playGreaterImpactEffect(target); @@ -458,7 +456,7 @@ public class TamingManager extends SkillManager { callOfWildEntity.setHealth(callOfWildEntity.getMaxHealth()); horse.setColor(Horse.Color.values()[Misc.getRandom().nextInt(Horse.Color.values().length)]); horse.setStyle(Horse.Style.values()[Misc.getRandom().nextInt(Horse.Style.values().length)]); - horse.setJumpStrength(Math.max(AdvancedConfig.getInstance().getMinHorseJumpStrength(), Math.min(Math.min(Misc.getRandom().nextDouble(), Misc.getRandom().nextDouble()) * 2, AdvancedConfig.getInstance().getMaxHorseJumpStrength()))); + horse.setJumpStrength(Math.max(mcMMO.p.getAdvancedConfig().getMinHorseJumpStrength(), Math.min(Math.min(Misc.getRandom().nextDouble(), Misc.getRandom().nextDouble()) * 2, mcMMO.p.getAdvancedConfig().getMaxHorseJumpStrength()))); horse.setAdult(); //TODO: setSpeed, once available diff --git a/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java b/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java index 9116c4fdf..79cd4802b 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.skills.taming; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.skills.subskills.taming.CallOfTheWildType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; @@ -19,7 +18,7 @@ public class TrackedTamingEntity extends BukkitRunnable { this.callOfTheWildType = callOfTheWildType; this.livingEntity = livingEntity; - int tamingCOTWLength = Config.getInstance().getTamingCOTWLength(callOfTheWildType.getConfigEntityTypeEntry()); + int tamingCOTWLength = mcMMO.p.getGeneralConfig().getTamingCOTWLength(callOfTheWildType.getConfigEntityTypeEntry()); if (tamingCOTWLength > 0) { int length = tamingCOTWLength * Misc.TICK_CONVERSION_FACTOR; diff --git a/src/main/java/com/gmail/nossr50/skills/unarmed/Unarmed.java b/src/main/java/com/gmail/nossr50/skills/unarmed/Unarmed.java index a39cbccc5..cb1124dd4 100644 --- a/src/main/java/com/gmail/nossr50/skills/unarmed/Unarmed.java +++ b/src/main/java/com/gmail/nossr50/skills/unarmed/Unarmed.java @@ -1,6 +1,6 @@ package com.gmail.nossr50.skills.unarmed; -import com.gmail.nossr50.config.Config; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundType; import org.bukkit.entity.Player; @@ -8,7 +8,7 @@ import org.bukkit.event.entity.EntityPickupItemEvent; import org.bukkit.inventory.ItemStack; public class Unarmed { - public static boolean blockCrackerSmoothBrick = Config.getInstance().getUnarmedBlockCrackerSmoothbrickToCracked(); + public static boolean blockCrackerSmoothBrick = mcMMO.p.getGeneralConfig().getUnarmedBlockCrackerSmoothbrickToCracked(); public static double berserkDamageModifier = 1.5; public static void handleItemPickup(Player player, EntityPickupItemEvent event) { diff --git a/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java b/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java index 35863772b..82029417f 100644 --- a/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java +++ b/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.skills.unarmed; import com.gmail.nossr50.api.ItemSpawnReason; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.skills.AbilityToolType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; @@ -112,7 +111,7 @@ public class UnarmedManager extends SkillManager { Item item = Misc.spawnItem(defender.getLocation(), defender.getInventory().getItemInMainHand(), ItemSpawnReason.UNARMED_DISARMED_ITEM); - if (item != null && AdvancedConfig.getInstance().getDisarmProtected()) { + if (item != null && mcMMO.p.getAdvancedConfig().getDisarmProtected()) { item.setMetadata(mcMMO.disarmedItemKey, UserManager.queryPlayer(defender).getPlayerMetadata()); } @@ -166,8 +165,8 @@ public class UnarmedManager extends SkillManager { double finalBonus = bonus + 0.5 + (rank / 2); - if(AdvancedConfig.getInstance().isSteelArmDamageCustom()) { - return AdvancedConfig.getInstance().getSteelArmOverride(RankUtils.getRank(getPlayer(), SubSkillType.UNARMED_STEEL_ARM_STYLE), finalBonus); + if(mcMMO.p.getAdvancedConfig().isSteelArmDamageCustom()) { + return mcMMO.p.getAdvancedConfig().getSteelArmOverride(RankUtils.getRank(getPlayer(), SubSkillType.UNARMED_STEEL_ARM_STYLE), finalBonus); } else { return finalBonus; } diff --git a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java index 2514a7a2f..e30213cef 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java @@ -1,8 +1,6 @@ package com.gmail.nossr50.skills.woodcutting; import com.gmail.nossr50.api.ItemSpawnReason; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; @@ -53,7 +51,7 @@ public class WoodcuttingManager extends SkillManager { public WoodcuttingManager(OnlineMMOPlayer mmoPlayer) { super(mmoPlayer, PrimarySkillType.WOODCUTTING); - treeFellerThreshold = Config.getInstance().getTreeFellerThreshold(); + treeFellerThreshold = mcMMO.p.getGeneralConfig().getTreeFellerThreshold(); } public boolean canUseLeafBlower(ItemStack heldItem) { @@ -71,7 +69,7 @@ public class WoodcuttingManager extends SkillManager { return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER) && RankUtils.hasReachedRank(1, mmoPlayer, SubSkillType.WOODCUTTING_HARVEST_LUMBER) && RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.WOODCUTTING_HARVEST_LUMBER, getPlayer()) - && Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, material); + && mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, material); } /** @@ -108,6 +106,11 @@ public class WoodcuttingManager extends SkillManager { treeFellerReachedThreshold = false; NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Woodcutting.Skills.TreeFeller.Threshold"); + + //Tree feller won't be activated for this block, award normal xp. + processWoodcuttingBlockXP(blockState); + processHarvestLumber(blockState); + return; } @@ -216,7 +219,7 @@ public class WoodcuttingManager extends SkillManager { for (BlockState blockState : treeFellerBlocks) { if (BlockUtils.hasWoodcuttingXP(blockState)) { - durabilityLoss += Config.getInstance().getAbilityToolDamage(); + durabilityLoss += mcMMO.p.getGeneralConfig().getAbilityToolDamage(); } } @@ -283,7 +286,7 @@ public class WoodcuttingManager extends SkillManager { Block block = blockState.getBlock(); if (!EventUtils.simulateBlockBreak(block, player, true)) { - break; // TODO: Shouldn't we use continue instead? + continue; } /* @@ -306,7 +309,7 @@ public class WoodcuttingManager extends SkillManager { Misc.spawnItemsFromCollection(Misc.getBlockCenter(blockState), block.getDrops(), ItemSpawnReason.TREE_FELLER_DISPLACED_BLOCK); if(RankUtils.hasReachedRank(2, mmoPlayer, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)) { - if(AdvancedConfig.getInstance().isKnockOnWoodXPOrbEnabled()) { + if(mcMMO.p.getAdvancedConfig().isKnockOnWoodXPOrbEnabled()) { if(RandomChanceUtil.rollDice(10, 100)) { int randOrbCount = Math.max(1, Misc.getRandom().nextInt(100)); Misc.spawnExperienceOrb(blockState.getLocation(), randOrbCount); diff --git a/src/main/java/com/gmail/nossr50/util/BlockUtils.java b/src/main/java/com/gmail/nossr50/util/BlockUtils.java index 8c5dd11c1..f8a2e9b47 100644 --- a/src/main/java/com/gmail/nossr50/util/BlockUtils.java +++ b/src/main/java/com/gmail/nossr50/util/BlockUtils.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.util; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.meta.BonusDropMeta; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; @@ -8,14 +7,17 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.repair.Repair; import com.gmail.nossr50.skills.salvage.Salvage; +import com.gmail.nossr50.util.compat.layers.world.WorldCompatibilityLayer; import com.gmail.nossr50.util.random.RandomChanceSkill; import com.gmail.nossr50.util.random.RandomChanceUtil; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.data.Ageable; import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; import java.util.HashSet; @@ -53,7 +55,7 @@ public final class BlockUtils { * @return true if the player succeeded in the check */ public static boolean checkDoubleDrops(Player player, BlockState blockState, PrimarySkillType skillType, SubSkillType subSkillType) { - if (Config.getInstance().getDoubleDropsEnabled(skillType, blockState.getType()) && Permissions.isSubSkillEnabled(player, subSkillType)) { + if (mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(skillType, blockState.getType()) && Permissions.isSubSkillEnabled(player, subSkillType)) { return RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkill(player, subSkillType, true)); } @@ -68,10 +70,10 @@ public final class BlockUtils { */ public static boolean shouldBeWatched(BlockState blockState) { return affectedByGigaDrillBreaker(blockState) || affectedByGreenTerra(blockState) || affectedBySuperBreaker(blockState) || hasWoodcuttingXP(blockState) - || Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.MINING, blockState.getType()) - || Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.EXCAVATION, blockState.getType()) - || Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, blockState.getType()) - || Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.SMELTING, blockState.getType()); + || mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.MINING, blockState.getType()) + || mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.EXCAVATION, blockState.getType()) + || mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, blockState.getType()) + || mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.SMELTING, blockState.getType()); } /** @@ -339,4 +341,12 @@ public final class BlockUtils { public static boolean isPartOfTree(Block rayCast) { return hasWoodcuttingXP(rayCast.getState()) || isNonWoodPartOfTree(rayCast.getType()); } + + public static boolean isWithinWorldBounds(@NotNull WorldCompatibilityLayer worldCompatibilityLayer, @NotNull Block block) { + World world = block.getWorld(); + + //World min height = inclusive | World max height = exclusive + return block.getY() >= worldCompatibilityLayer.getMinWorldHeight(world) && block.getY() < worldCompatibilityLayer.getMaxWorldHeight(world); + } + } diff --git a/src/main/java/com/gmail/nossr50/util/ChimaeraWing.java b/src/main/java/com/gmail/nossr50/util/ChimaeraWing.java index a5d4aeb9d..4a6c99300 100644 --- a/src/main/java/com/gmail/nossr50/util/ChimaeraWing.java +++ b/src/main/java/com/gmail/nossr50/util/ChimaeraWing.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.util; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; @@ -37,7 +36,7 @@ public final class ChimaeraWing { * @param player Player whose item usage to check */ public static void activationCheck(Player player) { - if (!Config.getInstance().getChimaeraEnabled()) { + if (!mcMMO.p.getGeneralConfig().getChimaeraEnabled()) { return; } @@ -64,13 +63,13 @@ public final class ChimaeraWing { int amount = inHand.getAmount(); - if (amount < Config.getInstance().getChimaeraUseCost()) { - NotificationManager.sendPlayerInformation(player, NotificationType.REQUIREMENTS_NOT_MET, "Item.ChimaeraWing.NotEnough",String.valueOf(Config.getInstance().getChimaeraUseCost() - amount), "Item.ChimaeraWing.Name"); + if (amount < mcMMO.p.getGeneralConfig().getChimaeraUseCost()) { + NotificationManager.sendPlayerInformation(player, NotificationType.REQUIREMENTS_NOT_MET, "Item.ChimaeraWing.NotEnough",String.valueOf(mcMMO.p.getGeneralConfig().getChimaeraUseCost() - amount), "Item.ChimaeraWing.Name"); return; } long lastTeleport = mmoPlayer.getChimeraWingLastUse(); - int cooldown = Config.getInstance().getChimaeraCooldown(); + int cooldown = mcMMO.p.getGeneralConfig().getChimaeraCooldown(); if (cooldown > 0) { int timeRemaining = SkillUtils.calculateTimeLeft(lastTeleport * Misc.TIME_CONVERSION_FACTOR, cooldown, player); @@ -82,7 +81,7 @@ public final class ChimaeraWing { } long recentlyHurt = mmoPlayer.getRecentlyHurtTimestamp(); - int hurtCooldown = Config.getInstance().getChimaeraRecentlyHurtCooldown(); + int hurtCooldown = mcMMO.p.getGeneralConfig().getChimaeraRecentlyHurtCooldown(); if (hurtCooldown > 0) { int timeRemaining = SkillUtils.calculateTimeLeft(recentlyHurt * Misc.TIME_CONVERSION_FACTOR, hurtCooldown, player); @@ -95,9 +94,9 @@ public final class ChimaeraWing { location = player.getLocation(); - if (Config.getInstance().getChimaeraPreventUseUnderground()) { + if (mcMMO.p.getGeneralConfig().getChimaeraPreventUseUnderground()) { if (location.getY() < player.getWorld().getHighestBlockYAt(location)) { - player.getInventory().setItemInMainHand(new ItemStack(getChimaeraWing(amount - Config.getInstance().getChimaeraUseCost()))); + player.getInventory().setItemInMainHand(new ItemStack(getChimaeraWing(amount - mcMMO.p.getGeneralConfig().getChimaeraUseCost()))); NotificationManager.sendPlayerInformation(player, NotificationType.REQUIREMENTS_NOT_MET, "Item.ChimaeraWing.Fail"); player.updateInventory(); player.setVelocity(new Vector(0, 0.5D, 0)); @@ -109,7 +108,7 @@ public final class ChimaeraWing { mmoPlayer.actualizeTeleportCommenceLocation(player); - long warmup = Config.getInstance().getChimaeraWarmup(); + long warmup = mcMMO.p.getGeneralConfig().getChimaeraWarmup(); if (warmup > 0) { NotificationManager.sendPlayerInformation(player, NotificationType.ITEM_MESSAGE, "Teleport.Commencing", String.valueOf(warmup)); @@ -123,7 +122,7 @@ public final class ChimaeraWing { public static void chimaeraExecuteTeleport() { Player player = Misc.adaptPlayer(mmoPlayer); - if (Config.getInstance().getChimaeraUseBedSpawn() && player.getBedSpawnLocation() != null) { + if (mcMMO.p.getGeneralConfig().getChimaeraUseBedSpawn() && player.getBedSpawnLocation() != null) { player.teleport(player.getBedSpawnLocation()); } else { @@ -136,12 +135,12 @@ public final class ChimaeraWing { } } - player.getInventory().setItemInMainHand(new ItemStack(getChimaeraWing(player.getInventory().getItemInMainHand().getAmount() - Config.getInstance().getChimaeraUseCost()))); + player.getInventory().setItemInMainHand(new ItemStack(getChimaeraWing(player.getInventory().getItemInMainHand().getAmount() - mcMMO.p.getGeneralConfig().getChimaeraUseCost()))); player.updateInventory(); mmoPlayer.actualizeChimeraWingLastUse(); mmoPlayer.setTeleportCommenceLocation(null); - if (Config.getInstance().getChimaeraSoundEnabled()) { + if (mcMMO.p.getGeneralConfig().getChimaeraSoundEnabled()) { SoundManager.sendSound(player, location, SoundType.CHIMAERA_WING); } @@ -149,7 +148,7 @@ public final class ChimaeraWing { } public static ItemStack getChimaeraWing(int amount) { - ItemStack itemStack = new ItemStack(Config.getInstance().getChimaeraItem(), amount); + ItemStack itemStack = new ItemStack(mcMMO.p.getGeneralConfig().getChimaeraItem(), amount); ItemMeta itemMeta = itemStack.getItemMeta(); //noinspection ConstantConditions @@ -165,8 +164,8 @@ public final class ChimaeraWing { } public static ShapelessRecipe getChimaeraWingRecipe() { - Material ingredient = Config.getInstance().getChimaeraItem(); - int amount = Config.getInstance().getChimaeraRecipeCost(); + Material ingredient = mcMMO.p.getGeneralConfig().getChimaeraItem(); + int amount = mcMMO.p.getGeneralConfig().getChimaeraRecipeCost(); ShapelessRecipe chimeraWing = new ShapelessRecipe(new NamespacedKey(mcMMO.p, "Chimera"), getChimaeraWing(1)); chimeraWing.addIngredient(amount, ingredient); diff --git a/src/main/java/com/gmail/nossr50/util/EventUtils.java b/src/main/java/com/gmail/nossr50/util/EventUtils.java index e80cec0b8..614eeb926 100644 --- a/src/main/java/com/gmail/nossr50/util/EventUtils.java +++ b/src/main/java/com/gmail/nossr50/util/EventUtils.java @@ -1,6 +1,8 @@ package com.gmail.nossr50.util; -import com.gmail.nossr50.config.Config; +import com.gmail.nossr50.datatypes.experience.XPGainReason; +import com.gmail.nossr50.datatypes.experience.XPGainSource; +import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; @@ -35,6 +37,7 @@ import com.gmail.nossr50.util.skills.CombatUtils; import com.neetgames.mcmmo.experience.XPGainReason; import com.neetgames.mcmmo.party.Party; import com.neetgames.mcmmo.player.OnlineMMOPlayer; +import com.gmail.nossr50.util.skills.SkillTools; import org.bukkit.block.Block; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Entity; @@ -405,10 +408,10 @@ public final class EventUtils { experienceChanged = event.getExperienceChanged(); PlayerProfile playerProfile = UserManager.queryPlayer(player); - for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { String skillName = primarySkillType.toString(); int playerSkillLevel = playerProfile.getSkillLevel(primarySkillType); - int threshold = Config.getInstance().getHardcoreDeathStatPenaltyLevelThreshold(); + int threshold = mcMMO.p.getGeneralConfig().getHardcoreDeathStatPenaltyLevelThreshold(); if(playerSkillLevel > threshold) { playerProfile.modifySkill(primarySkillType, Math.max(threshold, playerSkillLevel - levelChanged.get(skillName))); playerProfile.removeXp(primarySkillType, experienceChanged.get(skillName)); @@ -454,7 +457,7 @@ public final class EventUtils { PlayerProfile victimProfile = UserManager.queryPlayer(victim); - for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { String skillName = primarySkillType.toString(); int victimSkillLevel = victimProfile.getSkillLevel(primarySkillType); @@ -478,7 +481,7 @@ public final class EventUtils { } public static McMMOPlayerAbilityDeactivateEvent callAbilityDeactivateEvent(Player player, SuperAbilityType ability) { - McMMOPlayerAbilityDeactivateEvent event = new McMMOPlayerAbilityDeactivateEvent(player, PrimarySkillType.byAbility(ability)); + McMMOPlayerAbilityDeactivateEvent event = new McMMOPlayerAbilityDeactivateEvent(player, mcMMO.p.getSkillTools().getPrimarySkillBySuperAbility(ability)); mcMMO.p.getServer().getPluginManager().callEvent(event); return event; diff --git a/src/main/java/com/gmail/nossr50/util/HardcoreManager.java b/src/main/java/com/gmail/nossr50/util/HardcoreManager.java index 6290a962a..dfe4117ac 100644 --- a/src/main/java/com/gmail/nossr50/util/HardcoreManager.java +++ b/src/main/java/com/gmail/nossr50/util/HardcoreManager.java @@ -1,10 +1,12 @@ package com.gmail.nossr50.util; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.player.NotificationManager; +import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.skills.SkillTools; import com.gmail.nossr50.worldguard.WorldGuardManager; import com.gmail.nossr50.worldguard.WorldGuardUtils; import org.bukkit.entity.Player; @@ -21,8 +23,8 @@ public final class HardcoreManager { return; } - double statLossPercentage = Config.getInstance().getHardcoreDeathStatPenaltyPercentage(); - int levelThreshold = Config.getInstance().getHardcoreDeathStatPenaltyLevelThreshold(); + double statLossPercentage = mcMMO.p.getGeneralConfig().getHardcoreDeathStatPenaltyPercentage(); + int levelThreshold = mcMMO.p.getGeneralConfig().getHardcoreDeathStatPenaltyLevelThreshold(); if(UserManager.queryPlayer(player) == null) return; @@ -33,8 +35,8 @@ public final class HardcoreManager { HashMap levelChanged = new HashMap<>(); HashMap experienceChanged = new HashMap<>(); - for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { - if (!primarySkillType.getHardcoreStatLossEnabled()) { + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { + if (!mcMMO.p.getGeneralConfig().getHardcoreStatLossEnabled(primarySkillType)) { levelChanged.put(primarySkillType.toString(), 0); experienceChanged.put(primarySkillType.toString(), 0F); continue; @@ -72,8 +74,8 @@ public final class HardcoreManager { return; } - double vampirismStatLeechPercentage = Config.getInstance().getHardcoreVampirismStatLeechPercentage(); - int levelThreshold = Config.getInstance().getHardcoreVampirismLevelThreshold(); + double vampirismStatLeechPercentage = mcMMO.p.getGeneralConfig().getHardcoreVampirismStatLeechPercentage(); + int levelThreshold = mcMMO.p.getGeneralConfig().getHardcoreVampirismLevelThreshold(); if(UserManager.queryPlayer(killer) == null || UserManager.queryPlayer(victim) == null) return; @@ -85,8 +87,8 @@ public final class HardcoreManager { HashMap levelChanged = new HashMap<>(); HashMap experienceChanged = new HashMap<>(); - for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { - if (!primarySkillType.getHardcoreVampirismEnabled()) { + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { + if (!mcMMO.p.getGeneralConfig().getHardcoreVampirismEnabled(primarySkillType)) { levelChanged.put(primarySkillType.toString(), 0); experienceChanged.put(primarySkillType.toString(), 0F); continue; @@ -134,8 +136,8 @@ public final class HardcoreManager { public static boolean isStatLossEnabled() { boolean enabled = false; - for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { - if (primarySkillType.getHardcoreStatLossEnabled()) { + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { + if (mcMMO.p.getGeneralConfig().getHardcoreStatLossEnabled(primarySkillType)) { enabled = true; break; } @@ -152,8 +154,8 @@ public final class HardcoreManager { public static boolean isVampirismEnabled() { boolean enabled = false; - for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { - if (primarySkillType.getHardcoreVampirismEnabled()) { + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { + if (mcMMO.p.getGeneralConfig().getHardcoreVampirismEnabled(primarySkillType)) { enabled = true; break; } diff --git a/src/main/java/com/gmail/nossr50/util/ItemUtils.java b/src/main/java/com/gmail/nossr50/util/ItemUtils.java index 4ae96356e..b0e780314 100644 --- a/src/main/java/com/gmail/nossr50/util/ItemUtils.java +++ b/src/main/java/com/gmail/nossr50/util/ItemUtils.java @@ -1,7 +1,5 @@ package com.gmail.nossr50.util; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.config.party.ItemWeightConfig; import com.gmail.nossr50.datatypes.treasure.EnchantmentWrapper; @@ -233,7 +231,7 @@ public final class ItemUtils { * @return true if the item counts as unarmed, false otherwise */ public static boolean isUnarmed(@NotNull ItemStack item) { - if (Config.getInstance().getUnarmedItemsAsUnarmed()) { + if (mcMMO.p.getGeneralConfig().getUnarmedItemsAsUnarmed()) { return !isMinecraftTool(item); } @@ -669,7 +667,7 @@ public final class ItemUtils { if(itemMeta == null) return; - itemMeta.addEnchant(Enchantment.DIG_SPEED, existingEnchantLevel + AdvancedConfig.getInstance().getEnchantBuff(), true); + itemMeta.addEnchant(Enchantment.DIG_SPEED, existingEnchantLevel + mcMMO.p.getAdvancedConfig().getEnchantBuff(), true); itemStack.setItemMeta(itemMeta); } diff --git a/src/main/java/com/gmail/nossr50/util/MaterialMapStore.java b/src/main/java/com/gmail/nossr50/util/MaterialMapStore.java index 9503c3ba6..8f2cd7f20 100644 --- a/src/main/java/com/gmail/nossr50/util/MaterialMapStore.java +++ b/src/main/java/com/gmail/nossr50/util/MaterialMapStore.java @@ -422,6 +422,7 @@ public class MaterialMapStore { enchantables.addAll(pickAxes); enchantables.addAll(tridents); enchantables.addAll(bows); + enchantables.addAll(crossbows); enchantables.add("shears"); enchantables.add("fishing_rod"); diff --git a/src/main/java/com/gmail/nossr50/util/Misc.java b/src/main/java/com/gmail/nossr50/util/Misc.java index 8a83887f2..44ca57008 100644 --- a/src/main/java/com/gmail/nossr50/util/Misc.java +++ b/src/main/java/com/gmail/nossr50/util/Misc.java @@ -8,7 +8,6 @@ import com.google.common.collect.ImmutableSet; import com.neetgames.mcmmo.player.OnlineMMOPlayer; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.World; import org.bukkit.block.BlockState; import org.bukkit.entity.*; import org.bukkit.inventory.ItemStack; @@ -259,12 +258,6 @@ public final class Misc { } } - public static int getWorldMinCompat(World world) - { - // TODO this method should access the world min variable in a version safe manner so that we don't restrict usage to new versions of spigot only - return 0; - } - public static void printProgress(int convertedUsers, int progressInterval, long startMillis) { if ((convertedUsers % progressInterval) == 0) { mcMMO.p.getLogger().info(String.format("Conversion progress: %d users at %.2f users/second", convertedUsers, convertedUsers / (double) ((System.currentTimeMillis() - startMillis) / TIME_CONVERSION_FACTOR))); diff --git a/src/main/java/com/gmail/nossr50/util/MobHealthbarUtils.java b/src/main/java/com/gmail/nossr50/util/MobHealthbarUtils.java index d6b032db4..6df53461e 100644 --- a/src/main/java/com/gmail/nossr50/util/MobHealthbarUtils.java +++ b/src/main/java/com/gmail/nossr50/util/MobHealthbarUtils.java @@ -1,6 +1,7 @@ package com.gmail.nossr50.util; import com.gmail.nossr50.config.Config; +import com.gmail.nossr50.datatypes.MobHealthbarType; import com.gmail.nossr50.datatypes.meta.OldName; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.MobHealthDisplayUpdaterTask; @@ -36,7 +37,7 @@ public final class MobHealthbarUtils { * @param damage damage done by the attack triggering this */ public static void handleMobHealthbars(LivingEntity target, double damage, mcMMO plugin) { - if (mcMMO.isHealthBarPluginEnabled() || !Config.getInstance().getMobHealthbarEnabled()) { + if (mcMMO.isHealthBarPluginEnabled() || !mcMMO.p.getGeneralConfig().getMobHealthbarEnabled()) { return; } @@ -63,12 +64,12 @@ public final class MobHealthbarUtils { } boolean oldNameVisible = target.isCustomNameVisible(); - String newName = createHealthDisplay(Config.getInstance().getMobHealthbarDefault(), target, damage); + String newName = createHealthDisplay(mcMMO.p.getGeneralConfig().getMobHealthbarDefault(), target, damage); target.setCustomName(newName); target.setCustomNameVisible(true); - int displayTime = Config.getInstance().getMobHealthbarTime(); + int displayTime = mcMMO.p.getGeneralConfig().getMobHealthbarTime(); if (displayTime != -1) { boolean updateName = !ChatColor.stripColor(oldName).equalsIgnoreCase(ChatColor.stripColor(newName)); diff --git a/src/main/java/com/gmail/nossr50/util/ModManager.java b/src/main/java/com/gmail/nossr50/util/ModManager.java index 184b571b1..62646466a 100644 --- a/src/main/java/com/gmail/nossr50/util/ModManager.java +++ b/src/main/java/com/gmail/nossr50/util/ModManager.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.util; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.mods.CustomArmorConfig; import com.gmail.nossr50.config.mods.CustomBlockConfig; import com.gmail.nossr50.config.mods.CustomEntityConfig; @@ -89,67 +88,67 @@ public class ModManager { } public boolean isCustomBoots(Material material) { - return Config.getInstance().getArmorModsEnabled() && customBoots.contains(material); + return mcMMO.p.getGeneralConfig().getArmorModsEnabled() && customBoots.contains(material); } public boolean isCustomChestplate(Material material) { - return Config.getInstance().getArmorModsEnabled() && customChestplates.contains(material); + return mcMMO.p.getGeneralConfig().getArmorModsEnabled() && customChestplates.contains(material); } public boolean isCustomHelmet(Material material) { - return Config.getInstance().getArmorModsEnabled() && customHelmets.contains(material); + return mcMMO.p.getGeneralConfig().getArmorModsEnabled() && customHelmets.contains(material); } public boolean isCustomLeggings(Material material) { - return Config.getInstance().getArmorModsEnabled() && customLeggings.contains(material); + return mcMMO.p.getGeneralConfig().getArmorModsEnabled() && customLeggings.contains(material); } public boolean isCustomAxe(Material material) { - return Config.getInstance().getToolModsEnabled() && customAxes.contains(material); + return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customAxes.contains(material); } public boolean isCustomBow(Material material) { - return Config.getInstance().getToolModsEnabled() && customBows.contains(material); + return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customBows.contains(material); } public boolean isCustomHoe(Material material) { - return Config.getInstance().getToolModsEnabled() && customHoes.contains(material); + return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customHoes.contains(material); } public boolean isCustomPickaxe(Material material) { - return Config.getInstance().getToolModsEnabled() && customPickaxes.contains(material); + return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customPickaxes.contains(material); } public boolean isCustomShovel(Material material) { - return Config.getInstance().getToolModsEnabled() && customShovels.contains(material); + return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customShovels.contains(material); } public boolean isCustomSword(Material material) { - return Config.getInstance().getToolModsEnabled() && customSwords.contains(material); + return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customSwords.contains(material); } public boolean isCustomOre(Material data) { - return Config.getInstance().getBlockModsEnabled() && customOres.contains(data); + return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customOres.contains(data); } public boolean isCustomLog(BlockState state) { - return Config.getInstance().getBlockModsEnabled() && customLogs.contains(state.getType()); + return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customLogs.contains(state.getType()); } public boolean isCustomAbilityBlock(BlockState state) { - return Config.getInstance().getBlockModsEnabled() && customAbilityBlocks.contains(state.getType()); + return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customAbilityBlocks.contains(state.getType()); } public boolean isCustomExcavationBlock(BlockState state) { - return Config.getInstance().getBlockModsEnabled() && customExcavationBlocks.contains(state.getType()); + return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customExcavationBlocks.contains(state.getType()); } public boolean isCustomHerbalismBlock(BlockState state) { - return Config.getInstance().getBlockModsEnabled() && customHerbalismBlocks.contains(state.getType()); + return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customHerbalismBlocks.contains(state.getType()); } public boolean isCustomMiningBlock(BlockState state) { - return Config.getInstance().getBlockModsEnabled() && customMiningBlocks.contains(state.getType()); + return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customMiningBlocks.contains(state.getType()); } public CustomBlock getBlock(BlockState state) { @@ -167,7 +166,7 @@ public class ModManager { * @return true if the item is a custom tool, false otherwise */ public boolean isCustomTool(ItemStack item) { - return Config.getInstance().getToolModsEnabled() && item != null && customToolMap.containsKey(item.getType()); + return mcMMO.p.getGeneralConfig().getToolModsEnabled() && item != null && customToolMap.containsKey(item.getType()); } /** @@ -185,7 +184,7 @@ public class ModManager { } public boolean isCustomEntity(Entity entity) { - if (!Config.getInstance().getEntityModsEnabled()) { + if (!mcMMO.p.getGeneralConfig().getEntityModsEnabled()) { return false; } @@ -227,7 +226,7 @@ public class ModManager { } public void addCustomEntity(Entity entity) { - if (!Config.getInstance().getEntityModsEnabled()) { + if (!mcMMO.p.getGeneralConfig().getEntityModsEnabled()) { return; } diff --git a/src/main/java/com/gmail/nossr50/util/Motd.java b/src/main/java/com/gmail/nossr50/util/Motd.java index ac3fd4e70..ddad205c0 100644 --- a/src/main/java/com/gmail/nossr50/util/Motd.java +++ b/src/main/java/com/gmail/nossr50/util/Motd.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.util; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; @@ -70,11 +69,11 @@ public final class Motd { player.sendMessage(LocaleLoader.getString("MOTD.Hardcore.Enabled", statLossInfo + seperator + vampirismInfo)); if (deathStatLossEnabled) { - player.sendMessage(LocaleLoader.getString("MOTD.Hardcore.DeathStatLoss.Stats", Config.getInstance().getHardcoreDeathStatPenaltyPercentage())); + player.sendMessage(LocaleLoader.getString("MOTD.Hardcore.DeathStatLoss.Stats", mcMMO.p.getGeneralConfig().getHardcoreDeathStatPenaltyPercentage())); } if (vampirismEnabled) { - player.sendMessage(LocaleLoader.getString("MOTD.Hardcore.Vampirism.Stats", Config.getInstance().getHardcoreVampirismStatLeechPercentage())); + player.sendMessage(LocaleLoader.getString("MOTD.Hardcore.Vampirism.Stats", mcMMO.p.getGeneralConfig().getHardcoreVampirismStatLeechPercentage())); } } diff --git a/src/main/java/com/gmail/nossr50/util/Permissions.java b/src/main/java/com/gmail/nossr50/util/Permissions.java index 3d8026311..0e9f3d079 100644 --- a/src/main/java/com/gmail/nossr50/util/Permissions.java +++ b/src/main/java/com/gmail/nossr50/util/Permissions.java @@ -27,7 +27,6 @@ public final class Permissions { */ public static boolean motd(Permissible permissible) { return permissible.hasPermission("mcmmo.motd"); } public static boolean levelUpBroadcast(Permissible permissible) { return permissible.hasPermission("mcmmo.broadcast.levelup"); } - public static boolean mobHealthDisplay(Permissible permissible) { return permissible.hasPermission("mcmmo.mobhealthdisplay"); } public static boolean updateNotifications(Permissible permissible) {return permissible.hasPermission("mcmmo.tools.updatecheck"); } public static boolean chimaeraWing(Permissible permissible) { return permissible.hasPermission("mcmmo.item.chimaerawing"); } public static boolean showversion(Permissible permissible) { return permissible.hasPermission("mcmmo.showversion"); } @@ -35,8 +34,6 @@ public final class Permissions { /* BYPASS */ public static boolean hardcoreBypass(Permissible permissible) { return permissible.hasPermission("mcmmo.bypass.hardcoremode"); } public static boolean arcaneBypass(Permissible permissible) { return permissible.hasPermission("mcmmo.bypass.arcanebypass"); } - public static boolean krakenBypass(Permissible permissible) { return permissible.hasPermission("mcmmo.bypass.kraken"); } - public static boolean trapsBypass(Permissible permissible) { return permissible.hasPermission("mcmmo.bypass.fishingtraps"); } /* CHAT */ public static boolean partyChat(Permissible permissible) { return permissible.hasPermission("mcmmo.chat.partychat"); } @@ -61,9 +58,6 @@ public final class Permissions { public static boolean inspectFar(Permissible permissible) { return (permissible.hasPermission("mcmmo.commands.inspect.far")); } public static boolean inspectHidden(Permissible permissible) { return (permissible.hasPermission("mcmmo.commands.inspect.hidden")); } - public static boolean kraken(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.kraken"); } - public static boolean krakenOthers(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.kraken.others"); } - public static boolean mcability(Permissible permissible) { return (permissible.hasPermission("mcmmo.commands.mcability")); } public static boolean mcabilityOthers(Permissible permissible) { return (permissible.hasPermission("mcmmo.commands.mcability.others")); } @@ -99,9 +93,6 @@ public final class Permissions { public static boolean xprateSet(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.xprate.set"); } public static boolean xprateReset(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.xprate.reset"); } - public static boolean vampirismModify(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.vampirism.modify"); } - public static boolean vampirismToggle(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.vampirism.toggle"); } - public static boolean mcpurge(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.mcpurge"); } public static boolean mcremove(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.mcremove"); } public static boolean mmoupdate(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.mmoupdate"); } @@ -176,7 +167,6 @@ public final class Permissions { public static boolean vanillaXpBoost(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.ability." + skill.toString().toLowerCase(Locale.ENGLISH) + ".vanillaxpboost"); } public static boolean isSubSkillEnabled(Permissible permissible, SubSkillType subSkillType) { return permissible.hasPermission(subSkillType.getPermissionNodeAddress()); } public static boolean isSubSkillEnabled(Permissible permissible, AbstractSubSkill abstractSubSkill) { return permissible.hasPermission(abstractSubSkill.getPermissionNode()); } - public static boolean bonusDamage(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.ability." + skill.toString().toLowerCase(Locale.ENGLISH) + ".bonusdamage"); } /* ACROBATICS */ public static boolean dodge(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.acrobatics.dodge"); } @@ -213,7 +203,6 @@ public final class Permissions { public static boolean repairMaterialType(Permissible permissible, MaterialType repairMaterialType) { return permissible.hasPermission("mcmmo.ability.repair." + repairMaterialType.toString().toLowerCase(Locale.ENGLISH) + "repair"); } /* SALVAGE */ - public static boolean advancedSalvage(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.salvage.advancedsalvage"); } public static boolean arcaneSalvage(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.salvage.arcanesalvage"); } public static boolean salvageItemType(Permissible permissible, ItemType salvageItemType) { return permissible.hasPermission("mcmmo.ability.salvage." + salvageItemType.toString().toLowerCase(Locale.ENGLISH) + "salvage"); } diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/BitSetChunkStore.java b/src/main/java/com/gmail/nossr50/util/blockmeta/BitSetChunkStore.java index 4830c9045..d850cec06 100644 --- a/src/main/java/com/gmail/nossr50/util/blockmeta/BitSetChunkStore.java +++ b/src/main/java/com/gmail/nossr50/util/blockmeta/BitSetChunkStore.java @@ -1,6 +1,6 @@ package com.gmail.nossr50.util.blockmeta; -import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.mcMMO; import org.bukkit.Bukkit; import org.bukkit.World; import org.jetbrains.annotations.NotNull; @@ -25,7 +25,7 @@ public class BitSetChunkStore implements ChunkStore { private transient boolean dirty = false; public BitSetChunkStore(@NotNull World world, int cx, int cz) { - this(world.getUID(), Misc.getWorldMinCompat(world), world.getMaxHeight(), cx, cz); + this(world.getUID(), mcMMO.getCompatibilityManager().getWorldCompatibilityLayer().getMinWorldHeight(world), world.getMaxHeight(), cx, cz); } private BitSetChunkStore(@NotNull UUID worldUid, int worldMin, int worldMax, int cx, int cz) { @@ -109,15 +109,14 @@ public class BitSetChunkStore implements ChunkStore { return (z * 16 + x) + (256 * (y + yOffset)); } - private static int getWorldMin(@NotNull UUID worldUid, int storedWorldMin) - { + private static int getWorldMin(@NotNull UUID worldUid, int storedWorldMin) { World world = Bukkit.getWorld(worldUid); // Not sure how this case could come up, but might as well handle it gracefully. Loading a chunkstore for an unloaded world? if (world == null) return storedWorldMin; - return Misc.getWorldMinCompat(world); + return mcMMO.getCompatibilityManager().getWorldCompatibilityLayer().getMinWorldHeight(world); } private static int getWorldMax(@NotNull UUID worldUid, int storedWorldMax) diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/ChunkManagerFactory.java b/src/main/java/com/gmail/nossr50/util/blockmeta/ChunkManagerFactory.java index e2c47662e..a1e61fd5c 100644 --- a/src/main/java/com/gmail/nossr50/util/blockmeta/ChunkManagerFactory.java +++ b/src/main/java/com/gmail/nossr50/util/blockmeta/ChunkManagerFactory.java @@ -1,13 +1,12 @@ package com.gmail.nossr50.util.blockmeta; -import com.gmail.nossr50.config.HiddenConfig; +import com.gmail.nossr50.config.PersistentDataConfig; import org.jetbrains.annotations.NotNull; public class ChunkManagerFactory { public static @NotNull ChunkManager getChunkManager() { - HiddenConfig hConfig = HiddenConfig.getInstance(); - if (hConfig.getChunkletsEnabled()) { + if (PersistentDataConfig.getInstance().useBlockTracker()) { return new HashChunkManager(); } diff --git a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java b/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java index 4e1810d0a..2ab31c393 100644 --- a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java +++ b/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java @@ -16,7 +16,6 @@ import com.gmail.nossr50.commands.party.PartyCommand; import com.gmail.nossr50.commands.party.teleport.PtpCommand; import com.gmail.nossr50.commands.player.*; import com.gmail.nossr50.commands.skills.*; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; @@ -35,7 +34,7 @@ public final class CommandRegistrationManager { private static void registerSkillCommands() { for (PrimarySkillType skill : PrimarySkillType.values()) { String commandName = skill.toString().toLowerCase(Locale.ENGLISH); - String localizedName = skill.getName().toLowerCase(Locale.ENGLISH); + String localizedName = mcMMO.p.getSkillTools().getLocalizedSkillName(skill).toLowerCase(Locale.ENGLISH); PluginCommand command; @@ -290,7 +289,7 @@ public final class CommandRegistrationManager { private static void registerMcpurgeCommand() { PluginCommand command = mcMMO.p.getCommand("mcpurge"); - command.setDescription(LocaleLoader.getString("Commands.Description.mcpurge", Config.getInstance().getOldUsersCutoff())); + command.setDescription(LocaleLoader.getString("Commands.Description.mcpurge", mcMMO.p.getGeneralConfig().getOldUsersCutoff())); command.setPermission("mcmmo.commands.mcpurge"); command.setPermissionMessage(permissionsMessage); command.setUsage(LocaleLoader.getString("Commands.Usage.0", "mcpurge")); @@ -396,15 +395,6 @@ public final class CommandRegistrationManager { command.setUsage(LocaleLoader.getString("Commands.Usage.0", "mcnotify")); command.setExecutor(new McnotifyCommand()); } - - private static void registerMHDCommand() { - PluginCommand command = mcMMO.p.getCommand("mhd"); - command.setDescription("Resets all mob health bar settings for all players to the default"); //TODO: Localize - command.setPermission("mcmmo.commands.mhd"); - command.setPermissionMessage(permissionsMessage); - command.setUsage(LocaleLoader.getString("Commands.Usage.0", "mhd")); - command.setExecutor(new MHDCommand()); - } private static void registerMcscoreboardCommand() { PluginCommand command = mcMMO.p.getCommand("mcscoreboard"); @@ -452,7 +442,6 @@ public final class CommandRegistrationManager { registerMcnotifyCommand(); registerMcrefreshCommand(); registerMcscoreboardCommand(); - registerMHDCommand(); registerXprateCommand(); // Database Commands diff --git a/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java b/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java index 666928da1..01cafe833 100644 --- a/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java +++ b/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.util.commands; -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; @@ -8,6 +7,7 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.skills.SkillTools; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.StringUtils; import com.google.common.collect.ImmutableList; @@ -28,7 +28,7 @@ public final class CommandUtils { private CommandUtils() {} public static boolean isChildSkill(CommandSender sender, PrimarySkillType skill) { - if (skill == null || !skill.isChildSkill()) { + if (skill == null || !SkillTools.isChildSkill(skill)) { return false; } @@ -40,7 +40,7 @@ public final class CommandUtils { if(!target.isOnline() && !hasPermission) { sender.sendMessage(LocaleLoader.getString("Inspect.Offline")); return true; - } else if (sender instanceof Player && !Misc.isNear(((Player) sender).getLocation(), target.getLocation(), Config.getInstance().getInspectDistance()) && !hasPermission) { + } else if (sender instanceof Player && !Misc.isNear(((Player) sender).getLocation(), target.getLocation(), mcMMO.p.getGeneralConfig().getInspectDistance()) && !hasPermission) { sender.sendMessage(LocaleLoader.getString("Inspect.TooFar")); return true; } @@ -176,7 +176,7 @@ public final class CommandUtils { * @param display The sender to display stats to */ public static void printGatheringSkills(Player inspect, CommandSender display) { - printGroupedSkillData(inspect, display, LocaleLoader.getString("Stats.Header.Gathering"), PrimarySkillType.GATHERING_SKILLS); + printGroupedSkillData(inspect, display, LocaleLoader.getString("Stats.Header.Gathering"), mcMMO.p.getSkillTools().GATHERING_SKILLS); } public static void printGatheringSkills(Player player) { @@ -190,7 +190,7 @@ public final class CommandUtils { * @param display The sender to display stats to */ public static void printCombatSkills(Player inspect, CommandSender display) { - printGroupedSkillData(inspect, display, LocaleLoader.getString("Stats.Header.Combat"), PrimarySkillType.COMBAT_SKILLS); + printGroupedSkillData(inspect, display, LocaleLoader.getString("Stats.Header.Combat"), mcMMO.p.getSkillTools().COMBAT_SKILLS); } public static void printCombatSkills(Player player) { @@ -204,7 +204,7 @@ public final class CommandUtils { * @param display The sender to display stats to */ public static void printMiscSkills(Player inspect, CommandSender display) { - printGroupedSkillData(inspect, display, LocaleLoader.getString("Stats.Header.Misc"), PrimarySkillType.MISC_SKILLS); + printGroupedSkillData(inspect, display, LocaleLoader.getString("Stats.Header.Misc"), mcMMO.p.getSkillTools().getMiscSkills()); } public static void printMiscSkills(Player player) { @@ -212,27 +212,27 @@ public final class CommandUtils { } public static String displaySkill(@NotNull PlayerProfile profile, @NotNull PrimarySkillType skill) { - if (skill.isChildSkill()) { + if (SkillTools.isChildSkill(skill)) { return LocaleLoader.getString("Skills.ChildStats", LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".Listener") + " ", profile.getSkillLevel(skill)); } - if (profile.getExperienceHandler().getSkillLevel(skill) == Config.getInstance().getLevelCap(skill)){ + if (profile.getExperienceHandler().getSkillLevel(skill) == mcMMO.p.getSkillTools().getLevelCap(skill)){ return LocaleLoader.getString("Skills.Stats", LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".Listener") + " ", profile.getSkillLevel(skill), profile.getSkillXpLevel(skill), LocaleLoader.getString("Skills.MaxXP")); } return LocaleLoader.getString("Skills.Stats", LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".Listener") + " ", profile.getSkillLevel(skill), profile.getSkillXpLevel(skill), profile.getXpToLevel(skill)); } - private static void printGroupedSkillData(Player inspect, CommandSender display, String header, List skillGroup) { - if(UserManager.getPlayer(inspect) == null) + private static void printGroupedSkillData(Player inspectTarget, CommandSender display, String header, List skillGroup) { + if(UserManager.getPlayer(inspectTarget) == null) return; - PlayerProfile profile = UserManager.getPlayer(inspect).getProfile(); + PlayerProfile profile = UserManager.getPlayer(inspectTarget).getProfile(); List displayData = new ArrayList<>(); displayData.add(header); - for (PrimarySkillType skill : skillGroup) { - if (skill.getPermissions(inspect)) { - displayData.add(displaySkill(profile, skill)); + for (PrimarySkillType primarySkillType : skillGroup) { + if (mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(inspectTarget, primarySkillType)) { + displayData.add(displaySkill(profile, primarySkillType)); } } @@ -257,7 +257,7 @@ public final class CommandUtils { } public static String getMatchedPlayerName(String partialName) { - if (Config.getInstance().getMatchOfflinePlayers()) { + if (mcMMO.p.getGeneralConfig().getMatchOfflinePlayers()) { List matches = matchPlayer(partialName); if (matches.size() == 1) { diff --git a/src/main/java/com/gmail/nossr50/util/compat/CompatibilityLayer.java b/src/main/java/com/gmail/nossr50/util/compat/CompatibilityLayer.java index d09c52f99..51b240338 100644 --- a/src/main/java/com/gmail/nossr50/util/compat/CompatibilityLayer.java +++ b/src/main/java/com/gmail/nossr50/util/compat/CompatibilityLayer.java @@ -8,5 +8,5 @@ public interface CompatibilityLayer { * Whether or not this CompatibilityLayer successfully initialized and in theory should be functional * @return true if this CompatibilityLayer is functional */ - boolean noErrorsOnInitialize(); + default boolean noErrorsOnInitialize() { return true; }; } diff --git a/src/main/java/com/gmail/nossr50/util/compat/CompatibilityManager.java b/src/main/java/com/gmail/nossr50/util/compat/CompatibilityManager.java index 7a0a0e72a..1b78a55df 100644 --- a/src/main/java/com/gmail/nossr50/util/compat/CompatibilityManager.java +++ b/src/main/java/com/gmail/nossr50/util/compat/CompatibilityManager.java @@ -10,9 +10,12 @@ import com.gmail.nossr50.util.compat.layers.persistentdata.SpigotPersistentDataL import com.gmail.nossr50.util.compat.layers.persistentdata.SpigotPersistentDataLayer_1_14; import com.gmail.nossr50.util.compat.layers.skills.AbstractMasterAnglerCompatibility; import com.gmail.nossr50.util.compat.layers.skills.MasterAnglerCompatibilityLayer; +import com.gmail.nossr50.util.compat.layers.world.WorldCompatibilityLayer; +import com.gmail.nossr50.util.compat.layers.world.WorldCompatibilityLayer_1_16_4; import com.gmail.nossr50.util.nms.NMSVersion; import com.gmail.nossr50.util.platform.MinecraftGameVersion; import com.gmail.nossr50.util.text.StringUtils; +import org.bukkit.World; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -37,6 +40,7 @@ public class CompatibilityManager { private AbstractPersistentDataLayer persistentDataLayer; private AbstractBungeeSerializerCompatibilityLayer bungeeSerializerCompatibilityLayer; private AbstractMasterAnglerCompatibility masterAnglerCompatibility; + private WorldCompatibilityLayer worldCompatibilityLayer; public CompatibilityManager(MinecraftGameVersion minecraftGameVersion) { mcMMO.p.getLogger().info("Loading compatibility layers..."); @@ -67,10 +71,44 @@ public class CompatibilityManager { initPersistentDataLayer(); initBungeeSerializerLayer(); initMasterAnglerLayer(); + initWorldCompatibilityLayer(); isFullyCompatibleServerSoftware = true; } + private void initWorldCompatibilityLayer() { + if((minecraftGameVersion.getMinorVersion().asInt() >= 16 && minecraftGameVersion.getPatchVersion().asInt() >= 4) + || minecraftGameVersion.getMajorVersion().asInt() >= 2) { + if(hasNewWorldMinHeightAPI()) { + worldCompatibilityLayer = new WorldCompatibilityLayer_1_16_4(); + } else { + worldCompatibilityLayer = new WorldCompatibilityLayer() { + @Override + public int getMinWorldHeight(@NotNull World world) { + return WorldCompatibilityLayer.super.getMinWorldHeight(world); + } + + @Override + public int getMaxWorldHeight(@NotNull World world) { + return WorldCompatibilityLayer.super.getMaxWorldHeight(world); + } + }; + } + } else { + worldCompatibilityLayer = new WorldCompatibilityLayer() { + @Override + public int getMinWorldHeight(@NotNull World world) { + return WorldCompatibilityLayer.super.getMinWorldHeight(world); + } + + @Override + public int getMaxWorldHeight(@NotNull World world) { + return WorldCompatibilityLayer.super.getMaxWorldHeight(world); + } + }; + } + } + private void initMasterAnglerLayer() { if(minecraftGameVersion.getMinorVersion().asInt() >= 16 || minecraftGameVersion.getMajorVersion().asInt() >= 2) { if(hasNewFishingHookAPI()) { @@ -81,6 +119,16 @@ public class CompatibilityManager { } } + private boolean hasNewWorldMinHeightAPI() { + try { + Class checkForClass = Class.forName("org.bukkit.World"); + checkForClass.getMethod("getMinHeight"); + return true; + } catch (ClassNotFoundException | NoSuchMethodException e) { + return false; + } + } + private boolean hasNewFishingHookAPI() { try { Class checkForClass = Class.forName("org.bukkit.entity.FishHook"); @@ -182,4 +230,8 @@ public class CompatibilityManager { public @Nullable AbstractMasterAnglerCompatibility getMasterAnglerCompatibilityLayer() { return masterAnglerCompatibility; } + + public @NotNull WorldCompatibilityLayer getWorldCompatibilityLayer() { + return worldCompatibilityLayer; + } } diff --git a/src/main/java/com/gmail/nossr50/util/compat/layers/world/WorldCompatibilityLayer.java b/src/main/java/com/gmail/nossr50/util/compat/layers/world/WorldCompatibilityLayer.java new file mode 100644 index 000000000..115aeb7fb --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/compat/layers/world/WorldCompatibilityLayer.java @@ -0,0 +1,11 @@ +package com.gmail.nossr50.util.compat.layers.world; + +import com.gmail.nossr50.util.compat.CompatibilityLayer; +import org.bukkit.World; +import org.jetbrains.annotations.NotNull; + +public interface WorldCompatibilityLayer extends CompatibilityLayer { + default int getMinWorldHeight(@NotNull World world) { return 0; } + + default int getMaxWorldHeight(@NotNull World world) { return 256; } +} diff --git a/src/main/java/com/gmail/nossr50/util/compat/layers/world/WorldCompatibilityLayer_1_16_4.java b/src/main/java/com/gmail/nossr50/util/compat/layers/world/WorldCompatibilityLayer_1_16_4.java new file mode 100644 index 000000000..4e67aaf5c --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/compat/layers/world/WorldCompatibilityLayer_1_16_4.java @@ -0,0 +1,16 @@ +package com.gmail.nossr50.util.compat.layers.world; + +import org.bukkit.World; +import org.jetbrains.annotations.NotNull; + +public class WorldCompatibilityLayer_1_16_4 implements WorldCompatibilityLayer { + @Override + public int getMinWorldHeight(@NotNull World world) { + return world.getMinHeight(); + } + + @Override + public int getMaxWorldHeight(@NotNull World world) { + return world.getMaxHeight(); + } +} diff --git a/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java b/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java index 382c00d0b..21816c1ce 100644 --- a/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java +++ b/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.util.experience; -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.skills.PrimarySkillType; @@ -81,7 +80,7 @@ public class FormulaManager { public int[] calculateNewLevel(PrimarySkillType primarySkillType, int experience, FormulaType formulaType) { int newLevel = 0; int remainder = 0; - int maxLevel = Config.getInstance().getLevelCap(primarySkillType); + int maxLevel = mcMMO.p.getSkillTools().getLevelCap(primarySkillType); while (experience > 0 && newLevel < maxLevel) { int experienceToNextLevel = getXPtoNextLevel(newLevel, formulaType); diff --git a/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java b/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java index c582c6c3d..b2cfef92a 100644 --- a/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java +++ b/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java @@ -1,7 +1,5 @@ package com.gmail.nossr50.util.player; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.LevelUpBroadcastPredicate; import com.gmail.nossr50.datatypes.PowerLevelUpBroadcastPredicate; import com.gmail.nossr50.datatypes.interactions.NotificationType; @@ -52,7 +50,7 @@ public class NotificationManager { if(mmoPlayer == null || !mmoPlayer.hasSkillChatNotifications()) return; - McMMOMessageType destination = AdvancedConfig.getInstance().doesNotificationUseActionBar(notificationType) ? McMMOMessageType.ACTION_BAR : McMMOMessageType.SYSTEM; + McMMOMessageType destination = mcMMO.p.getAdvancedConfig().doesNotificationUseActionBar(notificationType) ? McMMOMessageType.ACTION_BAR : McMMOMessageType.SYSTEM; Component message = TextComponentFactory.getNotificationTextComponentFromLocale(key); McMMOPlayerNotificationEvent customEvent = checkNotificationEvent(player, notificationType, destination, message); @@ -116,7 +114,7 @@ public class NotificationManager { if(mmoPlayer != null && !mmoPlayer.hasSkillChatNotifications()) return; - McMMOMessageType destination = AdvancedConfig.getInstance().doesNotificationUseActionBar(notificationType) ? McMMOMessageType.ACTION_BAR : McMMOMessageType.SYSTEM; + McMMOMessageType destination = mcMMO.p.getAdvancedConfig().doesNotificationUseActionBar(notificationType) ? McMMOMessageType.ACTION_BAR : McMMOMessageType.SYSTEM; Component message = TextComponentFactory.getNotificationMultipleValues(key, values); McMMOPlayerNotificationEvent customEvent = checkNotificationEvent(player, notificationType, destination, message); @@ -148,7 +146,7 @@ public class NotificationManager { private static @NotNull McMMOPlayerNotificationEvent checkNotificationEvent(@NotNull Player player, @NotNull NotificationType notificationType, @NotNull McMMOMessageType destination, @NotNull Component message) { //Init event McMMOPlayerNotificationEvent customEvent = new McMMOPlayerNotificationEvent(player, - notificationType, message, destination, AdvancedConfig.getInstance().doesNotificationSendCopyToChat(notificationType)); + notificationType, message, destination, mcMMO.p.getAdvancedConfig().doesNotificationSendCopyToChat(notificationType)); //Call event Bukkit.getServer().getPluginManager().callEvent(customEvent); @@ -166,7 +164,7 @@ public class NotificationManager { if(!mmoPlayer.hasSkillChatNotifications()) return; - McMMOMessageType destination = AdvancedConfig.getInstance().doesNotificationUseActionBar(NotificationType.LEVEL_UP_MESSAGE) ? McMMOMessageType.ACTION_BAR : McMMOMessageType.SYSTEM; + McMMOMessageType destination = mcMMO.p.getAdvancedConfig().doesNotificationUseActionBar(NotificationType.LEVEL_UP_MESSAGE) ? McMMOMessageType.ACTION_BAR : McMMOMessageType.SYSTEM; Component levelUpTextComponent = TextComponentFactory.getNotificationLevelUpTextComponent(PrimarySkillType.getSkill(primarySkillType), levelsGained, newLevel); McMMOPlayerNotificationEvent customEvent = checkNotificationEvent(Misc.adaptPlayer(mmoPlayer), NotificationType.LEVEL_UP_MESSAGE, destination, levelUpTextComponent); @@ -194,7 +192,7 @@ public class NotificationManager { SoundManager.sendCategorizedSound(Misc.adaptPlayer(mmoPlayer), Misc.adaptPlayer(mmoPlayer).getLocation(), SoundType.SKILL_UNLOCKED, SoundCategory.MASTER); //ACTION BAR MESSAGE - /*if(AdvancedConfig.getInstance().doesNotificationUseActionBar(NotificationType.SUBSKILL_UNLOCKED)) + /*if(mcMMO.p.getAdvancedConfig().doesNotificationUseActionBar(NotificationType.SUBSKILL_UNLOCKED)) Misc.adaptPlayer(mmoPlayer).spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(LocaleLoader.getString("JSON.SkillUnlockMessage", subSkillType.getLocaleName(), String.valueOf(RankUtils.getRank(Misc.adaptPlayer(mmoPlayer), @@ -208,7 +206,7 @@ public class NotificationManager { */ private static void sendAdminNotification(@NotNull String msg) { //If its not enabled exit - if(!Config.getInstance().adminNotifications()) + if(!mcMMO.p.getGeneralConfig().adminNotifications()) return; for(Player player : Bukkit.getServer().getOnlinePlayers()) @@ -285,13 +283,13 @@ public class NotificationManager { return; //Check if broadcasting is enabled - if(Config.getInstance().shouldLevelUpBroadcasts()) { + if(mcMMO.p.getGeneralConfig().shouldLevelUpBroadcasts()) { //Permission check if(!Permissions.levelUpBroadcast(mmoPlayer.getPlayer())) { return; } - int levelInterval = Config.getInstance().getLevelUpBroadcastInterval(); + int levelInterval = mcMMO.p.getGeneralConfig().getLevelUpBroadcastInterval(); int remainder = level % levelInterval; if(remainder == 0) { @@ -302,10 +300,10 @@ public class NotificationManager { .append(Component.newline()) .append(Component.text(LocalDate.now().toString())) .append(Component.newline()) - .append(Component.text(primarySkillType.getName()+" reached level "+level)).color(TextColor.fromHexString(HEX_BEIGE_COLOR)) + .append(Component.text(mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType)+" reached level "+level)).color(TextColor.fromHexString(HEX_BEIGE_COLOR)) .asHoverEvent(); - String localeMessage = LocaleLoader.getString("Broadcasts.LevelUpMilestone", mmoPlayer.getPlayer().getDisplayName(), level, primarySkillType.getName()); + String localeMessage = LocaleLoader.getString("Broadcasts.LevelUpMilestone", mmoPlayer.getPlayer().getDisplayName(), level, mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType)); Component message = Component.text(localeMessage).hoverEvent(levelMilestoneHover); Bukkit.getScheduler().runTaskLater(mcMMO.p, () -> audience.sendMessage(Identity.nil(), message), 0); @@ -320,13 +318,13 @@ public class NotificationManager { return; //Check if broadcasting is enabled - if(Config.getInstance().shouldPowerLevelUpBroadcasts()) { + if(mcMMO.p.getGeneralConfig().shouldPowerLevelUpBroadcasts()) { //Permission check if(!Permissions.levelUpBroadcast(mmoPlayer.getPlayer())) { return; } - int levelInterval = Config.getInstance().getPowerLevelUpBroadcastInterval(); + int levelInterval = mcMMO.p.getGeneralConfig().getPowerLevelUpBroadcastInterval(); int remainder = powerLevel % levelInterval; if(remainder == 0) { diff --git a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java b/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java index a59cd2861..67982ce59 100644 --- a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java +++ b/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java @@ -1,10 +1,10 @@ package com.gmail.nossr50.util.random; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.events.skills.secondaryabilities.SubSkillEvent; import com.gmail.nossr50.events.skills.secondaryabilities.SubSkillRandomCheckEvent; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.EventUtils; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.skills.SkillActivationType; @@ -252,11 +252,11 @@ public class RandomChanceUtil { public static double getStaticRandomChance(@NotNull SubSkillType subSkillType) throws InvalidStaticChance { switch (subSkillType) { case AXES_ARMOR_IMPACT: - return AdvancedConfig.getInstance().getImpactChance(); + return mcMMO.p.getAdvancedConfig().getImpactChance(); case AXES_GREATER_IMPACT: - return AdvancedConfig.getInstance().getGreaterImpactChance(); + return mcMMO.p.getAdvancedConfig().getGreaterImpactChance(); case TAMING_FAST_FOOD_SERVICE: - return AdvancedConfig.getInstance().getFastFoodChance(); + return mcMMO.p.getAdvancedConfig().getFastFoodChance(); default: throw new InvalidStaticChance(); } @@ -328,10 +328,10 @@ public class RandomChanceUtil { } public static double getMaximumProbability(@NotNull SubSkillType subSkillType) { - return AdvancedConfig.getInstance().getMaximumProbability(subSkillType); + return mcMMO.p.getAdvancedConfig().getMaximumProbability(subSkillType); } public static double getMaxBonusLevelCap(@NotNull SubSkillType subSkillType) { - return AdvancedConfig.getInstance().getMaxBonusLevel(subSkillType); + return mcMMO.p.getAdvancedConfig().getMaxBonusLevel(subSkillType); } } 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 b4c24ff40..bbc308ed8 100644 --- a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java +++ b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.util.scoreboards; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.database.PlayerStat; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; @@ -71,7 +70,7 @@ public class ScoreboardManager { * Stylizes the targetBoard in a Rainbow Pattern * This is off by default */ - if (Config.getInstance().getScoreboardRainbows()) { + if (mcMMO.p.getGeneralConfig().getScoreboardRainbows()) { // Everything but black, gray, gold List colors = Lists.newArrayList( ChatColor.WHITE, @@ -91,14 +90,14 @@ public class ScoreboardManager { Collections.shuffle(colors, Misc.getRandom()); int i = 0; - for (PrimarySkillType type : PrimarySkillType.values()) { + for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { // Include child skills - skillLabelBuilder.put(type, getShortenedName(colors.get(i) + type.getName(), false)); + skillLabelBuilder.put(primarySkillType, getShortenedName(colors.get(i) + mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType), false)); - if (type.getSuperAbilityType() != null) { - abilityLabelBuilder.put(type.getSuperAbilityType(), getShortenedName(colors.get(i) + type.getSuperAbilityType().getLocalizedName())); + if (mcMMO.p.getSkillTools().getSuperAbility(primarySkillType) != null) { + abilityLabelBuilder.put(mcMMO.p.getSkillTools().getSuperAbility(primarySkillType), getShortenedName(colors.get(i) + mcMMO.p.getSkillTools().getSuperAbility(primarySkillType).getLocalizedName())); - if (type == PrimarySkillType.MINING) { + if (primarySkillType == PrimarySkillType.MINING) { abilityLabelBuilder.put(SuperAbilityType.BLAST_MINING, getShortenedName(colors.get(i) + SuperAbilityType.BLAST_MINING.getLocalizedName())); } } @@ -113,14 +112,14 @@ public class ScoreboardManager { * Stylizes the targetBoard using our normal color scheme */ else { - for (PrimarySkillType type : PrimarySkillType.values()) { + for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { // Include child skills - skillLabelBuilder.put(type, getShortenedName(ChatColor.GREEN + type.getName())); + skillLabelBuilder.put(primarySkillType, getShortenedName(ChatColor.GREEN + mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType))); - if (type.getSuperAbilityType() != null) { - abilityLabelBuilder.put(type.getSuperAbilityType(), formatAbility(type.getSuperAbilityType().getLocalizedName())); + if (mcMMO.p.getSkillTools().getSuperAbility(primarySkillType) != null) { + abilityLabelBuilder.put(mcMMO.p.getSkillTools().getSuperAbility(primarySkillType), formatAbility(mcMMO.p.getSkillTools().getSuperAbility(primarySkillType).getLocalizedName())); - if (type == PrimarySkillType.MINING) { + if (primarySkillType == PrimarySkillType.MINING) { abilityLabelBuilder.put(SuperAbilityType.BLAST_MINING, formatAbility(SuperAbilityType.BLAST_MINING.getLocalizedName())); } } @@ -152,7 +151,7 @@ public class ScoreboardManager { } private static String formatAbility(ChatColor color, String abilityName) { - if (Config.getInstance().getShowAbilityNames()) { + if (mcMMO.p.getGeneralConfig().getShowAbilityNames()) { return getShortenedName(color + abilityName); } else { @@ -243,11 +242,11 @@ public class ScoreboardManager { } } - if (Config.getInstance().getPowerLevelTagsEnabled() && !dirtyPowerLevels.contains(playerName)) { + if (mcMMO.p.getGeneralConfig().getPowerLevelTagsEnabled() && !dirtyPowerLevels.contains(playerName)) { dirtyPowerLevels.add(playerName); } - if (Config.getInstance().getSkillLevelUpBoard()) { + if (mcMMO.p.getGeneralConfig().getSkillLevelUpBoard()) { enablePlayerSkillLevelUpScoreboard(player, skill); } @@ -298,7 +297,7 @@ public class ScoreboardManager { wrapper.setOldScoreboard(); wrapper.setTypeSkill(skill); - changeScoreboard(wrapper, Config.getInstance().getSkillScoreboardTime()); + changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getSkillScoreboardTime()); } } @@ -317,7 +316,7 @@ public class ScoreboardManager { wrapper.setOldScoreboard(); wrapper.setTypeSkill(primarySkillType); - changeScoreboard(wrapper, Config.getInstance().getSkillScoreboardTime()); + changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getSkillScoreboardTime()); } } @@ -332,7 +331,7 @@ public class ScoreboardManager { wrapper.setOldScoreboard(); wrapper.setTypeSkill(skill); - changeScoreboard(wrapper, Config.getInstance().getSkillLevelUpTime()); + changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getSkillLevelUpTime()); } } @@ -346,7 +345,7 @@ public class ScoreboardManager { wrapper.setOldScoreboard(); wrapper.setTypeSelfStats(); - changeScoreboard(wrapper, Config.getInstance().getStatsScoreboardTime()); + changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getStatsScoreboardTime()); } public static void enablePlayerInspectScoreboard(@NotNull Player player, @NotNull PlayerProfile targetProfile) { @@ -361,7 +360,7 @@ public class ScoreboardManager { wrapper.setOldScoreboard(); wrapper.setTypeInspectStats(targetProfile); - changeScoreboard(wrapper, Config.getInstance().getInspectScoreboardTime()); + changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getInspectScoreboardTime()); } } @@ -377,7 +376,7 @@ public class ScoreboardManager { wrapper.setOldScoreboard(); wrapper.setTypeInspectStats(targetMcMMOPlayer); - changeScoreboard(wrapper, Config.getInstance().getInspectScoreboardTime()); + changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getInspectScoreboardTime()); } } @@ -393,7 +392,7 @@ public class ScoreboardManager { wrapper.setOldScoreboard(); wrapper.setTypeCooldowns(); - changeScoreboard(wrapper, Config.getInstance().getCooldownScoreboardTime()); + changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getCooldownScoreboardTime()); } } @@ -410,7 +409,7 @@ public class ScoreboardManager { wrapper.setTypeSelfRank(); wrapper.acceptRankData(rank); - changeScoreboard(wrapper, Config.getInstance().getRankScoreboardTime()); + changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getRankScoreboardTime()); } } @@ -427,7 +426,7 @@ public class ScoreboardManager { wrapper.setTypeInspectRank(targetName); wrapper.acceptRankData(rank); - changeScoreboard(wrapper, Config.getInstance().getRankScoreboardTime()); + changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getRankScoreboardTime()); } } @@ -445,7 +444,7 @@ public class ScoreboardManager { wrapper.setTypeTop(skill, pageNumber); wrapper.acceptLeaderboardData(stats); - changeScoreboard(wrapper, Config.getInstance().getTopScoreboardTime()); + changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getTopScoreboardTime()); } } @@ -462,7 +461,7 @@ public class ScoreboardManager { wrapper.setTypeTopPower(pageNumber); wrapper.acceptLeaderboardData(stats); - changeScoreboard(wrapper, Config.getInstance().getTopScoreboardTime()); + changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getTopScoreboardTime()); } } @@ -516,7 +515,7 @@ public class ScoreboardManager { * @return the main targetBoard objective, or null if disabled */ public static @Nullable Objective getPowerLevelObjective() { - if (!Config.getInstance().getPowerLevelTagsEnabled()) { + if (!mcMMO.p.getGeneralConfig().getPowerLevelTagsEnabled()) { if(getScoreboardManager() == null) return null; 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 0b85db49f..eef08679e 100644 --- a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java +++ b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.util.scoreboards; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.database.PlayerStat; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; @@ -17,6 +16,7 @@ import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager.SidebarType; +import com.gmail.nossr50.util.skills.SkillTools; import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -75,7 +75,7 @@ public class ScoreboardWrapper { registered = true; } - if (Config.getInstance().getPowerLevelTagsEnabled()) { + if (mcMMO.p.getGeneralConfig().getPowerLevelTagsEnabled()) { powerObjective.setDisplayName(ScoreboardManager.TAG_POWER_LEVEL); powerObjective.setDisplaySlot(DisplaySlot.BELOW_NAME); @@ -225,7 +225,7 @@ public class ScoreboardWrapper { PlayerProfile profile = UserManager.getPlayer(player).getProfile(); - if (profile.getScoreboardTipsShown() >= Config.getInstance().getTipsAmount()) { + if (profile.getScoreboardTipsShown() >= mcMMO.p.getGeneralConfig().getTipsAmount()) { return; } @@ -489,7 +489,7 @@ public class ScoreboardWrapper { case SKILL_BOARD: Validate.notNull(targetSkill); - if (!targetSkill.isChildSkill()) { + if (!SkillTools.isChildSkill(targetSkill)) { int currentXP = mcMMOPlayer.getSkillXpLevel(targetSkill); sidebarObjective.getScore(ScoreboardManager.LABEL_CURRENT_XP).setScore(currentXP); @@ -503,7 +503,7 @@ public class ScoreboardWrapper { sidebarObjective.getScore(ScoreboardManager.LABEL_LEVEL).setScore(mcMMOPlayer.getSkillLevel(targetSkill)); - if (targetSkill.getAbility() != null) { + if (mcMMO.p.getSkillTools().getSuperAbility(targetSkill) != null) { boolean stopUpdating; if (targetSkill == PrimarySkillType.MINING) { @@ -519,7 +519,7 @@ public class ScoreboardWrapper { stopUpdating = (secondsSB == 0 && secondsBM == 0); } else { - SuperAbilityType ability = targetSkill.getAbility(); + SuperAbilityType ability = mcMMO.p.getSkillTools().getSuperAbility(targetSkill); Score cooldown = sidebarObjective.getScore(ScoreboardManager.abilityLabelsSkill.get(ability)); int seconds = Math.max(mcMMOPlayer.calculateTimeRemaining(ability), 0); @@ -574,13 +574,13 @@ public class ScoreboardWrapper { // Calculate power level here int powerLevel = 0; - for (PrimarySkillType skill : PrimarySkillType.NON_CHILD_SKILLS) { // Don't include child skills, makes the list too long + for (PrimarySkillType skill : SkillTools.NON_CHILD_SKILLS) { // Don't include child skills, makes the list too long int level = newProfile.getSkillLevel(skill); powerLevel += level; // TODO: Verify that this is what we want - calculated in power level but not displayed - if (!skill.getPermissions(player)) { + if (!mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, skill)) { continue; } @@ -607,8 +607,8 @@ public class ScoreboardWrapper { Integer rank; Player player = mcMMO.p.getServer().getPlayerExact(playerName); - for (PrimarySkillType skill : PrimarySkillType.NON_CHILD_SKILLS) { - if (!skill.getPermissions(player)) { + for (PrimarySkillType skill : SkillTools.NON_CHILD_SKILLS) { + if (!mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, skill)) { continue; } diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index 6e8b88fe4..d9fd1d7c1 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.util.skills; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.meta.OldName; @@ -405,7 +404,7 @@ public final class CombatUtils { } if (ItemUtils.isSword(player.getInventory().getItemInMainHand())) { - if (!PrimarySkillType.SWORDS.shouldProcess(target)) { + if (!mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.SWORDS, target)) { return; } @@ -443,29 +442,29 @@ public final class CombatUtils { } if (ItemUtils.isSword(heldItem)) { - if (!PrimarySkillType.SWORDS.shouldProcess(target)) { + if (!mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.SWORDS, target)) { return; } - if (PrimarySkillType.SWORDS.getPermissions(player)) { + if (mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.SWORDS)) { processSwordCombat(target, player, event); } } else if (ItemUtils.isAxe(heldItem)) { - if (!PrimarySkillType.AXES.shouldProcess(target)) { + if (!mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.AXES, target)) { return; } - if (PrimarySkillType.AXES.getPermissions(player)) { + if (mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.AXES)) { processAxeCombat(target, player, event); } } else if (ItemUtils.isUnarmed(heldItem)) { - if (!PrimarySkillType.UNARMED.shouldProcess(target)) { + if (!mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.UNARMED, target)) { return; } - if (PrimarySkillType.UNARMED.getPermissions(player)) { + if (mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.UNARMED)) { processUnarmedCombat(target, player, event); } } @@ -484,10 +483,10 @@ public final class CombatUtils { Wolf wolf = (Wolf) painSource; AnimalTamer tamer = wolf.getOwner(); - if (tamer instanceof Player && PrimarySkillType.TAMING.shouldProcess(target)) { + if (tamer instanceof Player && mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.TAMING, target)) { Player master = (Player) tamer; - if (!Misc.isNPCEntityExcludingVillagers(master) && PrimarySkillType.TAMING.getPermissions(master)) { + if (!Misc.isNPCEntityExcludingVillagers(master) && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(master, PrimarySkillType.TAMING)) { processTamingCombat(target, master, wolf, event); } } @@ -504,7 +503,7 @@ public final class CombatUtils { if(arrow.getMetadata(mcMMO.PROJECTILE_ORIGIN_METAKEY).size() > 0) { if (isProjectileFromBow(arrow)) { if (PrimarySkillType.ARCHERY.shouldProcess(target)) { - if (!Misc.isNPCEntityExcludingVillagers(player) && PrimarySkillType.ARCHERY.getPermissions(player)) { + if (!Misc.isNPCEntityExcludingVillagers(player) && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.ARCHERY)) { processArcheryCombat(target, player, event, arrow); } } @@ -520,7 +519,7 @@ public final class CombatUtils { cleanupArrowMetadata(arrow); } - if (target.getType() != EntityType.CREEPER && !Misc.isNPCEntityExcludingVillagers(player) && PrimarySkillType.TAMING.getPermissions(player)) { + if (target.getType() != EntityType.CREEPER && !Misc.isNPCEntityExcludingVillagers(player) && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.TAMING)) { OnlineMMOPlayer mmoPlayer = UserManager.queryPlayer(player); if(mmoPlayer == null) { @@ -628,7 +627,7 @@ public final class CombatUtils { * @return true if the mmoPlayer has access to the limit break */ public static boolean canUseLimitBreak(@NotNull OnlineMMOPlayer mmoPlayer, LivingEntity target, @NotNull SubSkillType subSkillType) { - if(target instanceof Player || AdvancedConfig.getInstance().canApplyLimitBreakPVE()) { + if(target instanceof Player || mcMMO.p.getAdvancedConfig().canApplyLimitBreakPVE()) { return RankUtils.hasUnlockedSubskill(mmoPlayer, subSkillType) && Permissions.isSubSkillEnabled(Misc.adaptPlayer(mmoPlayer), subSkillType); } else { diff --git a/src/main/java/com/gmail/nossr50/util/skills/ParticleEffectUtils.java b/src/main/java/com/gmail/nossr50/util/skills/ParticleEffectUtils.java index f63b5dd83..a70f09471 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/ParticleEffectUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/ParticleEffectUtils.java @@ -1,6 +1,6 @@ package com.gmail.nossr50.util.skills; -import com.gmail.nossr50.config.Config; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundType; import org.apache.commons.lang.math.RandomUtils; @@ -24,7 +24,7 @@ public final class ParticleEffectUtils { } public static void playBleedEffect(LivingEntity livingEntity) { - if (!Config.getInstance().getBleedEffectEnabled()) { + if (!mcMMO.p.getGeneralConfig().getBleedEffectEnabled()) { return; } @@ -63,7 +63,7 @@ public final class ParticleEffectUtils { public static void playDodgeEffect(Player player) { - if (!Config.getInstance().getDodgeEffectEnabled()) { + if (!mcMMO.p.getGeneralConfig().getDodgeEffectEnabled()) { return; } @@ -71,7 +71,7 @@ public final class ParticleEffectUtils { } public static void playFluxEffect(Location location) { - if (!Config.getInstance().getFluxEffectEnabled()) { + if (!mcMMO.p.getGeneralConfig().getFluxEffectEnabled()) { return; } @@ -100,7 +100,7 @@ public final class ParticleEffectUtils { } public static void playGreaterImpactEffect(LivingEntity livingEntity) { - if (!Config.getInstance().getGreaterImpactEffectEnabled()) { + if (!mcMMO.p.getGeneralConfig().getGreaterImpactEffectEnabled()) { return; } @@ -110,7 +110,7 @@ public final class ParticleEffectUtils { } public static void playCallOfTheWildEffect(LivingEntity livingEntity) { - if (!Config.getInstance().getCallOfTheWildEffectEnabled()) { + if (!mcMMO.p.getGeneralConfig().getCallOfTheWildEffectEnabled()) { return; } @@ -118,7 +118,7 @@ public final class ParticleEffectUtils { } public static void playAbilityDisabledEffect(Player player) { - if (!Config.getInstance().getAbilityDeactivationEffectEnabled()) { + if (!mcMMO.p.getGeneralConfig().getAbilityDeactivationEffectEnabled()) { } /*if (hasHeadRoom(player)) { diff --git a/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java b/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java index b9d39ca1a..08268909c 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java @@ -6,6 +6,7 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.listeners.InteractionManager; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.skills.SkillUnlockNotificationTask; import com.gmail.nossr50.util.Permissions; import com.neetgames.mcmmo.player.OnlineMMOPlayer; @@ -27,7 +28,7 @@ public class RankUtils { */ public static void executeSkillUnlockNotifications(@NotNull Plugin plugin, @NotNull OnlineMMOPlayer mmoPlayer, @NotNull PrimarySkillType primarySkillType, int newLevel) { - for(SubSkillType subSkillType : mcMMO.p.getSkillRegister().getSkillAbilities()) + for(SubSkillType subSkillType : mcMMO.p.getSkillTools().getSubSkills(primarySkillType)) { int playerRankInSkill = getRank(mmoPlayer, subSkillType); diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java new file mode 100644 index 000000000..8d50873c5 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java @@ -0,0 +1,453 @@ +package com.gmail.nossr50.util.skills; + +import com.gmail.nossr50.api.exceptions.InvalidSkillException; +import com.gmail.nossr50.config.experience.ExperienceConfig; +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.datatypes.skills.SuperAbilityType; +import com.gmail.nossr50.datatypes.skills.ToolType; +import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.text.StringUtils; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Tameable; +import org.jetbrains.annotations.NotNull; + +import java.util.*; + +public class SkillTools { + private final mcMMO pluginRef; + + //TODO: Figure out which ones we don't need, this was copy pasted from a diff branch + public final @NotNull ImmutableList LOCALIZED_SKILL_NAMES; + public final @NotNull ImmutableList FORMATTED_SUBSKILL_NAMES; + public final @NotNull ImmutableSet EXACT_SUBSKILL_NAMES; + public final @NotNull ImmutableList CHILD_SKILLS; + public final static @NotNull ImmutableList NON_CHILD_SKILLS; + public final @NotNull ImmutableList COMBAT_SKILLS; + public final @NotNull ImmutableList GATHERING_SKILLS; + public final @NotNull ImmutableList MISC_SKILLS; + + private final @NotNull ImmutableMap subSkillParentRelationshipMap; + private final @NotNull ImmutableMap superAbilityParentRelationshipMap; + private final @NotNull ImmutableMap> primarySkillChildrenMap; + + // The map below is for the super abilities which require readying a tool, its everything except blast mining + private final ImmutableMap mainActivatedAbilityChildMap; + private final ImmutableMap primarySkillToolMap; + + static { + ArrayList tempNonChildSkills = new ArrayList<>(); + for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { + if (primarySkillType != PrimarySkillType.SALVAGE && primarySkillType != PrimarySkillType.SMELTING) + tempNonChildSkills.add(primarySkillType); + } + + NON_CHILD_SKILLS = ImmutableList.copyOf(tempNonChildSkills); + } + + public SkillTools(@NotNull mcMMO pluginRef) { + this.pluginRef = pluginRef; + + /* + * Setup subskill -> parent relationship map + */ + EnumMap tempSubParentMap = new EnumMap(SubSkillType.class); + + //Super hacky and disgusting + for(PrimarySkillType primarySkillType1 : PrimarySkillType.values()) { + for(SubSkillType subSkillType : SubSkillType.values()) { + String[] splitSubSkillName = subSkillType.toString().split("_"); + + if(primarySkillType1.toString().equalsIgnoreCase(splitSubSkillName[0])) { + //Parent Skill Found + tempSubParentMap.put(subSkillType, primarySkillType1); + } + } + } + + subSkillParentRelationshipMap = ImmutableMap.copyOf(tempSubParentMap); + + /* + * Setup primary -> (collection) subskill map + */ + + EnumMap> tempPrimaryChildMap = new EnumMap>(PrimarySkillType.class); + + //Init the empty Hash Sets + for(PrimarySkillType primarySkillType1 : PrimarySkillType.values()) { + tempPrimaryChildMap.put(primarySkillType1, new HashSet<>()); + } + + //Fill in the hash sets + for(SubSkillType subSkillType : SubSkillType.values()) { + PrimarySkillType parentSkill = subSkillParentRelationshipMap.get(subSkillType); + + //Add this subskill as a child + tempPrimaryChildMap.get(parentSkill).add(subSkillType); + } + + primarySkillChildrenMap = ImmutableMap.copyOf(tempPrimaryChildMap); + + /* + * Setup primary -> tooltype map + */ + EnumMap tempToolMap = new EnumMap(PrimarySkillType.class); + + tempToolMap.put(PrimarySkillType.AXES, ToolType.AXE); + tempToolMap.put(PrimarySkillType.WOODCUTTING, ToolType.AXE); + tempToolMap.put(PrimarySkillType.UNARMED, ToolType.FISTS); + tempToolMap.put(PrimarySkillType.SWORDS, ToolType.SWORD); + tempToolMap.put(PrimarySkillType.EXCAVATION, ToolType.SHOVEL); + tempToolMap.put(PrimarySkillType.HERBALISM, ToolType.HOE); + tempToolMap.put(PrimarySkillType.MINING, ToolType.PICKAXE); + + primarySkillToolMap = ImmutableMap.copyOf(tempToolMap); + + /* + * Setup ability -> primary map + * Setup primary -> ability map + */ + + EnumMap tempAbilityParentRelationshipMap = new EnumMap(SuperAbilityType.class); + EnumMap tempMainActivatedAbilityChildMap = new EnumMap(PrimarySkillType.class); + + for(SuperAbilityType superAbilityType : SuperAbilityType.values()) { + try { + PrimarySkillType parent = getSuperAbilityParent(superAbilityType); + tempAbilityParentRelationshipMap.put(superAbilityType, parent); + + if(superAbilityType != SuperAbilityType.BLAST_MINING) { + //This map is used only for abilities that have a tool readying phase, so blast mining is ignored + tempMainActivatedAbilityChildMap.put(parent, superAbilityType); + } + } catch (InvalidSkillException e) { + e.printStackTrace(); + } + } + + superAbilityParentRelationshipMap = ImmutableMap.copyOf(tempAbilityParentRelationshipMap); + mainActivatedAbilityChildMap = ImmutableMap.copyOf(tempMainActivatedAbilityChildMap); + + /* + * Build child skill and nonchild skill lists + */ + + List childSkills = new ArrayList<>(); +// List nonChildSkills = new ArrayList<>(); + + for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { + if (isChildSkill(primarySkillType)) + childSkills.add(primarySkillType); +// } { +// nonChildSkills.add(primarySkillType); +// } + } + + CHILD_SKILLS = ImmutableList.copyOf(childSkills); +// NON_CHILD_SKILLS = ImmutableList.copyOf(nonChildSkills); + + /* + * Build categorized skill lists + */ + + COMBAT_SKILLS = ImmutableList.of(PrimarySkillType.ARCHERY, PrimarySkillType.AXES, PrimarySkillType.SWORDS, PrimarySkillType.TAMING, PrimarySkillType.UNARMED); + GATHERING_SKILLS = ImmutableList.of(PrimarySkillType.EXCAVATION, PrimarySkillType.FISHING, PrimarySkillType.HERBALISM, PrimarySkillType.MINING, PrimarySkillType.WOODCUTTING); + MISC_SKILLS = ImmutableList.of(PrimarySkillType.ACROBATICS, PrimarySkillType.ALCHEMY, PrimarySkillType.REPAIR, PrimarySkillType.SALVAGE, PrimarySkillType.SMELTING); + + /* + * Build formatted/localized/etc string lists + */ + + LOCALIZED_SKILL_NAMES = ImmutableList.copyOf(buildLocalizedPrimarySkillNames()); + FORMATTED_SUBSKILL_NAMES = ImmutableList.copyOf(buildFormattedSubSkillNameList()); + EXACT_SUBSKILL_NAMES = ImmutableSet.copyOf(buildExactSubSkillNameList()); + } + + private @NotNull PrimarySkillType getSuperAbilityParent(SuperAbilityType superAbilityType) throws InvalidSkillException { + switch(superAbilityType) { + case BERSERK: + return PrimarySkillType.UNARMED; + case GREEN_TERRA: + return PrimarySkillType.HERBALISM; + case TREE_FELLER: + return PrimarySkillType.WOODCUTTING; + case SUPER_BREAKER: + case BLAST_MINING: + return PrimarySkillType.MINING; + case SKULL_SPLITTER: + return PrimarySkillType.AXES; + case SERRATED_STRIKES: + return PrimarySkillType.SWORDS; + case GIGA_DRILL_BREAKER: + return PrimarySkillType.EXCAVATION; + default: + throw new InvalidSkillException("No parent defined for super ability! "+superAbilityType.toString()); + } + } + + /** + * Makes a list of the "nice" version of sub skill names + * Used in tab completion mostly + * @return a list of formatted sub skill names + */ + private @NotNull ArrayList buildFormattedSubSkillNameList() { + ArrayList subSkillNameList = new ArrayList<>(); + + for(SubSkillType subSkillType : SubSkillType.values()) { + subSkillNameList.add(subSkillType.getNiceNameNoSpaces(subSkillType)); + } + + return subSkillNameList; + } + + private @NotNull HashSet buildExactSubSkillNameList() { + HashSet subSkillNameExactSet = new HashSet<>(); + + for(SubSkillType subSkillType : SubSkillType.values()) { + subSkillNameExactSet.add(subSkillType.toString()); + } + + return subSkillNameExactSet; + } + + /** + * Builds a list of localized {@link PrimarySkillType} names + * @return list of localized {@link PrimarySkillType} names + */ + @VisibleForTesting + private @NotNull ArrayList buildLocalizedPrimarySkillNames() { + ArrayList localizedSkillNameList = new ArrayList<>(); + + for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { + localizedSkillNameList.add(getLocalizedSkillName(primarySkillType)); + } + + Collections.sort(localizedSkillNameList); + + return localizedSkillNameList; + } + + /** + * Matches a string of a skill to a skill + * This is NOT case sensitive + * First it checks the locale file and tries to match by the localized name of the skill + * Then if nothing is found it checks against the hard coded "name" of the skill, which is just its name in English + * + * @param skillName target skill name + * @return the matching PrimarySkillType if one is found, otherwise null + */ + public PrimarySkillType matchSkill(String skillName) { + if (!pluginRef.getGeneralConfig().getLocale().equalsIgnoreCase("en_US")) { + for (PrimarySkillType type : PrimarySkillType.values()) { + if (skillName.equalsIgnoreCase(LocaleLoader.getString(StringUtils.getCapitalized(type.name()) + ".SkillName"))) { + return type; + } + } + } + + for (PrimarySkillType type : PrimarySkillType.values()) { + if (type.name().equalsIgnoreCase(skillName)) { + return type; + } + } + + if (!skillName.equalsIgnoreCase("all")) { + pluginRef.getLogger().warning("Invalid mcMMO skill (" + skillName + ")"); //TODO: Localize + } + + return null; + } + + /** + * Gets the PrimarySkillStype to which a SubSkillType belongs + * Return null if it does not belong to one.. which should be impossible in most circumstances + * @param subSkillType target subskill + * @return the PrimarySkillType of this SubSkill, null if it doesn't exist + */ + public PrimarySkillType getPrimarySkillBySubSkill(SubSkillType subSkillType) { + return subSkillParentRelationshipMap.get(subSkillType); + } + + /** + * Gets the PrimarySkillStype to which a SuperAbilityType belongs + * Return null if it does not belong to one.. which should be impossible in most circumstances + * @param superAbilityType target super ability + * @return the PrimarySkillType of this SuperAbilityType, null if it doesn't exist + */ + public PrimarySkillType getPrimarySkillBySuperAbility(SuperAbilityType superAbilityType) { + return superAbilityParentRelationshipMap.get(superAbilityType); + } + + public SuperAbilityType getSuperAbility(PrimarySkillType primarySkillType) { + if(mainActivatedAbilityChildMap.get(primarySkillType) == null) + return null; + + return mainActivatedAbilityChildMap.get(primarySkillType); + } + + public boolean isSuperAbilityUnlocked(PrimarySkillType primarySkillType, Player player) { + SuperAbilityType superAbilityType = mcMMO.p.getSkillTools().getSuperAbility(primarySkillType); + SubSkillType subSkillType = superAbilityType.getSubSkillTypeDefinition(); + return RankUtils.hasUnlockedSubskill(player, subSkillType); + } + + public boolean getPVPEnabled(PrimarySkillType primarySkillType) { + return pluginRef.getGeneralConfig().getPVPEnabled(primarySkillType); + } + + public boolean getPVEEnabled(PrimarySkillType primarySkillType) { + return pluginRef.getGeneralConfig().getPVEEnabled(primarySkillType); + } + + public boolean getHardcoreStatLossEnabled(PrimarySkillType primarySkillType) { + return pluginRef.getGeneralConfig().getHardcoreStatLossEnabled(primarySkillType); + } + + public boolean getHardcoreVampirismEnabled(PrimarySkillType primarySkillType) { + return pluginRef.getGeneralConfig().getHardcoreVampirismEnabled(primarySkillType); + } + + public ToolType getPrimarySkillToolType(PrimarySkillType primarySkillType) { + return primarySkillToolMap.get(primarySkillType); + } + + public Set getSubSkills(PrimarySkillType primarySkillType) { + //TODO: Cache this! + return primarySkillChildrenMap.get(primarySkillType); + } + + public double getXpModifier(PrimarySkillType primarySkillType) { + return ExperienceConfig.getInstance().getFormulaSkillModifier(primarySkillType); + } + + // TODO: This is a little "hacky", we probably need to add something to distinguish child skills in the enum, or to use another enum for them + public static boolean isChildSkill(PrimarySkillType primarySkillType) { + switch (primarySkillType) { + case SALVAGE: + case SMELTING: + return true; + + default: + return false; + } + } + + /** + * Get the localized name for a {@link PrimarySkillType} + * @param primarySkillType target {@link PrimarySkillType} + * @return the localized name for a {@link PrimarySkillType} + */ + public String getLocalizedSkillName(PrimarySkillType primarySkillType) { + //TODO: Replace with current impl + return StringUtils.getCapitalized(LocaleLoader.getString(StringUtils.getCapitalized(primarySkillType.toString()) + ".SkillName")); + } + + public boolean doesPlayerHaveSkillPermission(Player player, PrimarySkillType primarySkillType) { + return Permissions.skillEnabled(player, primarySkillType); + } + + public boolean canCombatSkillsTrigger(PrimarySkillType primarySkillType, Entity target) { + return (target instanceof Player || (target instanceof Tameable && ((Tameable) target).isTamed())) ? getPVPEnabled(primarySkillType) : getPVEEnabled(primarySkillType); + } + + public String getCapitalizedPrimarySkillName(PrimarySkillType primarySkillType) { + return StringUtils.getCapitalized(primarySkillType.toString()); + } + + public int getSuperAbilityCooldown(SuperAbilityType superAbilityType) { + return pluginRef.getGeneralConfig().getCooldown(superAbilityType); + } + + public int getSuperAbilityMaxLength(SuperAbilityType superAbilityType) { + return pluginRef.getGeneralConfig().getMaxLength(superAbilityType); + } + + public String getSuperAbilityOnLocaleKey(SuperAbilityType superAbilityType) { + return "SuperAbility." + StringUtils.getPrettyCamelCaseName(superAbilityType) + ".On"; + } + + public String getSuperAbilityOffLocaleKey(SuperAbilityType superAbilityType) { + return "SuperAbility." + StringUtils.getPrettyCamelCaseName(superAbilityType) + ".Off"; + } + + public String getSuperAbilityOtherPlayerActivationLocaleKey(SuperAbilityType superAbilityType) { + return "SuperAbility." + StringUtils.getPrettyCamelCaseName(superAbilityType) + ".Other.On"; + } + + public String getSuperAbilityOtherPlayerDeactivationLocaleKey(SuperAbilityType superAbilityType) { + return "SuperAbility." + StringUtils.getPrettyCamelCaseName(superAbilityType) + "Other.Off"; + } + + public String getSuperAbilityRefreshedLocaleKey(SuperAbilityType superAbilityType) { + return "SuperAbility." + StringUtils.getPrettyCamelCaseName(superAbilityType) + ".Refresh"; + } + + public int getLevelCap(@NotNull PrimarySkillType primarySkillType) { + return mcMMO.p.getGeneralConfig().getLevelCap(primarySkillType); + } + + /** + * Get the permissions for this ability. + * + * @param player Player to check permissions for + * @param superAbilityType target super ability + * @return true if the player has permissions, false otherwise + */ + public boolean superAbilityPermissionCheck(SuperAbilityType superAbilityType, Player player) { + switch (superAbilityType) { + case BERSERK: + return Permissions.berserk(player); + + case BLAST_MINING: + return Permissions.remoteDetonation(player); + + case GIGA_DRILL_BREAKER: + return Permissions.gigaDrillBreaker(player); + + case GREEN_TERRA: + return Permissions.greenTerra(player); + + case SERRATED_STRIKES: + return Permissions.serratedStrikes(player); + + case SKULL_SPLITTER: + return Permissions.skullSplitter(player); + + case SUPER_BREAKER: + return Permissions.superBreaker(player); + + case TREE_FELLER: + return Permissions.treeFeller(player); + + default: + return false; + } + } + + public @NotNull List getChildSkills() { + return CHILD_SKILLS; + } + + public @NotNull ImmutableList getNonChildSkills() { + return NON_CHILD_SKILLS; + } + + public @NotNull ImmutableList getCombatSkills() { + return COMBAT_SKILLS; + } + + public @NotNull ImmutableList getGatheringSkills() { + return GATHERING_SKILLS; + } + + public @NotNull ImmutableList getMiscSkills() { + return MISC_SKILLS; + } +} diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java index dcdd446c0..6574224aa 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java @@ -1,7 +1,5 @@ package com.gmail.nossr50.util.skills; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.HiddenConfig; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; @@ -64,10 +62,10 @@ public final class SkillUtils { * Skill Stat Calculations */ - public static @NotNull String[] calculateLengthDisplayValues(@NotNull OnlineMMOPlayer mmoPlayer, float skillValue, @NotNull PrimarySkillType skill) { - int maxLength = skill.getSuperAbilityType().getMaxLength(); - int abilityLengthVar = AdvancedConfig.getInstance().getAbilityLength(); - int abilityLengthCap = AdvancedConfig.getInstance().getAbilityLengthCap(); + public static String[] calculateLengthDisplayValues(Player player, float skillValue, PrimarySkillType skill) { + int maxLength = mcMMO.p.getSkillTools().getSuperAbilityMaxLength(mcMMO.p.getSkillTools().getSuperAbility(skill)); + int abilityLengthVar = mcMMO.p.getAdvancedConfig().getAbilityLength(); + int abilityLengthCap = mcMMO.p.getAdvancedConfig().getAbilityLengthCap(); int length; @@ -134,8 +132,8 @@ public final class SkillUtils { * @param skillName The name of the skill to check * @return true if this is a valid skill, false otherwise */ - public static boolean isSkill(@NotNull String skillName) { - return Config.getInstance().getLocale().equalsIgnoreCase("en_US") ? mcMMO.p.getSkillRegister().getSkill(skillName) != null : isLocalizedSkill(skillName); + public static boolean isSkill(String skillName) { + return mcMMO.p.getGeneralConfig().getLocale().equalsIgnoreCase("en_US") ? mcMMO.p.getSkillTools().matchSkill(skillName) != null : isLocalizedSkill(skillName); } public static void sendSkillMessage(@NotNull Player player, @NotNull NotificationType notificationType, @NotNull String key) { @@ -170,8 +168,7 @@ public final class SkillUtils { //1.13.2+ will have persistent metadata for this item AbstractPersistentDataLayer compatLayer = mcMMO.getCompatibilityManager().getPersistentDataLayer(); compatLayer.setSuperAbilityBoostedItem(heldItem, originalDigSpeed); - } - else { + } else { int duration = 0; int amplifier = 0; @@ -193,18 +190,18 @@ public final class SkillUtils { PrimarySkillType skill = mmoPlayer.getSuperAbilityManager().getAbilityMode(SuperAbilityType.SUPER_BREAKER) ? PrimarySkillType.MINING : PrimarySkillType.EXCAVATION; - int abilityLengthVar = AdvancedConfig.getInstance().getAbilityLength(); - int abilityLengthCap = AdvancedConfig.getInstance().getAbilityLengthCap(); + int abilityLengthVar = mcMMO.p.getAdvancedConfig().getAbilityLength(); + int abilityLengthCap = mcMMO.p.getAdvancedConfig().getAbilityLengthCap(); int ticks; if(abilityLengthCap > 0) { - ticks = PerksUtils.handleActivationPerks(player, Math.min(abilityLengthCap, 2 + (mmoPlayer.getExperienceHandler().getSkillLevel(skill) / abilityLengthVar)), - skill.getSuperAbilityType().getMaxLength()) * Misc.TICK_CONVERSION_FACTOR; + ticks = PerksUtils.handleActivationPerks(player, Math.min(abilityLengthCap, 2 + (mcMMOPlayer.getSkillLevel(skill) / abilityLengthVar)), + mcMMO.p.getSkillTools().getSuperAbilityMaxLength(mcMMO.p.getSkillTools().getSuperAbility(skill))) * Misc.TICK_CONVERSION_FACTOR; } else { - ticks = PerksUtils.handleActivationPerks(player, 2 + ((mmoPlayer.getExperienceHandler().getSkillLevel(skill)) / abilityLengthVar), - skill.getSuperAbilityType().getMaxLength()) * Misc.TICK_CONVERSION_FACTOR; + ticks = PerksUtils.handleActivationPerks(player, 2 + ((mcMMOPlayer.getSkillLevel(skill)) / abilityLengthVar), + mcMMO.p.getSkillTools().getSuperAbilityMaxLength(mcMMO.p.getSkillTools().getSuperAbility(skill))) * Misc.TICK_CONVERSION_FACTOR; } PotionEffect abilityBuff = new PotionEffect(PotionEffectType.FAST_DIGGING, duration + ticks, amplifier + 10); diff --git a/src/main/java/com/gmail/nossr50/util/skills/SmeltingTracker.java b/src/main/java/com/gmail/nossr50/util/skills/SmeltingTracker.java index 234377269..c2218441c 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SmeltingTracker.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SmeltingTracker.java @@ -2,7 +2,6 @@ package com.gmail.nossr50.util.skills; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.Permissions; import com.neetgames.mcmmo.player.OnlineMMOPlayer; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -88,7 +87,7 @@ public class SmeltingTracker { } public void processFurnaceOwnership(Furnace furnace, Player player) { - if(!Permissions.skillEnabled(player, PrimarySkillType.SMELTING)) + if(!mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.SMELTING)) return; //Don't swap ownership if its the same player diff --git a/src/main/java/com/gmail/nossr50/util/text/StringUtils.java b/src/main/java/com/gmail/nossr50/util/text/StringUtils.java index fe4ceeae3..c1ea94ad9 100644 --- a/src/main/java/com/gmail/nossr50/util/text/StringUtils.java +++ b/src/main/java/com/gmail/nossr50/util/text/StringUtils.java @@ -31,6 +31,35 @@ public class StringUtils { return shortDecimal.format(ticks / 20); } + public static String convertToCamelCaseString(String baseString, String splitBy) { + String[] substrings = baseString.split(splitBy); + String prettyString = ""; + int size = 1; + + for (String string : substrings) { + prettyString = prettyString.concat(getCapitalized(string)); + + if (size < substrings.length) { + prettyString = prettyString.concat(""); + } + + size++; + } + + return prettyString; + } + + public static String getPrettyCamelCaseName(Object o) { + return StringUtils.convertToCamelCaseString(o.toString(), "_"); + } + + public static String getPrettySuperAbilityName(SuperAbilityType superAbilityType) { + return StringUtils.getPrettySuperAbilityString(superAbilityType); + } + + public static String getPrettySuperAbilityString(SuperAbilityType ability) { + return createPrettyString(ability.toString()); + } /** * Creates a string from an array skipping the first n elements diff --git a/src/main/java/com/gmail/nossr50/util/text/TextComponentFactory.java b/src/main/java/com/gmail/nossr50/util/text/TextComponentFactory.java index 205fcba77..23cb13e06 100644 --- a/src/main/java/com/gmail/nossr50/util/text/TextComponentFactory.java +++ b/src/main/java/com/gmail/nossr50/util/text/TextComponentFactory.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.util.text; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.RankConfig; import com.gmail.nossr50.datatypes.json.McMMOUrl; import com.gmail.nossr50.datatypes.json.McMMOWebLinks; @@ -66,7 +65,7 @@ public class TextComponentFactory { public static void sendPlayerSubSkillWikiLink(OnlineMMOPlayer mmoPlayer, String subskillformatted) { - if(!Config.getInstance().getUrlLinksEnabled()) + if(!mcMMO.p.getGeneralConfig().getUrlLinksEnabled()) return; TextComponent.Builder wikiLinkComponent = Component.text().content(LocaleLoader.getString("Overhaul.mcMMO.MmoInfo.Wiki")); 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 55c747ffd..3ed01d378 100644 --- a/src/main/java/com/gmail/nossr50/util/upgrade/UpgradeManager.java +++ b/src/main/java/com/gmail/nossr50/util/upgrade/UpgradeManager.java @@ -2,6 +2,7 @@ package com.gmail.nossr50.util.upgrade; import com.gmail.nossr50.config.ConfigLoader; import com.gmail.nossr50.datatypes.database.UpgradeType; +import com.gmail.nossr50.mcMMO; import java.util.Arrays; import java.util.EnumSet; @@ -40,7 +41,7 @@ public class UpgradeManager extends ConfigLoader { return; } - plugin.debug("Saving upgrade status for type " + type.toString() + "..."); + mcMMO.p.debug("Saving upgrade status for type " + type.toString() + "..."); config.set("Upgrades_Finished." + type.toString(), true); @@ -60,6 +61,6 @@ public class UpgradeManager extends ConfigLoader { } } - plugin.debug("Needed upgrades: " + Arrays.toString(setNeededUpgrades.toArray(new UpgradeType[setNeededUpgrades.size()]))); + mcMMO.p.debug("Needed upgrades: " + Arrays.toString(setNeededUpgrades.toArray(new UpgradeType[setNeededUpgrades.size()]))); } } diff --git a/src/main/java/net/shatteredlands/shatt/backup/ZipLibrary.java b/src/main/java/net/shatteredlands/shatt/backup/ZipLibrary.java index 6c1c926ea..398f99449 100644 --- a/src/main/java/net/shatteredlands/shatt/backup/ZipLibrary.java +++ b/src/main/java/net/shatteredlands/shatt/backup/ZipLibrary.java @@ -1,6 +1,5 @@ package net.shatteredlands.shatt.backup; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.mcMMO; import java.io.File; @@ -27,7 +26,7 @@ public class ZipLibrary { private static final File REPAIR_FILE = new File(mcMMO.getMainDirectory() + "repair.vanilla.yml"); public static void mcMMOBackup() throws IOException { - if (Config.getInstance().getUseMySQL()) { + if (mcMMO.p.getGeneralConfig().getUseMySQL()) { mcMMO.p.getLogger().info("This server is running in SQL Mode."); mcMMO.p.getLogger().info("Only config files will be backed up."); } diff --git a/src/main/resources/locale/locale_de.properties b/src/main/resources/locale/locale_de.properties index 87cfc4240..74333581c 100644 --- a/src/main/resources/locale/locale_de.properties +++ b/src/main/resources/locale/locale_de.properties @@ -94,10 +94,10 @@ Broadcasts.LevelUpMilestone = &6(&amcMMO&6) {0}&7 hat nun Level &a{1}&7 mit der Chat.Channel.Off = &6(&amcMMO-Chat&6) &7Deine Nachrichten werden nicht l\u00E4nger automatisch an die spezifischen Kan\u00E4le versendet. Chat.Channel.On = &6(&amcMMO-Chat&6) &eDeine Nachrichten werden nun automatisch an den &a{0}&e Kanal gesendet. Chat.Identity.Console = &6* Konsole * -Chat.Spy.Party = &6[&eSPION&6-&a{2}&6] &r{0} &b\u2192�� &r{1} -Chat.Style.Admin = &b(A) &r{0} &b\u2192�� &r{1} -Chat.Style.Party = &a(P) &r{0} &a\u2192�� &r{1} -Chat.Style.Party.Leader = &a(P) &r{0} &6\u2192�� &r{1} +Chat.Spy.Party = &6[&eSPION&6-&a{2}&6] &r{0} &b\u2192 &r{1} +Chat.Style.Admin = &b(A) &r{0} &b\u2192 &r{1} +Chat.Style.Party = &a(P) &r{0} &a\u2192 &r{1} +Chat.Style.Party.Leader = &a(P) &r{0} &6\u2192 &r{1} Combat.ArrowDeflect = &a&o**Pfeil abgelenkt** Combat.BeastLore = &a&o**Biestkunde** @@ -112,9 +112,9 @@ Combat.TouchedFuzzy = &a&o**Du wurdest ungl\u00FCcklich ber\u00FChrt, ein Schwin Commands.Ability.Off = F\u00E4higkeiten Benutzung &cdeaktiviert Commands.Ability.On = F\u00E4higkeiten Benutzung &aaktiviert -Commands.Ability.Toggle = Benutzung von F\u00E4higkeiten wurde f\u00FCr &e{0} ge\u00E4ndert -Commands.AdminChat.Off = Exklusiver Admin-Chat wurde &c deaktiviert -Commands.AdminChat.On = Exklusiver Admin-Chat wurde &a aktiviert +Commands.Ability.Toggle = Benutzung von F\u00E4higkeiten wurde f\u00FCr &e{0} ge\u00E4ndert. +Commands.AdminChat.Off = Exklusiver Admin-Chat wurde &c deaktiviert. +Commands.AdminChat.On = Exklusiver Admin-Chat wurde &a aktiviert. Commands.AdminChatSpy.Chat = &6[Spy: &a{0}&6] &f{1} Commands.AdminChatSpy.Disabled = mcMMO Party Chat-Spy deaktiviert Commands.AdminChatSpy.Enabled = mcMMO Party Chat-Spy aktiviert @@ -137,7 +137,7 @@ Commands.Description.mcability = Schalte die Bereitschaft von F\u00E4higkeiten b Commands.Description.mcchatspy = Schalte den Party Chat-Spy an oder aus. Commands.Description.mcconvert = Konvertiert Datenbanktypen oder Erfahrungsformeln. Commands.Description.mccooldown = Sieh alle F\u00E4higkeiten-Cooldowns. -Commands.Description.mcgod = Schalte mcMMO godmode an oder aus. +Commands.Description.mcgod = Schalte mcMMO Godmode an oder aus. Commands.Description.mchud = \u00C4ndere deinen HUD Stil. Commands.Description.mcmmo = Zeige eine kurze Beschreibung \u00FCber mcMMO. Commands.Description.mcnotify = Schalte F\u00E4higkeiten-Hinweise im Chat an oder aus. @@ -151,7 +151,7 @@ Commands.Description.mctop = Zeige die Skill-Bestenlisten. Commands.Description.mmocompat = Informationen dar\u00FCber, ob mcMMO im Kompatibilit\u00E4tsmodus oder voll funktionsf\u00E4hig ist. Commands.Description.mmodebug = (De)aktiviere den Debugging-Modus, welcher n\u00FCtzliche Informationen ausgibt, wenn du einen Block schl\u00E4gst. Commands.Description.mmoedit = Editiere die Skill-Level eines Spielers. -Commands.Description.mmoinfo = Lese Details \u00FCber einen Skill oder andere Funktionen. +Commands.Description.mmoinfo = Zeige Details \u00FCber einen Skill oder andere Funktionen. Commands.Description.mmoshowdb = Zeige den Namen der aktuellen Datenbank (zur Benutzung mit /mmoupdate). Commands.Description.mmoupdate = Kopiere Daten von einer alten Datenbank zur aktuell benutzen. Commands.Description.mmoxpbar = Spielereinstellungen f\u00FCr die mcMMO Erfahrungsleisten. @@ -174,7 +174,7 @@ Commands.GodMode.Forbidden = [mcMMO] Der Godmode ist in dieser Welt nicht erlaub Commands.GodMode.Toggle = Godmode wurde f\u00FCr &e{0} aktiviert. Commands.Healthbars.Changed.BAR = [mcMMO] Deine Lebensanzeige wurde zu &eK\u00E4stchen&f ge\u00E4ndert. Commands.Healthbars.Changed.DISABLED = [mcMMO] Die Mob-Lebensanzeige wurde &7deaktiviert&f. -Commands.Healthbars.Changed.HEARTS = [mcMMO]Deine Lebensanzeige wurde zu &cHerzen&f ge\u00E4ndert. +Commands.Healthbars.Changed.HEARTS = [mcMMO] Deine Lebensanzeige wurde zu &cHerzen&f ge\u00E4ndert. Commands.Healthbars.Invalid = Ung\u00FCltiger Lebensanzeige-Typ! Commands.Inspect = &a- Siehe detaillierte Spielerinformationen Commands.Invite.Success = &aEinladung erfolgreich gesendet. @@ -184,25 +184,25 @@ Commands.MmoInfo.Header = &3-=[]=====[]&6 MMO Info &3[]=====[]=- Commands.MmoInfo.Mechanics = &3-=[]=====[]&6 Funktionen &3[]=====[]=- Commands.MmoInfo.Mystery = &7Diese F\u00E4higkeit hast du noch nicht freigeschaltet, wenn du das tust, kannst du hier Details \u00FCber diese finden! Commands.MmoInfo.NoMatch = Diese F\u00E4higkeit existiert nicht! -Commands.MmoInfo.OldSkill = &7mcMMO skills are being converted into an improved modular skill system, unfortunately this skill has not been converted yet and lacks detailed stats. The new system will allow for faster release times for new mcMMO skills and greater flexibility with existing skills. -Commands.MmoInfo.Stats = STATS: {0} +Commands.MmoInfo.OldSkill = &7mcMMO Skills werden in ein verbessertes und modulares Skill-System konvertiert - wovon dieser Skill jedoch noch nicht betroffen ist, weswegen detaillierte Statistiken fehlen. Das neue System erm\u00F6glicht eine schnellere Ver\u00F6ffentlichung neuer mcMMO-Skills und eine gr\u00F6ßere Flexibilit\u00E4t mit bereits existenten Skills. +Commands.MmoInfo.Stats = Statistik: {0} Commands.MmoInfo.SubSkillHeader = &6Name:&e {0} Commands.Mmodebug.Toggle = Der mcMMO Debugging-Modus ist nun &6{0}&7, benutze den Befehl erneut, um dies r\u00FCckg\u00E4ngig zu machen. Wenn der Debugging-Modus aktiviert wurde kannst du Bl\u00F6cke schlagen, um n\u00FCtzliche Informationen zu erhalten. Dies ist f\u00FCr den Support sehr n\u00FCtzlich. Commands.ModDescription = &a- Kurze Modbeschreibung Commands.NegativeNumberWarn = Benutze keine negativen Zahlen! Commands.NoConsole = Dieser Befehl kann nicht aus der Konsole verwendet werden. Commands.NotLoaded = Spielerprofil wurde noch nicht geladen. -Commands.Notifications.Off = F\u00E4higkeiten Hinweise wurden &cdeaktiviert -Commands.Notifications.On = F\u00E4higkeiten Hinweise wurden &aaktiviert +Commands.Notifications.Off = F\u00E4higkeiten Hinweise wurden &cdeaktiviert. +Commands.Notifications.On = F\u00E4higkeiten Hinweise wurden &aaktiviert. Commands.Offline = Dieser Befehl funktioniert nur bei eingeloggten Spielern. Commands.Other = ---[]&aBesondere Befehle&c[]--- Commands.Party.Accept = &a- Nimm Party-Einladung an Commands.Party.Alliance.Ally = &f{0} &8Ist verb\u00FCndet mit: &f{1} -Commands.Party.Alliance.AlreadyAllies = Deine Party ist bereits in einem B\u00FCndnis. Trenne es mit&3/party alliance disband +Commands.Party.Alliance.AlreadyAllies = Deine Party ist bereits in einem B\u00FCndnis. Trenne es mit&3/party alliance disband&e. Commands.Party.Alliance.Header = -----[]&aParty-B\u00FCndnisse&c[]----- Commands.Party.Alliance.Help.0 = Diese Party ist in keinem B\u00FCndnis. Lade einen Party-Anf\u00FChrer ein. -Commands.Party.Alliance.Help.1 = &c um zu verb\u00FCnden &3/party alliance invite &c. -Commands.Party.Alliance.Invite.0 = ALERT: &aDu hast eine B\u00FCndnis-Anfrage f\u00FCr {0} von {1} erhalten. +Commands.Party.Alliance.Help.1 = &c Zum Verb\u00FCnden: &3/party alliance invite &c. +Commands.Party.Alliance.Invite.0 = ACHTUNG: &aDu hast eine B\u00FCndnis-Anfrage f\u00FCr {0} von {1} erhalten. Commands.Party.Alliance.Invite.1 = Tippe &a/party alliance accept&e um die Anfrage anzunehmen. Commands.Party.Alliance.Invite.Accepted = &aB\u00FCndnis-Anfrage angenommen Commands.Party.Alliance.Members.Header = -----[]&aB\u00FCndnis-Mitglieder&c[]----- @@ -216,7 +216,7 @@ Commands.Party.ExpShare = &7Erfahrung &3({0}) Commands.Party.Features.Header = -----[]&aFunktionen&c[]----- Commands.Party.Header = &c-----[]&aParty&c[]----- Commands.Party.Invite = &a- Sende eine Party-Einladung -Commands.Party.Invite.0 = ALERT: &aDu hast eine Party-Einladung f\u00FCr {0} von {1} erhalten. +Commands.Party.Invite.0 = ACHTUNG: &aDu hast eine Party-Einladung f\u00FCr {0} von {1} erhalten. Commands.Party.Invite.1 = &eBenutze &a/party accept&e um die Einladung anzunehmen. Commands.Party.Invite.Accepted = &aEinladung angenommen. Du bist der {0} Party beigetreten. Commands.Party.ItemShare = &7Item &3({0}) @@ -231,7 +231,7 @@ Commands.Party.PartyFull = &6{0}&c ist voll! Commands.Party.PartyFull.Invite = Du kannst &e{0}&c nicht zur Party &a{1}&c einladen, weil sie schon &3{2}&c Spieler hat! Commands.Party.PartyFull.InviteAccept = Du kannst der Party &a{0}&c nicht beitreten, weil sie schon &3{1}&c Spieler hat! Commands.Party.Quit = &a- Verlasse deine aktuelle Party. -Commands.Party.Rename = &7Party Name wurde zu &f{0} &7ver\u00E4ndert +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.Status = &8Name: &f{0} {1} &8Level: &3{2} @@ -245,11 +245,11 @@ Commands.Party2 = &a- Tritt der Party eines Spielers bei. 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 -Commands.Reset.All = &aAlle deine Skilllevel wurden erfolgreich zur\u00FCckgesetzt. -Commands.Reset.Single = &aDein {0} Skilllevel wurde erfolgreich zur\u00FCckgesetzt. +Commands.Reset = &a- Setze ein Skill-Level auf 0 +Commands.Reset.All = &aAlle deine Skill-Level wurden erfolgreich zur\u00FCckgesetzt. +Commands.Reset.Single = &aDein {0} Skill-Level wurde erfolgreich zur\u00FCckgesetzt. Commands.Scoreboard.Clear = &3Das Scoreboard wurde ausgeblendet. -Commands.Scoreboard.Help.0 = &6 == &aHilfe f\u00FCr&c/mcscoreboard&6 == +Commands.Scoreboard.Help.0 = &6 == &aHilfe f\u00FCr&c /mcscoreboard&6 == Commands.Scoreboard.Help.1 = &3/mcscoreboard&b clear &f - blende die \u00DCbersicht aus Commands.Scoreboard.Help.2 = &3/mcscoreboard&b keep &f - behalte die \u00DCbersicht offen Commands.Scoreboard.Help.3 = &3/mcscoreboard&b time [n] &f - blende die \u00DCbersicht nach &dn&f Sekunden aus @@ -281,10 +281,10 @@ Commands.Usage.Rate = Rate Commands.Usage.Skill = Skill Commands.Usage.SubSkill = F\u00E4higkeit Commands.Usage.XP = Erfahrung -Commands.XPBar.DisableAll = &6Alle mcMMO Erfahrungsleisten wurden deaktiviert, benutze /mmoxpbar reset um die Standardeinstellungen wiederherzustellen. +Commands.XPBar.DisableAll = &6Alle mcMMO Erfahrungsleisten wurden deaktiviert, benutze &c/mmoxpbar reset&6 um die Standardeinstellungen wiederherzustellen. 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.XPBar.Usage = Die korrekte Verwendung ist &a/mmoxpbar Commands.XPGain = &8XP-Zuwachs: &f{0} Commands.XPGain.Acrobatics = Fallen Commands.XPGain.Alchemy = Tr\u00E4nke brauen @@ -316,7 +316,7 @@ Commands.mcconvert.Experience.Finish = &7Konvertierung vollendet - es wird jetzt Commands.mcconvert.Experience.Invalid = Unbekannter Formeltyp! G\u00FCltige Typen sind: &aLINEAR &cund &aEXPONENTIAL. Commands.mcconvert.Experience.Same = Formeltyp {0} wird bereits verwendet. Commands.mcconvert.Experience.Start = &7Beginne Konvertierung von Kurve {0} zu Kurve {1}. -Commands.mcgod = &a- Schalte Godmode um +Commands.mcgod = &a- Schalte den Godmode um Commands.mchud.Invalid = Das ist kein g\u00FCltiger HUD Typ. Commands.mcpurge.Success = &aDie Datenbank wurde erfolgreich ges\u00E4ubert! Commands.mcrank.Heading = &6-=Pers\u00F6nliche Rangliste=- @@ -339,19 +339,19 @@ Commands.ptp.Enabled = Party-Teleportierung &aaktiviert Commands.ptp.NoRequests = Du hast aktuell keine Teleportierungsanfragen. Commands.ptp.NoWorldPermissions = &c[mcMMO] Du hast nicht die n\u00F6tigen Rechte um dich in die Welt {0} zu teleportieren. Commands.ptp.Request1 = {0} &am\u00F6chte sich zu dir teleportieren. -Commands.ptp.Request2 = &aUm zu teleportieren tippe &e/ptp accept&a. Die Anfrage l\u00E4uft in &c{0} &aSekunden aus. +Commands.ptp.Request2 = &aZum Teleportieren tippe &e/ptp accept&a. Die Anfrage l\u00E4uft in &c{0} &aSekunden aus. Commands.ptp.RequestExpired = &cParty-Teleportierungsanfrage ist ausgelaufen. Commands.xplock.locked = &6Deine Erfahrungsanzeige ist nun auf {0} festgesetzt! Commands.xplock.unlocked = &6Deine Erfahrungsanzeige ist nun wieder &afreigeschaltet&6! Commands.xprate.modified = Die Erfahrungsrate wurde auf {0} gesetzt! Commands.xprate.over = Das Bonuserfahrungs-Event f\u00FCr Skills ist vor\u00FCber! -Commands.xprate.proper.0 = &cKorrekte Eingabe f\u00FCr Erfahrungs Raten Wechsel: /xprate -Commands.xprate.proper.1 = &cKorrekte Eingabe f\u00FCr R\u00FCcksetzung auf Standard Erfahrungs Rate: /xprate reset +Commands.xprate.proper.0 = &cKorrekte Eingabe f\u00FCr Erfahrungsratenwechsel: /xprate +Commands.xprate.proper.1 = &cKorrekte Eingabe f\u00FCr R\u00FCcksetzung auf Standard-Erfahrungsrate: /xprate reset Commands.xprate.proper.2 = &cBitte entscheide mit true/false ob dies ein XP-Event ist oder nicht. Commands.xprate.started.0 = &6Ein Bonuserfahrungs-Event f\u00FCr Skills hat begonnen! Commands.xprate.started.1 = &6Die Erfahrungsrate f\u00FCr Skills liegt jetzt bei {0}x! -Compatibility.Layer.PartialSupport = &6Diese Version besitzt keine vollst\u00E4ndige Unterst\u00FCtzung f\u00FCr &a{0}&6, jedoch verwendet mcMMO ein System, was die fehlenden Features versucht zu emulieren. +Compatibility.Layer.PartialSupport = &6Diese Version besitzt keine vollst\u00E4ndige Unterst\u00FCtzung f\u00FCr &a{0}&6, jedoch verwendet mcMMO ein System, welches versucht die fehlenden Features zu emulieren. Compatibility.Layer.Unsupported = &6Diese Version von Minecraft ist nicht kompatibel mit &a{0}&6. Effects.Child.Overhaul = &3Unterskill Level&e {0}&3: {1} @@ -375,7 +375,7 @@ Excavation.SubSkill.Archaeology.Description = Ergrabe die Sch\u00E4tze der Unter Excavation.SubSkill.Archaeology.Name = Arch\u00E4ologie Excavation.SubSkill.Archaeology.Stat = Arch\u00E4ologie Erfahrungspunkte-Chance Excavation.SubSkill.Archaeology.Stat.Extra = Arch\u00E4ologie Erfahrungspunkte-Anzahl -Excavation.SubSkill.GigaDrillBreaker.Description = Dreifache Droprate, dreifache Erfahrung und Bonus-Geschwindigkeit. +Excavation.SubSkill.GigaDrillBreaker.Description = Dreifache Droprate, dreifache Erfahrung und Bonus-Abbaugeschwindigkeit. Excavation.SubSkill.GigaDrillBreaker.Name = Gigabohrer Excavation.SubSkill.GigaDrillBreaker.Stat = Gigabohrer-Dauer @@ -395,8 +395,8 @@ Fishing.Scared = &7&oHektische Bewegungen ver\u00E4ngstigen Fische! Fishing.SkillName = Angeln Fishing.SubSkill.FishermansDiet.Description = Verbessert den N\u00E4hrwert von geangelter Nahrung. Fishing.SubSkill.FishermansDiet.Name = Fischers-Di\u00E4t -Fishing.SubSkill.FishermansDiet.Stat = Fishers-Di\u00E4t:&a Rang {0} -Fishing.SubSkill.IceFishing.Description = Erm\u00F6glicht dir in Eisbiomen zu angeln. +Fishing.SubSkill.FishermansDiet.Stat = Fischers-Di\u00E4t:&a Rang {0} +Fishing.SubSkill.IceFishing.Description = Erm\u00F6glicht es dir in Eisbiomen zu angeln. Fishing.SubSkill.IceFishing.Name = Eisangeln Fishing.SubSkill.IceFishing.Stat = Eisangeln Fishing.SubSkill.MagicHunter.Description = Finde verzauberte Gegenst\u00E4nde. @@ -406,7 +406,7 @@ Fishing.SubSkill.MasterAngler.Description = Fische k\u00F6nnen h\u00E4ufiger gef Fishing.SubSkill.MasterAngler.Name = Superangel Fishing.SubSkill.MasterAngler.Stat = Mindestwartezeit beim Angeln reduziert um: &a-{0} Sekunden Fishing.SubSkill.MasterAngler.Stat.Extra = Maximalwartezeit beim Angeln reduziert um: &a-{0} Sekunden -Fishing.SubSkill.Shake.Description = Rei\u00DFe mit deiner Angel Gegenst\u00E4nde weg von Lebewesen und Spielern. +Fishing.SubSkill.Shake.Description = Entrei\u00DFe Lebewesen und Spielern mit deiner Angel Gegenst\u00E4nde. Fishing.SubSkill.Shake.Name = Rei\u00DFen Fishing.SubSkill.Shake.Stat = Rei\u00DFen Chance Fishing.SubSkill.TreasureHunter.Description = Angle verschiedene Objekte. @@ -414,10 +414,10 @@ Fishing.SubSkill.TreasureHunter.Name = Schatz-J\u00E4ger Fishing.SubSkill.TreasureHunter.Stat = Schatz-J\u00E4ger Rang: &a{0}&3/&a{1} Fishing.SubSkill.TreasureHunter.Stat.Extra = Drop-Rate: &7\u00DCblich: &e{0} &aUn\u00FCblich: &e{1}\n&9Selten: &e{2} &dEpisch: &e{3} &6Legend\u00E4r: &e{4} &bMythic: &e{5} -Guides.Acrobatics.Section.0 = &3\u00DCber Akrobatik:\n&eAkrobatik ist die Kunst sich anmutig fortzubewegen.\n&eFall- und Kampfschaden werden reduziert\n\n&3XP GAIN:\n&eErfahrung sammelst du indem du in K\u00E4mpfen\n&eausweichst oder St\u00FCrze aus gro\u00DFen H\u00F6hen \u00FCberlebst. +Guides.Acrobatics.Section.0 = &3\u00DCber Akrobatik:\n&eAkrobatik ist die Kunst sich anmutig fortzubewegen.\n&eFall- und Kampfschaden werden reduziert.\n\n&3XP-Zuwachs:\n&eErfahrung sammelst du indem du in K\u00E4mpfen\n&eausweichst oder St\u00FCrze aus gro\u00DFen H\u00F6hen \u00FCberlebst. Guides.Acrobatics.Section.1 = &3Wie funktioniert Abrollen?\n&eAb und zu rollst du beim Fallen ab und der Fallschaden wird\n&ereduziert. Wenn du die Schleichen-Taste w\u00E4hrend dem Fallen\n&eh\u00E4ltst, verdoppelt sich die Chance abzurollen.\n&eIn dem Fall rollst du anmutig ab.\n&eAnmutige Rollen sind wie normale Rollen, nur dass\n&esie \u00F6fter passieren und damit mehr Schutz vor St\u00FCrzen\n&eliefern. Guides.Acrobatics.Section.2 = &3Wie funktioniert Ausweichen?\n&eAusweichen ist eine passive F\u00E4higkeit\n&edie ab und zu den Schaden in K\u00E4mpfen halbiert.\n&eDie Chance auszuweichen ist abh\u00E4ngig vom \n&eAkrobatiklevel. -Guides.Alchemy.Section.0 = &3\u00DCber Alchemie:\n&eIn Alchemie musst du Tr\u00E4nke brauen.\n&eMit h\u00F6herem Level werden die Tr\u00E4nke schneller\n&egebraut und neue Zutaten f\u00FCr zun\u00E4chst unerh\u00E4ltliche Tr\u00E4nke \n&efreigeschaltet.\n\n&3XP ZUWACHS:\n&eTr\u00E4nke brauen. +Guides.Alchemy.Section.0 = &3\u00DCber Alchemie:\n&eIn Alchemie musst du Tr\u00E4nke brauen.\n&eMit h\u00F6herem Level werden die Tr\u00E4nke schneller\n&egebraut und neue Zutaten f\u00FCr zun\u00E4chst unerh\u00E4ltliche Tr\u00E4nke \n&efreigeschaltet.\n\n&3XP-Zuwachs:\n&eTr\u00E4nke brauen. Guides.Alchemy.Section.1 = &3Wie funktioniert Katalyse?\n&eKatalyse beschleunigt das Brauen von Tr\u00E4nken bis\n&ezu 4-facher Geschwindigkeit bei Level 1000. Guides.Alchemy.Section.2 = &3Wie funktioniert Gebr\u00E4u?\n&eGebr\u00E4u erm\u00F6glich das Brauen weiterer Tr\u00E4nke mit neuen\n&eZutaten.\n&eWelche Zutaten m\u00F6glich sind, h\u00E4ngt vom Rang ab.\n&eInsgesamt gibt es 8 R\u00E4nge freizuschalten. Guides.Alchemy.Section.3 = &3Gebr\u00E4u Tier 1 Zutaten:\n&eLohnenstaub, Fermentierte Spinnenaugen, Ghast Tr\u00E4nen,\n&eRedstone, Glowstonestaub, Zucker, Glitzernde Melone,\n&eGoldene Karotte, Magma Creme, Netherwarzen, Spinnenaugen, \n&eSchwarzpulver, Seerose, Kugelfisch (Vanilla Tr\u00E4nke) @@ -425,23 +425,23 @@ Guides.Alchemy.Section.4 = &3Gebr\u00E4u Tier 2 Zutaten:\n&eKarotte (Eile)\n&eSc Guides.Alchemy.Section.5 = &3Gebr\u00E4u Tier 4 Zutaten:\n&eApfel (Gesundheitsboost)\n&eVerrottetes Fleisch (Hunger)\n\n&3Gebr\u00E4u Tier 5 Zutaten:\n&eBrauner Pilz(\u00DCbelkeit)\n&eTintensack (Blindheit) Guides.Alchemy.Section.6 = &3Gebr\u00E4u Tier 6 Zutaten:\n&eGras (S\u00E4ttigung)\n\n&3Gebr\u00E4u Tier 7 Zutaten:\n&eGiftige Kartoffel (Verwesung)\n\n&3Gebr\u00E4u Tier 8 Zutaten:\n&eNormaler Goldener Apfel (Resistenz) Guides.Archery.Section.0 = &3\u00DCber Bogenschie\u00DFen:\n&eIn Bogenschie\u00DFen geht es um die Verwendung von Pfeil und\n&eBogen.\n\n&eEs gibt unterschiedliche Kampfboni, wie Zusatzschaden,\n&eder mit dem Level steigt und der F\u00E4higkeit Feinde im PVP\n&ezu bet\u00E4uben. Zus\u00E4tzlich kannst du einige verschossene\n&ePfeile aus den Leichen deiner Feinde wiedergewinnen. -Guides.Archery.Section.1 = &3XP ZUWACHS:\n&eXP erh\u00E4ltst du durch das Abschie\u00DFen von Monstern und\n&eanderen Spielern. +Guides.Archery.Section.1 = &3XP-Zuwachs:\n&eXP erh\u00E4ltst du durch das Abschie\u00DFen von Monstern und\n&eanderen Spielern. Guides.Archery.Section.2 = &3Wie funktioniert der Kunstschuss?\n&eKunstschuss erh\u00F6ht den Schaden deines Schusses.\n&eDer Zusatzschaden steigt mit deinem Bogen-Level.\n&eIn den Standardeinstellungen steigt der Schaden um 10%\n&ealle 50 Level, mit einem Maximum von 200% extra. Guides.Archery.Section.3 = &3Wie Funktioniert Bet\u00E4ubung?\n&eDu hast eine passive Chance andere Spieler\n&ezu bet\u00E4uben wenn du sie anschie\u00DFt. Der Spieler wird\n&egezwungen f\u00FCr eine kurze Weile senkrecht nach oben zu\n&eschauen.\n&eEin Bet\u00E4ubungsschuss f\u00FCgt au\u00DFerdem 4 Schadenspunkte \n&e(2 Herzen) extra zu. Guides.Available = &7Anleitung f\u00FCr {0} vorhanden - tippe /{1} ? [Seite] Guides.Axes.Section.0 = &3\u00DCber Axt:\n&eMit dem Axt-Skill kannst du die Axt f\u00FCr viel mehr als\n&enur abholzen verwenden! Du kannst Monster und Spieler\n&esprichw\u00F6rtlich weghacken und ihnen t\u00F6dliche\n&eSchl\u00E4ge verpassen oder sie zur\u00FCckweichen lassen.\n&eDeine Axt zerst\u00F6rt au\u00DFerdem sehr gut R\u00FCstungen,\n&ewas mit h\u00F6herem Level noch mehr ansteigt. -Guides.Axes.Section.1 = &3XP ZUWACHS:\n&eUm XP zu bekommen musst du Spieler oder Monster \n&emit einer Axt schlagen. +Guides.Axes.Section.1 = &3XP-Zuwachs:\n&eUm XP zu bekommen musst du Spieler oder Monster \n&emit einer Axt schlagen. Guides.Axes.Section.2 = &3Wie funktioniert der Sch\u00E4delspalter?\n&eDiese F\u00E4higkeit erlaubt dir einen Angriff mit Fl\u00E4chenschaden\n&eauszuf\u00FChren.\n&eDer Fl\u00E4chenschaden ist halb so gro\u00DF wie der \n&eHauptangriff, also perfekt f\u00FCr gro\u00DFe Ansammlungen von Mobs. -Guides.Axes.Section.3 = &3Wie funktionieren kritische Treffer?\n&eKritische Treffer sind eine passive F\u00E4higkeit\n&edie ab und zu Zusatzschaden zuf\u00FCgen.\n&eIn den Standardeinstellungen wird alle 2 Level \n&edie Chance um 0.1% erh\u00F6ht. Das f\u00FCgt Mobs\n&edoppelten und anderen Spielern 1,5 fachen Schaden zu. +Guides.Axes.Section.3 = &3Wie funktionieren kritische Treffer?\n&eKritische Treffer sind eine passive F\u00E4higkeit\n&edie ab und zu Zusatzschaden zuf\u00FCgen.\n&eIn den Standardeinstellungen wird alle 2 Level \n&edie Chance um 0.1% erh\u00F6ht. Das f\u00FCgt Mobs\n&edoppelten und anderen Spielern 1,5-fachen Schaden zu. Guides.Axes.Section.4 = &3Wie funktioniert die Axt-Beherrschung?\n&eAxt-Beherrschung ist eine passive F\u00E4higkeit die deinen\n&eAxt-Schl\u00E4gen Zusatzschaden hinzuf\u00FCgt.\n&eStandardm\u00E4\u00DFig steigt der Schaden um 1 alle 50 Level,\n&emaximal auf 4 Extraschaden bei Level 200. Guides.Axes.Section.5 = &3Wie funktioniert Wucht?\n&eSchlage m\u00E4chtig zu und zerst\u00F6re R\u00FCstungen!\n&eWucht hat eine passive Chance gegnerische\n&eR\u00FCstung zu besch\u00E4digen. Dieser Schaden steigt mit deinem Axt-\n&eLevel. -Guides.Excavation.Section.0 = &3\u00DCber Graben:\n&eGraben ist die F\u00E4higkeit Sch\u00E4tze im Dreck zu finden.\n&eDurch Aufgraben des Landes wirst du Sch\u00E4tze finden.\n&eJe l\u00E4nger du das tust, desto mehr Sch\u00E4tze findest du.\n\n&3XP ZUWACHS:\n&eXP erh\u00E4ltst du durch Schaufeln.\n&eNur bestimmte Materialen geben XP und Sch\u00E4tze. +Guides.Excavation.Section.0 = &3\u00DCber Graben:\n&eGraben ist die F\u00E4higkeit Sch\u00E4tze im Dreck zu finden.\n&eDurch Aufgraben des Landes wirst du Sch\u00E4tze finden.\n&eJe l\u00E4nger du das tust, desto mehr Sch\u00E4tze findest du.\n\n&3XP-Zuwachs:\n&eXP erh\u00E4ltst du durch Schaufeln.\n&eNur bestimmte Materialen geben XP und Sch\u00E4tze. Guides.Excavation.Section.1 = &3Kompatible Materialien:\n&eGras, Erde, Sand, Lehm, Kies, Myzel, Seelensand, Schnee Guides.Excavation.Section.2 = &3Wie funktioniert der Giga-Bohrer?\n&eHalte eine Schaufel in der Hand und mach Rechtsklick.\n&eVon nun an hast du ca. 4 Sekunden um einen kompatiblem\n&eBlock abzubauen.\n&eDaraufhin wird der Giga-Bohrer aktiviert. Guides.Excavation.Section.3 = &3Was ist der Giga-Bohrer?\n&eGiga-Bohrer ist eine F\u00E4higkeit deren Dauer vom Graben-Skill\n&eabh\u00E4ngt.\n&eEs verdreifacht die Chance Sch\u00E4tze zu finden\n&eund erm\u00F6glicht sofortiges Abbauen kompatibler Materialien. Guides.Excavation.Section.4 = &3Wie funktioniert der Schatz-J\u00E4ger?\n&eJeder m\u00F6gliche Schatz hat seine eigene Level-Voraussetzung\n&eum zu erscheinen, folglich ist es schwer&ezu sagen inwiefern es \n&edir hilft ein h\u00F6heres Level zu haben.\n&eJe h\u00F6her das Level, desto mehr Sch\u00E4tze k\u00F6nnen gefunden\n&ewerden. Guides.Excavation.Section.5 = Beachte au\u00DFerdem, dass jedes kompatible Material seine\n&eeigenen einzigartigen Sch\u00E4tze hat.\n&eAnders ausgedr\u00FCckt: Sch\u00E4tze die du in Kies findest\n&egibt es nicht zwingend in Erde. -Guides.Fishing.Section.0 = &3\u00DCber Angeln:\n&eMit dem Angeln-Skill ist Angeln wieder aufregend!\n&eFinde versteckte Sch\u00E4tze oder rei\u00DFe Items von Monstern.\n\n&3XP ZUWACHS:\n&eFang Fische. +Guides.Fishing.Section.0 = &3\u00DCber Angeln:\n&eMit dem Angeln-Skill ist Angeln wieder aufregend!\n&eFinde versteckte Sch\u00E4tze oder rei\u00DFe Items von Monstern.\n\n&3XP-Zuwachs:\n&eFange Fische. Guides.Fishing.Section.1 = &3Wie funktioniert der Schatz-J\u00E4ger?\n&eMit dieser F\u00E4higkeit kannst du beim Angeln Sch\u00E4tze finden.\n&eDiese k\u00F6nnen sogar verzaubert sein!\n&eJeder m\u00F6gliche Schatz kann mit jedem Level gefunden\n&ewerden. Die H\u00E4ufigkeit h\u00E4ngt von dem Wert des Items ab.\n&eJe h\u00F6her der Angeln-Skill ist, desto einfacher wird es\n&ewertvolle Sch\u00E4tze zu finden. Guides.Fishing.Section.2 = &3Wie funktioniert Eisangeln?\n&eMit dieser F\u00E4higkeit kannst du in Eisseen angeln!\n&eWirf deine Angeln in einem Eissee aus\n&eum ein kleines Loch zum Angeln zu erstellen. Guides.Fishing.Section.3 = &3Wie funktioniert die Profiangel?\n&eMit dieser passiven F\u00E4higkeit bei\u00DFen mehr Fische an.\n&eSobald die F\u00E4higkeit freigeschaltet ist bringt das Angeln\n&ein einem Boot oder Ozean die doppelte \n&eAnbei\u00DFchance. @@ -449,15 +449,15 @@ Guides.Fishing.Section.4 = &3Wie funktioniert Rei\u00DFen?\n&eDiese F\u00E4higke Guides.Fishing.Section.5 = &3Wie funktioniert die Fischer-Mahlzeit?\n&eDu wirst beim Essen von Fisch besser satt. Guides.Fishing.Section.6 = &3Bemerkung zum Angeln:\n&eAngel-Drops sind vollkommen anpassbar.\n&eErgebnisse unterscheiden sich deshalb von Server zu Server. Guides.Header = &6-=&a{0} Anleitung&6=- -Guides.Herbalism.Section.0 = &3\u00DCber Kr\u00E4uterkunde\n&eIn Kr\u00E4uterkunde geht es um das Ernten.\n\n&3XP ZUWACHS:\n&eErnte Pflanzen. +Guides.Herbalism.Section.0 = &3\u00DCber Kr\u00E4uterkunde\n&eIn Kr\u00E4uterkunde geht es um das Ernten.\n\n&3XP-Zuwachs:\n&eErnte Pflanzen. Guides.Herbalism.Section.1 = &3Kompatible Pflanzen:\n&eWeizen, Kartoffeln, Karotten, Melonen, K\u00FCrbisse,\n&eZuckerrohr, Kakaobohnen, Blumen, Kakteen,\n&ePilze, Netherwarzen, Seerosen und Ranken. Guides.Herbalism.Section.2 = &3Wie funktioniert Gr\u00FCnes Land?\n&eGr\u00FCnes Land ist eine aktive F\u00E4higkeit die du aktivierst indem du\n&emit einer Harke in der Hand rechtsklickst.\n&eGr\u00FCnes Land erm\u00F6glicht einen 3-fachen Ertrag beim Ernten.\n&eAu\u00DFerdem erm\u00F6glich es Leben einzuhauchen und sie\n&emithilfe von Samen aus dem Inventar zu verwandeln. Guides.Herbalism.Section.3 = &3Wie funktioniert der Gr\u00FCne Daumen (Samen)?\n&eDiese passive F\u00E4higkeit pflanz automatisch beim Ernten nach.\n&eDer Erfolg h\u00E4ngt vom Kr\u00E4uterkunde Level ab. -Guides.Herbalism.Section.4 = &3Wie funktioniert der Gr\u00FCne Daumen(Blocks)?\n&eDiese aktive F\u00E4higkeit erm\u00F6glich es Bl\u00F6cke in ihre \n&e"naturverwandte" Form zu verwandeln. Klicke dazu mit der\n&erechten Maustaste auf einen Block, w\u00E4hrend du Samen in\n&eder Hand h\u00E4ltst. \n&ePro Versuch kostet es dich einen Samen.\n&eDer Erfolg h\u00E4ngt vom Kr\u00E4uterkunde-Level ab. +Guides.Herbalism.Section.4 = &3Wie funktioniert der Gr\u00FCne Daumen (Bl\u00F6cke)?\n&eDiese aktive F\u00E4higkeit erm\u00F6glich es Bl\u00F6cke in ihre \n&e"naturverwandte" Form zu verwandeln. Klicke dazu mit der\n&erechten Maustaste auf einen Block, w\u00E4hrend du Samen in\n&eder Hand h\u00E4ltst. \n&ePro Versuch kostet es dich einen Samen.\n&eDer Erfolg h\u00E4ngt vom Kr\u00E4uterkunde-Level ab. Guides.Herbalism.Section.5 = &3Wie funktioniert das Bauernfr\u00FChst\u00FCck?\n&eDu wirst beim Essen von Brot, Keksen, Melonen, Pilzsuppe,\n&eKarotten und Kartoffeln satter. Guides.Herbalism.Section.6 = &3Wie funktioniert Hylians Gl\u00FCck?\n&eDiese passive F\u00E4higkeit gibt dir eine Chance Items zu finden\n&ewenn du bestimmte Bl\u00F6cke mit dem Schwert abbaust. Guides.Herbalism.Section.7 = &3Wie funktionieren Doppeldrops?\n&eDu erh\u00E4ltst beim Ernten mehr Ertrag. -Guides.Mining.Section.0 = &3\u00DCber Bergbau:\n&eIm Bergbau musst du Steine und Erze sammeln. Du erh\u00E4ltst\n&eab und zu zus\u00E4tzliche Drops.\n\n&3XP ZUWACHS:\n&eUm Erfahrung zu sammeln musst du mit der Spitzhacke abbauen.\n&eNur bestimmte Bl\u00F6cke geben XP. +Guides.Mining.Section.0 = &3\u00DCber Bergbau:\n&eIm Bergbau musst du Steine und Erze sammeln. Du erh\u00E4ltst\n&eab und zu zus\u00E4tzliche Drops.\n\n&3XP-Zuwachs:\n&eUm Erfahrung zu sammeln musst du mit der Spitzhacke abbauen.\n&eNur bestimmte Bl\u00F6cke geben XP. Guides.Mining.Section.1 = &3Kompatible Materialien:\n&eStein, Kohleerz, Eisenerz, Golderz, Diamanterz, Redstoneerz,\n&eLapiserz, Obsidian, Bemooster Bruchstein, Endstein,\n&eGlowstone, und Netherrack. Guides.Mining.Section.2 = &3Wie funktioniert der Super-Brecher?:\n&eMache einen Rechtsklick w\u00E4hrend du eine Spitzhacke in der\n&eHand h\u00E4ltst.\n&eVon nun an hast du ungef\u00E4hr 4 Sekunden um ein mit Bergbau\n&ekompatibles Material abzubauen, daraufhin wird der Super-Brecher\n&eaktiviert. Guides.Mining.Section.3 = &3Was ist der Super-Brecher?\n&eSuper-Brecher ist eine F\u00E4higkeit deren Dauer\n&evom Bergbau-Skill abh\u00E4ngt. Es verdreifacht die \n&eChance Sch\u00E4tze zu finden und erm\u00F6glicht\n&esofortiges Abbauen kompatibler Materialien. @@ -465,45 +465,45 @@ Guides.Mining.Section.4 = &3Wie benutzt man Z\u00FCndstoff?:\n&eHalte eine Spitz Guides.Mining.Section.5 = &3Wie funktioniert Z\u00FCndstoff?\n&eZ\u00FCndstoff ist eine F\u00E4higkeit mit einer Abklingzeit, deren St\u00E4rke\n&evom Level abh\u00E4ngt. Sie erlaubt dir beim Abbauen mit TNT dieses\n&eaus der Ferne zu z\u00FCnden. Z\u00FCndstoff besteht aus 3 Teilen.\n&eErstens dem Sprengmeister mit gr\u00F6\u00DFeren Explosionen.\n&eZweitens dem Explosions-Experten, der Schaden von TNT\n&ereduziert.\n&eDie dritte F\u00E4higkeit erh\u00F6ht einfach den Erzertrag\n&eund reduziert den Schutt. Guides.Page.Invalid = Keine g\u00FCltige Seitenzahl! Guides.Page.OutOfRange = Es gibt nur insgesamt {0} Seiten. -Guides.Repair.Section.0 = &3\u00DCber Reparatur:\n&eReparatur erlaubt dir an einem Eisenblock Werkzeuge und\n&eWaffen zu reparieren.\n\n&3XP ZUWACHS:\n&eRepariere Werkzeuge am Eisenblock-Amboss\n&cAchtung: &eDas ist nicht der normale Minecraft Amboss! +Guides.Repair.Section.0 = &3\u00DCber Reparatur:\n&eReparatur erlaubt dir an einem Eisenblock Werkzeuge und\n&eWaffen zu reparieren.\n\n&3XP-Zuwachs:\n&eRepariere Werkzeuge am Eisenblock-Amboss\n&cAchtung: &eDas ist nicht der normale Minecraft Amboss! Guides.Repair.Section.1 = &3Wie kann ich Reparatur verwenden?\n&ePlatziere einen mcMMO Amboss, halte das zu reparierende Item\n&ein der Hand und klicke mit der rechten Maustaste auf ihn. Zum\n&eReparieren ben\u00F6tigst du die Ausgangsmaterialien im Inventar,\n&ediese werden dir im Zuge der Reparatur abgezogen. Guides.Repair.Section.2 = &3Wie funktioniert der Reparatur Meister?\n&eMit dem Reparatur Meister wird dein Werkzeug ein bisschen\n&ebesser als normalerweise repariert.\n&eDer Bonus ist abh\u00E4ngig vom Reparatur Level. Guides.Repair.Section.3 = &3Wie funktioniert Super-Reparatur?\n&eMit Super-Reparatur werden ab und zu deine Items\n&edoppelt so gut repariert. Guides.Repair.Section.4 = &3Wie funktioniert Arkanes Schmieden?\n&eDiese F\u00E4higkeit erm\u00F6glicht dir mit einer gewissen\n&eChance Verzauberungen auf Items zu erhalten.\n&eVerzauberungen k\u00F6nnen erhalten werden, vermindert werden oder\n&eganz verloren gehen. -Guides.Salvage.Section.0 = &3\u00DCber Verwerten:\n&eMit einem Goldamboss kannst du R\u00FCstungen und\n&eWerkzeuge verwerten.\n\n&3XP ZUWACHS:\n&eVerwerten ist ein vom Angeln und Reparieren abh\u00E4ngiger Skill.\n&eSein Level ist die H\u00E4lfte von deren Summe. +Guides.Salvage.Section.0 = &3\u00DCber Verwerten:\n&eMit einem Goldamboss kannst du R\u00FCstungen und\n&eWerkzeuge verwerten.\n\n&3XP-Zuwachs:\n&eVerwerten ist ein vom Angeln und Reparieren abh\u00E4ngiger Skill.\n&eSein Level ist die H\u00E4lfte von deren Summe. Guides.Salvage.Section.1 = &3Wie funktioniert Verwerten?\n&ePlatziere einen Goldamboss und rechtsklicke mit dem Item in\n&eder Hand. Das Item wird zerst\u00F6rt und in seine\n&eBestandteile zerlegt.\n\n&eBeispielsweise gibt eine Eisenaxt Eisenbarren. Guides.Salvage.Section.2 = &3Wie funktioniert Fortgeschrittenes Verwerten?\n&eSobald freigeschaltet, kannst du besch\u00E4digte Items verwerten.\n&eDer Ertrag steigt mit dem Level.\n&eDer Mindestertrag ist immer 1 Item, ansonsten kannst du nicht\n&everwerten. Guides.Salvage.Section.3 = &3Zur Verbildlichung ein Beispiel:\n&eVerwerten wir eine Goldspitzhacke mit 80%\n&eHaltbarkeit, bedeutet das, dass wir nur 2 Gold bekommen\n&ek\u00F6nnen (Spitzhacke=3 Goldbarren, also jeder 33,33%\n&eHaltbarkeit) was 66% entspricht. Wenn dein\n&eErtragsprozentsatz unter 66% liegt wirst du keine 2 Barren\n&ebekommen k\u00F6nnen. Wenn sie dar\u00FCber ist, kannst du den\n&e"gesamten Betrag" bekommen, der aus 2 Eisenbarren besteht. Guides.Salvage.Section.4 = &3Wie funktioniert Arkanes Verwerten?\n&eDiese F\u00E4higkeit erm\u00F6glicht es verzauberte B\u00FCcher beim\n&eVerwerten von verzauberten Items zu bekommen.\n&eVerzauberungen k\u00F6nnen vollkommen oder teilweise extrahiert\n&ewerden.\n&eBei einer teilweisen Extraktion wird das Verzauberungslevel\n&ereduziert. Guides.Smelting.Section.0 = Kommt irgendwann mal... -Guides.Swords.Section.0 = &3\u00DCber Schwerter:\n&eDiese F\u00E4higkeit gibt Kampfboni bei Benutzung\n&edes Schwertes.\n\n&3XP ZUWACHS:\n&eVerletze Monster und Spieler mit dem Schwert. +Guides.Swords.Section.0 = &3\u00DCber Schwerter:\n&eDiese F\u00E4higkeit gibt Kampfboni bei Benutzung\n&edes Schwertes.\n\n&3XP-Zuwachs:\n&eVerletze Monster und Spieler mit dem Schwert. Guides.Swords.Section.1 = &3Wie funktioniert der S\u00E4gezahnschlag?\n&eS\u00E4gezahnschlag ist eine aktive F\u00E4higkeit die du mit Rechtsklick \n&eaktivierst.\n&eMit dieser F\u00E4higkeit kannst du Fl\u00E4chenschaden verteilen.\n&eAu\u00DFerdem blutet das Ziel f\u00FCr kurze Zeit. Guides.Swords.Section.2 = &3Wie funktioniert der Gegenangriff?\n&eGegenangriff ist eine aktive F\u00E4higkeit,\n&ebei der Angriffe von Monstern beim Blocken um bis zu 50%\n&edes erhaltenen Schadens reflektiert werden k\u00F6nnen. Guides.Swords.Section.3 = &3Wie funktioniert Blutung?\n&eBlutung f\u00FCgt den Gegnern alle 2 Sekunden Schaden zu. Das\n&eBluten geht solange bis die F\u00E4higkeit ausl\u00E4uft oder der\n&eGegner stirbt.\n&eDie Dauer der Blutung erh\u00F6ht sich mit dem Schwert-Skill. -Guides.Taming.Section.0 = &3\u00DCber Z\u00E4hmen:\n&eZ\u00E4hmen gibt dem Spieler diverse Kampfboni beim Kampf mit\n&egez\u00E4hmten W\u00F6lfen.\n\n&3XP ZUWACHS:\n&eUm XP zu bekommen musst du Tiere z\u00E4hmen oder mit\n&edeinen W\u00F6lfen k\u00E4mpfen. +Guides.Taming.Section.0 = &3\u00DCber Z\u00E4hmen:\n&eZ\u00E4hmen gibt dem Spieler diverse Kampfboni beim Kampf mit\n&egez\u00E4hmten W\u00F6lfen.\n\n&3XP-Zuwachs:\n&eUm XP zu bekommen musst du Tiere z\u00E4hmen oder mit\n&edeinen W\u00F6lfen k\u00E4mpfen. Guides.Taming.Section.1 = &3Wie funktioniert Ruf der Wildnis?\n&eRuf der Wildnis ist eine aktive F\u00E4higkeit die dir erlaubt\n&eeinen Wolf, einen Ozelot oder ein Pferd an deine Seite zu\n&erufen.\n&eDas tust du, indem du linksklickst w\u00E4hrend du Knochen, Fisch\n&eoder \u00C4pfel in der Hand h\u00E4ltst. Guides.Taming.Section.2 = &3Wie funktioniert Bestienkunde?\n&eBestienkunde erlaubt es die Haustiere zu inspizieren.\n&eHalte einen Knochen in der Hand und klick mit linker Maustaste\n&eauf das Haustier um Bestienkunde zu aktivieren. Guides.Taming.Section.3 = &3Wie funktioniert Aufschlitzen?\n&eAufschlitzen ist eine passive F\u00E4higkeit die beim Ziel\n&edes Wolfes Blutungen hervorrufen kann. Der Erfolg h\u00E4ngt\n&evom Z\u00E4hmen-Level ab. -Guides.Taming.Section.4 = &3Wie funktionieren gesch\u00E4rfte Klauen?\n&eGesch\u00E4rfte Klauen geben Zusatzschaden in Abh\u00E4ngigkeit\n&evom Z\u00E4hmen Level. +Guides.Taming.Section.4 = &3Wie funktionieren gesch\u00E4rfte Klauen?\n&eGesch\u00E4rfte Klauen geben Zusatzschaden in Abh\u00E4ngigkeit\n&evom Z\u00E4hmen-Level. Guides.Taming.Section.5 = &3Wie funktioniert Umweltbewusst?\n&eDiese passive F\u00E4higkeit erm\u00F6glich W\u00F6lfen sich zu dir zu\n&eteleportieren wenn sie in die N\u00E4he von Gefahren wie\n&eKakteen/Lava kommen.\n&eZus\u00E4tzlich sind W\u00F6lfe immun gegen Fallschaden. Guides.Taming.Section.6 = &3Wie funktioniert Dicker Pelz?\n&eDiese passive F\u00E4higkeit reduziert Schaden und\n&emacht W\u00F6lfe feuerresistent. Guides.Taming.Section.7 = &3Wie funktioniert Schocksicher?\n&eDiese passive F\u00E4higkeit reduziert den Schaden\n&edurch Explosionen. Guides.Taming.Section.8 = &3Wie funktioniert Schnell-Imbiss?\n&eDiese passive F\u00E4higkeit gibt dem Wolf eine Chance sich zu\n&eerholen wann immer er einen Gegner verletzt. -Guides.Unarmed.Section.0 = &3\u00DCber Unbewaffnet:\n&eMit Unbewaffnet kann der echte Mann endlich mit seinen\n&eF\u00E4usten angemessen zuschlagen.\n\n&3XP ZUWACHS:\n&eK\u00E4mpfe unbewaffnet gegen Monster und andere Spieler. +Guides.Unarmed.Section.0 = &3\u00DCber Unbewaffnet:\n&eMit Unbewaffnet kann der echte Mann endlich mit seinen\n&eF\u00E4usten angemessen zuschlagen.\n\n&3XP-Zuwachs:\n&eK\u00E4mpfe unbewaffnet gegen Monster und andere Spieler. Guides.Unarmed.Section.1 = &3Wie funktioniert Berserker?\n&eBerserker ist eine aktive F\u00E4higkeit die mit Rechtsklick\n&eaktiviert wird.\n&eIm Berserker-Modus f\u00FCgst du 50% mehr Schaden zu und\n&ekannst weiche Materialien wie Gras und Erde sofort abbauen. Guides.Unarmed.Section.2 = &3Wie funktioniert der Eiserne Arm?\n&eEiserner Arm erh\u00F6ht den Monstern und Spielern mit den\n&eF\u00E4usten zugef\u00FCgten Schaden. Guides.Unarmed.Section.3 = &3Wie funktioniert Pfeilablenkung?\n&ePfeilablenkung ist eine passive F\u00E4higkeit die ab und zu\n&ePfeile von Skeletten und angreifenden Spielern ablenkt.\n&eDiese Pfeile prallen einfach ab und fallen auf den Boden. Guides.Unarmed.Section.4 = &3Wie funktioniert der Eiserne Griff?\n&eEiserner Griff ist eine passive F\u00E4higkeit die Entwaffnung\n&everhindert. Mit h\u00F6herem Level ist es umso einfacher\n&eEntwaffnung zu verhindern. Guides.Unarmed.Section.5 = &3Wie funktioniert Entwaffnen?\n&eDiese passive F\u00E4higkeit erm\u00F6glich es den Gegner zu\n&eentwaffnen, sodass seine Waffe auf den Boden f\u00E4llt. Guides.Usage = Der Befehl ist /{0} ? [Seite] -Guides.Woodcutting.Section.0 = &3\u00DCber Holzf\u00E4ller:\n&eIm Holzf\u00E4llen geht es um das F\u00E4llen von B\u00E4umen.\n\n&3XP ZUWACHS:\n&eDu bekommst XP f\u00FCr das Abholzen von Baumst\u00E4mmen. +Guides.Woodcutting.Section.0 = &3\u00DCber Holzf\u00E4ller:\n&eIm Holzf\u00E4llen geht es um das F\u00E4llen von B\u00E4umen.\n\n&3XP-Zuwachs:\n&eDu bekommst XP f\u00FCr das Abholzen von Baumst\u00E4mmen. Guides.Woodcutting.Section.1 = &3Wie funktioniert der Baumf\u00E4ller?\n&eBaumf\u00E4ller ist eine aktive F\u00E4higkeit. Mache mit der Axt in der\n&eHand einen Rechtsklick um sie zu aktivieren. Der Baum\n&ewird sofortig gef\u00E4llt und alle St\u00E4mme abgebaut. Guides.Woodcutting.Section.2 = &3Wie funktioniert Bl\u00E4ttersturm?\n&eBl\u00E4ttersturm ist eine passive F\u00E4higkeit die Bl\u00E4tter\n&ebei Ber\u00FChrung mit der Axt sofortig bricht. Standardm\u00E4\u00DFig\n&ewird diese F\u00E4higkeit bei Level 100 freigeschaltet. Guides.Woodcutting.Section.3 = &3Wie funktionieren Doppel-Drops?\n&eDiese passive F\u00E4higkeit gibt dir ab und zu doppelten\n&eErtrag f\u00FCr jeden Stamm den du f\u00E4llst. Hardcore.DeathStatLoss.Name = Skillverlust bei Tod: Hardcore.DeathStatLoss.PercentageChanged = &6[mcMMO] Der Verlustprozentsatz wurde auf {0} ge\u00E4ndert. -Hardcore.DeathStatLoss.PlayerDeath = &6[mcMMO] &4Du hast durch den Tod&9{0}&4 Level verloren. +Hardcore.DeathStatLoss.PlayerDeath = &6[mcMMO] &4Du hast durch den Tod &9{0}&4 Level verloren. Hardcore.Mode.Disabled = &6[mcMMO] Hardcore Modus {0} deaktiviert f\u00FCr {1}. Hardcore.Mode.Enabled = &6[mcMMO] Hardcore Modus {0} aktiviert f\u00FCr {1}. Hardcore.Vampirism.Killer.Failure = &6[mcMMO] &e{0}&7 war nicht erfahren genug um dir Wissen zu hinterlassen. @@ -511,14 +511,14 @@ Hardcore.Vampirism.Killer.Success = &6[mcMMO] &3Du hast &9{0}&3 Level von &e{1} Hardcore.Vampirism.Name = Vampirismus Hardcore.Vampirism.PercentageChanged = &6[mcMMO] Der Vampirismus Prozentsatz wurde auf {0} ge\u00E4ndert. Hardcore.Vampirism.Victim.Failure = &6[mcMMO] &e{0}&7 hat es nicht geschafft Wissen von dir zu stehlen! -Hardcore.Vampirism.Victim.Success = &6[mcMMO] &e{0}&4 hat&9{1}&4 Level von dir gestohlen! +Hardcore.Vampirism.Victim.Success = &6[mcMMO] &e{0}&4 hat &9{1}&4 Level von dir gestohlen! Herbalism.Ability.GTe.NeedMore = Du brauchst mehr Samen um Gr\u00FCnes Land zu verbreiten. Herbalism.Ability.GTh = &a**Gr\u00FCner Daumen** Herbalism.Ability.GTh.Fail = **Gr\u00FCner Daumen gescheitert** Herbalism.Ability.Lower = &7&o**Du senkst deine Harke.** Herbalism.Ability.Ready = &a&o**Du hebst deine Harke...** -Herbalism.Ability.ShroomThumb.Fail = **Gr\u00FCne Zehe gescheitert** +Herbalism.Ability.ShroomThumb.Fail = **Gr\u00FCner Daumen gescheitert** Herbalism.Effect.4 = Gr\u00FCner Daumen Herbalism.HylianLuck = &aHeute ist das Gl\u00FCck von Hyrule mit dir! Herbalism.Listener = Kr\u00E4uterkunde: @@ -546,10 +546,10 @@ Herbalism.SubSkill.HylianLuck.Description = Gibt eine kleine M\u00F6glichkeit, s Herbalism.SubSkill.HylianLuck.Name = Hylian Gl\u00FCck Herbalism.SubSkill.HylianLuck.Stat = Hylian Gl\u00FCck Chance Herbalism.SubSkill.ShroomThumb.Description = Verbreite Myzel auf Gras und Erde. -Herbalism.SubSkill.ShroomThumb.Name = Pilz-Zehe -Herbalism.SubSkill.ShroomThumb.Stat = Pilz-Zehe Chance +Herbalism.SubSkill.ShroomThumb.Name = Pilz-Daumen +Herbalism.SubSkill.ShroomThumb.Stat = Pilz-Daumen Chance -Holiday.Anniversary = &9Alles gute zu mcMMO's {0} j\u00E4hrigen Geburtstag!\n&9In Ehren von nossr50 und all den anderen flei\u00DFigen Entwicklern, hier ist eine kleine Feuerwerk Show! +Holiday.Anniversary = &9Alles Gute zu mcMMO's {0} j\u00E4hrigen Geburtstag!\n&9In Ehren von nossr50 und all den anderen flei\u00DFigen Entwicklern ist hier eine kleine Feuerwerk-Show! Holiday.AprilFools.Levelup = &6{0} ist jetzt Level &a{1}&6! Inspect.Offline = &cDu hast nicht die Rechte um Offline-Spieler zu inspizieren! @@ -561,7 +561,7 @@ 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! -Item.ChimaeraWing.Pass = **CHIMAERA FL\u00DCGEL* +Item.ChimaeraWing.Pass = **Chimarea Fl\u00FCgel** Item.FluxPickaxe.Lore.1 = &7Hat eine Chance Erze sofort zu schmelzen. Item.FluxPickaxe.Lore.2 = &7Ben\u00F6tigt Schmelzen-Level {0} oder mehr. Item.FluxPickaxe.Name = Schmelzhacke @@ -620,14 +620,14 @@ JSON.Woodcutting = Holzf\u00E4llen LevelCap.PowerLevel = &6(&amcMMO&6) &eDu hast das Level-Limit von &c{0}&e erreicht. Du kannst deine F\u00E4higkeiten nun nicht mehr weiter verbessern. LevelCap.Skill = &6(&amcMMO&6) &eDu hast das Level-Limit von &c{0}&e f\u00FCr &6{1}&e erreicht. Du kannst diese F\u00E4higkeit von nun an nicht mehr weiter verbessern. -Locale.Reloaded = &aDie Sprachdateien wurden neugeladen! +Locale.Reloaded = &aDie Sprachdateien wurden neu geladen! MOTD.Donate = &3Spenden Info: MOTD.Hardcore.DeathStatLoss.Stats = &6[mcMMO] &3Skillverlust bei Tod: &4{0}% MOTD.Hardcore.Enabled = &6[mcMMO] &3Hardcore Modus aktiviert: &4{0} MOTD.Hardcore.Vampirism.Stats = &6[mcMMO] &3Vampirismus Prozentsatz: &4{0}% MOTD.PerksPrefix = &6[mcMMO Boni] -MOTD.Version = &6[mcMMO] Verwende Version&3{0} +MOTD.Version = &6[mcMMO] Verwende Version &3{0} MOTD.Version.Overhaul = &6[mcMMO] &3\u00DCberholungs Era&6 - &3{0} MOTD.Website = &6[mcMMO] &a{0}&e - mcMMO Website @@ -648,7 +648,7 @@ Mining.Skills.SuperBreaker.On = &a&o**Super-Brecher aktiviert** Mining.Skills.SuperBreaker.Other.Off = {0}s &cSuper-Brecher&a ist &aausgelaufen. Mining.Skills.SuperBreaker.Other.On = &a{0}&2 benutzte &cSuper-Brecher! Mining.Skills.SuperBreaker.Refresh = &aDein &eSuper-Brecher &aist wieder bereit! -Mining.SubSkill.BiggerBombs.Description = Erh\u00F6ht den Explosions-Radius. +Mining.SubSkill.BiggerBombs.Description = Erh\u00F6ht den Explosionsradius. Mining.SubSkill.BiggerBombs.Name = Sprengmeister Mining.SubSkill.BlastMining.Description = Bonus beim Abbauen mit TNT. Mining.SubSkill.BlastMining.Name = Z\u00FCndstoff @@ -785,7 +785,7 @@ Profile.Loading.FailurePlayer = &cmcMMO hat Probleme beim Laden deiner Daten nac Profile.Loading.Success = &aDein Profil wurde geladen. Profile.PendingLoad = &cDeine mcMMO Daten wurden noch nicht geladen. -Reminder.Squelched = &7Erinnerung: Du erh\u00E4lst aktuell keinerlei Benachrichtigungen von mcMMO, um dies zu \u00E4ndern, nutze den /mcnotify Befehl. Dies ist eine st\u00FCndliche, automatische Erinnerung. +Reminder.Squelched = &7Erinnerung: Du erh\u00E4ltst aktuell keinerlei Benachrichtigungen von mcMMO, um dies zu \u00E4ndern, nutze den /mcnotify Befehl. Dies ist eine st\u00FCndliche, automatische Erinnerung. Repair.Arcane.Downgrade = Zauber-Wert des Gegenstands vermindert. Repair.Arcane.Fail = Der Gegenstands wurde entzaubert. @@ -863,7 +863,7 @@ Scoreboard.Misc.CurrentXP = &aAktuelle XP Scoreboard.Misc.Level = &3Level Scoreboard.Misc.Overall = &6Insgesamt Scoreboard.Misc.PowerLevel = &6Gesamt-Level -Scoreboard.Misc.RemainingXP = Verbliebene XP +Scoreboard.Misc.RemainingXP = Verbleibende XP Server.ConsoleName = &e[Server] @@ -890,7 +890,7 @@ Smelting.Effect.4 = Vanilla XP-Boost Smelting.Effect.5 = Erh\u00F6ht die erhaltene Erfahrung beim Schmelzen. Smelting.Listener = Schmelzen: Smelting.SkillName = Schmelzen -Smelting.SubSkill.FluxMining.Description = M\u00F6glichkeit, Erze direkt beim Abbauen zu schmelzen. +Smelting.SubSkill.FluxMining.Description = M\u00F6glichkeit, um Erze direkt beim Abbauen zu schmelzen. Smelting.SubSkill.FluxMining.Name = Schmelztiegel Smelting.SubSkill.FluxMining.Stat = Schmelztiegel Chance Smelting.SubSkill.FuelEfficiency.Description = Erh\u00F6he die Brenndauer des Brennstoffes in \u00D6fen. @@ -936,7 +936,7 @@ Swords.SubSkill.Rupture.Stat.Extra = Entzweiung: &a{0} ticks [{1} Schaden gegen Swords.SubSkill.SerratedStrikes.Description = {0} Fl\u00E4chenschaden, Fl\u00E4chenblutung+ Swords.SubSkill.SerratedStrikes.Name = S\u00E4gezahnschlag Swords.SubSkill.SerratedStrikes.Stat = S\u00E4gezahnschlag L\u00E4nge -Swords.SubSkill.Stab.Description = F\u00FCgt extra Schaden zu deinem Angriff hinzu. +Swords.SubSkill.Stab.Description = F\u00FCgt deinem Angriff extra Schaden hinzu. Swords.SubSkill.Stab.Name = Erstechen Swords.SubSkill.Stab.Stat = Schaden durch Erstechen Swords.SubSkill.SwordsLimitBreak.Description = \u00DCberschreite deine Grenzen. @@ -946,7 +946,7 @@ Swords.SubSkill.SwordsLimitBreak.Stat = Bonus-Schaden durch \u00DCberwindung Taming.Ability.Bonus.0 = Umweltbewusst Taming.Ability.Bonus.1 = W\u00F6lfe weichen Gefahren aus. Taming.Ability.Bonus.10 = Heiliger Hund -Taming.Ability.Bonus.11 = Regenerierung auch mit Tr\u00E4nken und Zaubern m\u00F6glich. +Taming.Ability.Bonus.11 = Regenerierung ist auch mit Tr\u00E4nken und Zaubern m\u00F6glich. Taming.Ability.Bonus.2 = Dicker Pelz Taming.Ability.Bonus.3 = 1/{0} Schaden, Feuer-Resistent Taming.Ability.Bonus.4 = Schock-Sicher @@ -968,7 +968,7 @@ Taming.SkillName = Z\u00C4HMEN Taming.SubSkill.BeastLore.Description = Knochenschlag inspiziert W\u00F6lfe und Ozelots. Taming.SubSkill.BeastLore.Name = Bestienkunde Taming.SubSkill.CallOfTheWild.Description = Beschw\u00F6re ein Tier an deine Seite. -Taming.SubSkill.CallOfTheWild.Description.2 = &7RdW: B\u00FCcken und Linksklick mit {0} {1} (Ozelot), {2} {3} (Wolf), {4} {5} (Pferd) +Taming.SubSkill.CallOfTheWild.Description.2 = &7Ruf der Wildnis: B\u00FCcken und Linksklick mit {0} {1} (Ozelot), {2} {3} (Wolf), {4} {5} (Pferd) Taming.SubSkill.CallOfTheWild.Name = Ruf der Wildnis Taming.SubSkill.EnvironmentallyAware.Description = Kaktus/Lava-Furcht, Immun gegen Fallschaden Taming.SubSkill.EnvironmentallyAware.Name = Umweltbewusst @@ -1004,11 +1004,11 @@ Unarmed.Ability.Bonus.1 = +{0} Schadens-Bonus Unarmed.Ability.IronGrip.Attacker = Dein Gegner hat einen eisernen Griff! Unarmed.Ability.IronGrip.Defender = &aDein eiserner Griff hat dich vor Entwaffnung gesch\u00FCtzt! Unarmed.Ability.Lower = &7&o**Du senkst deine F\u00E4uste.** -Unarmed.Ability.Ready = &a&o**Du hebste deine F\u00E4uste...** +Unarmed.Ability.Ready = &a&o**Du hebst deine F\u00E4uste...** Unarmed.Listener = Faustkampf: Unarmed.SkillName = Faustkampf Unarmed.Skills.Berserk.Off = **Berserker ausgelaufen** -Unarmed.Skills.Berserk.On = &a**Berserker aktiviertT** +Unarmed.Skills.Berserk.On = &a**Berserker aktiviert** Unarmed.Skills.Berserk.Other.Off = {0}s &cBerserker&a ist &aausgelaufen. Unarmed.Skills.Berserk.Other.On = &a{0}&2 benutzte &cBerserker! Unarmed.Skills.Berserk.Refresh = &aDein &eBerserker &aist wieder bereit! @@ -1020,7 +1020,7 @@ Unarmed.SubSkill.Berserk.Name = Berserker Unarmed.SubSkill.Berserk.Stat = Berserker L\u00E4nge Unarmed.SubSkill.BlockCracker.Description = Durchbreche Stein mit deinen F\u00E4usten. Unarmed.SubSkill.BlockCracker.Name = Schwarzgurt -Unarmed.SubSkill.Disarm.Description = L\u00E4sst Gegenstand aus der Hand des Feindes fallen. +Unarmed.SubSkill.Disarm.Description = L\u00E4sst den Gegenstand aus der Hand des Feindes fallen. Unarmed.SubSkill.Disarm.Name = Entwaffnen Unarmed.SubSkill.Disarm.Stat = Entwaffnen Chance Unarmed.SubSkill.IronGrip.Description = Sch\u00FCtzt dich davor, entwaffnet zu werden. diff --git a/src/main/resources/locale/locale_pl.properties b/src/main/resources/locale/locale_pl.properties index 4cbc5109c..96bc89e2e 100644 --- a/src/main/resources/locale/locale_pl.properties +++ b/src/main/resources/locale/locale_pl.properties @@ -21,7 +21,7 @@ JSON.Alchemy=Alchemia JSON.Archery=\u0141ucznictwo JSON.Axes=Siekiery JSON.Excavation=Wykopalisko -JSON.Fishing=Rybarz +JSON.Fishing=Rybak JSON.Herbalism=Zielarstwo JSON.Mining=G\u00f3rnictwo JSON.Repair=Naprawiacz @@ -29,7 +29,7 @@ JSON.Salvage=Odzyskiwacz JSON.Swords=Miecze JSON.Taming=Tresowanie JSON.Unarmed=Niezr\u0119czno\u015b\u0107 -JSON.Woodcutting=\u015acinacz Drzew +JSON.Woodcutting=Drwal JSON.URL.Website=Oficjalna strona mcMMO! JSON.URL.Discord=Oficjalny discord mcMMO! JSON.URL.Patreon=Wesprzyj nossr50 i jego projekt mcMMO na Patreon! @@ -88,7 +88,7 @@ Overhaul.Name.Alchemy=Alchemia Overhaul.Name.Archery=\u0141ucznictwo Overhaul.Name.Axes=Siekiery Overhaul.Name.Excavation=Wykopalisko -Overhaul.Name.Fishing=Rybarz +Overhaul.Name.Fishing=Rybak Overhaul.Name.Herbalism=Zielarstwo Overhaul.Name.Mining=G\u00f3rnictwo Overhaul.Name.Repair=Naprawiacz @@ -97,7 +97,7 @@ Overhaul.Name.Smelting=Przepalanie Overhaul.Name.Swords=Miecze Overhaul.Name.Taming=Tresowanie Overhaul.Name.Unarmed=Niezr\u0119czno\u015b\u0107 -Overhaul.Name.Woodcutting=\u015acinacz Drzew +Overhaul.Name.Woodcutting=Drwal # /mcMMO Command Style Stuff Commands.mcc.Header=&c---[]&amcMMO Komendy&c[]--- Commands.Other=&c---[]&aSPECJALNE KOMENDY&c[]--- @@ -112,7 +112,7 @@ XPBar.Alchemy=Alchemia Lv.&6{0} XPBar.Archery=\u0141ucznictwo Lv.&6{0} XPBar.Axes=Siekiery Lv.&6{0} XPBar.Excavation=Wykopalisko Lv.&6{0} -XPBar.Fishing=Rybarz Lv.&6{0} +XPBar.Fishing=Rybak Lv.&6{0} XPBar.Herbalism=Zielarstwo Lv.&6{0} XPBar.Mining=G\u00f3rnictwo Lv.&6{0} XPBar.Repair=Naprawiacz Lv.&6{0} @@ -121,7 +121,7 @@ XPBar.Smelting=Przepalanie Lv.&6{0} XPBar.Swords=Miecze Lv.&6{0} XPBar.Taming=Tresowanie Lv.&6{0} XPBar.Unarmed=Niezr\u0119czno\u015b\u0107 Lv.&6{0} -XPBar.Woodcutting=\u015acinacz Drzew Lv.&6{0} +XPBar.Woodcutting=Drwal Lv.&6{0} #This is just a preset template that gets used if the 'ExtraDetails' setting is turned on in experience.yml (off by default), you can ignore this template and just edit the strings above XPBar.Complex.Template={0} &3 {4}&f% &3(&f{1}&3/&f{2}&3) # XP BAR Allows for the following variables -- {0} = Skill Level, {1} Current XP, {2} XP Needed for next level, {3} Power Level, {4} Percentage of Level @@ -132,7 +132,7 @@ XPBar.Complex.Template={0} &3 {4}&f% &3(&f{1}&3/&f{2}&3) Acrobatics.Ability.Proc=&a**\u0141askawe L\u0105dowanie** Acrobatics.Combat.Proc=&a**Unik** Acrobatics.SubSkill.Roll.Stats=&6Szansa na &e{0}%&6 Szansa na \u0142\u0105ske&e {1}% -Acrobatics.SubSkill.Roll.Stat=Szansa na +Acrobatics.SubSkill.Roll.Stat=Szansa na Przewr\u00f3t Acrobatics.SubSkill.Roll.Stat.Extra=Szansa na \u0141agodny Przewr\u00f3t Acrobatics.SubSkill.Roll.Name=Przewr\u00f3t Acrobatics.SubSkill.Roll.Description=Wyl\u0105duj strategicznie, aby unikn\u0105\u0107 uszkodze\u0144. @@ -143,7 +143,7 @@ Acrobatics.SubSkill.GracefulRoll.Name=\u0141agodny przewr\u00f3t Acrobatics.SubSkill.GracefulRoll.Description=Podwaja efekt normalnego przewrotu. Acrobatics.SubSkill.Dodge.Name=Unik Acrobatics.SubSkill.Dodge.Description=Redukuje obra\u017cenia od ataku o po\u0142ow\u0119 -Acrobatics.SubSkill.Dodge.Stat=Szansa na unik +Acrobatics.SubSkill.Dodge.Stat=Szansa na Unik Acrobatics.Listener=Akrobatyka: Acrobatics.Roll.Text=&o**Przewr\u00f3t** Acrobatics.SkillName=AKROBATYKA @@ -267,7 +267,7 @@ Fishing.SkillName=W\u0118DKARSTWO #HERBALISM Herbalism.Ability.GTe.NeedMore=Potrzebujesz wi\u0119cej nasion, aby rozprzestrzeni\u0107 Zielona Tera. Herbalism.Ability.GTh.Fail=**ZIELONA TERA ZAWODZI** -Herbalism.Ability.GTh=&a**GREEN THUMB** +Herbalism.Ability.GTh=&a**ZIELONY L\u0104D** Herbalism.Ability.Lower=&7Opuszczasz swoj\u0105 motyk\u0119. Herbalism.Ability.Ready=&6Przygotowujesz&3 swoj\u0105 motyk\u0119. Herbalism.Ability.ShroomThumb.Fail=**HALUCYNKI ZAWODZ\u0104** @@ -304,22 +304,22 @@ Mining.Ability.Locked.0=ZABLOKOWANE DO {0}+ UMIEJ\u0118TNO\u015a\u0106 (PODMUCH Mining.Ability.Locked.1=ZABLOKOWANE DO {0}+ UMIEJ\u0118TNO\u015a\u0106 (WI\u0118KSZE BOMBY) Mining.Ability.Locked.2=ZABLOKOWANE DO {0}+ UMIEJ\u0118TNO\u015a\u0106 (EKSPERTYZY ROZBI\u00d3RKI) Mining.Ability.Lower=&7Opuszczasz sw\u00f3j kilof. -Mining.Ability.Ready=&3You &6ready&3 Tw\u00f3j kilof. +Mining.Ability.Ready=&6Przygotowujesz&3 sw\u00f3j kilof. Mining.SubSkill.SuperBreaker.Name=Super Niszczyciel Mining.SubSkill.SuperBreaker.Description=Pr\u0119dko\u015b\u0107+, Szansa na potr\u00f3jny \u0142up Mining.SubSkill.SuperBreaker.Stat=Trwanie: Super Niszczyciel Mining.SubSkill.DoubleDrops.Name=Podw\u00f3jny drop Mining.SubSkill.DoubleDrops.Description=Podwaja normalny \u0142up -Mining.SubSkill.DoubleDrops.Stat=Podw\u00f3jna szansa na upuszczenie +Mining.SubSkill.DoubleDrops.Stat=Podw\u00f3jna szansa na upuszczenie \u0142upu Mining.SubSkill.BlastMining.Name=Podmuch G\u00f3rnictwa Mining.SubSkill.BlastMining.Description=Premie do wydobywania z TNT -Mining.SubSkill.BlastMining.Stat=Blast Mining:&a Rank {0}/{1} &7({2}) -Mining.SubSkill.BlastMining.Stat.Extra=Blast Radius Increase: &a+{0} +Mining.SubSkill.BlastMining.Stat=Ranga Podmuchu G\u00f3rnictwa:&a {0}/{1} &7({2}) +Mining.SubSkill.BlastMining.Stat.Extra=Dodatkowy Zasi\u0119g Podmuchu G\u00f3rnictwa: &a+{0} Mining.SubSkill.BiggerBombs.Name=Wi\u0119ksze bomby Mining.SubSkill.BiggerBombs.Description=Zwi\u0119ksza promie\u0144 wybuchu -Mining.SubSkill.DemolitionsExpertise.Name=Ekspertyzy Rozbi\u00f3rki +Mining.SubSkill.DemolitionsExpertise.Name=Ekspertyza Rozbi\u00f3rki Mining.SubSkill.DemolitionsExpertise.Description=Zmniejsza obra\u017cenia zadawane TNT -Mining.SubSkill.DemolitionsExpertise.Stat=Zmniejszenie obra\u017ce\u0144 od eksperta od wyburze\u0144 +Mining.SubSkill.DemolitionsExpertise.Stat=Zmniejszenie obra\u017ce\u0144 od Eksperyza Rozbi\u00f3rki Mining.Listener=G\u00f3rnictwo: Mining.SkillName=G\u00d3RNICTWO Mining.Skills.SuperBreaker.Off=**Super Niszczyciel wy\u0142\u0105czy\u0142 si\u0119** @@ -405,7 +405,7 @@ Anvil.Unbreakable=Ten przedmiot jest niezniszczalny! #SWORDS Swords.Ability.Lower=&7Opuszczasz sw\u00f3j miecz. Swords.Ability.Ready=&6Przygotowujesz&3 sw\u00f3j miecz. -Swords.Combat.Rupture.Note=&7NOTATKA: &e1 P\u0119kni\u0119cie zdarza si\u0119 co 0,5 sekundy! +Swords.Combat.Rupture.Note=&7NOTATKA: &eP\u0119kni\u0119cie to okresowe obra\u017cenia, kt\u00f3re s\u0105 zadawane 2 razy na sekunde oraz omijaj\u0105 one zbroj\u0119! Swords.Combat.Bleeding.Started=&4 Krwawisz! Swords.Combat.Bleeding.Stopped=&7Krwawienie ju\u017c si\u0119 zatrzyma\u0142o&7! Swords.Combat.Bleeding=&a**PRZECIWNIK KRWAWI** @@ -427,7 +427,9 @@ Swords.SubSkill.SwordsLimitBreak.Name=Prze\u0142amywanie limit\u00f3w miecza Swords.SubSkill.SwordsLimitBreak.Description=Prze\u0142amywanie limit\u00f3w. Zwi\u0119kszone obra\u017cenia zadawane trudnym przeciwnikom. Przeznaczony dla PVP, zale\u017cnie od ustawie\u0144 serwera, czy zwi\u0119kszy obra\u017cenia w PVE, czy nie. Swords.SubSkill.SwordsLimitBreak.Stat=Prze\u0142amywanie limit\u00f3w max obra\u017ce\u0144 Swords.SubSkill.Rupture.Stat=Szansa na Rozerwanie -Swords.SubSkill.Rupture.Stat.Extra=Rozerwanie: &a{0} ticks [{1} DMG vs Gracz] [{2} DMG vs Moby] +Swords.SubSkill.Rupture.Stat.Extra=[[DARK_AQUA]]Czas Rozerwania: &a{0}s przeciwko Graczom, {1}s przeciwko Mobom. +Swords.SubSkill.Rupture.Stat.TickDamage=[[DARK_AQUA]]Obra\u017cenia Rozerwania na tik: &e{0}&a przeciwko Graczom, &e{1}&a przeciwko Mobom. +Swords.SubSkill.Rupture.Stat.ExplosionDamage=[[DARK_AQUA]]Obra\u017cenia eksplozji Rozerwania: &e{0}&a przeciwko Graczom, &e{1}&a przeciwko Mobom. Swords.Effect.4=Krwawienie+ z\u0105bkowane uderzenia Swords.Effect.5={0} Tick Rupture Swords.Listener=Miecze: @@ -547,8 +549,8 @@ Woodcutting.SubSkill.BarkSurgeon.Name=Chirurg Kory Woodcutting.SubSkill.BarkSurgeon.Description=Wydobywaj przydatne materia\u0142y podczas \u015bcinania drzew. Woodcutting.SubSkill.NaturesBounty.Name=Nagroda natury Woodcutting.SubSkill.NaturesBounty.Description=Zbieraj do\u015bwiadczenie z natury. -Woodcutting.Listener=\u015acinacz Drzew: -Woodcutting.SkillName=\u015aCINACZ DRZEW +Woodcutting.Listener=Drwal: +Woodcutting.SkillName=DRWAL Woodcutting.Skills.TreeFeller.Off=**\u015acinacz Drzew przesta\u0142 dzia\u0142a\u0107** Woodcutting.Skills.TreeFeller.On=&a**\u015aCINACZ DRZEW AKTYWOWANY** Woodcutting.Skills.TreeFeller.Refresh=&aTwoja umiej\u0119tno\u015b\u015b &e\u015acinacz Drzew &azosta\u0142a od\u015bwie\u017cona! @@ -822,7 +824,7 @@ Party.ItemShare.Category.Herbalism=Tresowanie Party.ItemShare.Category.Woodcutting=\u015acinanie Drzew Party.ItemShare.Category.Misc=R\u00f3\u017cne ##xp -Commands.XPGain.Acrobatics=Spadanie +Commands.XPGain.Acrobatics=Spadanie z wysoko\u015bci Commands.XPGain.Alchemy=Warzenie Mikstur Commands.XPGain.Archery=Atakowanie potwor\u00f3w Commands.XPGain.Axes=Atakowanie potwor\u00f3w @@ -831,7 +833,7 @@ Commands.XPGain.Excavation=Kopanie i znajdowanie skarb\u00f3w Commands.XPGain.Fishing=\u0141owienie Commands.XPGain.Herbalism=Zbieranie zi\u00f3\u0142 Commands.XPGain.Mining=Kopanie kamienia & rud -Commands.XPGain.Repair=Naprawa +Commands.XPGain.Repair=Naprawa u\u017cywaj\u0105c specjalnego kowad\u0142a Commands.XPGain.Swords=Atakowanie potwor\u00f3w Commands.XPGain.Taming=Rozmna\u017canie zwierz\u0105t, albo walka w/ z twoimi psami Commands.XPGain.Unarmed=Atakowanie potwor\u00f3w @@ -872,88 +874,88 @@ Guides.Page.OutOfRange=Ta strona nie istnieje, jest/s\u0105 tylko {0} stron/a/y. Guides.Usage= Prawod\u0142owe u\u017cycie to /{0} ? [strona] ##Acrobatics Guides.Acrobatics.Section.0=&3O Akrobatyce:\n&eakrobatyka to sztuka poruszania si\u0119 z wdzi\u0119kiem w mcMMO.\n&eZapewnia premie bojowe i premie do obra\u017ce\u0144 otoczenia.\n\n&3ZDOBYWANIE XP:\n&eAby zdoby\u0107 PD w tej umiej\u0119tno\u015bci, musisz wykona\u0107 unik\n&ew walce lub przetrwa\u0107 upadki z wysoko\u015bci, kt\u00f3re ci\u0119 rani\u0105. -Guides.Acrobatics.Section.1=&3How does Rolling work?\n&eYou have a passive chance when you take fall damage\n&eto negate the damage done. You can hold the sneak button to\n&edouble your chances during the fall.\n&eThis triggers a Graceful Roll instead of a standard one.\n&eGraceful Rolls are like regular rolls but are twice as likely to\n&eoccur and provide more damage safety than regular rolls.\n&eRolling chance is tied to your skill level -Guides.Acrobatics.Section.2=&3How does Dodge work?\n&eDodge is a passive chance when you are\n&einjured in combat to halve the damage taken.\n&eIt is tied to your skill level. +Guides.Acrobatics.Section.1=&3Jak dzia\u0142a Przewr\u00f3t??\n&eMasz pasywn\u0105 szans\u0119, gdy odniesiesz obra\u017cenia od upadku, aby zneutralizowa\u0107 zadane obra\u017cenia. Mo\u017cesz przytrzyma\u0107 przycisk skradania si\u0119, aby podwoi\u0107 swoje szanse podczas upadku. To wyzwala \u014agodny Przwr\u00f3t zamiast standardowego. \u0141agodne Przewroty s\u0105 jak zwyk\u0142e, ale prawdopodobie\u0144stwo wyst\u0105pienia Przewrotu jest dwukrotnie wi\u0119ksze i zapewnia wi\u0119ksze bezpiecze\u0144stwo obra\u017ce\u0144 ni\u017c zwyk\u0142e Przewroty.\n&eSzansa na przewr\u00f3t zale\u017cy od poziomu Twojej umiej\u0119tno\u015bci. +Guides.Acrobatics.Section.2=&3Jak dzia\u0142a unik?\n&eUnik to pasywna szansa na zmniejszenie o po\u0142ow\u0119 otrzymywanych obra\u017ce\u0144, gdy odniesiesz obra\u017cenia w walce. Jest to powi\u0105zane z Twoim poziomem umiej\u0119tno\u015bci. ##Alchemy Guides.Alchemy.Section.0=&3O Alchemi:\n&eAlchemia polega na warzeniu mikstur.\n&eZapewnia przyspieszenie czasu warzenia mikstury,\n&ea tak\u017ce dodanie nowych (wcze\u015bniej) nieosi\u0105galnych mikstur. \n\n\n&3ZDOBYWANIE XP:\n&eAby zdoby\u0107 XP tej umiej\u0119tno\u015bci, musisz warzy\u0107 mikstury. -Guides.Alchemy.Section.1=&3How does Catalysis work?\n&eCatalysis speeds of the brewing process, with a\n&emax speed of 4x at level 1000.\n&eThis ability is unlocked at level 100 by default. -Guides.Alchemy.Section.2=&3How does Concoctions work?\n&eConcoctions allows brewing of more potions with custom ingredients.\n&eWhich special ingredients are unlocked is determined\n&eby your Rank. There are 8 ranks to unlock. -Guides.Alchemy.Section.3=&3Concoctions tier 1 ingredients:\n&eBlaze Powder, Fermented Spider Eye, Ghast Tear, Redstone,\n&eGlowstone Dust, Sugar, Glistering Melon, Golden Carrot,\n&eMagma Cream, Nether Wart, Spider Eye, Suplhur, Water Lily,\n&ePufferfish\n&e(Vanilla Potions) -Guides.Alchemy.Section.4=&3Concoctions tier 2 ingredients:\n&eCarrot (Potion of Haste)\n&eSlimeball (Potion of Dullness)\n\n&3Concoctions tier 3 ingredients:\n&eQuartz (Potion of Absorption)\n&eRed Mushroom (Potion of Leaping) -Guides.Alchemy.Section.5=&3Concoctions tier 4 ingredients:\n&eApple (Potion of Health Boost)\n&eRotten Flesh (Potion of Hunger)\n\n&3Concoctions tier 5 ingredients:\n&eBrown Mushroom (Potion of Nausea)\n&eInk Sack (Potion of Blindness) -Guides.Alchemy.Section.6=&3Concoctions tier 6 ingredients:\n&eFern (Potion of Saturation)\n\n&3Concoctions tier 7 ingredients:\n&ePoisonous Potato (Potion of Decay)\n\n&3Concoctions tier 8 ingredients:\n&eRegular Golden Apple (Potion of Resistance) +Guides.Alchemy.Section.1=&3Jak dzia\u0142a Kataliza?\n&eSzybko\u015b\u0107 katalizy procesu warzenia, z maksymaln\u0105 pr\u0119dko\u015bci\u0105 4x na poziomie 1000. Ta umiej\u0119tno\u015b\u0107 jest domy\u015blnie odblokowywana na poziomie 100. +Guides.Alchemy.Section.2=&3Jak dzia\u0142aj\u0105 Mikstury?\n&eMikstury pozwalaj\u0105 na warzenie wi\u0119kszej liczby mikstur z niestandardowych sk\u0142adnik\u00f3w. To, kt\u00f3re specjalne sk\u0142adniki zostan\u0105 odblokowane, zale\u017cy od Twojej rangi. Do odblokowania jest 8 stopni. +Guides.Alchemy.Section.3=&3Sk\u0142adniki mikstur tieru 1:\n&eP\u0142omienny Proszek, Fermentowane Oko Paj\u0105ka, \u0141za Ghasta, Redstone,\n&eJasnopy\u0142, Cukier, Poz\u0142acany Arbuz, Z\u0142ota Marchewka,\n&eMagmowy Krem, Brodawka, Oko Paj\u0105ka, Proch, Lilia Wodna,\n&eRozdymka\n&e(Mikstury Wanilla) +Guides.Alchemy.Section.4=&3Sk\u0142adniki mikstur tieru 2:\n&eMarchwka (Miktura Szybko\u015bci)\n&eKulka Szlamu (Miktura Ot\u0119pienia)\n\n&3Sk\u0142adniki mikstur tieru 3:\n&eKwarc (Miksutra Absorpcji)\n&eMuchomor (Mikstura Skoku) +Guides.Alchemy.Section.5=&3Sk\u0142adniki mikstur tieru 4:\n&eJab\u0142ko (Mikstura boostu zdrowia)\n&eZgni\u0142e Mi\u0119so (PMiksutra G\u0142odu)\n\n&3Sk\u0142adniki mikstur tieru 5:\n&eBr\u0105zowy Grzyb (Mikstura Md\u0142o\u015bci)\n&eAtrament (Mikstura O\u015blepienia) +Guides.Alchemy.Section.6=&3Sk\u0142adniki mikstur tieru 6:\n&ePapro\u0107 (Mikstura Nasycenia)\n\n&3Sk\u0142adniki mikstur tieru 7:\n&eZatruty Ziemniak (Mikstura Rozk\u0142adu)\n\n&3Sk\u0142adniki mikstur tieru 8:\n&eZ\u0142ote Jab\u0142ko (Mikstura Odporno\u015bci) ##Archery Guides.Archery.Section.0=&3O \u0141ucznictwie:\n&e\u0141ucznictwo polega na strzelaniu z \u0142uku strza\u0142.\n&eZapewnia r\u00f3\u017cne bonusy bojowe, takie jak zwi\u0119kszenie obra\u017ce\u0144,\n&ekt\u00f3re skaluje si\u0119 z twoim poziomem i daje mo\u017cliwo\u015b\u0107 oszo\u0142omienia\n&eprzeciwnik\u00f3w w PvP. W dodatku mo\u017cesz odzyska\u0107\n&ecz\u0119\u015b\u0107 strza\u0142 z martwych wrog\u00f3w.\n\n\n&3ZDOBYWANIE XP:\n&eAby zdoby\u0107 XP w tej umiej\u0119tno\u015bci, musisz strzela\u0107 do mob\u00f3w lub\n&edo innych graczy. -Guides.Archery.Section.1=&3How does Skill Shot work?\n&eSkill Shot provides additional damage to your shots.\n&eThe bonus damage from Skill Shot increases as you\n&elevel in Archery.\n&eWith the default settings, your archery damage increases 10%\n&eevery 50 levels, to a maximum of 200% bonus damage. -Guides.Archery.Section.2=&3How does Daze work?\n&eYou have a passive chance to daze other players when\n&eyou shoot them. When Daze triggers it forces your opponents\n&eto look straight up for a short duration.\n&eA Daze shot also deals an additional 4 damage (2 hearts). -Guides.Archery.Section.3=&3How does Arrow Retrieval work?\n&eYou have a passive chance to retrieve some of your arrows\n&ewhen you kill a mob with your bow.\n&eThis chance increases as you level in Archery.\n&eBy default, this ability increases by 0.1% per level, up to 100%\n&eat level 1000. +Guides.Archery.Section.1=&3Jak dzia\u0142a Umiej\u0119tne Strzelanie??\n&eUmiej\u0119tne strzelanie zapewnia dodatkowe obra\u017cenia strza\u0142om.\n&eDodatkowe obra\u017cenia rosn\u0105 wraz z poziomem \u0141ucznictwa.\n&ePrzy domy\u015blnych ustawieniach twoje obra\u017cenia zwi\u0119kszaj\u0105 si\u0119 o 10% co 50 poziom\u00f3w, do maksymalnie 200% dodatkowych obra\u017ce\u0144. +Guides.Archery.Section.2=&3Jak dzia\u0142a Oszo\u0142omienie?\n&eMasz pasywn\u0105 szans\u0119 oszo\u0142omienia innych graczy, gdy do nich strzelasz. Aktywacja Oszo\u0142omienia zmusza przeciwnik\u00f3w do patrzenia prosto w g\u00f3r\u0119 przez kr\u00f3tki czas. Strza\u0142a oszo\u0142omiaj\u0105ca zadaje dodatkowe 4 obra\u017cenia (2 serca). +Guides.Archery.Section.3=&3Jak dzia\u0142a Odzyskiwanie Strza\u0142?\n&eMasz pasywn\u0105 szans\u0119 na odzyskanie niekt\u00f3rych strza\u0142, gdy zabijesz \u0142ukiem. Ta szansa ro\u015bnie wraz ze zdobywaniem kolejnych poziom\u00f3w w \u0141ucznictwie. Domy\u015blnie zdolno\u015b\u0107 ta ro\u015bnie o 0,1% na poziom, do 100% na poziomie 1000. ##Axes -Guides.Axes.Section.0=&3About Axes:\n&eZ umiej\u0119tno\u015bci\u0105 Topory mo\u017cesz zrobi\u0107 co\u015b wi\u0119cej\n&eni\u017c niszczy\u0107 lasy! Mo\u017cesz hakowa\u0107 i sieka\u0107 moby\n&ei graczy, aby zdobywa\u0107 XP, musisz atakowa\u0107 moby siekier\u0105 z efektem\n&eodrzucenie i zada\u0107 \u015bmiertelny cios.\n&eTw\u00f3j top\u00f3r r\u00f3wnie\u017c staje si\u0119 r\u0119cznym r\u0119bakiem,\n&eponiewa\u017c bardzo obni\u017casz poziom zbroi\n&przeciwnika wraz z poziomiem umiej\u0119tno\u015bci.\n&3ZDOBYWANIE XP:\n&eAby zdobywa\u0107 XP musisz atakowa\u0107 moby\n&elub graczy siekier\u0105. -Guides.Axes.Section.1=&3How does Skull Splitter work?\n&eThis ability allows you to deal an AoE (Area of Effect) hit.\n&eThis AoE hit will deal half as much damage as you did to the\n&emain target, so it's great for clearing out large piles of mobs. -Guides.Axes.Section.2=&3How does Critical Strikes work?\n&eCritical Strikes is a passive ability which gives players a\n&echance to deal additional damage.\n&eWith the default settings, every 2 skill levels in Axes awards a\n&e0.1% chance to deal a Critical Strike, causing 2.0 times damage\n&eto mobs or 1.5 times damage against other players. -Guides.Axes.Section.3=&3How does Axe Mastery work?\n&eAxe Mastery is a passive ability that will add additional damage\n&eto your hits when using Axes.\n&eBy default, the bonus damage increases by 1 every 50 levels,\n&eup to a cap of 4 extra damage at level 200. -Guides.Axes.Section.4=&3How does Armor Impact work?\n&eStrike with enough force to shatter armor!\n&eArmor Impact has a passive chance to damage your\n&eopponent's armor. This damage increases as you level in Axes. -Guides.Axes.Section.5=&3How does Greater Impact work?\n&eYou have a passive chance to achieve a greater impact when\n&ehitting mobs or players with your axe.\n&eBy default this chance is 25%. This passive ability has an\n&eextreme knockback effect, similar to the Knockback II\n&eenchantment. In addition, it deals bonus damage to the target. +Guides.Axes.Section.0=&3O Siekierach:\n&eZ umiej\u0119tno\u015bci\u0105 Topory mo\u017cesz zrobi\u0107 co\u015b wi\u0119cej\n&eni\u017c niszczy\u0107 lasy! Mo\u017cesz hakowa\u0107 i sieka\u0107 moby\n&ei graczy, aby zdobywa\u0107 XP, musisz atakowa\u0107 moby siekier\u0105 z efektem\n&eodrzucenie i zada\u0107 \u015bmiertelny cios.\n&eTw\u00f3j top\u00f3r r\u00f3wnie\u017c staje si\u0119 r\u0119cznym r\u0119bakiem,\n&eponiewa\u017c bardzo obni\u017casz poziom zbroi\n&eprzeciwnikom wraz z poziomiem umiej\u0119tno\u015bci.\n&3ZDOBYWANIE XP:\n&eAby zdobywa\u0107 XP musisz atakowa\u0107 moby\n&elub graczy siekier\u0105. +Guides.Axes.Section.1=&3Jak dzia\u0142a Przecinacz Czaszek?\n&eTa umiej\u0119tno\u015b\u0107 pozwala Ci zada\u0107 obra\u017cenia AoE (Obszarowe). Obra\u017cenia obszarowe zadaj\u0105 po\u0142ow\u0119 Twoich obra\u017ce\u0144, co czyni je dobrym sposobem do zabijania grup mob\u00f3w. +Guides.Axes.Section.2=&3Jak dzia\u0142a Trafienie Krytyczne?\n&eTrafienia krytyczne jest to pasywna umiej\u0119tno\u015b\u0107, kt\u00f3ra daje Ci mo\u017cliwo\u015b\u0107 zadania dodatkowych obra\u017ce\u0144. Przy domy\u015blnych ustawieniach co 2 poziom umiej\u0119tno\u015bci daje Ci 0.1% szansy na trafienie krytyczne, kt\u00f3re zadaje 2x mobom lub 1.5x przeciwko graczom. +Guides.Axes.Section.3=&3Jak dzia\u0142a Mistrz Siekier?\n&eJest to umiej\u0119tno\u015b\u0107 pasywna, kt\u00f3ra daje Ci mo\u017cliwo\u015b\u0107 zadania dodatkowych obra\u017ce\u0144 przy u\u017cyciu toporka. Obra\u017cenia zwi\u0119kszaj\u0105 si\u0119 o 1 co 50 poziom\u00f3w, do maksymalnie 4 obra\u017ce\u0144 na poziomie 200. +Guides.Axes.Section.4=&3Jak dzia\u0142a Uderzenie Pancerza?\n&eUderz z wystarczaj\u0105c\u0105 si\u0142\u0105, aby rozbi\u0107 zbroj\u0119! Uderzenie Pancerza posiada pasywn\u0105 umiej\u0119tno\u015b\u0107, kt\u00f3ra mo\u017ce uszkodzi\u0107 pancerz Twojego przeciwnika. Obra\u017cenia te s\u0105 zwi\u0119kszanie wraz z poziomem Siekiery. +Guides.Axes.Section.5=&3Jak dzia\u0142a Wi\u0119kszy Wp\u0142yw?\n&eZ ka\u017cdym uderzeniem masz coraz wi\u0119ksz\u0105 szanse na aktywacje Wi\u0119kszy Wp\u0142yw, gdy uderzasz gracza lub moba skiekier\u0105. Domy\u015blna szansa wynosi 25%. Pasywna umiej\u0119tno\u015b\u0107 posiada extremalny efekt odrzutu, podobny do Odrzutu II, jednak\u017ce zadaje ona wi\u0119cej obra\u017ce\u0144\n&eenchantment. Ponadto zadaje dodatkowe obra\u017cenia celowi. ##Excavation -Guides.Excavation.Section.0=&3About Excavation:\n&eExcavation is the act of digging up dirt to find treasures.\n&eBy excavating the land you will find treasures.\n&eThe more you do this the more treasures you can find.\n\n&3XP GAIN:\n&eTo gain XP in this skill you must dig with a shovel in hand.\n&eOnly certain materials can be dug up for treasures and XP. -Guides.Excavation.Section.1=&3Compatible Materials:\n&eGrass, Dirt, Sand, Clay, Gravel, Mycelium, Soul Sand, Snow -Guides.Excavation.Section.2=&3How to use Giga Drill Breaker:\n&eWith a shovel in hand right click to ready your tool.\n&eOnce in this state you have about 4 seconds to make\n&econtact with Excavation compatible materials this will\n&eactivate Giga Drill Breaker. -Guides.Excavation.Section.3=&3What is Giga Drill Breaker?\n&eGiga Drill Breaker is an ability with a cooldown\n&etied to Excavation skill. It triples your chance\n&eof finding treasures and enables instant break\n&eon Excavation materials. -Guides.Excavation.Section.4=&3How does Archaeology work?\n&eEvery possible treasure for Excavation has its own\n&eskill level requirement for it to drop, as a result it's\n&edifficult to say how much it is helping you.\n&eJust keep in mind that the higher your Excavation skill\n&eis, the more treasures that can be found.\n&eAnd also keep in mind that each type of Excavation\n&ecompatible material has its own unique list of treasures.\n&eIn other words you will find different treasures in Dirt\nðan you would in Gravel. -Guides.Excavation.Section.5=&3Notes about Excavation:\n&eExcavation drops are completely customizeable\n&eSo results vary server to server. +Guides.Excavation.Section.0=&3O Wykopalisku:\n&eWykopaliska to czynno\u015b\u0107 polegaj\u0105ca na wykopywaniu ziemi w celu znalezienia skarb\u00f3w..\n&eIm wi\u0119cej b\u0119dziesz kopa\u0107, tym wi\u0119cej znajdziesz skarb\u00f3w.\n\n&3ZDOBYWANIE XP:\n&eAby zdoby\u0107 XP w tej umiej\u0119tno\u015bci nale\u017cy kopa\u0107 \u0142opat\u0105. Tylko niekt\u00f3re rzeczy mo\u017cna wykopa\u0107, aby zdoby\u0107 skarby i EXP. Aby przygotowa\u0107 narz\u0119dzie wci\u015bnij prawy przycisk myszy z \u0142opat\u0105 w d\u0142oni. +Guides.Excavation.Section.1=&3Kompatybilne Materia\u0142y:\n&eTrawa, Ziemia, Piasek, Glina, \u017bwir, Mycelinium, Piasek Dusz, \u015anieg +Guides.Excavation.Section.2=&3Jak u\u017cy\u0107 Giga Wiert\u0142o:\n&eKliknij prawy przycisk z \u0142opat\u0105 w r\u0119ce, aby aktywowa\u0107 Giga Wiert\u0142o.\n&eGdy znajdziesz si\u0119 w tym stanie, masz oko\u0142o 4 sekund na kontakt z materia\u0142ami kompatybilnymi z Wykopalisko, aktywuje to Giga Wiert\u0142o. +Guides.Excavation.Section.3=&3Co to Giga Wiert\u0142o?\n&eGiga Wiert\u0142o to umiej\u0119tno\u015b\u0107 posiadaj\u0105ca czas odnowienia. Daje Ci potr\u00f3jn\u0105 szans\u0119 na znalezienie skarb\u00f3w oraz umo\u017cliwia natychmiastowe kopanie. +Guides.Excavation.Section.4=&3Jak dzia\u0142a Archeologia?\n&eKa\u017cdy skarb posiada sw\u00f3j wymagany poziom, dlatego otrzymujesz skarb w zale\u017clo\u015bci od Twojego poziomu umiej\u0119tno\u015bci. Pami\u0119taj im wy\u017cszy jest Tw\u00f3j poziom umiej\u0119tno\u015bci, tym wi\u0119cej skarb\u00f3w mo\u017cesz znale\u017a\u0107. Ka\u017cdy skarb, wykopywany z r\u00f3\u017cnych materia\u0142\u00f3w posiada swoj\u0105 unikalna list\u0119 przedmiot\u00f3w, kt\u00f3re si\u0119 w nim znajduj\u0105. Inny skarb otrzymasz z bruku, a zupe\u0142nie inny ze \u017cwiru. +Guides.Excavation.Section.5=&3Notatki o Wykopaliskach:\n&ePrzedmioty z wykopalisk s\u0105 w pe\u0142ni konfigurowalne, tak wi\u0119c wyniki r\u00f3\u017cni\u0105 si\u0119 mi\u0119dzy serwerami. ##Fishing -Guides.Fishing.Section.0=&3About Fishing:\n&eWith the Fishing skill, Fishing is exciting again!\n&eFind hidden treasures, and shake items off mobs.\n\n&3XP GAIN:\n&eCatch fish. -Guides.Fishing.Section.1=&3How does Treasure Hunter work?\n&eThis ability allows you to find treasure from fishing \n&ewith a small chance of the items being enchanted.\n&eEvery possible treasure for Fishing has a chance\n&eto drop on any level. It depends however\n&ewhat the rarity of the item is how often it will drop.\n&eThe higher your Fishing skill is, the better\n&eyour chances are to find better treasures. -Guides.Fishing.Section.2=&3How does Ice Fishing work?\n&eThis passive skill allows you to fish in ice lakes!\n&eCast your fishing rod in an ice lake and the ability will\n&ecreate a small hole in the ice to fish in. -Guides.Fishing.Section.3=&3How does Master Angler work?\n&eThis passive skill increases the bite chance while fishing.\n&eWhen you've unlocked this ability, fishing while in\n&ea boat improves odds of catching a fish. -Guides.Fishing.Section.4=&3How does Shake work?\n&eThis active ability allows you to shake items loose from mobs\n&eby hooking them with the fishing rod. \n&eMobs will drop items they would normally drop on death.\n&eIt is also possible to acquire mob skulls, which are normally \n&eunobtainable in survival mode. -Guides.Fishing.Section.5=&3How does Fisherman's Diet work?\n&eThis passive skill increases the amount of hunger restored \n&efrom eating fish. -Guides.Fishing.Section.6=&3Notes about Fishing:\n&eFishing drops are completely customizable,\n&eso results vary server to server. +Guides.Fishing.Section.0=&3O W\u0119dkarstwie:\n&eDzi\u0119ki umiej\u0119tno\u015bci W\u0119dkarstwo, w\u0119dkarstwo zn\u00f3w jest ekscytuj\u0105ce! Znajd\u017a ukryte skarby i strz\u0105\u015bnij przedmioty z mob\u00f3w.\n\n&3ZDOBYWANIE XP:\n&e\u0141owienie ryb. +Guides.Fishing.Section.1=&3Jak dzia\u0142a \u0141owca Skarb\u00f3w?\n&eTa umiej\u0119tno\u015b\u0107 pozwala ci znale\u017a\u0107 skarb z \u0142owienia z niewielk\u0105 szans\u0105 na zakl\u0119cie przedmiot\u00f3w. Ka\u017cdy mo\u017cliwy skarb dla w\u0119dkarzy ma szans\u0119 spa\u015b\u0107 na dowolnym poziomie. Zale\u017cy to jednak od rzadko\u015bci przedmiotu, jak cz\u0119sto b\u0119dzie on wypada\u0142. Im wy\u017cszy poziom umiej\u0119tno\u015bci \u0141owienie ryb, tym wi\u0119ksze masz szanse na znalezienie lepszych skarb\u00f3w. +Guides.Fishing.Section.2=&3Jak dzia\u0142aj\u0105 Mro\u017ane Po\u0142owy?\n&eTa umiej\u0119tno\u015b\u0107 pasywna pozwala \u0142owi\u0107 ryby w lodowych jeziorach! Wrzu\u0107 w\u0119dk\u0119 do lodowego jeziora, a stworzysz w lodzie ma\u0142\u0105 dziur\u0119 do \u0142owienia. +Guides.Fishing.Section.3=&3Jak dzia\u0142a Mistrz W\u0119dkarstwa?\n&eTa umiej\u0119tno\u015b\u0107 pasywna zwi\u0119ksza szans\u0119 brania podczas \u0142owienia. Po odblokowaniu tej umiej\u0119tno\u015bci \u0142owienie na \u0142odzi zwi\u0119ksza szanse na z\u0142owienie ryby. +Guides.Fishing.Section.4=&3Jak dzia\u0142a Potrz\u0105sanie?\n&eTa aktywna umiej\u0119tno\u015b\u0107 pozwala strz\u0105sa\u0107 przedmioty z mob\u00f3w poprzez zaczepienie ich w\u0119dk\u0105. Moby upuszczaj\u0105 przedmioty, kt\u00f3re normalnie upuszczaj\u0105 po \u015bmierci. Mo\u017cliwe jest r\u00f3wnie\u017c zdobycie czaszek mob\u00f3w, kt\u00f3re normalnie s\u0105 nieosi\u0105galne w trybie przetrwania. +Guides.Fishing.Section.5=&3Jak dzia\u0142a Dieta Rybaka?\n&eTa umiej\u0119tno\u015b\u0107 pasywna zwi\u0119ksza ilo\u015b\u0107 przywracanego g\u0142odu po jedzeniu ryby. +Guides.Fishing.Section.6=&3Notatki o W\u0119dkarstwie:\n&ePrzedmioty z \u0142owienia s\u0105 w pe\u0142ni konfigurowalne, tak wi\u0119c wyniki r\u00f3\u017cni\u0105 si\u0119 mi\u0119dzy serwerami. ##Herbalism -Guides.Herbalism.Section.0=&3About Herbalism:\n&eHerbalism is about collecting herbs and plants.\n\n\n&3XP GAIN:\n&eCollect plants and herbs. -Guides.Herbalism.Section.1=&3Compatible Blocks\n&eWheat, Potatoes, Carrots, Melons, \n&ePumpkins, Sugar Canes, Cocoa Beans, Flowers, Cacti, Mushrooms,\n&eNether Wart, Lily Pads, and Vines. -Guides.Herbalism.Section.2=&3How does Green Terra work?\n&eGreen Terra is an active ability, you can right-click\n&ewhile holding a hoe to activate Green Terra.\n&eGreen Terra grants players a chance to get 3x drops from\n&eharvesting plants. It also gives players the ability to\n&espread life into blocks and transform them using seeds\n&efrom your inventory. -Guides.Herbalism.Section.3=&3How does Green Thumb (Crops) work?\n&eThis passive ability will automatically replant crops when\n&eharvesting.\n&eYour chance of success depends on your Herbalism skill. -Guides.Herbalism.Section.4=&3How does Green Thumb (Cobble/Stone Brick/Dirt) work?\n&eThis active ability allows you to turn blocks into their\n&e"plant-related" counterparts. You can do this by right-clicking\n&ea block, while holding seeds. This will consume 1 seed. -Guides.Herbalism.Section.5=&3How does Farmer's Diet work?\n&eThis passive skill increases the amount of hunger restored \n&ewhen eating Bread, Cookies, Melons, Mushroom Soup, Carrots,\n&eand Potatoes. -Guides.Herbalism.Section.6=&3How does Hylian Luck work?\n&eThis passive ability gives you a chance to find rare items\n&ewhen certain blocks are broken with a sword. -Guides.Herbalism.Section.7=&3How do Double Drops work?\n&eThis passive ability gives players more yield from their\n&eharvests. +Guides.Herbalism.Section.0=&3O Zielarstwie:\n&eZielarstwo polega na zbieraniu zi\u00f3\u0142 i ro\u015blin.\n\n\n&3ZDOBYWANIE XP:\n&eZbieraj ro\u015bliny i zio\u0142a. +Guides.Herbalism.Section.1=&3Kompatybilne ro\u015bliny:\n&eSiano, Ziemniaki, Marchewki, Arbuzy, \n&eDynie, Trzcina Cukrowa, Kakao, Kwiaty, Kaktusy, Grzyby,\n&eBrodawka, Lilie Wodne, i Liany. +Guides.Herbalism.Section.2=&3Jak dzia\u0142a Zielona Terra?\n&eZielona Terra to umiej\u0119tno\u015b\u0107 aktywna, mo\u017cesz przytrzyma\u0107 motyk\u0119 prawym przyciskiem myszy, aby aktywowa\u0107 Zielon\u0105 Terr\u0119. Zielona Terra daje graczom szans\u0119 na zdobycie 3x przedmiot\u00f3w ze zbioru ro\u015blin. Daje tak\u017ce graczom mo\u017cliwo\u015b\u0107 dzielenia \u017cycia na bloki i przekszta\u0142cania ich za pomoc\u0105 nasion z ekwipunku. +Guides.Herbalism.Section.3=&3Jak dzia\u0142a Zielona R\u0105czka (Nasiona)?\n&eTa pasywna umiej\u0119tno\u015b\u0107 automatycznie przesadza plony podczas zbioru. Twoja szansa na sukces zale\u017cy od umiej\u0119tno\u015bci zielarstwa. +Guides.Herbalism.Section.4=&3Jak dzia\u0142a Zielona R\u0105czka (Bruk/Kamienne Ceg\u0142y/Ziemia)?\n&eTa aktywna zdolno\u015b\u0107 pozwala zamieni\u0107 bloki w ich odpowiedniki „zwi\u0105zane z ro\u015blinami”. Mo\u017cesz to zrobi\u0107, klikaj\u0105c prawym przyciskiem myszy blok, trzymaj\u0105c jednocze\u015bnie nasiona. To poch\u0142onie 1 ziarno. +Guides.Herbalism.Section.5=&3Jak dzia\u0142a Dieta Farmera?\n&eTa umiej\u0119tno\u015b\u0107 pasywna zwi\u0119ksza ilo\u015b\u0107 przywracanego g\u0142odu podczas jedzenia chleba, ciastek, arbuz\u00f3w, zupy grzybowej, marchwi i ziemniak\u00f3w. +Guides.Herbalism.Section.6=&3Jak dzia\u0142a Wielkie Szcz\u0119\u015bcie?\n&eTa pasywna umiej\u0119tno\u015b\u0107 daje ci szans\u0119 na znalezienie rzadkich przedmiot\u00f3w, gdy niekt\u00f3re bloki zostan\u0105 rozbite mieczem. +Guides.Herbalism.Section.7=&3Jak dzia\u0142a Podw\u00f3jny \u0141up?\n&eTa pasywna umiej\u0119tno\u015b\u0107 zapewnia graczom wi\u0119ksze plony. ##Mining -Guides.Mining.Section.0=&3About Mining:\n&eMining consists of mining stone and ores. It provides bonuses\n&eto the amount of materials dropped while mining.\n\n&3XP GAIN:\n&eTo gain XP in this skill, you must mine with a pickaxe in hand.\n&eOnly certain blocks award XP. -Guides.Mining.Section.1=&3Compatible Materials:\n&eStone, Coal Ore, Iron Ore, Gold Ore, Diamond Ore, Redstone Ore,\n&eLapis Ore, Obsidian, Mossy Cobblestone, Ender Stone,\n&eGlowstone, and Netherrack. -Guides.Mining.Section.2=&3How to use Super Breaker:\n&eWith a pickaxe in your hand, right click to ready your tool.\n&eOnce in this state, you have about 4 seconds to make contact\n&ewith Mining compatible materials, which will activate Super\n&eBreaker. -Guides.Mining.Section.3=&3What is Super Breaker?\n&eSuper Breaker is an ability with a cooldown tied to the Mining\n&eskill. It triples your chance of extra items dropping and\n&eenables instant break on Mining materials. -Guides.Mining.Section.4=&3How to use Blast Mining:\n&eWith a pickaxe in hand,\n&ecrouch and right-click on TNT from a distance. This will cause the TNT\n&eto instantly explode. -Guides.Mining.Section.5=&3How does Blast Mining work?\n&eBlast Mining is an ability with a cooldown tied to the Mining\n&eskill. It gives bonuses when mining with TNT and allows you\n&eto remote detonate TNT. There are three parts to Blast Mining.\n&eThe first part is Bigger Bombs, which increases blast radius.\n&eThe second is Demolitions Expert, which decreases damage\n&efrom TNT explosions. The third part simply increases the\n&eamount of ores dropped from TNT and decreases the\n&edebris dropped. +Guides.Mining.Section.0=&3O G\u00f3rnictwie:\n&eG\u00f3rnictwo obejmuje wydobywanie kamienia i rud. Zapewnia bonusy do ilo\u015bci upuszczanych materia\u0142\u00f3w podczas wydobywania.\n\n&3ZDOBYWANIE XP:\n&eAby zdoby\u0107 XP w tej umiej\u0119tno\u015bci, musisz kopa\u0107 z kilofem w d\u0142oni. Tylko niekt\u00f3re bloki zapewniaj\u0105 XP . +Guides.Mining.Section.1=&3Kompatybilne Minera\u0142y:\n&eKamie\u0144, Ruda W\u0119gla, Ruda \u017belaza, Ruda Z\u0142ota, Ruda Diamentu, Ruda Redstone,\n&eRuda Lapisu, Obsydian, Zamszony Bruk, Kamie\u0144 Endu,\n&eJasnog\u0142az, i Netherrack. +Guides.Mining.Section.2=&3Jak u\u017cy\u0107 Super Niszczyciela:\n&eKliknij prawy przycisk z kilofem w r\u0119ce, aby aktywowa\u0107 Super Niszczyciel.\n&eGdy znajdziesz si\u0119 w tym stanie, masz oko\u0142o 4 sekund na kontakt z materia\u0142ami kompatybilnymi z Wykopalisko, aktywuje to Super Niszczyciel. +Guides.Mining.Section.3=&3Co to Super Niszczyciel?\n&eSuper Niszczyciel to umiej\u0119tno\u015b\u0107, kt\u00f3rej czas odnowienia jest powi\u0105zany z umiej\u0119tno\u015bci\u0105 G\u00f3rnictwo. Potroi szans\u0119 na upuszczenie dodatkowych przedmiot\u00f3w i umo\u017cliwia natychmiastowe niszczenie przy wydobywaniu materia\u0142\u00f3w. +Guides.Mining.Section.4=&3Jak u\u017cy\u0107 Podm\u00f3ch G\u00f3rnictwa:\n&eZ kilofem w d\u0142oni kucnij i kliknij prawym przyciskiem myszy na TNT z daleka. Spowoduje to natychmiastow\u0105 eksplozj\u0119 TNT. +Guides.Mining.Section.5=&3Jak dzia\u0142\u0105 Podm\u00f3ch G\u00f3rnictwa?\n&ePodm\u00f3ch G\u00f3rnictwa to umiej\u0119tno\u015b\u0107, kt\u00f3rej czas odnowienia jest powi\u0105zany z umiej\u0119tno\u015bci\u0105 G\u00f3rnictwo. Daje bonusy podczas wydobywania z TNT i pozwala zdalnie zdetonowa\u0107 TNT. Podm\u00f3ch G\u00f3rnictwa sk\u0142ada si\u0119 z trzech cz\u0119\u015bci. Pierwsza cz\u0119\u015b\u0107 to Wi\u0119ksze Bomby, kt\u00f3ra zwi\u0119ksza zasi\u0119g ra\u017cenia. Druga to Eksportyza Rozbi\u00f3rki, kt\u00f3ra zmniejsza obra\u017cenia od wybuch\u00f3w TNT. Trzecia cz\u0119\u015b\u0107 po prostu zwi\u0119ksza ilo\u015b\u0107 rud zrzucanych z trotylu i zmniejsza ilo\u015b\u0107 upuszczanych gruzu. ##Repair -Guides.Repair.Section.0=&3About Repair:\n&eRepair allows you to use an iron block to repair armor and\n&etools.\n\n&3XP GAIN:\n&eRepair tools or armor using the mcMMO Anvil. This is an\n&eiron block by default and should not be confused with\nðe Vanilla Minecraft Anvil. -Guides.Repair.Section.1=&3How can I use Repair?\n&ePlace down a mcMMO Anvil and right-click to repair the item \n&eyou're currently holding. This consumes 1 item on every use. -Guides.Repair.Section.2=&3How does Repair Mastery work?\n&eRepair Mastery increases the repair amount. The extra amount\n&erepaired is influenced by your Repair skill level. -Guides.Repair.Section.3=&3How does Super Repair work?\n&eSuper Repair is a passive ability. When repairing an item,\n&eit grants players a chance to repair an item with\n&edouble effectiveness. -Guides.Repair.Section.4=&3How does Arcane Forging work?\n&eThis passive ability allows you to repair items with a certain\n&echance of maintaining its enchantments. The enchants may be\n&ekept at their existing levels, downgraded to a lower level,\n&eor lost entirely. +Guides.Repair.Section.0=&3O Naprawianiu:\n&eNaprawa umo\u017cliwia u\u017cycie \u017celaznego bloku do naprawy zbroi i narz\u0119dzi .\n\n&3ZDOBYWANIE XP:\n&eNapraw narz\u0119dzia lub zbroj\u0119 za pomoc\u0105 kowad\u0142a mcMMO. Jest to domy\u015blnie \u017celazny blok i nie nale\u017cy go myli\u0107 z kowad\u0142em Vanilla. +Guides.Repair.Section.1=&3Jak naprawia\u0107 w mcMMO?\n&ePo\u0142\u00f3\u017c kowad\u0142o mcMMO i kliknij prawym przyciskiem myszy, aby naprawi\u0107 przedmiot, kt\u00f3ry aktualnie trzymasz. Przy ka\u017cdym u\u017cyciu zu\u017cywa 1 przedmiot (Na przyk\u0142ad przy \u017celaznych narz\u0119dziach zu\u017cyje jedno \u017celazo). +Guides.Repair.Section.2=&3Jak dzia\u0142a Mistrz Napraw?\n&ePoziom Mistrza Napraw zwi\u0119ksza si\u0119 wraz z naprawianymi przedmiotami. Dodatkow\u0105 przywr\u00f3con\u0105 wytrzyma\u0142o\u015b\u0107 zale\u017cy od poziomu Naprawianie. +Guides.Repair.Section.3=&3Jak dzia\u0142a Super Naprawa?\n&eSuper Naprawa to umiej\u0119tno\u015b\u0107 pasywna. Podczas naprawy przedmiotu daje graczom szans\u0119 na naprawienie przedmiotu z podw\u00f3jn\u0105 skuteczno\u015bci\u0105. +Guides.Repair.Section.4=&3Jak dzia\u0142a Tajemne Fa\u0142szowanie?\n&eTa pasywna umiej\u0119tno\u015b\u0107 pozwala naprawia\u0107 przedmioty z pewn\u0105 szans\u0105 na utrzymanie zakl\u0119\u0107. Zakl\u0119cia mog\u0105 pozosta\u0107 na dotychczasowych poziomach, zdegradowane do ni\u017cszych lub ca\u0142kowicie utracone. ##Salvage -Guides.Salvage.Section.0=&3About Salvage:\n&eSalvage allows you to use a gold block to salvage armor and\n&etools.\n\n&3XP GAIN:\n&eSalvage is a child skill of Repair and Fishing, your Salvage\n&eskill level is based on your Fishing and Repair skill levels. -Guides.Salvage.Section.1=&3How can I use Salvage?\n&ePlace down a mcMMO Salvage Anvil and right-click to salvage\nðe item you're currently holding. This will break apart the item,\n&eand give back materials used to craft the item.\n\n&eFor example, salvaging an iron pickaxe will give you iron bars. -Guides.Salvage.Section.2=&3How does Advanced Salvage work?\n&eWhen unlocked, this ability allows you to salvage damaged items.\n&eThe yield percentage increases as you level up. A higher yield\n&emeans that you can get more materials back.\n&eWith advanced salvage you will always get 1 material back,\n&eunless the item is too damaged. So you don't have to worry\n&eabout destroying items without getting anything in return. -Guides.Salvage.Section.3=&3To illustrate how this works, here's an example:\n&eLet's say we salvage a gold pickaxe which is damaged for 20%,\nðis means that the maximum amount you could get is only 2\n&e(because the pick is crafted with 3 ingots - each worth\n&e33,33% durability) which is equal to 66%. If your yield\n&epercentage is below 66% you are not able to get 2 ingots.\n&eIf it is above this value you are able to gain the "full amount",\n&ewhich means that you will get 2 ingots. -Guides.Salvage.Section.4=&3How does Arcane Salvage work?\n&eThis ability allows you to get enchanted books when salvaging\n&eenchanted items. Depending on your level the chance of\n&esuccessfully extracting a full or partial enchantment varies.\n\n&eWhen an enchantment is partially extracted, the enchantment\n&ebook will have a lower level enchantment compared to what\n&eit was on the item. +Guides.Salvage.Section.0=&3O odzyskiwaniu:\n&eUmie\u015bci\u0142e\u015b odzyskiwanie pozwala ci u\u017cy\u015b z\u0142otego bloku do odzyskania zbroi i narz\u0119dzi..\n\n&3ZDOBYWANIE XP:\n&eOdzyskiwanie to umiej\u0119tno\u015b\u0107 podrz\u0119dna Naprawy i W\u0119dkarstwa, wi\u0119c Tw\u00f3j poziom umiej\u0119tno\u015bci Odzyskiwania jest oparty na twoich poziomach umiej\u0119tno\u015bci W\u0119dkarstwa i Naprawy. +Guides.Salvage.Section.1=&3Jak u\u017cwa\u0107 Odzyskiwanie?\n&ePo\u0142\u00f3\u017c kowad\u0142o mcMMO (tj. z\u0142oty blok) i kliknij prawym przyciskiem myszy, aby odzyska\u0107 przedmioty z narz\u0119dzia, kt\u00f3ry aktualnie trzymasz. Spowoduje to zniszczenie przedmiotu i zwr\u00f3cenie materia\u0142\u00f3w u\u017cytych do wytworzenia przedmiotu. +Guides.Salvage.Section.2=&3Jak dzia\u0142a Zaawansowane Odzyskiwanie?\n&ePo odblokowaniu umiej\u0119tno\u015b\u0107 ta pozwala na odzyskanie uszkodzonych przedmiot\u00f3w. Procent zysku ro\u015bnie wraz ze wzrostem poziomu. Wy\u017csza wydajno\u015b\u0107 oznacza, \u017ce mo\u017cna odzyska\u0107 wi\u0119cej materia\u0142\u00f3w. Dzi\u0119ki zaawansowanemu odzyskowi zawsze otrzymasz 1 materia\u0142 z powrotem, chyba \u017ce przedmiot jest zbyt uszkodzony. Nie musisz wi\u0119c martwi\u0107 si\u0119 o niszczenie przedmiot\u00f3w, nie otrzymuj\u0105c niczego w zamian. +Guides.Salvage.Section.3=&3Aby pokaza\u0107 przyk\u0142ad, tutaj go opisujemy:\n&ePowiedzmy, \u017ce odzyskujemy z\u0142oty kilof, kt\u00f3ry jest uszkodzony o 20%, co oznacza, \u017ce maksymalna kwota, jak\u0105 mo\u017cesz zdoby\u0107, to tylko 2 (poniewa\u017c kilof jest tworzony z 3 sztabek - ka\u017cdy wart 33,33% wytrzyma\u0142o\u015bci), co jest r\u00f3wne 66% . Je\u015bli Tw\u00f3j procent wytrzyma\u0142o\u015bci jest ni\u017cszy ni\u017c 66%, nie jeste\u015b w stanie uzyska\u0107 2 sztabek. Je\u015bli jest powy\u017cej tej warto\u015bci, mo\u017cesz uzyska\u0107 „pe\u0142n\u0105 kwot\u0119”, co oznacza, \u017ce otrzymasz 2 sztabki. +Guides.Salvage.Section.4=&3Jak dzia\u0142a Tajemne Odzyskiwanie?\n&eTa umiej\u0119tno\u015b\u0107 pozwala zdoby\u0107 zakl\u0119te ksi\u0105\u017cki podczas odzyskiwania zakl\u0119tych przedmiot\u00f3w. W zale\u017cno\u015bci od twojego poziomu, szansa na pomy\u015blne wyodr\u0119bnienie pe\u0142nego lub cz\u0119\u015bciowego zakl\u0119cia jest r\u00f3\u017cna.\n\n&eKiedy zakl\u0119cie zostanie cz\u0119\u015bciowo wydobyte, ksi\u0119ga zakl\u0119\u0107 b\u0119dzie mia\u0142a ni\u017cszy poziom zakl\u0119cia w por\u00f3wnaniu z tym, co znajdowa\u0142o si\u0119 na przedmiocie. ##Smelting -Guides.Smelting.Section.0=Coming soon... +Guides.Smelting.Section.0=Wkr\u00f3tce... ##Swords -Guides.Swords.Section.0=&3About Swords:\n&eThis skill awards combat bonuses to anyone fighting with a\n&esword.\n\n&3XP GAIN:\n&eXP is gained based on the amount of damage dealt to mobs or \n&eother players when wielding a sword. -Guides.Swords.Section.1=&3How does Serrated Strikes work?\n&eSerrated Strikes is an active ability, you can activate it by\n&eright-clicking with a sword. This ability allows you to deal \n&ean AoE (Area of Effect) hit. This AoE will do a bonus 25%\n&edamage and will inflict a bleed effect that lasts for 5 ticks. -Guides.Swords.Section.2=&3How does Counter Attack work?\n&eCounter Attack is an active ability. When blocking and taking\n&ehits from mobs, you will have a chance to reflect 50% of \nðe damage that was taken. -Guides.Swords.Section.3=&3How does Rupture work?\n&eRupture causes enemies to take damage every two seconds. The \n&etarget will bleed until the effect wears off, or death, \n&ewhichever comes first.\n&eThe duration of the bleed is increased by your sword skill. +Guides.Swords.Section.0=&3O Mieczach:\n&eTa umiej\u0119tno\u015b\u0107 zapewnia premie bojowe ka\u017cdemu, kto walczy mieczem..\n\n&3ZDOBYWANIE XP:\n&eXP jest zdobywane w oparciu o ilo\u015b\u0107 obra\u017ce\u0144 zadanych mobom lub innym graczom, gdy dzier\u017cysz miecz. . +Guides.Swords.Section.1=&3Jak dzia\u0142aj\u0105 Z\u0105bkowane Uderzenia?\n&eZ\u0105bkowane Uderzenia to umiej\u0119tno\u015b\u0107 aktywna, kt\u00f3r\u0105 mo\u017cna aktywowa\u0107, klikaj\u0105c prawym przyciskiem myszy mieczem. Ta umiej\u0119tno\u015b\u0107 pozwala na zadanie trafienia obszarowego. Ten obszar dzia\u0142ania zadaje dodatkowe 25% obra\u017ce\u0144 i wywo\u0142a efekt krwawienia trwaj\u0105cy 5 tik\u00f3w. +Guides.Swords.Section.2=&3Jak dzia\u0142a Kontraatak?\n&eKontratak to aktywna umiej\u0119tno\u015b\u0107. Podczas blokowania i przyjmowania trafie\u0144 od mob\u00f3w, b\u0119dziesz mia\u0142 szans\u0119 odbi\u0107 50% otrzymanych obra\u017ce\u0144. +Guides.Swords.Section.3=&3Jak dzia\u0142a Rozerwanie?\n&eRozerwanie powoduje, \u017ce wrogowie otrzymuj\u0105 obra\u017cenia co dwie sekundy. Cel b\u0119dzie krwawi\u0142 do momentu ust\u0105pienia efektu lub \u015bmierci, w zale\u017cno\u015bci od tego, co nast\u0105pi wcze\u015bniej. Poziom umiej\u0119tno\u015bci Miecze zwi\u0119ksza czas trwania krwawienia. ##Taming -Guides.Taming.Section.0=&3About Taming:\n&eTaming will give players various combat bonuses when using\n&etamed wolves.\n\n&3XP GAIN:\n&eTo gain XP in this skill, you need to tame wolves/ocelots or\n&eget into combat with your wolves. -Guides.Taming.Section.1=&3How does Call of the Wild work?\n&eCall of the Wild is an active ability that will allow you to summon\n&ea wolf or an ocelot by your side. You can do this by\n&esneaking + left-clicking while holding bones or fish. -Guides.Taming.Section.2=&3How does Beast Lore work?\n&eBeast Lore allows players to inspect pets and to check the\n&estats of wolves and ocelots. Left-click a wolf or ocelot to use\n&eBeast Lore. -Guides.Taming.Section.3=&3How does Gore work?\n&eGore is a passive ability that has a chance of inflicting a\n&ebleeding effect on your wolves' targets. -Guides.Taming.Section.4=&3How does Sharpened Claws work?\n&eSharpened Claws provides a damage bonus to damage dealt\n&eby wolves. The damage bonus depends on your Taming level. -Guides.Taming.Section.5=&3How does Environmentally Aware work?\n&eThis passive ability will allow wolves to teleport to you when\nðey get near hazards, such as Cacti/Lava. It will also give\n&ewolves fall damage immunity. -Guides.Taming.Section.6=&3How does Thick Fur work?\n&eThis passive ability will reduce damage and make wolves\n&efire resistant. -Guides.Taming.Section.7=&3How does Shock Proof work?\n&eThis passive ability reduces damage done to wolves\n&efrom explosions. -Guides.Taming.Section.8=&3How does Fast Food Service work?\n&eThis passive ability gives wolves a chance to heal whenever\nðey perform an attack. +Guides.Taming.Section.0=&3O Oswajaniu:\n&eOswajanie zapewni graczom r\u00f3\u017cne bonusy bojowe podczas u\u017cywania oswojonych wilk\u00f3w.\n\n&3ZDOBYWANIE XP:\n&eAby zdoby\u0107 XP w tej umiej\u0119tno\u015bci, musisz oswoi\u0107 wilki lub oceloty i wyruszy\u0107 do walki ze swoimi sprzymierze\u0144cami. +Guides.Taming.Section.1=&3Jak dzia\u0142a Zew Natury?\n&eZew Natury to aktywna umiej\u0119tno\u015b\u0107, kt\u00f3ra pozwoli ci przywo\u0142a\u0107 wilka lub ocelota do swojego boku. Mo\u017cesz to zrobi\u0107 kucaj\u0105c (shift) + klikni\u0119cie lewym przyciskiem myszy, trzymaj\u0105c ko\u015bci lub ryb\u0119. +Guides.Taming.Section.2=&3Jak dzia\u0142a Wiedza Bestii?\n&eWiedza Bestii pozwala graczom na zbadanie zwierzak\u00f3w i sprawdzanie stanu wilk\u00f3w i ocelot\u00f3w. Kliknij lewym przyciskiem myszy na wilka lub ocelota, aby u\u017cy\u0107 Wiedzy Bestii. +Guides.Taming.Section.3=&3How does Gore work?\n&eKrwawienie to pasywna umiej\u0119tno\u015b\u0107, kt\u00f3ra ma szans\u0119 wywo\u0142a\u0107 efekt krwawienia na celach przez Twoich wilk\u00f3w. +Guides.Taming.Section.4=&3Jak dzia\u0142aj\u0105 Zaostrzone Pazury?\n&eZaostrzone Pazury zapewnia premi\u0119 do obra\u017ce\u0144 zadawanych przez wilki. Premia do obra\u017ce\u0144 zale\u017cy od Twojego poziomu Oswajania. +Guides.Taming.Section.5=&3Jak dzia\u0142a Sprzymierzeniec Natury?\n&eTa pasywna umiej\u0119tno\u015b\u0107 pozwoli wilkom teleportowa\u0107 si\u0119 do ciebie, gdy zbli\u017c\u0105 si\u0119 do niebezpiecze\u0144stw, takich jak kaktusy czy lawa. Zapewni tak\u017ce wilkom odporno\u015b\u0107 na obra\u017cenia od upadku. +Guides.Taming.Section.6=&3Jak dzia\u0142a grube futro??\n&eTa pasywna umiej\u0119tno\u015b\u0107 zmniejszy obra\u017cenia i sprawi, \u017ce wilki b\u0119d\u0105 odporne na ogie\u0144. +Guides.Taming.Section.7=&3Jak dzia\u0142a odporno\u015b\u0107 na wstrz\u0105sy?\n&eTa umiej\u0119tno\u015b\u0107 pasywna zmniejsza obra\u017cenia zadawane wilkom od eksplozji. +Guides.Taming.Section.8=&3Jak dzia\u0142a serwis Fast Food??\n&eTa pasywna umiej\u0119tno\u015b\u0107 daje wilkom szans\u0119 na uleczenie si\u0119, gdy wykonaj\u0105 atak. ##Unarmed Guides.Unarmed.Section.0=&3About Unarmed:\n&eUnarmed will give players various combat bonuses when using\n&eyour fists as a weapon. \n\n&3XP GAIN:\n&eXP is gained based on the amount of damage dealt to mobs \n&eor other players when unarmed. Guides.Unarmed.Section.1=&3How does Berserk work?\n&eBeserk is an active ability that is activated by\n&eright-clicking. While in Beserk mode, you deal 50% more\n&edamage and you can break weak materials instantly, such as\n&eDirt and Grass. @@ -962,10 +964,10 @@ Guides.Unarmed.Section.3=&3How does Arrow Deflect work?\n&eArrow Deflect is a pa Guides.Unarmed.Section.4=&3How does Iron Grip work?\n&eIron Grip is a passive ability that counters disarm. As your\n&eunarmed level increases, the chance of preventing a disarm increases. Guides.Unarmed.Section.5=&3How does Disarm work?\n&eThis passive ability allows players to disarm other players,\n&ecausing the target's equipped item to fall to the ground. ##Woodcutting -Guides.Woodcutting.Section.0=&3About Woodcutting:\n&eWoodcutting is all about chopping down trees.\n\n&3XP GAIN:\n&eXP is gained whenever you break log blocks. -Guides.Woodcutting.Section.1=&3How does Tree Feller work?\n&eTree Feller is an active ability, you can right-click\n&ewhile holding an ax to activate Tree Feller. This will\n&ecause the entire tree to break instantly, dropping all\n&eof its logs at once. -Guides.Woodcutting.Section.2=&3How does Leaf Blower work?\n&eLeaf Blower is a passive ability that will cause leaf\n&eblocks to break instantly when hit with an axe. By default,\nðis ability unlocks at level 100. -Guides.Woodcutting.Section.3=&3How do Double Drops work?\n&eThis passive ability gives you a chance to obtain an extra\n&eblock for every log you chop. +Guides.Woodcutting.Section.0=&3O Drwalu:\n&eDrwal polega na wycinaniu drzew.\n\n&3ZDOBYWANIE XP:\n&eXP jest zdobywany za ka\u017cdym razem, gdy niszczysz bloki k\u0142\u00f3d. +Guides.Woodcutting.Section.1=&3Jak dzia\u0142a \u015acinacz Drzew?\n&e\u015cinacz Drzew to aktywna umiej\u0119tno\u015b\u0107, mo\u0107na klikn\u0105\u0107 prawym przyciskiem trzymaj\u0105c siekier\u0119, aby aktywowa\u0107 \u015cinacz Drzew. Spowoduje to natychmiastowe zniszczenie ca\u0142ego drzewa, zrzucaj\u0105c jednocze\u015bnie wszystkie k\u0142ody. +Guides.Woodcutting.Section.2=&3Jak dzia\u0142a Dmuchawa Do Li\u015bci?\n&eDmuchawa do li\u015bci to umiej\u0119tno\u015b\u0107 pasywna, kt\u00f3ra powoduje, \u017ce bloki li\u015bci natychmiast si\u0119 niszcz\u0105 po uderzeniu siekier\u0105. Umiej\u0119tno\u015b\u0107 ta domy\u015blnie odblokowuje si\u0119 na poziomie 100. +Guides.Woodcutting.Section.3=&3Jak dzia\u0142a Podw\u00f3jny \u0141up?\n&eTa pasywna umiej\u0119tno\u015b\u0107 daje ci szans\u0119 na uzyskanie dodatkowego bloku za ka\u017cd\u0105 posiekan\u0105 k\u0142od\u0119. #INSPECT Inspect.Offline= &cNie masz uprawnie\u0144 do sprawdzania graczy offline! Inspect.OfflineStats=Statystyki mcMMO dla gracza off-line &e{0} @@ -982,7 +984,7 @@ Item.Generic.Wait=Musisz odczeka\u0107 zanim ponownie to u\u017cyjesz! &e({0}s) Item.Injured.Wait=Niedawno by\u0142e\u015b kontuzjowany i musisz poczeka\u0107, zanim to wykorzystasz. &e({0}s) Item.FluxPickaxe.Name=Topi\u0105cy Kilof Item.FluxPickaxe.Lore.1=&7Ma szanse na natychmiastowe przepalenie rudy. -Item.FluxPickaxe.Lore.2=&7Wymaga poziomu &6Przepalanie: &7{0}+ +Item.FluxPickaxe.Lore.2=&7Wymaga poziomu &6Przepalania: &7{0}+ #TELEPORTATION Teleport.Commencing=&7Rozpoczynanie teleportacji… Przez &6({0}) &7sekund, nie ruszaj si\u0119... Teleport.Cancelled=&4Teleportacja anulowana! diff --git a/src/main/resources/persistent_data.yml b/src/main/resources/persistent_data.yml index 6b39879cd..8508ab84f 100644 --- a/src/main/resources/persistent_data.yml +++ b/src/main/resources/persistent_data.yml @@ -29,4 +29,9 @@ Persistent_Data: Saved_To_Disk: false # By default mcMMO gives 0 XP for this type of mob, not adjustable currently PLAYER_TAMED_MOB: - Saved_To_Disk: false \ No newline at end of file + Saved_To_Disk: false +# When players put down a block we track it, the system used to track player blocks is super efficient and has been coded extremely well +# It is never recommended to turn this off as it allows exploits such as player dupes etc +# We use our own file system for this outside of NBT which has been programmed to be lightning fast +mcMMO_Region_System: + Enabled: true \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 9b0b03ab4..64f2c982d 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -171,9 +171,6 @@ commands: aliases: [notify] description: Toggle mcMMO abilities chat display notifications on/off permission: mcmmo.commands.mcnotify - mhd: - description: Sets all players mob health settings to default - permission: mcmmo.commands.mhd mcscoreboard: aliases: [mcsb] description: Manage your mcMMO Scoreboard diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDataProcessorTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDataProcessorTest.java new file mode 100644 index 000000000..2acbd41f8 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDataProcessorTest.java @@ -0,0 +1,23 @@ +package com.gmail.nossr50.database; + +import org.junit.Test; + +public class FlatFileDataProcessorTest { + + @SuppressWarnings("ResultOfMethodCallIgnored") + @Test + public void testGetExpectedValueType() { + for(int i = 0; i < FlatFileDatabaseManager.DATA_ENTRY_COUNT; i++) { + FlatFileDataProcessor.getExpectedValueType(i); + } + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + @Test(expected = IndexOutOfBoundsException.class) + public void testGetExpectedValueTypeException() { + for(int i = 0; i < FlatFileDatabaseManager.DATA_ENTRY_COUNT+1; i++) { + FlatFileDataProcessor.getExpectedValueType(i); + } + } + +} \ No newline at end of file diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java new file mode 100644 index 000000000..62d13f69a --- /dev/null +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -0,0 +1,1019 @@ +package com.gmail.nossr50.database; + +import com.gmail.nossr50.TestUtil; +import com.gmail.nossr50.database.flatfile.LeaderboardStatus; +import com.gmail.nossr50.datatypes.database.DatabaseType; +import com.gmail.nossr50.datatypes.player.PlayerProfile; +import com.gmail.nossr50.datatypes.player.UniqueDataType; +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.datatypes.skills.SuperAbilityType; +import com.gmail.nossr50.util.skills.SkillTools; +import com.google.common.io.Files; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.Statistic; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.*; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.logging.Filter; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +import static org.junit.jupiter.api.Assertions.*; + +//This class uses JUnit5/Jupiter +public class FlatFileDatabaseManagerTest { + + public static final @NotNull String TEST_FILE_NAME = "test.mcmmo.users"; + public static final @NotNull String BAD_FILE_LINE_ONE = "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:"; + public static final @NotNull String BAD_DATA_FILE_LINE_TWENTY_THREE = "nossr51:baddata:::baddata:baddata:640:baddata:1000:1000:1000:baddata:baddata:baddata:baddata:16:0:500:20273:0:0:0:0::1000:0:0:baddata:1593543012:0:0:0:0::1000:0:0:baddata:IGNORED:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1:0:"; + public static final @NotNull String DB_BADDATA = "baddatadb.users"; + public static final @NotNull String DB_HEALTHY = "healthydb.users"; + public static final @NotNull String HEALTHY_DB_LINE_1 = "nossr50:1:IGNORED:IGNORED:10:2:20:3:4:5:6:7:8:9:10:30:40:50:60:70:80:90:100:IGNORED:11:110:111:222:333:444:555:666:777:IGNORED:12:120:888:IGNORED:HEARTS:13:130:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1111:999:2020:"; + public static final @NotNull String HEALTHY_DB_LINE_ONE_UUID_STR = "588fe472-1c82-4c4e-9aa1-7eefccb277e3"; + public static final String DB_MISSING_LAST_LOGIN = "missinglastlogin.users"; + public static final String LINE_TWO_FROM_MISSING_DB = "nossr50:1:IGNORED:IGNORED:10:2:20:3:4:5:6:7:8:9:10:30:40:50:60:70:80:90:100:IGNORED:11:110:111:222:333:444:555:666:777:IGNORED:12:120:888:0:HEARTS:13:130:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1111:999:"; + private static File tempDir; + private final static @NotNull Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); + private final long PURGE_TIME = 2630000000L; + private static @Nullable FlatFileDatabaseManager db; + + //Making them all unique makes it easier on us to edit this stuff later + int expectedLvlMining = 1, expectedLvlWoodcutting = 2, expectedLvlRepair = 3, + expectedLvlUnarmed = 4, expectedLvlHerbalism = 5, expectedLvlExcavation = 6, + expectedLvlArchery = 7, expectedLvlSwords = 8, expectedLvlAxes = 9, expectedLvlAcrobatics = 10, + expectedLvlTaming = 11, expectedLvlFishing = 12, expectedLvlAlchemy = 13; + + float expectedExpMining = 10, expectedExpWoodcutting = 20, expectedExpRepair = 30, + expectedExpUnarmed = 40, expectedExpHerbalism = 50, expectedExpExcavation = 60, + expectedExpArchery = 70, expectedExpSwords = 80, expectedExpAxes = 90, expectedExpAcrobatics = 100, + expectedExpTaming = 110, expectedExpFishing = 120, expectedExpAlchemy = 130; + + long expectedBerserkCd = 111, expectedGigaDrillBreakerCd = 222, expectedTreeFellerCd = 333, + expectedGreenTerraCd = 444, expectedSerratedStrikesCd = 555, expectedSkullSplitterCd = 666, + expectedSuperBreakerCd = 777, expectedBlastMiningCd = 888, expectedChimaeraWingCd = 999; + + int expectedScoreboardTips = 1111; + Long expectedLastLogin = 2020L; + + @BeforeAll + static void initBeforeAll() { + logger.setFilter(new DebugFilter()); + } + + @BeforeEach + public void init() { + assertNull(db); + //noinspection UnstableApiUsage + tempDir = Files.createTempDir(); + db = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + } + + private @NotNull String getTemporaryUserFilePath() { + return tempDir.getPath() + File.separator + TEST_FILE_NAME; + } + + @AfterEach + public void tearDown() { + TestUtil.recursiveDelete(tempDir); + db = null; + } + + //Nothing wrong with this database + private static final String[] normalDatabaseData = { + "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", + "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:", + "powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:" + }; + + private static final String[] badUUIDDatabaseData = { + "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", + "z750:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:3:5:1600906906:", //This one has an incorrect UUID representation + "powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:" + }; + + private static final String[] outdatedDatabaseData = { + "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", + "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:", + "electronicboy:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:" //This user is missing data added after UUID index + }; + + private static final String[] emptyLineDatabaseData = { + "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", + "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:", + "kashike:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:", + "" //EMPTY LINE + }; + + private static final String[] emptyNameDatabaseData = { + ":1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", + "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:", + "aikar:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:" + }; + + private static final String[] duplicateNameDatabaseData = { + "mochi:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", + "mochi:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:631e3896-da2a-4077-974b-d047859d76bc:0:0:", + }; + + private static final String[] duplicateUUIDDatabaseData = { + "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", + "mrfloris:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", + }; + + private static final String[] corruptDatabaseData = { + "nossr50:1000:::0:100:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", + "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:", + "corruptdataboy:の:::ののの0:2452:0:1983:1937:1790:3042ののののの:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617のののののの583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:d20c6e8d-5615-4284-b8d1-e20b92011530:5:1600906906:", + "のjapaneseuserの:333:::0:2452:0:444:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:25870f0e-7558-4659-9f60-417e24cb3332:5:1600906906:", + "sameUUIDasjapaneseuser:333:::0:442:0:544:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:25870f0e-7558-4659-9f60-417e24cb3332:5:1600906906:", + }; + + private static final String[] badDatabaseData = { + //First entry here is missing some values + "nossr50:1000:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", + //Second entry here has an integer value replaced by a string + "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:badvalue:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:" + }; + + @Test + public void testDefaultInit() { + db = new FlatFileDatabaseManager(getTemporaryUserFilePath(), logger, PURGE_TIME, 0); + } + + @Test + public void testUpdateLeaderboards() { + assertNotNull(db); + assertEquals(LeaderboardStatus.UPDATED, db.updateLeaderboards()); + } + + @Test + public void testSaveUser() { + //Make a Profile to save and check to see if it worked + UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); + String playerName = "nossr50"; + PlayerProfile testProfile = new PlayerProfile(playerName, uuid, 0); + //The above profile should be "zero" initialized + + //Save the zero version and see if it looks correct + assertNotNull(db); + assertTrue(db.getUsersFile().exists()); //Users file should have been created from the above com.gmail.nossr50.database.FlatFileDatabaseManager.checkFileHealthAndStructure + assertNotNull(db.getUsersFile()); + + //The DB is empty at this point, add our user + assertTrue(db.saveUser(testProfile)); //True means we saved the user + + //Check for the empty profile + PlayerProfile retrievedFromData = db.loadPlayerProfile(uuid); + assertTrue(retrievedFromData.isLoaded()); //PlayerProfile::isLoaded returns true if the data was created from the file, false if it wasn't found and a dummy profile was returned + assertEquals(uuid, retrievedFromData.getUniqueId()); + assertEquals(playerName, retrievedFromData.getPlayerName()); + + /* + * Test overwriting names with new names + */ + + String alteredName = "changedmyname"; + PlayerProfile changedNameProfile = new PlayerProfile(alteredName, uuid, 0); + assertTrue(db.saveUser(changedNameProfile)); //True means we saved the user + + retrievedFromData = db.loadPlayerProfile(uuid); + assertTrue(retrievedFromData.isLoaded()); //PlayerProfile::isLoaded returns true if the data was created from the file, false if it wasn't found and a dummy profile was returned + assertEquals(uuid, retrievedFromData.getUniqueId()); + assertEquals(alteredName, retrievedFromData.getPlayerName()); + } + + @Test + public void testAddedMissingLastLoginValues() { + File dbFile = prepareDatabaseTestResource(DB_MISSING_LAST_LOGIN); + + //This makes sure our private method is working before the tests run afterwards + ArrayList dataFromFile = getSplitDataFromFile(dbFile); + logger.info("File Path: "+ dbFile.getAbsolutePath()); + assertArrayEquals(LINE_TWO_FROM_MISSING_DB.split(":"), dataFromFile.get(1)); + assertEquals(dataFromFile.get(1)[FlatFileDatabaseManager.UUID_INDEX], HEALTHY_DB_LINE_ONE_UUID_STR); + + db = new FlatFileDatabaseManager(dbFile, logger, PURGE_TIME, 0, true); + List flagsFound = db.checkFileHealthAndStructure(); + assertNotNull(flagsFound); + assertTrue(flagsFound.contains(FlatFileDataFlag.LAST_LOGIN_SCHEMA_UPGRADE)); + + //Check for the fixed value + PlayerProfile profile = db.loadPlayerProfile("nossr50"); + assertEquals(-1, (long) profile.getLastLogin()); + } + + @Test + public void testLoadByName() { + File healthyDB = prepareDatabaseTestResource(DB_HEALTHY); + + /* + * We have established the files are in good order, so now for the actual testing + */ + + //This makes sure our private method is working before the tests run afterwards + ArrayList dataFromFile = getSplitDataFromFile(healthyDB); + logger.info("File Path: "+healthyDB.getAbsolutePath()); + assertArrayEquals(HEALTHY_DB_LINE_1.split(":"), dataFromFile.get(0)); + assertEquals(dataFromFile.get(0)[FlatFileDatabaseManager.UUID_INDEX], HEALTHY_DB_LINE_ONE_UUID_STR); + UUID healthDBEntryOneUUID = UUID.fromString(HEALTHY_DB_LINE_ONE_UUID_STR); + + db = new FlatFileDatabaseManager(healthyDB, logger, PURGE_TIME, 0, true); + List flagsFound = db.checkFileHealthAndStructure(); + assertNull(flagsFound); //No flags should be found + + /* + * Once the DB looks fine load the profile + */ + + String playerName = "nossr50"; + UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); + + PlayerProfile profile = db.loadPlayerProfile(playerName); + testHealthyDataProfileValues(playerName, uuid, profile); + } + + @Test + public void testNewUser() { + //We will test that new user values line up with our expectations + UUID uuid = new UUID(0, 1); + String playerName = "nossr50"; + + int newUserTestStartingLvl = 1337; + db = new FlatFileDatabaseManager(new File(tempDir.getPath() + File.separator + TEST_FILE_NAME), logger, PURGE_TIME, newUserTestStartingLvl, true); + db.checkFileHealthAndStructure(); + + PlayerProfile playerProfile = db.newUser(playerName, uuid); + + assertTrue(playerProfile.isLoaded()); + assertEquals(playerName, playerProfile.getPlayerName()); + assertEquals(uuid, playerProfile.getUniqueId()); + + PlayerProfile retrievedFromDisk = db.loadPlayerProfile(uuid); + assertTrue(retrievedFromDisk.isLoaded()); + assertEquals(playerName, retrievedFromDisk.getPlayerName()); + assertEquals(uuid, retrievedFromDisk.getUniqueId()); + + //Checking a new user for being "zero" initialized + checkNewUserValues(playerProfile, newUserTestStartingLvl); + checkNewUserValues(retrievedFromDisk, newUserTestStartingLvl); + + //TODO: Should we do any dupe checking? Probably not needed as it would be caught on the next load + db.newUser("disco", new UUID(3, 3)); + db.newUser("dingus", new UUID(3, 4)); + db.newUser("duped_dingus", new UUID(3, 4)); + + assertEquals(5, getSplitDataFromFile(db.getUsersFile()).size()); + } + + @Test + public void testAddingUsersToEndOfExistingDB() { + //We will test that new user values line up with our expectations + UUID uuid = new UUID(0, 80); + String playerName = "the_kitty_man"; + + File file = prepareDatabaseTestResource(DB_HEALTHY); //Existing DB + + int newUserTestStartingLvl = 1337; + db = new FlatFileDatabaseManager(file, logger, PURGE_TIME, newUserTestStartingLvl, true); + db.checkFileHealthAndStructure(); + + PlayerProfile playerProfile = db.newUser(playerName, uuid); + + assertTrue(playerProfile.isLoaded()); + assertEquals(playerName, playerProfile.getPlayerName()); + assertEquals(uuid, playerProfile.getUniqueId()); + + PlayerProfile retrievedFromDisk = db.loadPlayerProfile(uuid); + assertTrue(retrievedFromDisk.isLoaded()); + assertEquals(playerName, retrievedFromDisk.getPlayerName()); + assertEquals(uuid, retrievedFromDisk.getUniqueId()); + + //Checking a new user for being "zero" initialized + checkNewUserValues(playerProfile, newUserTestStartingLvl); + checkNewUserValues(retrievedFromDisk, newUserTestStartingLvl); + + //TODO: Should we do any dupe checking? Probably not needed as it would be caught on the next load + db.newUser("bidoof", new UUID(3, 3)); + db.newUser("derp", new UUID(3, 4)); + db.newUser("pizza", new UUID(3, 4)); + + assertEquals(7, getSplitDataFromFile(db.getUsersFile()).size()); + + //Now we *fix* the DB and there should be one less + db.checkFileHealthAndStructure(); + assertEquals(6, getSplitDataFromFile(db.getUsersFile()).size()); + } + + private void checkNewUserValues(@NotNull PlayerProfile playerProfile, int startingLevel) { + //Checking a new user for being zero initialized + for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { + if(SkillTools.isChildSkill(primarySkillType)) + continue; + + assertEquals(startingLevel, playerProfile.getSkillLevel(primarySkillType)); + assertEquals(0, playerProfile.getSkillXpLevelRaw(primarySkillType), 0); + } + + for(SuperAbilityType superAbilityType : SuperAbilityType.values()) { + assertEquals(0, playerProfile.getAbilityDATS(superAbilityType)); + } + + assertTrue(playerProfile.getLastLogin() > 0); + assertEquals(playerProfile.getChimaerWingDATS(), 0); + assertEquals(playerProfile.getScoreboardTipsShown(), 0); + } + + @Test + public void testLoadByUUID() { + File dbFile = prepareDatabaseTestResource(DB_HEALTHY); + + /* + * We have established the files are in good order, so now for the actual testing + */ + + //This makes sure our private method is working before the tests run afterwards + ArrayList dataFromFile = getSplitDataFromFile(dbFile); + logger.info("File Path: " + dbFile.getAbsolutePath()); + assertArrayEquals(HEALTHY_DB_LINE_1.split(":"), dataFromFile.get(0)); + assertEquals(dataFromFile.get(0)[FlatFileDatabaseManager.UUID_INDEX], HEALTHY_DB_LINE_ONE_UUID_STR); + + db = new FlatFileDatabaseManager(dbFile, logger, PURGE_TIME, 0, true); + List flagsFound = db.checkFileHealthAndStructure(); + assertNull(flagsFound); //No flags should be found + + /* + * Once the DB looks fine load the profile + */ + + String playerName = "nossr50"; + UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); + + PlayerProfile profile1 = db.loadPlayerProfile(uuid); + testHealthyDataProfileValues(playerName, uuid, profile1); + + + assertFalse(db.loadPlayerProfile(new UUID(0, 1)).isLoaded()); //This profile should not exist and therefor will return unloaded + } + + @Test + public void testLoadByUUIDAndName() { + File dbFile = prepareDatabaseTestResource(DB_HEALTHY); + + /* + * We have established the files are in good order, so now for the actual testing + */ + + //This makes sure our private method is working before the tests run afterwards + ArrayList dataFromFile = getSplitDataFromFile(dbFile); + logger.info("File Path: " + dbFile.getAbsolutePath()); + assertArrayEquals(HEALTHY_DB_LINE_1.split(":"), dataFromFile.get(0)); + assertEquals(dataFromFile.get(0)[FlatFileDatabaseManager.UUID_INDEX], HEALTHY_DB_LINE_ONE_UUID_STR); + + db = new FlatFileDatabaseManager(dbFile, logger, PURGE_TIME, 0, true); + List flagsFound = db.checkFileHealthAndStructure(); + assertNull(flagsFound); //No flags should be found + + /* + * Once the DB looks fine load the profile + */ + + String playerName = "nossr50"; + UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); + + TestOfflinePlayer player = new TestOfflinePlayer(playerName, uuid); + PlayerProfile profile1 = db.loadPlayerProfile(player); + testHealthyDataProfileValues(playerName, uuid, profile1); + + String updatedName = "updatedName"; + TestOfflinePlayer updatedNamePlayer = new TestOfflinePlayer(updatedName, uuid); + PlayerProfile updatedNameProfile = db.loadPlayerProfile(updatedNamePlayer); + testHealthyDataProfileValues(updatedName, uuid, updatedNameProfile); + + TestOfflinePlayer shouldNotExist = new TestOfflinePlayer("doesntexist", new UUID(0, 1)); + PlayerProfile profile3 = db.loadPlayerProfile(shouldNotExist); + assertFalse(profile3.isLoaded()); + } + + private File prepareDatabaseTestResource(@NotNull String dbFileName) { + ClassLoader classLoader = getClass().getClassLoader(); + URI resourceFileURI = null; + + try { + resourceFileURI = classLoader.getResource(dbFileName).toURI(); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + + assertNotNull(resourceFileURI); + File fromResourcesFile = new File(resourceFileURI); + assertNotNull(resourceFileURI); + File copyOfFile = new File(tempDir.getPath() + File.separator + dbFileName); + + if(copyOfFile.exists()) { + //noinspection ResultOfMethodCallIgnored + copyOfFile.delete(); + } + + assertTrue(fromResourcesFile.exists()); + + try { + //noinspection UnstableApiUsage + Files.copy(fromResourcesFile, copyOfFile); + } catch (IOException e) { + e.printStackTrace(); + } + + assertNotNull(copyOfFile); + return copyOfFile; + } + + private void testHealthyDataProfileValues(@NotNull String playerName, @NotNull UUID uuid, @NotNull PlayerProfile profile) { + assertTrue(profile.isLoaded()); //PlayerProfile::isLoaded returns true if the data was created from the file, false if it wasn't found and a dummy profile was returned + assertEquals(uuid, profile.getUniqueId()); + assertEquals(playerName, profile.getPlayerName()); + + /* + * Player is a match and data is loaded, check values + */ + + for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { + if(SkillTools.isChildSkill(primarySkillType)) + continue; + +// logger.info("Checking expected values for: "+primarySkillType); +// logger.info("Profile Level Value: "+profile.getSkillLevel(primarySkillType)); +// logger.info("Expected Lvl Value: "+getExpectedLevelHealthyDBEntryOne(primarySkillType)); +// logger.info("Profile Exp Value: "+profile.getSkillXpLevelRaw(primarySkillType)); +// logger.info("Expected Exp Value: "+getExpectedExperienceHealthyDBEntryOne(primarySkillType)); + + assertEquals(getExpectedLevelHealthyDBEntryOne(primarySkillType), profile.getSkillLevel(primarySkillType)); + assertEquals(getExpectedExperienceHealthyDBEntryOne(primarySkillType), profile.getSkillXpLevelRaw(primarySkillType), 0); + } + + //Check the other things + for(SuperAbilityType superAbilityType : SuperAbilityType.values()) { + assertEquals(getExpectedSuperAbilityDATS(superAbilityType), profile.getAbilityDATS(superAbilityType)); + } + + assertEquals(expectedChimaeraWingCd, profile.getUniqueData(UniqueDataType.CHIMAERA_WING_DATS)); + assertEquals(expectedScoreboardTips, profile.getScoreboardTipsShown()); + assertEquals(expectedLastLogin, profile.getLastLogin()); + } + + private long getExpectedSuperAbilityDATS(@NotNull SuperAbilityType superAbilityType) { + switch(superAbilityType) { + case BERSERK: + return expectedBerserkCd; + case SUPER_BREAKER: + return expectedSuperBreakerCd; + case GIGA_DRILL_BREAKER: + return expectedGigaDrillBreakerCd; + case GREEN_TERRA: + return expectedGreenTerraCd; + case SKULL_SPLITTER: + return expectedSkullSplitterCd; + case TREE_FELLER: + return expectedTreeFellerCd; + case SERRATED_STRIKES: + return expectedSerratedStrikesCd; + case BLAST_MINING: + return expectedBlastMiningCd; + } + + return -1; + } + + //TODO: Why is this stuff a float? + private float getExpectedExperienceHealthyDBEntryOne(@NotNull PrimarySkillType primarySkillType) { + switch(primarySkillType) { + case ACROBATICS: + return expectedExpAcrobatics; + case ALCHEMY: + return expectedExpAlchemy; + case ARCHERY: + return expectedExpArchery; + case AXES: + return expectedExpAxes; + case EXCAVATION: + return expectedExpExcavation; + case FISHING: + return expectedExpFishing; + case HERBALISM: + return expectedExpHerbalism; + case MINING: + return expectedExpMining; + case REPAIR: + return expectedExpRepair; + case SALVAGE: + case SMELTING: + return 0; + case SWORDS: + return expectedExpSwords; + case TAMING: + return expectedExpTaming; + case UNARMED: + return expectedExpUnarmed; + case WOODCUTTING: + return expectedExpWoodcutting; + } + + return -1; + } + + private int getExpectedLevelHealthyDBEntryOne(@NotNull PrimarySkillType primarySkillType) { + switch(primarySkillType) { + case ACROBATICS: + return expectedLvlAcrobatics; + case ALCHEMY: + return expectedLvlAlchemy; + case ARCHERY: + return expectedLvlArchery; + case AXES: + return expectedLvlAxes; + case EXCAVATION: + return expectedLvlExcavation; + case FISHING: + return expectedLvlFishing; + case HERBALISM: + return expectedLvlHerbalism; + case MINING: + return expectedLvlMining; + case REPAIR: + return expectedLvlRepair; + case SALVAGE: + case SMELTING: + return 0; + case SWORDS: + return expectedLvlSwords; + case TAMING: + return expectedLvlTaming; + case UNARMED: + return expectedLvlUnarmed; + case WOODCUTTING: + return expectedLvlWoodcutting; + } + + return -1; + } + + @Test + public void testOverwriteName() { + overwriteDataAndCheckForFlag(db, duplicateNameDatabaseData, FlatFileDataFlag.DUPLICATE_NAME); + ArrayList splitDataLines = getSplitDataFromFile(db.getUsersFile()); + assertNotEquals(splitDataLines.get(1)[0], splitDataLines.get(0)[0]); //Name comparison + } + + @Test + public void testDataNotFound() { + //Save the zero version and see if it looks correct + assertNotNull(db); + assertTrue(db.getUsersFile().exists()); + assertNotNull(db.getUsersFile()); + + //Check for the "unloaded" profile + PlayerProfile retrievedFromData = db.loadPlayerProfile("nossr50"); + assertFalse(retrievedFromData.isLoaded()); //PlayerProfile::isLoaded returns false if data doesn't exist for the user + } + + @Test + public void testPurgePowerlessUsers() { + replaceDataInFile(db, normalDatabaseData); + int purgeCount = db.purgePowerlessUsers(); + assertEquals(purgeCount, 1); //1 User should have been purged + } + + @Test + public void testCheckFileHealthAndStructure() { + replaceDataInFile(db, badDatabaseData); + + List dataFlags = db.checkFileHealthAndStructure(); + assertNotNull(dataFlags); + assertNotEquals(dataFlags.size(), 0); + } + + @Test + public void testFindFixableDuplicateNames() { + overwriteDataAndCheckForFlag(db, duplicateNameDatabaseData, FlatFileDataFlag.DUPLICATE_NAME); + } + + @Test + public void testFindDuplicateUUIDs() { + overwriteDataAndCheckForFlag(db, duplicateUUIDDatabaseData, FlatFileDataFlag.DUPLICATE_UUID); + } + + @Test() + public void findBadUUIDData() { + overwriteDataAndCheckForFlag(db, badUUIDDatabaseData, FlatFileDataFlag.BAD_UUID_DATA); + } + + @Test + public void testFindCorruptData() { + overwriteDataAndCheckForFlag(db, corruptDatabaseData, FlatFileDataFlag.CORRUPTED_OR_UNRECOGNIZABLE); + } + + @Test + public void testFindEmptyNames() { + overwriteDataAndCheckForFlag(db, emptyNameDatabaseData, FlatFileDataFlag.MISSING_NAME); + } + + @Test + public void testFindBadValues() { + overwriteDataAndCheckForFlag(db, badDatabaseData, FlatFileDataFlag.BAD_VALUES); + } + + @Test + public void testFindOutdatedData() { + overwriteDataAndCheckForFlag(db, outdatedDatabaseData, FlatFileDataFlag.INCOMPLETE); + } + + @Test + public void testGetDatabaseType() { + assertNotNull(db); + assertEquals(db.getDatabaseType(), DatabaseType.FLATFILE); + } + + @Test + public void testReadRank() { + //This is an empty DB + assertNotNull(db); + String rankBoyName = "rankBoy"; + UUID rankBoyUUID = new UUID(1337, 1337); + String rankGirlName = "rankGirl"; + UUID rankGirlUUID = new UUID(7331, 7331); + + PlayerProfile rankGirlProfile = addPlayerProfileWithLevelsAndSave(rankGirlName, rankGirlUUID, 100); //Rank 1 + PlayerProfile rankBoyProfile = addPlayerProfileWithLevelsAndSave(rankBoyName, rankBoyUUID, 10); //Rank 2 + + assertEquals(LeaderboardStatus.UPDATED, db.updateLeaderboards()); + Map rankGirlPositions = db.readRank(rankGirlName); + Map rankBoyPositions = db.readRank(rankBoyName); + + for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { + if(primarySkillType.isChildSkill()) { + assertNull(rankBoyPositions.get(primarySkillType)); + assertNull(rankGirlPositions.get(primarySkillType)); + } else { + assertEquals(1, rankGirlPositions.get(primarySkillType)); + assertEquals(2, rankBoyPositions.get(primarySkillType)); + } + } + + assertEquals(1, db.readRank(rankGirlName).get(null)); //Girl should be position 1 + assertEquals(2, db.readRank(rankBoyName).get(null)); //Boy should be position 2 + } + + @Test + public void testLoadFromFile() { + ClassLoader classLoader = getClass().getClassLoader(); + URI resourceFileURI = null; + + try { + resourceFileURI = classLoader.getResource(DB_BADDATA).toURI(); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + + assertNotNull(resourceFileURI); + File fromResourcesFile = new File(resourceFileURI); + assertNotNull(resourceFileURI); + File copyOfFile = new File(tempDir.getPath() + File.separator + DB_BADDATA); + + if(copyOfFile.exists()) { + copyOfFile.delete(); + } + + assertTrue(fromResourcesFile.exists()); + + try { + Files.copy(fromResourcesFile, copyOfFile); + } catch (IOException e) { + e.printStackTrace(); + } + + assertNotNull(copyOfFile); + + //This makes sure our private method is working before the tests run afterwards + ArrayList dataFromFile = getSplitDataFromFile(copyOfFile); + logger.info("File Path: "+copyOfFile.getAbsolutePath()); + assertArrayEquals(BAD_FILE_LINE_ONE.split(":"), dataFromFile.get(0)); + assertEquals(dataFromFile.get(22)[0], "nossr51"); + assertArrayEquals(BAD_DATA_FILE_LINE_TWENTY_THREE.split(":"), dataFromFile.get(22)); + + FlatFileDatabaseManager db_a = new FlatFileDatabaseManager(copyOfFile, logger, PURGE_TIME, 0, true); + List flagsFound = db_a.checkFileHealthAndStructure(); + assertNotNull(flagsFound); + assertTrue(flagsFound.contains(FlatFileDataFlag.BAD_VALUES)); + } + + private @NotNull ArrayList getSplitDataFromFile(@NotNull File file) { + ArrayList splitDataList = new ArrayList<>(); + + try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) { + String line; + + while ((line = bufferedReader.readLine()) != null) { + if (line.isEmpty()) + continue; + + String[] splitData = line.split(":"); + splitDataList.add(splitData); + } + + } catch (Exception e) { + e.printStackTrace(); + } + + return splitDataList; + } + + private @NotNull PlayerProfile addPlayerProfileWithLevelsAndSave(String playerName, UUID uuid, int levels) { + assertNotNull(db); + assertFalse(db.loadPlayerProfile(uuid).isLoaded()); + + db.newUser(playerName, uuid); + PlayerProfile leveledProfile = db.loadPlayerProfile(uuid); + + assertTrue(leveledProfile.isLoaded()); + assertEquals(playerName, leveledProfile.getPlayerName()); + assertEquals(uuid, leveledProfile.getUniqueId()); + + for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { + if(SkillTools.isChildSkill(primarySkillType)) + continue; + + leveledProfile.modifySkill(primarySkillType, levels); //TODO: This method also resets XP, not cool + } + + db.saveUser(leveledProfile); + leveledProfile = db.loadPlayerProfile(uuid); + + for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { + if(SkillTools.isChildSkill(primarySkillType)) { + continue; + } + + assertEquals(levels, leveledProfile.getSkillLevel(primarySkillType)); + } + + return leveledProfile; + } + + private void replaceDataInFile(@NotNull FlatFileDatabaseManager flatFileDatabaseManager, @NotNull String[] dataEntries) { + String filePath = flatFileDatabaseManager.getUsersFile().getAbsolutePath(); + BufferedReader in = null; + FileWriter out = null; + + try { + StringBuilder writer = new StringBuilder(); + + for(String data : dataEntries) { + writer.append(data).append("\r\n"); + } + + out = new FileWriter(filePath); + out.write(writer.toString()); + } catch (FileNotFoundException e) { + e.printStackTrace(); + logger.info("File not found"); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (out != null) { + try { + out.close(); + } + catch (IOException e) { + // Ignore + } + } + } + + try { + logger.info("Added the following lines to the FlatFileDatabase for the purposes of the test..."); + // Open the file + in = new BufferedReader(new FileReader(filePath)); + String line; + while ((line = in.readLine()) != null) { + logger.info(line); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (in != null) { + try { + in.close(); + } + catch (IOException e) { + // Ignore + } + } + } + } + + private void overwriteDataAndCheckForFlag(@NotNull FlatFileDatabaseManager targetDatabase, @NotNull String[] data, @NotNull FlatFileDataFlag flag) { + replaceDataInFile(targetDatabase, data); + + List dataFlags = targetDatabase.checkFileHealthAndStructure(); + assertNotNull(dataFlags); + assertTrue(dataFlags.contains(flag)); + } + + private class TestOfflinePlayer implements OfflinePlayer { + + private final @NotNull String name; + private final @NotNull UUID uuid; + + private TestOfflinePlayer(@NotNull String name, @NotNull UUID uuid) { + this.name = name; + this.uuid = uuid; + } + + @Override + public boolean isOnline() { + return false; + } + + @Nullable + @Override + public String getName() { + return name; + } + + @NotNull + @Override + public UUID getUniqueId() { + return uuid; + } + + @Override + public boolean isBanned() { + return false; + } + + @Override + public boolean isWhitelisted() { + return false; + } + + @Override + public void setWhitelisted(boolean value) { + + } + + @Nullable + @Override + public Player getPlayer() { + return null; + } + + @Override + public long getFirstPlayed() { + return 0; + } + + @Override + public long getLastPlayed() { + return 0; + } + + @Override + public boolean hasPlayedBefore() { + return false; + } + + @Nullable + @Override + public Location getBedSpawnLocation() { + return null; + } + + @Override + public void incrementStatistic(@NotNull Statistic statistic) throws IllegalArgumentException { + + } + + @Override + public void decrementStatistic(@NotNull Statistic statistic) throws IllegalArgumentException { + + } + + @Override + public void incrementStatistic(@NotNull Statistic statistic, int amount) throws IllegalArgumentException { + + } + + @Override + public void decrementStatistic(@NotNull Statistic statistic, int amount) throws IllegalArgumentException { + + } + + @Override + public void setStatistic(@NotNull Statistic statistic, int newValue) throws IllegalArgumentException { + + } + + @Override + public int getStatistic(@NotNull Statistic statistic) throws IllegalArgumentException { + return 0; + } + + @Override + public void incrementStatistic(@NotNull Statistic statistic, @NotNull Material material) throws IllegalArgumentException { + + } + + @Override + public void decrementStatistic(@NotNull Statistic statistic, @NotNull Material material) throws IllegalArgumentException { + + } + + @Override + public int getStatistic(@NotNull Statistic statistic, @NotNull Material material) throws IllegalArgumentException { + return 0; + } + + @Override + public void incrementStatistic(@NotNull Statistic statistic, @NotNull Material material, int amount) throws IllegalArgumentException { + + } + + @Override + public void decrementStatistic(@NotNull Statistic statistic, @NotNull Material material, int amount) throws IllegalArgumentException { + + } + + @Override + public void setStatistic(@NotNull Statistic statistic, @NotNull Material material, int newValue) throws IllegalArgumentException { + + } + + @Override + public void incrementStatistic(@NotNull Statistic statistic, @NotNull EntityType entityType) throws IllegalArgumentException { + + } + + @Override + public void decrementStatistic(@NotNull Statistic statistic, @NotNull EntityType entityType) throws IllegalArgumentException { + + } + + @Override + public int getStatistic(@NotNull Statistic statistic, @NotNull EntityType entityType) throws IllegalArgumentException { + return 0; + } + + @Override + public void incrementStatistic(@NotNull Statistic statistic, @NotNull EntityType entityType, int amount) throws IllegalArgumentException { + + } + + @Override + public void decrementStatistic(@NotNull Statistic statistic, @NotNull EntityType entityType, int amount) { + + } + + @Override + public void setStatistic(@NotNull Statistic statistic, @NotNull EntityType entityType, int newValue) { + + } + + @NotNull + @Override + public Map serialize() { + return null; + } + + @Override + public boolean isOp() { + return false; + } + + @Override + public void setOp(boolean value) { + + } + } + + private static class DebugFilter implements Filter { + + @Override + public boolean isLoggable(LogRecord record) { + return false; + } + } +} \ No newline at end of file diff --git a/src/test/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtilTest.java b/src/test/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtilTest.java new file mode 100644 index 000000000..ee6e71ffb --- /dev/null +++ b/src/test/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtilTest.java @@ -0,0 +1,27 @@ +package com.gmail.nossr50.database.flatfile; + +import com.gmail.nossr50.database.FlatFileDatabaseManager; +import org.junit.Test; + +import java.util.HashSet; + +public class FlatFileDataUtilTest { + + @Test + public void getPreparedSaveDataLine() { + } + + @Test + public void repairBadData() { + } + + @Test + public void getZeroInitialisedData() { + } + + @Test(expected = AssertionError.class) + public void testTooManyDataEntriesSplitString() { + FlatFileDataContainer dataContainer = new CategorizedFlatFileData(0, new HashSet<>(), new String[FlatFileDatabaseManager.DATA_ENTRY_COUNT + 1]); + FlatFileDataUtil.getPreparedSaveDataLine(dataContainer); + } +} \ No newline at end of file diff --git a/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java b/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java index 99e61dbe5..8876c99d6 100644 --- a/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java +++ b/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java @@ -1,20 +1,35 @@ package com.gmail.nossr50.util.blockmeta; import com.gmail.nossr50.TestUtil; -import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.BlockUtils; +import com.gmail.nossr50.util.compat.CompatibilityManager; +import com.gmail.nossr50.util.compat.layers.world.WorldCompatibilityLayer; +import com.gmail.nossr50.util.platform.PlatformManager; import com.google.common.io.Files; -import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.block.Block; +import org.bukkit.*; +import org.bukkit.block.*; +import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Entity; +import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.MetadataValue; +import org.bukkit.plugin.Plugin; +import org.bukkit.util.BoundingBox; +import org.bukkit.util.RayTraceResult; +import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.junit.*; import org.junit.runner.RunWith; import org.mockito.Mockito; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; import java.io.*; +import java.util.Collection; +import java.util.List; import java.util.UUID; import static org.mockito.Mockito.mock; @@ -23,8 +38,10 @@ import static org.mockito.Mockito.mock; * Could be a lot better. But some tests are better than none! Tests the major things, still kinda unit-testy. Verifies that the serialization isn't completely broken. */ @RunWith(PowerMockRunner.class) -@PrepareForTest({ Bukkit.class, Misc.class }) +@PrepareForTest({ Bukkit.class, mcMMO.class}) public class ChunkStoreTest { + public static final int LEGACY_WORLD_HEIGHT_MAX = 256; + public static final int LEGACY_WORLD_HEIGHT_MIN = 0; private static File tempDir; @BeforeClass public static void setUpClass() { @@ -37,6 +54,10 @@ public class ChunkStoreTest { } private World mockWorld; + private CompatibilityManager compatibilityManager; + private WorldCompatibilityLayer worldCompatibilityLayer; + private PlatformManager platformManager; + @Before public void setUpMock(){ UUID worldUUID = UUID.randomUUID(); @@ -46,6 +67,67 @@ public class ChunkStoreTest { Mockito.when(mockWorld.getWorldFolder()).thenReturn(tempDir); PowerMockito.mockStatic(Bukkit.class); Mockito.when(Bukkit.getWorld(worldUUID)).thenReturn(mockWorld); + + platformManager = mock(PlatformManager.class); + compatibilityManager = mock(CompatibilityManager.class); + worldCompatibilityLayer = mock(WorldCompatibilityLayer.class); + + Whitebox.setInternalState(mcMMO.class, "platformManager", platformManager); + Mockito.when(mcMMO.getCompatibilityManager()).thenReturn(compatibilityManager); + + Assert.assertNotNull(mcMMO.getCompatibilityManager()); + Mockito.when(platformManager.getCompatibilityManager()).thenReturn(compatibilityManager); + Mockito.when(platformManager.getCompatibilityManager().getWorldCompatibilityLayer()).thenReturn(worldCompatibilityLayer); + Assert.assertNotNull(mcMMO.getCompatibilityManager().getWorldCompatibilityLayer()); + Mockito.when(worldCompatibilityLayer.getMinWorldHeight(mockWorld)).thenReturn(LEGACY_WORLD_HEIGHT_MIN); + Mockito.when(worldCompatibilityLayer.getMaxWorldHeight(mockWorld)).thenReturn(LEGACY_WORLD_HEIGHT_MAX); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testIndexOutOfBounds() { + Mockito.when(mcMMO.getCompatibilityManager().getWorldCompatibilityLayer().getMinWorldHeight(mockWorld)).thenReturn(-64); + HashChunkManager hashChunkManager = new HashChunkManager(); + + + //Top Block + TestBlock illegalHeightBlock = new TestBlock(1337, 256, -1337, mockWorld); + Assert.assertFalse(hashChunkManager.isTrue(illegalHeightBlock)); + hashChunkManager.setTrue(illegalHeightBlock); + } + + @Test + public void testSetTrue() { + Mockito.when(mcMMO.getCompatibilityManager().getWorldCompatibilityLayer().getMinWorldHeight(mockWorld)).thenReturn(-64); + HashChunkManager hashChunkManager = new HashChunkManager(); + int radius = 2; //Could be anything but drastically changes test time + + for(int x = -radius; x <= radius; x++) { + for(int y = mockWorld.getMinHeight(); y < mockWorld.getMaxHeight(); y++) { + for(int z = -radius; z <= radius; z++) { + TestBlock testBlock = new TestBlock(x, y, z, mockWorld); + hashChunkManager.setTrue(testBlock); + Assert.assertTrue(hashChunkManager.isTrue(testBlock)); + hashChunkManager.setFalse(testBlock); + Assert.assertFalse(hashChunkManager.isTrue(testBlock)); + } + } + } + + //Bot Block + TestBlock bottomBlock = new TestBlock(1337, 0, -1337, mockWorld); + Assert.assertFalse(hashChunkManager.isTrue(bottomBlock)); + + Assert.assertTrue(BlockUtils.isWithinWorldBounds(worldCompatibilityLayer, bottomBlock)); + hashChunkManager.setTrue(bottomBlock); + Assert.assertTrue(hashChunkManager.isTrue(bottomBlock)); + + //Top Block + TestBlock topBlock = new TestBlock(1337, 255, -1337, mockWorld); + Assert.assertFalse(hashChunkManager.isTrue(topBlock)); + + Assert.assertTrue(BlockUtils.isWithinWorldBounds(worldCompatibilityLayer, topBlock)); + hashChunkManager.setTrue(topBlock); + Assert.assertTrue(hashChunkManager.isTrue(topBlock)); } @Test @@ -79,8 +161,7 @@ public class ChunkStoreTest { @Test public void testNegativeWorldMin() throws IOException { - PowerMockito.mockStatic(Misc.class); - Mockito.when(Misc.getWorldMinCompat(mockWorld)).thenReturn(-64); + Mockito.when(mcMMO.getCompatibilityManager().getWorldCompatibilityLayer().getMinWorldHeight(mockWorld)).thenReturn(-64); BitSetChunkStore original = new BitSetChunkStore(mockWorld, 1, 2); original.setTrue(14, -32, 12); @@ -99,8 +180,7 @@ public class ChunkStoreTest { original.setTrue(13, 3, 12); byte[] serializedBytes = serializeChunkstore(original); - PowerMockito.mockStatic(Misc.class); - Mockito.when(Misc.getWorldMinCompat(mockWorld)).thenReturn(-64); + Mockito.when(mcMMO.getCompatibilityManager().getWorldCompatibilityLayer().getMinWorldHeight(mockWorld)).thenReturn(-64); ChunkStore deserialized = BitSetChunkStore.Serialization.readChunkStore(new DataInputStream(new ByteArrayInputStream(serializedBytes))); assertEqualIgnoreMinMax(original, deserialized); } @@ -360,4 +440,276 @@ public class ChunkStoreTest { super.writeUTF(str); } } + + private class TestBlock implements Block { + + private final int x, y, z; + private final @NotNull World world; + + private TestBlock(int x, int y, int z, World world) { + this.x = x; + this.y = y; + this.z = z; + this.world = world; + } + + @Override + public byte getData() { + return 0; + } + + @NotNull + @Override + public BlockData getBlockData() { + return null; + } + + @NotNull + @Override + public Block getRelative(int modX, int modY, int modZ) { + return null; + } + + @NotNull + @Override + public Block getRelative(@NotNull BlockFace face) { + return null; + } + + @NotNull + @Override + public Block getRelative(@NotNull BlockFace face, int distance) { + return null; + } + + @NotNull + @Override + public Material getType() { + return null; + } + + @Override + public byte getLightLevel() { + return 0; + } + + @Override + public byte getLightFromSky() { + return 0; + } + + @Override + public byte getLightFromBlocks() { + return 0; + } + + @NotNull + @Override + public World getWorld() { + return world; + } + + @Override + public int getX() { + return x; + } + + @Override + public int getY() { + return y; + } + + @Override + public int getZ() { + return z; + } + + @NotNull + @Override + public Location getLocation() { + return null; + } + + @Nullable + @Override + public Location getLocation(@Nullable Location loc) { + return null; + } + + @NotNull + @Override + public Chunk getChunk() { + return null; + } + + @Override + public void setBlockData(@NotNull BlockData data) { + + } + + @Override + public void setBlockData(@NotNull BlockData data, boolean applyPhysics) { + + } + + @Override + public void setType(@NotNull Material type) { + + } + + @Override + public void setType(@NotNull Material type, boolean applyPhysics) { + + } + + @Nullable + @Override + public BlockFace getFace(@NotNull Block block) { + return null; + } + + @NotNull + @Override + public BlockState getState() { + return null; + } + + @NotNull + @Override + public Biome getBiome() { + return null; + } + + @Override + public void setBiome(@NotNull Biome bio) { + + } + + @Override + public boolean isBlockPowered() { + return false; + } + + @Override + public boolean isBlockIndirectlyPowered() { + return false; + } + + @Override + public boolean isBlockFacePowered(@NotNull BlockFace face) { + return false; + } + + @Override + public boolean isBlockFaceIndirectlyPowered(@NotNull BlockFace face) { + return false; + } + + @Override + public int getBlockPower(@NotNull BlockFace face) { + return 0; + } + + @Override + public int getBlockPower() { + return 0; + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public boolean isLiquid() { + return false; + } + + @Override + public double getTemperature() { + return 0; + } + + @Override + public double getHumidity() { + return 0; + } + + @NotNull + @Override + public PistonMoveReaction getPistonMoveReaction() { + return null; + } + + @Override + public boolean breakNaturally() { + return false; + } + + @Override + public boolean breakNaturally(@Nullable ItemStack tool) { + return false; + } + + @Override + public boolean applyBoneMeal(@NotNull BlockFace face) { + return false; + } + + @NotNull + @Override + public Collection getDrops() { + return null; + } + + @NotNull + @Override + public Collection getDrops(@Nullable ItemStack tool) { + return null; + } + + @NotNull + @Override + public Collection getDrops(@NotNull ItemStack tool, @Nullable Entity entity) { + return null; + } + + @Override + public boolean isPassable() { + return false; + } + + @Nullable + @Override + public RayTraceResult rayTrace(@NotNull Location start, @NotNull Vector direction, double maxDistance, @NotNull FluidCollisionMode fluidCollisionMode) { + return null; + } + + @NotNull + @Override + public BoundingBox getBoundingBox() { + return null; + } + + @Override + public void setMetadata(@NotNull String metadataKey, @NotNull MetadataValue newMetadataValue) { + + } + + @NotNull + @Override + public List getMetadata(@NotNull String metadataKey) { + return null; + } + + @Override + public boolean hasMetadata(@NotNull String metadataKey) { + return false; + } + + @Override + public void removeMetadata(@NotNull String metadataKey, @NotNull Plugin owningPlugin) { + + } + } } diff --git a/src/test/java/com/gmail/nossr50/util/skills/SkillToolsTest.java b/src/test/java/com/gmail/nossr50/util/skills/SkillToolsTest.java new file mode 100644 index 000000000..4a295d5d3 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/util/skills/SkillToolsTest.java @@ -0,0 +1,16 @@ +//package com.gmail.nossr50.util.skills; +// +//import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +//import com.google.common.collect.ImmutableList; +//import org.junit.Before; +//import org.junit.Test; +//import org.junit.runner.RunWith; +//import org.powermock.core.classloader.annotations.PrepareForTest; +//import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; +//import org.powermock.modules.junit4.PowerMockRunner; +// +//@RunWith(PowerMockRunner.class) +//@PrepareForTest(SkillTools.class) +//public class SkillToolsTest { +// +//} \ No newline at end of file diff --git a/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java b/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java index fee41b9b3..da1e021db 100644 --- a/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java +++ b/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java @@ -2,8 +2,8 @@ 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; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; /** * This Unit Test checks if Adventure was set up correctly and works as expected. @@ -26,7 +26,6 @@ public class TextUtilsTest { */ TextComponent component = TextUtils.colorizeText(inputText); - Assert.assertEquals("Looks like Adventure is not working correctly.", - NamedTextColor.DARK_RED, component.color()); + Assertions.assertEquals(NamedTextColor.DARK_RED, component.color(), "Looks like Adventure is not working correctly."); } } diff --git a/src/test/resources/baddatadb.users b/src/test/resources/baddatadb.users new file mode 100644 index 000000000..12584deca --- /dev/null +++ b/src/test/resources/baddatadb.users @@ -0,0 +1,23 @@ +mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906: +ender_vine:434:::33:93:0:115:115:389:216:88:287:130:468:380:944:150:90:0:0:1948:584::2:0:1584896276:1586477151:1585264062:0:1576456374:1534725135:1577535765::404:4207:0:1616024209:HEARTS:3:0:812c10b0-7bbf-49e5-ac53-3f0521eb504b:5:0: +electronicboy:225:::1876:16:0:99:137:148:308:109:418:193:430:0:854:0:0:0:0:260:2816::19:0:1604048398:1601216462:1563297488:1533836917:1571449594:1601219209:1601215461::406:4207:0:1617465739:HEARTS:7:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:0: +z750:1074:::21081:231:0:280:65:156:463:612:742:550:1060:1000:1751:3666:5834:4871:11278:1943:13642::25:460:1613103021:1610212680:1609278207:0:1610076033:1586744907:1610150046::399:7050:0:1613611193:HEARTS:11:0:1594aa76-6ce0-46f6-90b2-83896a829db8:5:0: +Aikar:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1617623810:HEARTS:0:0:6c4ed41d-9936-45da-9f57-b0f4cfa451b4:0: +wizjany:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1617624693:HEARTS:0:0:0609efd6-e9ae-4f6a-bcff-69a6c890192f:0: +SpottedLeaf:0:::0:0:0:0:0:0:0:0:0:0:21:0:0:0:0:0:0:0:231::0:0:0:0:0:0:0:0:0::0:0:0:1617628585:HEARTS:0:0:6c002484-c964-4627-8026-9955d0d30aaf:0:0: +Cheesy:0:::0:0:0:0:0:0:0:0:0:0:6:0:0:0:0:0:0:0:882::0:0:0:0:0:0:0:0:0::0:0:0:1617636874:HEARTS:0:0:0a5804b3-f127-4962-8b83-f5f3dfe6d8e3:0:0: +Mochi:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1617642310:HEARTS:0:0:468fb276-444f-4c79-bb07-8a7a30f95606:0: +Futan:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1617644058:HEARTS:0:0:98f9e3c2-75ce-448c-b30b-01f93b69f0ca:0: +Dave:0:::0:0:0:0:0:0:0:0:0:0:0:0:61:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1617653877:HEARTS:0:0:23926471-655b-4117-8ee6-7c718677f2e1:0:0: +MomShroom:0:::0:0:0:0:0:0:0:0:0:0:1:0:0:0:0:0:0:0:231::0:0:0:0:0:0:0:0:0::0:0:0:1617700103:HEARTS:0:0:eda1c2d5-7cf6-461c-aced-86954675b905:0:0: +broccolai:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1617736110:HEARTS:0:0:8a4f8f1c-8242-4c52-bd63-3a4f6fe85771:0: +gabizou:0:::0:0:0:0:0:0:0:0:0:0:6:0:0:0:0:0:692:897:231::0:0:0:0:0:0:0:0:0::0:302:0:1617744451:HEARTS:0:0:fd1ad842-8959-4433-9f09-406da1567f98:0:0: +Vera:18:::150:1:769:0:0:0:0:0:0:0:0:0:0:183:0:0:0:540:0::0:0:0:0:0:0:0:0:0::0:0:0:1617744730:HEARTS:0:0:0a95d72c-4316-4b25-a4ad-b0719843d723:0:0: +proxy:0:::189:1:0:1:1:0:0:0:0:1:0:36:96:0:0:0:0:181:0::1:0:0:0:0:0:0:0:0::0:0:0:1617792154:HEARTS:1:0:d8531191-e49b-4132-8223-e3b46f8450d2:0:0: +chew:4:::1011:0:0:0:0:0:2:0:0:0:0:0:61:0:432:0:0:0:651::0:0:0:0:0:0:0:0:0::0:0:0:1617794539:HEARTS:0:0:58cea4a2-1979-48e4-a171-eaa631376835:0:0: +t00thpick1:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1617798657:HEARTS:0:0:1300f1de-0108-43c3-839f-d40d7e0c7027:0: +kashike:1:::756:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1617826439:HEARTS:0:0:891825c2-2ceb-4b69-82c3-f2dfb47f9a6d:0:0: +camm:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1617830574:HEARTS:0:0:5c34f924-f7f6-4547-9e36-4234133e2162:0: +brandonxp4000:0:::0:0:0:0:0:0:0:0:2:0:1:0:181:0:0:0:54:0:231::0:0:0:0:0:0:0:0:0::0:0:0:1617887039:HEARTS:0:0:cbf7122b-0271-4daa-aeaa-3bc44e6dae88:0:0: +Tapola:1:::111:0:0:1:0:0:0:0:3:2:0:111:193:0:0:0:1010:92:0::0:0:0:0:0:0:0:0:0::0:0:0:1617886681:HEARTS:0:0:4a21353a-8ca1-436f-9b5f-d2e522dcf79e:0:0: +nossr51:baddata:::baddata:baddata:640:baddata:1000:1000:1000:baddata:baddata:baddata:baddata:16:0:500:20273:0:0:0:0::1000:0:0:baddata:1593543012:0:0:0:0::1000:0:0:baddata:IGNORED:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1:0: diff --git a/src/test/resources/healthydb.users b/src/test/resources/healthydb.users new file mode 100644 index 000000000..7ce5ccbad --- /dev/null +++ b/src/test/resources/healthydb.users @@ -0,0 +1,3 @@ +nossr50:1:IGNORED:IGNORED:10:2:20:3:4:5:6:7:8:9:10:30:40:50:60:70:80:90:100:IGNORED:11:110:111:222:333:444:555:666:777:IGNORED:12:120:888:IGNORED:HEARTS:13:130:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1111:999:2020: +mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:3030: +powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1337:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:4040: \ No newline at end of file diff --git a/src/test/resources/missinglastlogin.users b/src/test/resources/missinglastlogin.users new file mode 100644 index 000000000..54378e194 --- /dev/null +++ b/src/test/resources/missinglastlogin.users @@ -0,0 +1,4 @@ +# A single comment line is sometimes at the top of the DB +nossr50:1:IGNORED:IGNORED:10:2:20:3:4:5:6:7:8:9:10:30:40:50:60:70:80:90:100:IGNORED:11:110:111:222:333:444:555:666:777:IGNORED:12:120:888:0:HEARTS:13:130:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1111:999: +mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906: +powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1337:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906: \ No newline at end of file