فهرست منبع

More API migration, feels like a mountain of work left lol

nossr50 4 سال پیش
والد
کامیت
4199ea0095
100فایلهای تغییر یافته به همراه2340 افزوده شده و 2450 حذف شده
  1. 1220 1222
      src/main/java/com/gmail/nossr50/api/ExperienceAPI.java
  2. 3 3
      src/main/java/com/gmail/nossr50/chat/ChatManager.java
  3. 1 1
      src/main/java/com/gmail/nossr50/commands/AbilityToggleCommand.java
  4. 1 1
      src/main/java/com/gmail/nossr50/commands/McgodCommand.java
  5. 1 1
      src/main/java/com/gmail/nossr50/commands/McrefreshCommand.java
  6. 1 1
      src/main/java/com/gmail/nossr50/commands/ToggleCommand.java
  7. 1 1
      src/main/java/com/gmail/nossr50/commands/admin/PlayerDebugCommand.java
  8. 1 1
      src/main/java/com/gmail/nossr50/commands/chat/McChatSpy.java
  9. 0 1
      src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java
  10. 0 2
      src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java
  11. 1 1
      src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java
  12. 0 1
      src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java
  13. 1 2
      src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java
  14. 1 1
      src/main/java/com/gmail/nossr50/commands/party/PartyRenameCommand.java
  15. 11 9
      src/main/java/com/gmail/nossr50/commands/party/teleport/PtpCommand.java
  16. 1 1
      src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java
  17. 1 1
      src/main/java/com/gmail/nossr50/commands/player/McrankCommand.java
  18. 14 14
      src/main/java/com/gmail/nossr50/commands/player/XPBarCommand.java
  19. 2 2
      src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java
  20. 4 2
      src/main/java/com/gmail/nossr50/commands/skills/AlchemyCommand.java
  21. 1 1
      src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java
  22. 2 2
      src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java
  23. 1 1
      src/main/java/com/gmail/nossr50/commands/skills/ExcavationCommand.java
  24. 1 1
      src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java
  25. 11 11
      src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java
  26. 1 1
      src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java
  27. 4 4
      src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java
  28. 8 8
      src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java
  29. 1 1
      src/main/java/com/gmail/nossr50/commands/skills/SalvageCommand.java
  30. 31 26
      src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java
  31. 6 1
      src/main/java/com/gmail/nossr50/commands/skills/SkillGuideCommand.java
  32. 3 3
      src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java
  33. 3 3
      src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java
  34. 2 2
      src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java
  35. 1 1
      src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java
  36. 1 1
      src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java
  37. 1 0
      src/main/java/com/gmail/nossr50/config/Config.java
  38. 31 2
      src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java
  39. 5 4
      src/main/java/com/gmail/nossr50/database/DatabaseManager.java
  40. 0 459
      src/main/java/com/gmail/nossr50/datatypes/experience/ExperienceManager.java
  41. 6 0
      src/main/java/com/gmail/nossr50/datatypes/experience/OfflineExperienceProcessor.java
  42. 379 0
      src/main/java/com/gmail/nossr50/datatypes/experience/OnlineExperienceProcessor.java
  43. 0 21
      src/main/java/com/gmail/nossr50/datatypes/experience/XPGainReason.java
  44. 0 10
      src/main/java/com/gmail/nossr50/datatypes/experience/XPGainSource.java
  45. 1 1
      src/main/java/com/gmail/nossr50/datatypes/party/PartyMemberManager.java
  46. 19 28
      src/main/java/com/gmail/nossr50/datatypes/player/AbstractMMOPlayer.java
  47. 39 30
      src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java
  48. 2 3
      src/main/java/com/gmail/nossr50/datatypes/player/PersistentPlayerData.java
  49. 27 138
      src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java
  50. 0 151
      src/main/java/com/gmail/nossr50/datatypes/skills/CoreSkillConstants.java
  51. 224 0
      src/main/java/com/gmail/nossr50/datatypes/skills/CoreSkills.java
  52. 1 1
      src/main/java/com/gmail/nossr50/datatypes/skills/SkillRegisterImpl.java
  53. 9 10
      src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java
  54. 0 1
      src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerExperienceEvent.java
  55. 0 1
      src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelChangeEvent.java
  56. 0 1
      src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelDownEvent.java
  57. 0 1
      src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelUpEvent.java
  58. 0 1
      src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerXpGainEvent.java
  59. 10 10
      src/main/java/com/gmail/nossr50/listeners/BlockListener.java
  60. 2 2
      src/main/java/com/gmail/nossr50/listeners/EntityListener.java
  61. 5 5
      src/main/java/com/gmail/nossr50/listeners/PlayerListener.java
  62. 7 8
      src/main/java/com/gmail/nossr50/listeners/SelfListener.java
  63. 12 12
      src/main/java/com/gmail/nossr50/party/PartyManager.java
  64. 1 3
      src/main/java/com/gmail/nossr50/party/ShareHandler.java
  65. 3 2
      src/main/java/com/gmail/nossr50/runnables/items/ChimaeraWingWarmup.java
  66. 7 5
      src/main/java/com/gmail/nossr50/runnables/items/TeleportationWarmup.java
  67. 9 4
      src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java
  68. 3 3
      src/main/java/com/gmail/nossr50/runnables/skills/AbilityCooldownTask.java
  69. 1 1
      src/main/java/com/gmail/nossr50/runnables/skills/AbilityDisableTask.java
  70. 5 2
      src/main/java/com/gmail/nossr50/runnables/skills/AlchemyBrewTask.java
  71. 0 2
      src/main/java/com/gmail/nossr50/runnables/skills/AwardCombatXpTask.java
  72. 1 1
      src/main/java/com/gmail/nossr50/runnables/skills/DelayedHerbalismXPCheckTask.java
  73. 6 7
      src/main/java/com/gmail/nossr50/runnables/skills/ExperienceBarHideTask.java
  74. 1 1
      src/main/java/com/gmail/nossr50/runnables/skills/SkillUnlockNotificationTask.java
  75. 1 1
      src/main/java/com/gmail/nossr50/runnables/skills/ToolLowerTask.java
  76. 2 4
      src/main/java/com/gmail/nossr50/skills/SkillManager.java
  77. 0 1
      src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java
  78. 0 2
      src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyManager.java
  79. 16 12
      src/main/java/com/gmail/nossr50/skills/child/FamilyTree.java
  80. 3 3
      src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowManager.java
  81. 0 1
      src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java
  82. 21 22
      src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java
  83. 3 5
      src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java
  84. 0 1
      src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java
  85. 0 1
      src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java
  86. 0 2
      src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java
  87. 0 1
      src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java
  88. 0 1
      src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java
  89. 3 2
      src/main/java/com/gmail/nossr50/util/ChimaeraWing.java
  90. 1 3
      src/main/java/com/gmail/nossr50/util/EventUtils.java
  91. 5 5
      src/main/java/com/gmail/nossr50/util/HardcoreManager.java
  92. 5 1
      src/main/java/com/gmail/nossr50/util/Misc.java
  93. 2 0
      src/main/java/com/gmail/nossr50/util/Permissions.java
  94. 2 2
      src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java
  95. 19 16
      src/main/java/com/gmail/nossr50/util/experience/ExperienceBarWrapper.java
  96. 3 5
      src/main/java/com/gmail/nossr50/util/experience/ExperienceUtils.java
  97. 57 59
      src/main/java/com/gmail/nossr50/util/experience/MMOExperienceBarManager.java
  98. 4 4
      src/main/java/com/gmail/nossr50/util/input/AbilityActivationProcessor.java
  99. 10 10
      src/main/java/com/gmail/nossr50/util/input/SuperAbilityManager.java
  100. 24 20
      src/main/java/com/gmail/nossr50/util/player/NotificationManager.java

+ 1220 - 1222
src/main/java/com/gmail/nossr50/api/ExperienceAPI.java

@@ -1,1222 +1,1220 @@
-package com.gmail.nossr50.api;
-
-import com.gmail.nossr50.api.exceptions.*;
-import com.gmail.nossr50.config.Config;
-import com.gmail.nossr50.config.experience.ExperienceConfig;
-import com.gmail.nossr50.datatypes.experience.FormulaType;
-import com.gmail.nossr50.datatypes.experience.XPGainReason;
-import com.gmail.nossr50.datatypes.experience.XPGainSource;
-import com.neetgames.mcmmo.player.OnlineMMOPlayer;
-import com.gmail.nossr50.datatypes.player.PlayerProfile;
-import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
-import com.gmail.nossr50.mcMMO;
-import com.gmail.nossr50.skills.child.FamilyTree;
-import com.gmail.nossr50.util.skills.CombatUtils;
-import org.bukkit.block.BlockState;
-import org.bukkit.entity.LivingEntity;
-import org.bukkit.entity.Player;
-
-import java.util.ArrayList;
-import java.util.Set;
-import java.util.UUID;
-
-public final class ExperienceAPI {
-    private ExperienceAPI() {}
-
-    /**
-     * Returns whether given string is a valid type of skill suitable for the
-     * other API calls in this class.
-     * </br>
-     * 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 mmoPlayer The attacking player
-     * @param target The defending entity
-     * @param primarySkillType The skill being used
-     * @param multiplier final XP result will be multiplied by this
-     * @deprecated Draft API
-     */
-    @Deprecated
-    public static void addCombatXP(OnlineMMOPlayer mmoPlayer, LivingEntity target, PrimarySkillType primarySkillType, double multiplier) {
-        CombatUtils.processCombatXP(mmoPlayer, target, primarySkillType, multiplier);
-    }
-
-    /**
-     * Start the task that gives combat XP.
-     * Processes combat XP like mcMMO normally would, so mcMMO will check whether or not the entity should reward XP when giving out the XP
-     *
-     * @param mmoPlayer The attacking player
-     * @param target The defending entity
-     * @param primarySkillType The skill being used
-     * @deprecated Draft API
-     */
-    @Deprecated
-    public static void addCombatXP(OnlineMMOPlayer mmoPlayer, LivingEntity target, PrimarySkillType primarySkillType) {
-        CombatUtils.processCombatXP(mmoPlayer, target, primarySkillType);
-    }
-
-    /**
-     * Returns whether the given skill type string is both valid and not a
-     * child skill. (Child skills have no XP of their own, and their level is
-     * derived from the parent(s).)
-     * </br>
-     * 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.
-     * </br>
-     * 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.
-     * </br>
-     * 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.
-     * </br>
-     * 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).getExperienceManager().beginUnsharedXpGain(player, getSkillType(skillType), XP, getXPGainReason(xpGainReason), XPGainSource.CUSTOM);
-            return;
-        }
-
-        getPlayer(player).getExperienceManager().applyXpGain(player, getSkillType(skillType), XP, getXPGainReason(xpGainReason), XPGainSource.CUSTOM);
-    }
-
-    /**
-     * Adds raw XP to an offline player.
-     * </br>
-     * 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.
-     * </br>
-     * 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.
-     * </br>
-     * 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.
-     * </br>
-     * 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.
-     * </br>
-     * 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).getExperienceManager().applyXpGain(player, getSkillType(skillType), (int) (XP * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()), getXPGainReason(xpGainReason), XPGainSource.CUSTOM);
-    }
-
-    /**
-     * Adds XP to an offline player, calculates for XP Rate only.
-     * </br>
-     * 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.
-     * </br>
-     * 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.
-     * </br>
-     * 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.
-     * </br>
-     * 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).getExperienceManager().beginUnsharedXpGain(player, skill, (int) (XP / skill.getXpModifier() * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()), getXPGainReason(xpGainReason), XPGainSource.CUSTOM);
-            return;
-        }
-
-        getPlayer(player).getExperienceManager().applyXpGain(player, skill, (int) (XP / skill.getXpModifier() * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()), getXPGainReason(xpGainReason), XPGainSource.CUSTOM);
-    }
-
-    /**
-     * Adds XP to an offline player, calculates for XP Rate and skill modifier.
-     * </br>
-     * 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.
-     * </br>
-     * 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.
-     * </br>
-     * 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.
-     * </br>
-     * 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).getExperienceManager().beginUnsharedXpGain(player, getSkillType(skillType), XP, getXPGainReason(xpGainReason), XPGainSource.CUSTOM);
-            return;
-        }
-
-        getPlayer(player).getExperienceManager().beginXpGain(player, getSkillType(skillType), XP, getXPGainReason(xpGainReason), XPGainSource.CUSTOM);
-    }
-
-    /**
-     * Get the amount of XP a player has in a specific skill.
-     * </br>
-     * 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).getExperienceManager().getSkillXpValue(getNonChildSkillType(skillType));
-    }
-
-    /**
-     * Get the amount of XP an offline player has in a specific skill.
-     * </br>
-     * 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).getExperienceManager().getSkillXpValue(getNonChildSkillType(skillType));
-    }
-
-    /**
-     * Get the amount of XP an offline player has in a specific skill.
-     * </br>
-     * 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).getExperienceManager().getSkillXpValue(getNonChildSkillType(skillType));
-    }
-
-    /**
-     * Get the raw amount of XP a player has in a specific skill.
-     * </br>
-     * 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).getExperienceManager().getSkillXpLevelRaw(getNonChildSkillType(skillType));
-    }
-
-    /**
-     * Get the raw amount of XP an offline player has in a specific skill.
-     * </br>
-     * 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).getExperienceManager().getSkillXpLevelRaw(getNonChildSkillType(skillType));
-    }
-
-    /**
-     * Get the raw amount of XP an offline player has in a specific skill.
-     * </br>
-     * 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).getExperienceManager().getSkillXpLevelRaw(getNonChildSkillType(skillType));
-    }
-
-    /**
-     * Get the total amount of XP needed to reach the next level.
-     * </br>
-     * 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).getExperienceManager().getExperienceToNextLevel(getNonChildSkillType(skillType));
-    }
-
-    /**
-     * Get the total amount of XP an offline player needs to reach the next level.
-     * </br>
-     * 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).getExperienceManager().getExperienceToNextLevel(getNonChildSkillType(skillType));
-    }
-
-    /**
-     * Get the total amount of XP an offline player needs to reach the next level.
-     * </br>
-     * 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).getExperienceManager().getExperienceToNextLevel(getNonChildSkillType(skillType));
-    }
-
-    /**
-     * Get the amount of XP remaining until the next level.
-     * </br>
-     * This function is designed for API usage.
-     *
-     * @param player The player to get the XP amount for
-     * @param skillType The skill to get the XP amount for
-     * @return the amount of XP remaining until the next level
-     *
-     * @throws InvalidSkillException if the given skill is not valid
-     * @throws UnsupportedOperationException if the given skill is a child skill
-     */
-    public static int getXPRemaining(Player player, String skillType) {
-        PrimarySkillType skill = getNonChildSkillType(skillType);
-
-        PlayerProfile profile = getPlayer(player);
-
-        return profile.getExperienceManager().getExperienceToNextLevel(skill) - profile.getExperienceManager().getSkillXpValue(skill);
-    }
-
-    /**
-     * Get the amount of XP an offline player has left before leveling up.
-     * </br>
-     * 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.getExperienceManager().getExperienceToNextLevel(skill) - profile.getExperienceManager().getSkillXpValue(skill);
-    }
-
-    /**
-     * Get the amount of XP an offline player has left before leveling up.
-     * </br>
-     * 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.getExperienceManager().getExperienceToNextLevel(skill) - profile.getExperienceManager().getSkillXpLevelRaw(skill);
-    }
-
-    /**
-     * Add levels to a skill.
-     * </br>
-     * 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).getExperienceManager().addLevels(getSkillType(skillType), levels);
-    }
-
-    /**
-     * Add levels to a skill for an offline player.
-     * </br>
-     * 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<PrimarySkillType> parentSkills = FamilyTree.getParents(skill);
-
-            for (PrimarySkillType parentSkill : parentSkills) {
-                profile.getExperienceManager().addLevels(parentSkill, (levels / parentSkills.size()));
-            }
-
-            mcMMO.getUserManager().scheduleAsyncSave(profile.getPersistentPlayerData());
-            return;
-        }
-
-        profile.getExperienceManager().addLevels(skill, levels);
-        mcMMO.getUserManager().scheduleAsyncSave(profile.getPersistentPlayerData());
-    }
-
-    /**
-     * Add levels to a skill for an offline player.
-     * </br>
-     * 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<PrimarySkillType> parentSkills = FamilyTree.getParents(skill);
-
-            for (PrimarySkillType parentSkill : parentSkills) {
-                profile.getExperienceManager().addLevels(parentSkill, (levels / parentSkills.size()));
-            }
-
-            mcMMO.getUserManager().scheduleAsyncSave(profile.getPersistentPlayerData());
-            return;
-        }
-
-        profile.getExperienceManager().addLevels(skill, levels);
-        mcMMO.getUserManager().scheduleAsyncSave(profile.getPersistentPlayerData());
-    }
-
-    /**
-     * Get the level a player has in a specific skill.
-     * </br>
-     * 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).getExperienceManager().getSkillLevel(getSkillType(skillType));
-    }
-
-    /**
-     * Get the level a player has in a specific skill.
-     * </br>
-     * 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).getExperienceManager().getSkillLevel(skillType);
-    }
-
-    /**
-     * Get the level an offline player has in a specific skill.
-     * </br>
-     * This function is designed for API usage.
-     *
-     * @param playerName The player to get the level for
-     * @param skillType The skill to get the level for
-     * @return the level of a given skill
-     *
-     * @throws InvalidSkillException if the given skill is not valid
-     * @throws InvalidPlayerException if the given player does not exist in the database
-     */
-    @Deprecated
-    public static int getLevelOffline(String playerName, String skillType) {
-        return getOfflineProfile(playerName).getExperienceManager().getSkillLevel(getSkillType(skillType));
-    }
-
-    /**
-     * Get the level an offline player has in a specific skill.
-     * </br>
-     * 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).getExperienceManager().getSkillLevel(getSkillType(skillType));
-    }
-
-    /**
-     * Gets the power level of a player.
-     * </br>
-     * 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).getExperienceManager().getPowerLevel();
-    }
-
-    /**
-     * Gets the power level of an offline player.
-     * </br>
-     * 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.getExperienceManager().getSkillLevel(type);
-        }
-
-        return powerLevel;
-    }
-
-    /**
-     * Gets the power level of an offline player.
-     * </br>
-     * 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.getExperienceManager().getSkillLevel(type);
-        }
-
-        return powerLevel;
-    }
-
-    /**
-     * Get the level cap of a specific skill.
-     * </br>
-     * 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.
-     * </br>
-     * 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.
-     * </br>
-     * 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.
-     * </br>
-     * 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.
-     * </br>
-     * 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.
-     * </br>
-     * 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.
-     * </br>
-     * 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).getExperienceManager().setSkillLevel(getSkillType(skillType), skillLevel);
-    }
-
-    /**
-     * Sets the level of an offline player in a specific skill type.
-     * </br>
-     * 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).getExperienceManager().setSkillLevel(getSkillType(skillType), skillLevel);
-    }
-
-    /**
-     * Sets the level of an offline player in a specific skill type.
-     * </br>
-     * 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).getExperienceManager().setSkillLevel(getSkillType(skillType), skillLevel);
-    }
-
-    /**
-     * Sets the XP of a player in a specific skill type.
-     * </br>
-     * 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).getExperienceManager().setSkillXpValue(getNonChildSkillType(skillType), (float) newValue);
-    }
-
-    /**
-     * Sets the XP of an offline player in a specific skill type.
-     * </br>
-     * 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).getExperienceManager().setSkillXpValue(getNonChildSkillType(skillType), newValue);
-    }
-
-    /**
-     * Sets the XP of an offline player in a specific skill type.
-     * </br>
-     * 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).getExperienceManager().setSkillXpValue(getNonChildSkillType(skillType), newValue);
-    }
-
-    /**
-     * Removes XP from a player in a specific skill type.
-     * </br>
-     * 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).getExperienceManager().removeXp(getNonChildSkillType(skillType), xp);
-    }
-
-    /**
-     * Removes XP from an offline player in a specific skill type.
-     * </br>
-     * 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).getExperienceManager().removeXp(getNonChildSkillType(skillType), xp);
-    }
-
-    /**
-     * Removes XP from an offline player in a specific skill type.
-     * </br>
-     * 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).getExperienceManager().removeXp(getNonChildSkillType(skillType), xp);
-    }
-
-    /**
-     * Check how much XP is needed for a specific level with the selected level curve.
-     * </br>
-     * 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.
-     * </br>
-     * This function is designed for API usage.
-     *
-     * @param level The level to get the amount of XP for
-     * @param formulaType The formula type to get the amount of XP for
-     *
-     * @throws InvalidFormulaTypeException if the given formulaType is not valid
-     */
-    public static int getXpNeededToLevel(int level, String formulaType) {
-        return mcMMO.getFormulaManager().getXPtoNextLevel(level, getFormulaType(formulaType));
-    }
-
-    /**
-     * Will add the appropriate type of XP from the block to the player based on the material of the blocks given
-     * @param blockStates the blocks to reward XP for
-     * @param mmoPlayer the target player
-     */
-    public static void addXpFromBlocks(ArrayList<BlockState> blockStates, OnlineMMOPlayer mmoPlayer)
-    {
-        for(BlockState bs : blockStates)
-        {
-            for(PrimarySkillType skillType : PrimarySkillType.values())
-            {
-                if(ExperienceConfig.getInstance().getXp(skillType, bs.getType()) > 0)
-                {
-                    mmoPlayer.getExperienceManager().applyXpGain(mmoPlayer.getPlayer(), skillType, ExperienceConfig.getInstance().getXp(skillType, bs.getType()), XPGainReason.PVE, XPGainSource.SELF);
-                }
-            }
-        }
-    }
-
-    /**
-     * Will add the appropriate type of XP from the block to the player based on the material of the blocks given if it matches the given skillType
-     * @param blockStates the blocks to reward XP for
-     * @param mmoPlayer the target player
-     * @param skillType target primary skill
-     */
-    public static void addXpFromBlocksBySkill(ArrayList<BlockState> blockStates, OnlineMMOPlayer mmoPlayer, PrimarySkillType skillType)
-    {
-        for(BlockState bs : blockStates)
-        {
-            if(ExperienceConfig.getInstance().getXp(skillType, bs.getType()) > 0)
-            {
-                mmoPlayer.getExperienceManager().applyXpGain(mmoPlayer.getPlayer(), skillType, ExperienceConfig.getInstance().getXp(skillType, bs.getType()), XPGainReason.PVE, XPGainSource.SELF);
-            }
-        }
-    }
-
-    /**
-     * Will add the appropriate type of XP from the block to the player based on the material of the blocks given
-     * @param blockState The target blockstate
-     * @param mmoPlayer The target player
-     */
-    public static void addXpFromBlock(BlockState blockState, OnlineMMOPlayer mmoPlayer)
-    {
-        for(PrimarySkillType skillType : PrimarySkillType.values())
-        {
-            if(ExperienceConfig.getInstance().getXp(skillType, blockState.getType()) > 0)
-            {
-                mmoPlayer.getExperienceManager().applyXpGain(mmoPlayer.getPlayer(), skillType, ExperienceConfig.getInstance().getXp(skillType, blockState.getType()), XPGainReason.PVE, XPGainSource.SELF);
-            }
-        }
-    }
-
-    /**
-     * Will add the appropriate type of XP from the block to the player based on the material of the blocks given if it matches the given skillType
-     * @param blockState The target blockstate
-     * @param mmoPlayer The target player
-     * @param skillType target primary skill
-     */
-    public static void addXpFromBlockBySkill(BlockState blockState, OnlineMMOPlayer mmoPlayer, PrimarySkillType skillType)
-    {
-        if(ExperienceConfig.getInstance().getXp(skillType, blockState.getType()) > 0)
-        {
-            mmoPlayer.getExperienceManager().applyXpGain(mmoPlayer.getPlayer(), 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.getExperienceManager().addXp(skill, XP);
-        mcMMO.getUserManager().scheduleAsyncSave(profile.getPersistentPlayerData());
-    }
-
-    @Deprecated
-    private static void addOfflineXP(String playerName, PrimarySkillType skill, int XP) {
-        PlayerProfile profile = getOfflineProfile(playerName);
-
-        profile.getExperienceManager().addXp(skill, XP);
-        mcMMO.getUserManager().scheduleAsyncSave(profile.getPersistentPlayerData());
-    }
-
-    private static PlayerProfile getOfflineProfile(UUID uuid) {
-        PlayerProfile profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(uuid);
-
-        if (profile == null) {
-            throw new InvalidPlayerException();
-        }
-
-        return profile;
-    }
-
-    @Deprecated
-    private static PlayerProfile getOfflineProfile(String playerName) {
-        UUID uuid = mcMMO.p.getServer().getOfflinePlayer(playerName).getUniqueId();
-        PlayerProfile profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(uuid);
-
-        if (profile == null) {
-            throw new InvalidPlayerException();
-        }
-
-        return profile;
-    }
-
-    private static PrimarySkillType getSkillType(String skillType) throws InvalidSkillException {
-        PrimarySkillType skill = 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 OnlineMMOPlayer for that player if the profile is loaded, otherwise null
-     * @throws McMMOPlayerNotFoundException
-     */
-    @Deprecated
-    private static OnlineMMOPlayer getPlayer(Player player) throws McMMOPlayerNotFoundException {
-        if (!mcMMO.getUserManager().hasPlayerDataKey(player)) {
-            throw new McMMOPlayerNotFoundException(player);
-        }
-
-        return mcMMO.getUserManager().queryPlayer(player);
-    }
-}
+//package com.gmail.nossr50.api;
+//
+//import com.gmail.nossr50.api.exceptions.*;
+//import com.gmail.nossr50.config.Config;
+//import com.gmail.nossr50.config.experience.ExperienceConfig;
+//import com.gmail.nossr50.datatypes.experience.FormulaType;
+//import com.neetgames.mcmmo.player.OnlineMMOPlayer;
+//import com.gmail.nossr50.datatypes.player.PlayerProfile;
+//import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
+//import com.gmail.nossr50.mcMMO;
+//import com.gmail.nossr50.skills.child.FamilyTree;
+//import com.gmail.nossr50.util.skills.CombatUtils;
+//import org.bukkit.block.BlockState;
+//import org.bukkit.entity.LivingEntity;
+//import org.bukkit.entity.Player;
+//
+//import java.util.ArrayList;
+//import java.util.Set;
+//import java.util.UUID;
+//
+//public final class ExperienceAPI {
+//    private ExperienceAPI() {}
+//
+//    /**
+//     * Returns whether given string is a valid type of skill suitable for the
+//     * other API calls in this class.
+//     * </br>
+//     * 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 mmoPlayer The attacking player
+//     * @param target The defending entity
+//     * @param primarySkillType The skill being used
+//     * @param multiplier final XP result will be multiplied by this
+//     * @deprecated Draft API
+//     */
+//    @Deprecated
+//    public static void addCombatXP(OnlineMMOPlayer mmoPlayer, LivingEntity target, PrimarySkillType primarySkillType, double multiplier) {
+//        CombatUtils.processCombatXP(mmoPlayer, target, primarySkillType, multiplier);
+//    }
+//
+//    /**
+//     * Start the task that gives combat XP.
+//     * Processes combat XP like mcMMO normally would, so mcMMO will check whether or not the entity should reward XP when giving out the XP
+//     *
+//     * @param mmoPlayer The attacking player
+//     * @param target The defending entity
+//     * @param primarySkillType The skill being used
+//     * @deprecated Draft API
+//     */
+//    @Deprecated
+//    public static void addCombatXP(OnlineMMOPlayer mmoPlayer, LivingEntity target, PrimarySkillType primarySkillType) {
+//        CombatUtils.processCombatXP(mmoPlayer, target, primarySkillType);
+//    }
+//
+//    /**
+//     * Returns whether the given skill type string is both valid and not a
+//     * child skill. (Child skills have no XP of their own, and their level is
+//     * derived from the parent(s).)
+//     * </br>
+//     * 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.
+//     * </br>
+//     * 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.
+//     * </br>
+//     * 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.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param player The player to add XP to
+//     * @param skillType The skill to add XP to
+//     * @param XP The amount of XP to add
+//     * @param xpGainReason The reason to gain XP
+//     * @param isUnshared true if the XP cannot be shared with party members
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws InvalidXPGainReasonException if the given xpGainReason is not valid
+//     */
+//    public static void addRawXP(Player player, String skillType, float XP, String xpGainReason, boolean isUnshared) {
+//        if (isUnshared) {
+//            getPlayer(player).getExperienceHandler().beginUnsharedXpGain(player, getSkillType(skillType), XP, getXPGainReason(xpGainReason), XPGainSource.CUSTOM);
+//            return;
+//        }
+//
+//        getPlayer(player).getExperienceHandler().applyXpGain(player, getSkillType(skillType), XP, getXPGainReason(xpGainReason), XPGainSource.CUSTOM);
+//    }
+//
+//    /**
+//     * Adds raw XP to an offline player.
+//     * </br>
+//     * 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.
+//     * </br>
+//     * 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.
+//     * </br>
+//     * 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.
+//     * </br>
+//     * 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.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param player The player to add XP to
+//     * @param skillType The skill to add XP to
+//     * @param XP The amount of XP to add
+//     * @param xpGainReason The reason to gain XP
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws InvalidXPGainReasonException if the given xpGainReason is not valid
+//     */
+//    public static void addMultipliedXP(Player player, String skillType, int XP, String xpGainReason) {
+//        getPlayer(player).getExperienceHandler().applyXpGain(player, getSkillType(skillType), (int) (XP * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()), getXPGainReason(xpGainReason), XPGainSource.CUSTOM);
+//    }
+//
+//    /**
+//     * Adds XP to an offline player, calculates for XP Rate only.
+//     * </br>
+//     * 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.
+//     * </br>
+//     * 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.
+//     * </br>
+//     * 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.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param player The player to add XP to
+//     * @param skillType The skill to add XP to
+//     * @param XP The amount of XP to add
+//     * @param xpGainReason The reason to gain XP
+//     * @param isUnshared true if the XP cannot be shared with party members
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws InvalidXPGainReasonException if the given xpGainReason is not valid
+//     */
+//    public static void addModifiedXP(Player player, String skillType, int XP, String xpGainReason, boolean isUnshared) {
+//        PrimarySkillType skill = getSkillType(skillType);
+//
+//        if (isUnshared) {
+//            getPlayer(player).getExperienceHandler().beginUnsharedXpGain(player, skill, (int) (XP / skill.getXpModifier() * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()), getXPGainReason(xpGainReason), XPGainSource.CUSTOM);
+//            return;
+//        }
+//
+//        getPlayer(player).getExperienceHandler().applyXpGain(player, skill, (int) (XP / skill.getXpModifier() * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()), getXPGainReason(xpGainReason), XPGainSource.CUSTOM);
+//    }
+//
+//    /**
+//     * Adds XP to an offline player, calculates for XP Rate and skill modifier.
+//     * </br>
+//     * 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.
+//     * </br>
+//     * 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.
+//     * </br>
+//     * 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.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param player The player to add XP to
+//     * @param skillType The skill to add XP to
+//     * @param XP The amount of XP to add
+//     * @param xpGainReason The reason to gain XP
+//     * @param isUnshared true if the XP cannot be shared with party members
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws InvalidXPGainReasonException if the given xpGainReason is not valid
+//     */
+//    public static void addXP(Player player, String skillType, int XP, String xpGainReason, boolean isUnshared) {
+//        if (isUnshared) {
+//            getPlayer(player).getExperienceHandler().beginUnsharedXpGain(player, getSkillType(skillType), XP, getXPGainReason(xpGainReason), XPGainSource.CUSTOM);
+//            return;
+//        }
+//
+//        getPlayer(player).getExperienceHandler().beginXpGain(player, getSkillType(skillType), XP, getXPGainReason(xpGainReason), XPGainSource.CUSTOM);
+//    }
+//
+//    /**
+//     * Get the amount of XP a player has in a specific skill.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param player The player to get XP for
+//     * @param skillType The skill to get XP for
+//     * @return the amount of XP in a given skill
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws UnsupportedOperationException if the given skill is a child skill
+//     */
+//    public static int getXP(Player player, String skillType) {
+//        return getPlayer(player).getExperienceHandler().getSkillXpValue(getNonChildSkillType(skillType));
+//    }
+//
+//    /**
+//     * Get the amount of XP an offline player has in a specific skill.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param playerName The player to get XP for
+//     * @param skillType The skill to get XP for
+//     * @return the amount of XP in a given skill
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws InvalidPlayerException if the given player does not exist in the database
+//     * @throws UnsupportedOperationException if the given skill is a child skill
+//     */
+//    @Deprecated
+//    public static int getOfflineXP(String playerName, String skillType) {
+//        return getOfflineProfile(playerName).getExperienceHandler().getSkillXpValue(getNonChildSkillType(skillType));
+//    }
+//
+//    /**
+//     * Get the amount of XP an offline player has in a specific skill.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param uuid The player to get XP for
+//     * @param skillType The skill to get XP for
+//     * @return the amount of XP in a given skill
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws InvalidPlayerException if the given player does not exist in the database
+//     * @throws UnsupportedOperationException if the given skill is a child skill
+//     */
+//    public static int getOfflineXP(UUID uuid, String skillType) {
+//        return getOfflineProfile(uuid).getExperienceHandler().getSkillXpValue(getNonChildSkillType(skillType));
+//    }
+//
+//    /**
+//     * Get the raw amount of XP a player has in a specific skill.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param player The player to get XP for
+//     * @param skillType The skill to get XP for
+//     * @return the amount of XP in a given skill
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws UnsupportedOperationException if the given skill is a child skill
+//     */
+//    public static float getXPRaw(Player player, String skillType) {
+//        return getPlayer(player).getExperienceHandler().getSkillXpLevelRaw(getNonChildSkillType(skillType));
+//    }
+//
+//    /**
+//     * Get the raw amount of XP an offline player has in a specific skill.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param playerName The player to get XP for
+//     * @param skillType The skill to get XP for
+//     * @return the amount of XP in a given skill
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws InvalidPlayerException if the given player does not exist in the database
+//     * @throws UnsupportedOperationException if the given skill is a child skill
+//     */
+//    @Deprecated
+//    public static float getOfflineXPRaw(String playerName, String skillType) {
+//        return getOfflineProfile(playerName).getExperienceHandler().getSkillXpLevelRaw(getNonChildSkillType(skillType));
+//    }
+//
+//    /**
+//     * Get the raw amount of XP an offline player has in a specific skill.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param uuid The player to get XP for
+//     * @param skillType The skill to get XP for
+//     * @return the amount of XP in a given skill
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws InvalidPlayerException if the given player does not exist in the database
+//     * @throws UnsupportedOperationException if the given skill is a child skill
+//     */
+//    public static float getOfflineXPRaw(UUID uuid, String skillType) {
+//        return getOfflineProfile(uuid).getExperienceHandler().getSkillXpLevelRaw(getNonChildSkillType(skillType));
+//    }
+//
+//    /**
+//     * Get the total amount of XP needed to reach the next level.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param player The player to get the XP amount for
+//     * @param skillType The skill to get the XP amount for
+//     * @return the total amount of XP needed to reach the next level
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws UnsupportedOperationException if the given skill is a child skill
+//     */
+//    public static int getXPToNextLevel(Player player, String skillType) {
+//        return getPlayer(player).getExperienceHandler().getExperienceToNextLevel(getNonChildSkillType(skillType));
+//    }
+//
+//    /**
+//     * Get the total amount of XP an offline player needs to reach the next level.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param playerName The player to get XP for
+//     * @param skillType The skill to get XP for
+//     * @return the total amount of XP needed to reach the next level
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws InvalidPlayerException if the given player does not exist in the database
+//     * @throws UnsupportedOperationException if the given skill is a child skill
+//     */
+//    @Deprecated
+//    public static int getOfflineXPToNextLevel(String playerName, String skillType) {
+//        return getOfflineProfile(playerName).getExperienceHandler().getExperienceToNextLevel(getNonChildSkillType(skillType));
+//    }
+//
+//    /**
+//     * Get the total amount of XP an offline player needs to reach the next level.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param uuid The player to get XP for
+//     * @param skillType The skill to get XP for
+//     * @return the total amount of XP needed to reach the next level
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws InvalidPlayerException if the given player does not exist in the database
+//     * @throws UnsupportedOperationException if the given skill is a child skill
+//     */
+//    public static int getOfflineXPToNextLevel(UUID uuid, String skillType) {
+//        return getOfflineProfile(uuid).getExperienceHandler().getExperienceToNextLevel(getNonChildSkillType(skillType));
+//    }
+//
+//    /**
+//     * Get the amount of XP remaining until the next level.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param player The player to get the XP amount for
+//     * @param skillType The skill to get the XP amount for
+//     * @return the amount of XP remaining until the next level
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws UnsupportedOperationException if the given skill is a child skill
+//     */
+//    public static int getXPRemaining(Player player, String skillType) {
+//        PrimarySkillType skill = getNonChildSkillType(skillType);
+//
+//        PlayerProfile profile = getPlayer(player);
+//
+//        return profile.getExperienceHandler().getExperienceToNextLevel(skill) - profile.getExperienceHandler().getSkillXpValue(skill);
+//    }
+//
+//    /**
+//     * Get the amount of XP an offline player has left before leveling up.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param playerName The player to get XP for
+//     * @param skillType The skill to get XP for
+//     * @return the amount of XP needed to reach the next level
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws InvalidPlayerException if the given player does not exist in the database
+//     * @throws UnsupportedOperationException if the given skill is a child skill
+//     */
+//    @Deprecated
+//    public static int getOfflineXPRemaining(String playerName, String skillType) {
+//        PrimarySkillType skill = getNonChildSkillType(skillType);
+//        PlayerProfile profile = getOfflineProfile(playerName);
+//
+//        return profile.getExperienceHandler().getExperienceToNextLevel(skill) - profile.getExperienceHandler().getSkillXpValue(skill);
+//    }
+//
+//    /**
+//     * Get the amount of XP an offline player has left before leveling up.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param uuid The player to get XP for
+//     * @param skillType The skill to get XP for
+//     * @return the amount of XP needed to reach the next level
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws InvalidPlayerException if the given player does not exist in the database
+//     * @throws UnsupportedOperationException if the given skill is a child skill
+//     */
+//    public static float getOfflineXPRemaining(UUID uuid, String skillType) {
+//        PrimarySkillType skill = getNonChildSkillType(skillType);
+//        PlayerProfile profile = getOfflineProfile(uuid);
+//
+//        return profile.getExperienceHandler().getExperienceToNextLevel(skill) - profile.getExperienceHandler().getSkillXpLevelRaw(skill);
+//    }
+//
+//    /**
+//     * Add levels to a skill.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param player The player to add levels to
+//     * @param skillType Type of skill to add levels to
+//     * @param levels Number of levels to add
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     */
+//    public static void addLevel(Player player, String skillType, int levels) {
+//        getPlayer(player).getExperienceHandler().addLevels(getSkillType(skillType), levels);
+//    }
+//
+//    /**
+//     * Add levels to a skill for an offline player.
+//     * </br>
+//     * 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<PrimarySkillType> parentSkills = FamilyTree.getParents(skill);
+//
+//            for (PrimarySkillType parentSkill : parentSkills) {
+//                profile.getExperienceHandler().addLevels(parentSkill, (levels / parentSkills.size()));
+//            }
+//
+//            mcMMO.getUserManager().scheduleAsyncSave(profile.getPersistentPlayerData());
+//            return;
+//        }
+//
+//        profile.getExperienceHandler().addLevels(skill, levels);
+//        mcMMO.getUserManager().scheduleAsyncSave(profile.getPersistentPlayerData());
+//    }
+//
+//    /**
+//     * Add levels to a skill for an offline player.
+//     * </br>
+//     * 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<PrimarySkillType> parentSkills = FamilyTree.getParents(skill);
+//
+//            for (PrimarySkillType parentSkill : parentSkills) {
+//                profile.getExperienceHandler().addLevels(parentSkill, (levels / parentSkills.size()));
+//            }
+//
+//            mcMMO.getUserManager().scheduleAsyncSave(profile.getPersistentPlayerData());
+//            return;
+//        }
+//
+//        profile.getExperienceHandler().addLevels(skill, levels);
+//        mcMMO.getUserManager().scheduleAsyncSave(profile.getPersistentPlayerData());
+//    }
+//
+//    /**
+//     * Get the level a player has in a specific skill.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param player The player to get the level for
+//     * @param skillType The skill to get the level for
+//     * @return the level of a given skill
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @deprecated Use getLevel(Player player, PrimarySkillType skillType) instead
+//     */
+//    @Deprecated
+//    public static int getLevel(Player player, String skillType) {
+//        return getPlayer(player).getExperienceHandler().getSkillLevel(getSkillType(skillType));
+//    }
+//
+//    /**
+//     * Get the level a player has in a specific skill.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param player The player to get the level for
+//     * @param skillType The skill to get the level for
+//     * @return the level of a given skill
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     */
+//    public static int getLevel(Player player, PrimarySkillType skillType) {
+//        return getPlayer(player).getExperienceHandler().getSkillLevel(skillType);
+//    }
+//
+//    /**
+//     * Get the level an offline player has in a specific skill.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param playerName The player to get the level for
+//     * @param skillType The skill to get the level for
+//     * @return the level of a given skill
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws InvalidPlayerException if the given player does not exist in the database
+//     */
+//    @Deprecated
+//    public static int getLevelOffline(String playerName, String skillType) {
+//        return getOfflineProfile(playerName).getExperienceHandler().getSkillLevel(getSkillType(skillType));
+//    }
+//
+//    /**
+//     * Get the level an offline player has in a specific skill.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param uuid The player to get the level for
+//     * @param skillType The skill to get the level for
+//     * @return the level of a given skill
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws InvalidPlayerException if the given player does not exist in the database
+//     */
+//    public static int getLevelOffline(UUID uuid, String skillType) {
+//        return getOfflineProfile(uuid).getExperienceHandler().getSkillLevel(getSkillType(skillType));
+//    }
+//
+//    /**
+//     * Gets the power level of a player.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param player The player to get the power level for
+//     * @return the power level of the player
+//     */
+//    public static int getPowerLevel(Player player) {
+//        return getPlayer(player).getExperienceHandler().getPowerLevel();
+//    }
+//
+//    /**
+//     * Gets the power level of an offline player.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param playerName The player to get the power level for
+//     * @return the power level of the player
+//     *
+//     * @throws InvalidPlayerException if the given player does not exist in the database
+//     */
+//    @Deprecated
+//    public static int getPowerLevelOffline(String playerName) {
+//        int powerLevel = 0;
+//        PlayerProfile profile = getOfflineProfile(playerName);
+//
+//        for (PrimarySkillType type : PrimarySkillType.NON_CHILD_SKILLS) {
+//            powerLevel += profile.getExperienceHandler().getSkillLevel(type);
+//        }
+//
+//        return powerLevel;
+//    }
+//
+//    /**
+//     * Gets the power level of an offline player.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param uuid The player to get the power level for
+//     * @return the power level of the player
+//     *
+//     * @throws InvalidPlayerException if the given player does not exist in the database
+//     */
+//    public static int getPowerLevelOffline(UUID uuid) {
+//        int powerLevel = 0;
+//        PlayerProfile profile = getOfflineProfile(uuid);
+//
+//        for (PrimarySkillType type : PrimarySkillType.NON_CHILD_SKILLS) {
+//            powerLevel += profile.getExperienceHandler().getSkillLevel(type);
+//        }
+//
+//        return powerLevel;
+//    }
+//
+//    /**
+//     * Get the level cap of a specific skill.
+//     * </br>
+//     * 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.
+//     * </br>
+//     * 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.
+//     * </br>
+//     * 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.
+//     * </br>
+//     * 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.
+//     * </br>
+//     * 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.
+//     * </br>
+//     * 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.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param player The player to set the level of
+//     * @param skillType The skill to set the level for
+//     * @param skillLevel The value to set the level to
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     */
+//    public static void setLevel(Player player, String skillType, int skillLevel) {
+//        getPlayer(player).getExperienceHandler().setSkillLevel(getSkillType(skillType), skillLevel);
+//    }
+//
+//    /**
+//     * Sets the level of an offline player in a specific skill type.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param playerName The player to set the level of
+//     * @param skillType The skill to set the level for
+//     * @param skillLevel The value to set the level to
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws InvalidPlayerException if the given player does not exist in the database
+//     */
+//    @Deprecated
+//    public static void setLevelOffline(String playerName, String skillType, int skillLevel) {
+//        getOfflineProfile(playerName).getExperienceHandler().setSkillLevel(getSkillType(skillType), skillLevel);
+//    }
+//
+//    /**
+//     * Sets the level of an offline player in a specific skill type.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param uuid The player to set the level of
+//     * @param skillType The skill to set the level for
+//     * @param skillLevel The value to set the level to
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws InvalidPlayerException if the given player does not exist in the database
+//     */
+//    public static void setLevelOffline(UUID uuid, String skillType, int skillLevel) {
+//        getOfflineProfile(uuid).getExperienceHandler().setSkillLevel(getSkillType(skillType), skillLevel);
+//    }
+//
+//    /**
+//     * Sets the XP of a player in a specific skill type.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param player The player to set the XP of
+//     * @param skillType The skill to set the XP for
+//     * @param newValue The value to set the XP to
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws UnsupportedOperationException if the given skill is a child skill
+//     */
+//    public static void setXP(Player player, String skillType, int newValue) {
+//        getPlayer(player).getExperienceHandler().setSkillXpValue(getNonChildSkillType(skillType), (float) newValue);
+//    }
+//
+//    /**
+//     * Sets the XP of an offline player in a specific skill type.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param playerName The player to set the XP of
+//     * @param skillType The skill to set the XP for
+//     * @param newValue The value to set the XP to
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws InvalidPlayerException if the given player does not exist in the database
+//     * @throws UnsupportedOperationException if the given skill is a child skill
+//     */
+//    @Deprecated
+//    public static void setXPOffline(String playerName, String skillType, int newValue) {
+//        getOfflineProfile(playerName).getExperienceHandler().setSkillXpValue(getNonChildSkillType(skillType), newValue);
+//    }
+//
+//    /**
+//     * Sets the XP of an offline player in a specific skill type.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param uuid The player to set the XP of
+//     * @param skillType The skill to set the XP for
+//     * @param newValue The value to set the XP to
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws InvalidPlayerException if the given player does not exist in the database
+//     * @throws UnsupportedOperationException if the given skill is a child skill
+//     */
+//    public static void setXPOffline(UUID uuid, String skillType, int newValue) {
+//        getOfflineProfile(uuid).getExperienceHandler().setSkillXpValue(getNonChildSkillType(skillType), newValue);
+//    }
+//
+//    /**
+//     * Removes XP from a player in a specific skill type.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param player The player to change the XP of
+//     * @param skillType The skill to change the XP for
+//     * @param xp The amount of XP to remove
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws UnsupportedOperationException if the given skill is a child skill
+//     */
+//    public static void removeXP(Player player, String skillType, int xp) {
+//        getPlayer(player).getExperienceHandler().removeXp(getNonChildSkillType(skillType), xp);
+//    }
+//
+//    /**
+//     * Removes XP from an offline player in a specific skill type.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param playerName The player to change the XP of
+//     * @param skillType The skill to change the XP for
+//     * @param xp The amount of XP to remove
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws InvalidPlayerException if the given player does not exist in the database
+//     * @throws UnsupportedOperationException if the given skill is a child skill
+//     */
+//    @Deprecated
+//    public static void removeXPOffline(String playerName, String skillType, int xp) {
+//        getOfflineProfile(playerName).getExperienceHandler().removeXp(getNonChildSkillType(skillType), xp);
+//    }
+//
+//    /**
+//     * Removes XP from an offline player in a specific skill type.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param uuid The player to change the XP of
+//     * @param skillType The skill to change the XP for
+//     * @param xp The amount of XP to remove
+//     *
+//     * @throws InvalidSkillException if the given skill is not valid
+//     * @throws InvalidPlayerException if the given player does not exist in the database
+//     * @throws UnsupportedOperationException if the given skill is a child skill
+//     */
+//    public static void removeXPOffline(UUID uuid, String skillType, int xp) {
+//        getOfflineProfile(uuid).getExperienceHandler().removeXp(getNonChildSkillType(skillType), xp);
+//    }
+//
+//    /**
+//     * Check how much XP is needed for a specific level with the selected level curve.
+//     * </br>
+//     * 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.
+//     * </br>
+//     * This function is designed for API usage.
+//     *
+//     * @param level The level to get the amount of XP for
+//     * @param formulaType The formula type to get the amount of XP for
+//     *
+//     * @throws InvalidFormulaTypeException if the given formulaType is not valid
+//     */
+//    public static int getXpNeededToLevel(int level, String formulaType) {
+//        return mcMMO.getFormulaManager().getXPtoNextLevel(level, getFormulaType(formulaType));
+//    }
+//
+//    /**
+//     * Will add the appropriate type of XP from the block to the player based on the material of the blocks given
+//     * @param blockStates the blocks to reward XP for
+//     * @param mmoPlayer the target player
+//     */
+//    public static void addXpFromBlocks(ArrayList<BlockState> blockStates, OnlineMMOPlayer mmoPlayer)
+//    {
+//        for(BlockState bs : blockStates)
+//        {
+//            for(PrimarySkillType skillType : PrimarySkillType.values())
+//            {
+//                if(ExperienceConfig.getInstance().getXp(skillType, bs.getType()) > 0)
+//                {
+//                    mmoPlayer.getExperienceHandler().applyXpGain(Misc.adaptPlayer(mmoPlayer), skillType, ExperienceConfig.getInstance().getXp(skillType, bs.getType()), XPGainReason.PVE, XPGainSource.SELF);
+//                }
+//            }
+//        }
+//    }
+//
+//    /**
+//     * Will add the appropriate type of XP from the block to the player based on the material of the blocks given if it matches the given skillType
+//     * @param blockStates the blocks to reward XP for
+//     * @param mmoPlayer the target player
+//     * @param skillType target primary skill
+//     */
+//    public static void addXpFromBlocksBySkill(ArrayList<BlockState> blockStates, OnlineMMOPlayer mmoPlayer, PrimarySkillType skillType)
+//    {
+//        for(BlockState bs : blockStates)
+//        {
+//            if(ExperienceConfig.getInstance().getXp(skillType, bs.getType()) > 0)
+//            {
+//                mmoPlayer.getExperienceHandler().applyXpGain(Misc.adaptPlayer(mmoPlayer), skillType, ExperienceConfig.getInstance().getXp(skillType, bs.getType()), XPGainReason.PVE, XPGainSource.SELF);
+//            }
+//        }
+//    }
+//
+//    /**
+//     * Will add the appropriate type of XP from the block to the player based on the material of the blocks given
+//     * @param blockState The target blockstate
+//     * @param mmoPlayer The target player
+//     */
+//    public static void addXpFromBlock(BlockState blockState, OnlineMMOPlayer mmoPlayer)
+//    {
+//        for(PrimarySkillType skillType : PrimarySkillType.values())
+//        {
+//            if(ExperienceConfig.getInstance().getXp(skillType, blockState.getType()) > 0)
+//            {
+//                mmoPlayer.getExperienceHandler().applyXpGain(Misc.adaptPlayer(mmoPlayer), skillType, ExperienceConfig.getInstance().getXp(skillType, blockState.getType()), XPGainReason.PVE, XPGainSource.SELF);
+//            }
+//        }
+//    }
+//
+//    /**
+//     * Will add the appropriate type of XP from the block to the player based on the material of the blocks given if it matches the given skillType
+//     * @param blockState The target blockstate
+//     * @param mmoPlayer The target player
+//     * @param skillType target primary skill
+//     */
+//    public static void addXpFromBlockBySkill(BlockState blockState, OnlineMMOPlayer mmoPlayer, PrimarySkillType skillType)
+//    {
+//        if(ExperienceConfig.getInstance().getXp(skillType, blockState.getType()) > 0)
+//        {
+//            mmoPlayer.getExperienceHandler().applyXpGain(Misc.adaptPlayer(mmoPlayer), skillType, ExperienceConfig.getInstance().getXp(skillType, blockState.getType()), XPGainReason.PVE, XPGainSource.SELF);
+//        }
+//    }
+//
+//
+//
+//    // Utility methods follow.
+//    private static void addOfflineXP(UUID playerUniqueId, PrimarySkillType skill, int XP) {
+//        PlayerProfile profile = getOfflineProfile(playerUniqueId);
+//
+//        profile.getExperienceHandler().addXp(skill, XP);
+//        mcMMO.getUserManager().scheduleAsyncSave(profile.getPersistentPlayerData());
+//    }
+//
+//    @Deprecated
+//    private static void addOfflineXP(String playerName, PrimarySkillType skill, int XP) {
+//        PlayerProfile profile = getOfflineProfile(playerName);
+//
+//        profile.getExperienceHandler().addXp(skill, XP);
+//        mcMMO.getUserManager().scheduleAsyncSave(profile.getPersistentPlayerData());
+//    }
+//
+//    private static PlayerProfile getOfflineProfile(UUID uuid) {
+//        PlayerProfile profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(uuid);
+//
+//        if (profile == null) {
+//            throw new InvalidPlayerException();
+//        }
+//
+//        return profile;
+//    }
+//
+//    @Deprecated
+//    private static PlayerProfile getOfflineProfile(String playerName) {
+//        UUID uuid = mcMMO.p.getServer().getOfflinePlayer(playerName).getUniqueId();
+//        PlayerProfile profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(uuid);
+//
+//        if (profile == null) {
+//            throw new InvalidPlayerException();
+//        }
+//
+//        return profile;
+//    }
+//
+//    private static PrimarySkillType getSkillType(String skillType) throws InvalidSkillException {
+//        PrimarySkillType skill = 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 OnlineMMOPlayer for that player if the profile is loaded, otherwise null
+//     * @throws McMMOPlayerNotFoundException
+//     */
+//    @Deprecated
+//    private static OnlineMMOPlayer getPlayer(Player player) throws McMMOPlayerNotFoundException {
+//        if (!mcMMO.getUserManager().hasPlayerDataKey(player)) {
+//            throw new McMMOPlayerNotFoundException(player);
+//        }
+//
+//        return mcMMO.getUserManager().queryPlayer(player);
+//    }
+//}

+ 3 - 3
src/main/java/com/gmail/nossr50/chat/ChatManager.java

@@ -127,11 +127,11 @@ public class ChatManager {
     public void setOrToggleChatChannel(@NotNull OnlineMMOPlayer mmoPlayer, @NotNull ChatChannel targetChatChannel) {
         if(targetChatChannel == mmoPlayer.getChatChannel()) {
             //Disabled message
-            mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Chat.Channel.Off", StringUtils.getCapitalized(targetChatChannel.toString())));
+            Misc.adaptPlayer(mmoPlayer).sendMessage(LocaleLoader.getString("Chat.Channel.Off", StringUtils.getCapitalized(targetChatChannel.toString())));
             mmoPlayer.setChatMode(ChatChannel.NONE);
         } else {
             mmoPlayer.setChatMode(targetChatChannel);
-            mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Chat.Channel.On", StringUtils.getCapitalized(targetChatChannel.toString())));
+            Misc.adaptPlayer(mmoPlayer).sendMessage(LocaleLoader.getString("Chat.Channel.On", StringUtils.getCapitalized(targetChatChannel.toString())));
         }
     }
 
@@ -162,7 +162,7 @@ public class ChatManager {
     public boolean isMessageAllowed(@NotNull OnlineMMOPlayer mmoPlayer) {
         switch (mmoPlayer.getChatChannel()) {
             case ADMIN:
-                if(mmoPlayer.getPlayer().isOp() || Permissions.adminChat(mmoPlayer.getPlayer())) {
+                if(Misc.adaptPlayer(mmoPlayer).isOp() || Permissions.adminChat(mmoPlayer.getPlayer())) {
                     return true;
                 }
                 break;

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/AbilityToggleCommand.java

@@ -19,7 +19,7 @@ public class AbilityToggleCommand extends ToggleCommand {
 
     @Override
     protected void applyCommandAction(@NotNull OnlineMMOPlayer mmoPlayer) {
-        mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Commands.Ability." + (mmoPlayer.getSuperAbilityManager().getAbilityActivationPermission() ? "Off" : "On")));
+        Misc.adaptPlayer(mmoPlayer).sendMessage(LocaleLoader.getString("Commands.Ability." + (mmoPlayer.getSuperAbilityManager().getAbilityActivationPermission() ? "Off" : "On")));
         mmoPlayer.getSuperAbilityManager().toggleAbilityActivationPermission();
     }
 

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/McgodCommand.java

@@ -19,7 +19,7 @@ public class McgodCommand extends ToggleCommand {
 
     @Override
     protected void applyCommandAction(@NotNull OnlineMMOPlayer mmoPlayer) {
-        mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Commands.GodMode." + (mmoPlayer.getGodMode() ? "Disabled" : "Enabled")));
+        Misc.adaptPlayer(mmoPlayer).sendMessage(LocaleLoader.getString("Commands.GodMode." + (mmoPlayer.getGodMode() ? "Disabled" : "Enabled")));
         mmoPlayer.toggleGodMode();
     }
 

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/McrefreshCommand.java

@@ -24,7 +24,7 @@ public class McrefreshCommand extends ToggleCommand {
         mmoPlayer.getSuperAbilityManager().unprimeAllAbilityTools();
         mmoPlayer.getSuperAbilityManager().disableSuperAbilities();
 
-        mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Ability.Generic.Refresh"));
+        Misc.adaptPlayer(mmoPlayer).sendMessage(LocaleLoader.getString("Ability.Generic.Refresh"));
     }
 
     @Override

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/ToggleCommand.java

@@ -40,7 +40,7 @@ public abstract class ToggleCommand implements TabExecutor {
                 if(mmoPlayer != null) {
                     applyCommandAction(mmoPlayer);
                 } else {
-                    mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Commands.NotLoaded"));
+                    Misc.adaptPlayer(mmoPlayer).sendMessage(LocaleLoader.getString("Commands.NotLoaded"));
                 }
 
                 return true;

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/admin/PlayerDebugCommand.java

@@ -23,7 +23,7 @@ public class PlayerDebugCommand implements CommandExecutor {
             }
 
             mmoPlayer.toggleDebugMode(); //Toggle debug mode
-            NotificationManager.sendPlayerInformationChatOnlyPrefixed(mmoPlayer.getPlayer(), "Commands.Mmodebug.Toggle", String.valueOf(mmoPlayer.isDebugMode()));
+            NotificationManager.sendPlayerInformationChatOnlyPrefixed(Misc.adaptPlayer(mmoPlayer), "Commands.Mmodebug.Toggle", String.valueOf(mmoPlayer.isDebugMode()));
             return true;
         } else {
             return false;

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/chat/McChatSpy.java

@@ -20,7 +20,7 @@ public class McChatSpy extends ToggleCommand {
 
     @Override
     protected void applyCommandAction(@NotNull OnlineMMOPlayer mmoPlayer) {
-        mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Commands.AdminChatSpy." + (mmoPlayer.isPartyChatSpying() ? "Disabled" : "Enabled")));
+        Misc.adaptPlayer(mmoPlayer).sendMessage(LocaleLoader.getString("Commands.AdminChatSpy." + (mmoPlayer.isPartyChatSpying() ? "Disabled" : "Enabled")));
         mmoPlayer.togglePartyChatSpying();
     }
 

+ 0 - 1
src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java

@@ -1,6 +1,5 @@
 package com.gmail.nossr50.commands.experience;
 
-import com.gmail.nossr50.datatypes.experience.XPGainReason;
 import com.gmail.nossr50.datatypes.player.PlayerProfile;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.locale.LocaleLoader;

+ 0 - 2
src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java

@@ -1,7 +1,5 @@
 package com.gmail.nossr50.commands.experience;
 
-import com.gmail.nossr50.datatypes.experience.XPGainReason;
-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;

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java

@@ -109,7 +109,7 @@ public abstract class ExperienceCommand implements TabExecutor {
                     editValues(null, profile, skill, value, isSilent(args));
                 }
                 else {
-                    editValues(mmoPlayer.getPlayer(), mcMMOPlayer.getProfile(), skill, value, isSilent(args));
+                    editValues(Misc.adaptPlayer(mmoPlayer), mcMMOPlayer.getProfile(), skill, value, isSilent(args));
                 }
 
                 handleSenderMessage(sender, playerName, skill);

+ 0 - 1
src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java

@@ -1,6 +1,5 @@
 package com.gmail.nossr50.commands.experience;
 
-import com.gmail.nossr50.datatypes.experience.XPGainReason;
 import com.gmail.nossr50.datatypes.player.PlayerProfile;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.locale.LocaleLoader;

+ 1 - 2
src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java

@@ -1,6 +1,5 @@
 package com.gmail.nossr50.commands.experience;
 
-import com.gmail.nossr50.datatypes.experience.XPGainReason;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.datatypes.player.PlayerProfile;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
@@ -91,7 +90,7 @@ public class SkillresetCommand implements TabExecutor {
                     editValues(null, profile, skill);
                 }
                 else {
-                    editValues(mmoPlayer.getPlayer(), mmoPlayer, skill);
+                    editValues(Misc.adaptPlayer(mmoPlayer), mmoPlayer, skill);
                 }
 
                 handleSenderMessage(sender, playerName, skill);

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/party/PartyRenameCommand.java

@@ -33,7 +33,7 @@ public class PartyRenameCommand implements CommandExecutor {
                 return true;
             }
 
-            Player player = mmoPlayer.getPlayer();
+            Player player = Misc.adaptPlayer(mmoPlayer);
 
             // Check to see if the party exists, and if it does cancel renaming the party
             if (mcMMO.getPartyManager().isParty(newPartyName)) {

+ 11 - 9
src/main/java/com/gmail/nossr50/commands/party/teleport/PtpCommand.java

@@ -5,6 +5,7 @@ import com.gmail.nossr50.config.WorldBlacklist;
 import com.gmail.nossr50.datatypes.party.Party;
 import com.gmail.nossr50.datatypes.party.PartyFeature;
 import com.gmail.nossr50.datatypes.party.PartyTeleportRecord;
+import com.gmail.nossr50.datatypes.player.McMMOPlayer;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.mcMMO;
@@ -196,7 +197,7 @@ public class PtpCommand implements TabExecutor {
     }
 
     protected static boolean canTeleport(CommandSender sender, Player player, String targetName) {
-        OnlineMMOPlayer mcMMOTarget = mcMMO.getUserManager().getPlayer(targetName);
+        OnlineMMOPlayer mcMMOTarget = mcMMO.getUserManager().queryPlayer(targetName);
 
         if (!CommandUtils.checkPlayerExistence(sender, targetName, mcMMOTarget)) {
             return false;
@@ -228,28 +229,29 @@ public class PtpCommand implements TabExecutor {
     }
 
     protected static void handleTeleportWarmup(Player teleportingPlayer, Player targetPlayer) {
-        if(mcMMO.getUserManager().queryPlayer(targetPlayer) == null)
-        {
+        if(mcMMO.getUserManager().queryPlayer(targetPlayer) == null) {
             targetPlayer.sendMessage(LocaleLoader.getString("Profile.PendingLoad"));
             return;
         }
 
-        if(mcMMO.getUserManager().queryPlayer(teleportingPlayer) == null)
-        {
+        if(mcMMO.getUserManager().queryPlayer(teleportingPlayer) == null) {
             teleportingPlayer.sendMessage(LocaleLoader.getString("Profile.PendingLoad"));
             return;
         }
 
-        OnlineMMOPlayer mmoPlayer = mcMMO.getUserManager().queryPlayer(teleportingPlayer);
-        OnlineMMOPlayer mcMMOTarget = mcMMO.getUserManager().queryPlayer(targetPlayer);
+        McMMOPlayer mmoPlayer = (McMMOPlayer) mcMMO.getUserManager().queryPlayer(teleportingPlayer);
+        McMMOPlayer mmoTargetPlayer = (McMMOPlayer) mcMMO.getUserManager().queryPlayer(targetPlayer);
+
+        if(mmoPlayer == null || mmoTargetPlayer == null)
+            return;
 
         long warmup = Config.getInstance().getPTPCommandWarmup();
 
-        mmoPlayer.actualizeTeleportCommenceLocation(teleportingPlayer);
+        mmoPlayer.actualizeTeleportCommenceLocation();
 
         if (warmup > 0) {
             teleportingPlayer.sendMessage(LocaleLoader.getString("Teleport.Commencing", warmup));
-            new TeleportationWarmup(mmoPlayer, mcMMOTarget).runTaskLater(mcMMO.p, 20 * warmup);
+            new TeleportationWarmup(mmoPlayer, mmoTargetPlayer).runTaskLater(mcMMO.p, 20 * warmup);
         }
         else {
             EventUtils.handlePartyTeleportEvent(teleportingPlayer, targetPlayer);

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java

@@ -88,7 +88,7 @@ public class InspectCommand implements TabExecutor {
                 CommandUtils.printGatheringSkills(targetPlayer, sender);
                 CommandUtils.printCombatSkills(targetPlayer, sender);
                 CommandUtils.printMiscSkills(targetPlayer, sender);
-                sender.sendMessage(LocaleLoader.getString("Commands.PowerLevel", playerProfile.getExperienceManager().getPowerLevel()));
+                sender.sendMessage(LocaleLoader.getString("Commands.PowerLevel", playerProfile.getExperienceHandler().getPowerLevel()));
             }
 
             return true;

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/player/McrankCommand.java

@@ -55,7 +55,7 @@ public class McrankCommand implements TabExecutor {
                 OnlineMMOPlayer mmoPlayer = mcMMO.getUserManager().queryPlayerName(playerName);
 
                 if (mmoPlayer != null) {
-                    Player player = mmoPlayer.getPlayer();
+                    Player player = Misc.adaptPlayer(mmoPlayer);
                     playerName = player.getName();
 
                     if (CommandUtils.tooFar(sender, player, Permissions.mcrankFar(sender))) {

+ 14 - 14
src/main/java/com/gmail/nossr50/commands/player/XPBarCommand.java

@@ -25,7 +25,7 @@ public class XPBarCommand implements TabExecutor {
         if(sender instanceof Player) {
             OnlineMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer((Player) sender);
             if(mmoPlayer == null) {
-                NotificationManager.sendPlayerInformationChatOnlyPrefixed(mmoPlayer.getPlayer(), "Profile.PendingLoad");
+                NotificationManager.sendPlayerInformationChatOnlyPrefixed(Misc.adaptPlayer(mmoPlayer), "Profile.PendingLoad");
                 return false;
             }
 
@@ -34,10 +34,10 @@ public class XPBarCommand implements TabExecutor {
             } else if(args.length < 2) {
               String option = args[0];
 
-              if(option.equalsIgnoreCase(MMOExperienceBarManager.XPBarSettingTarget.RESET.toString())) {
-                  mmoPlayer.getExperienceBarManager().xpBarSettingToggle(MMOExperienceBarManager.XPBarSettingTarget.RESET, null);
+              if(option.equalsIgnoreCase(SkillBossBarSetting.RESET.toString())) {
+                  mmoPlayer.getExperienceBarManager().xpBarSettingToggle(SkillBossBarSetting.RESET, null);
                   return true;
-              } else if(option.equalsIgnoreCase(MMOExperienceBarManager.XPBarSettingTarget.DISABLE.toString())) {
+              } else if(option.equalsIgnoreCase(SkillBossBarSetting.DISABLE.toString())) {
                   mmoPlayer.getExperienceBarManager().disableAllBars();
                   return true;
               } else {
@@ -55,8 +55,8 @@ public class XPBarCommand implements TabExecutor {
                     //Target setting
                     String option = args[0].toLowerCase();
 
-                    MMOExperienceBarManager.XPBarSettingTarget settingTarget = getSettingTarget(option);
-                    if(settingTarget != null && settingTarget != MMOExperienceBarManager.XPBarSettingTarget.RESET) {
+                    SkillBossBarSetting settingTarget = getSettingTarget(option);
+                    if(settingTarget != null && settingTarget != SkillBossBarSetting.RESET) {
                         //Change setting
                         mmoPlayer.getExperienceBarManager().xpBarSettingToggle(settingTarget, targetSkill);
                         return true;
@@ -74,16 +74,16 @@ public class XPBarCommand implements TabExecutor {
         }
     }
 
-    private @Nullable MMOExperienceBarManager.XPBarSettingTarget getSettingTarget(String string) {
+    private @Nullable SkillBossBarSetting getSettingTarget(String string) {
         switch (string.toLowerCase()) {
             case "hide":
-                return MMOExperienceBarManager.XPBarSettingTarget.HIDE;
+                return SkillBossBarSetting.HIDE;
             case "show":
-                return MMOExperienceBarManager.XPBarSettingTarget.SHOW;
+                return SkillBossBarSetting.SHOW;
             case "reset":
-                return MMOExperienceBarManager.XPBarSettingTarget.RESET;
+                return SkillBossBarSetting.RESET;
             case "disable":
-                return MMOExperienceBarManager.XPBarSettingTarget.DISABLE;
+                return SkillBossBarSetting.DISABLE;
         }
 
         return null;
@@ -95,13 +95,13 @@ public class XPBarCommand implements TabExecutor {
             case 1:
                 List<String> options = new ArrayList<>();
 
-                for(MMOExperienceBarManager.XPBarSettingTarget settingTarget : MMOExperienceBarManager.XPBarSettingTarget.values()) {
+                for(SkillBossBarSetting settingTarget : SkillBossBarSetting.values()) {
                     options.add(StringUtils.getCapitalized(settingTarget.toString()));
                 }
 
-                return StringUtil.copyPartialMatches(args[0], options, new ArrayList<>(MMOExperienceBarManager.XPBarSettingTarget.values().length));
+                return StringUtil.copyPartialMatches(args[0], options, new ArrayList<>(SkillBossBarSetting.values().length));
             case 2:
-                if(!args[0].equalsIgnoreCase(MMOExperienceBarManager.XPBarSettingTarget.RESET.toString()))
+                if(!args[0].equalsIgnoreCase(SkillBossBarSetting.RESET.toString()))
                     return StringUtil.copyPartialMatches(args[1], PrimarySkillType.SKILL_NAMES, new ArrayList<>(PrimarySkillType.SKILL_NAMES.size()));
             default:
                 return ImmutableList.of();

+ 2 - 2
src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java

@@ -61,10 +61,10 @@ public class AcrobaticsCommand extends SkillCommand {
                 double rollChance, graceChance;
 
                 //Chance to roll at half
-                RandomChanceSkill roll_rcs  = new RandomChanceSkill(mmoPlayer.getPlayer(), SubSkillType.ACROBATICS_ROLL);
+                RandomChanceSkill roll_rcs  = new RandomChanceSkill(Misc.adaptPlayer(mmoPlayer), SubSkillType.ACROBATICS_ROLL);
 
                 //Chance to graceful roll
-                RandomChanceSkill grace_rcs = new RandomChanceSkill(mmoPlayer.getPlayer(), SubSkillType.ACROBATICS_ROLL);
+                RandomChanceSkill grace_rcs = new RandomChanceSkill(Misc.adaptPlayer(mmoPlayer), SubSkillType.ACROBATICS_ROLL);
                 grace_rcs.setSkillLevel(grace_rcs.getSkillLevel() * 2); //Double Odds
 
                 //Chance Stat Calculations

+ 4 - 2
src/main/java/com/gmail/nossr50/commands/skills/AlchemyCommand.java

@@ -1,5 +1,7 @@
 package com.gmail.nossr50.commands.skills;
 
+import com.gmail.nossr50.datatypes.player.McMMOPlayer;
+import com.gmail.nossr50.util.Misc;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.SubSkillType;
@@ -44,10 +46,10 @@ public class AlchemyCommand extends SkillCommand {
     }
 
     protected String[] calculateAbilityDisplayValues(@NotNull OnlineMMOPlayer mmoPlayer) {
-        AlchemyManager alchemyManager = mmoPlayer.getAlchemyManager();
+        AlchemyManager alchemyManager = ((McMMOPlayer) (mmoPlayer)).getAlchemyManager();
         String[] displayValues = new String[2];
 
-        boolean isLucky = Permissions.lucky(mmoPlayer.getPlayer(), PrimarySkillType.ALCHEMY);
+        boolean isLucky = Permissions.lucky(Misc.adaptPlayer(mmoPlayer), PrimarySkillType.ALCHEMY);
 
         displayValues[0] = decimal.format(alchemyManager.calculateBrewSpeed(false)) + "x";
         displayValues[1] = isLucky ? decimal.format(alchemyManager.calculateBrewSpeed(true)) + "x" : null;

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/skills/AxesCommand.java

@@ -38,7 +38,7 @@ public class AxesCommand extends SkillCommand {
     protected void dataCalculations(@NotNull OnlineMMOPlayer mmoPlayer, float skillValue) {
         // ARMOR IMPACT
         if (canImpact) {
-            impactDamage = mmoPlayer.getAxesManager().getImpactDurabilityDamage();
+            impactDamage = ((McMMOPlayer) (mmoPlayer)).getArcheryManager().getImpactDurabilityDamage();
         }
 
         // AXE MASTERY

+ 2 - 2
src/main/java/com/gmail/nossr50/commands/skills/CrossbowsCommand.java

@@ -30,7 +30,7 @@ public class CrossbowsCommand extends SkillCommand {
     protected @NotNull List<String> statsDisplay(@NotNull OnlineMMOPlayer mmoPlayer, float skillValue, boolean hasEndurance, boolean isLucky) {
         List<String> messages = new ArrayList<>();
 
-        CrossbowManager crossbowManager = mmoPlayer.getCrossbowManager();
+        CrossbowManager crossbowManager = ((McMMOPlayer) (mmoPlayer)).getCrossbowManager();
 
         if(canUseSubskill(mmoPlayer, SubSkillType.CROSSBOWS_SUPER_SHOTGUN)) {
             String additionalArrowCount = String.valueOf(crossbowManager.getSuperShotgunAdditionalArrowCount());
@@ -41,7 +41,7 @@ public class CrossbowsCommand extends SkillCommand {
     }
 
     @Override
-    protected List<Component> getTextComponents(@NotNull OnlineMMOPlayer mmoPlayer) {
+    protected @NotNull List<Component> getTextComponents(@NotNull OnlineMMOPlayer mmoPlayer) {
         List<Component> textComponents = new ArrayList<>();
 
         TextComponentFactory.getSubSkillTextComponents(mmoPlayer, textComponents, PrimarySkillType.CROSSBOWS);

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/skills/ExcavationCommand.java

@@ -45,7 +45,7 @@ public class ExcavationCommand extends SkillCommand {
     protected @NotNull List<String> statsDisplay(@NotNull OnlineMMOPlayer mmoPlayer, float skillValue, boolean hasEndurance, boolean isLucky) {
         List<String> messages = new ArrayList<>();
 
-        ExcavationManager excavationManager = mmoPlayer.getExcavationManager();
+        ExcavationManager excavationManager = ((McMMOPlayer) (mmoPlayer)).getExcavationManager();
 
         if (canGigaDrill) {
             messages.add(getStatMessage(SubSkillType.EXCAVATION_GIGA_DRILL_BREAKER, gigaDrillBreakerLength)

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/skills/FishingCommand.java

@@ -48,7 +48,7 @@ public class FishingCommand extends SkillCommand {
 
     @Override
     protected void dataCalculations(@NotNull OnlineMMOPlayer mmoPlayer, float skillValue) {
-        FishingManager fishingManager = mmoPlayer.getFishingManager();
+        FishingManager fishingManager = ((McMMOPlayer) (mmoPlayer)).getFishingManager();
 
         // TREASURE HUNTER
         if (canTreasureHunt) {

+ 11 - 11
src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java

@@ -92,19 +92,19 @@ public class HerbalismCommand extends SkillCommand {
         hasHylianLuck = canUseSubskill(mmoPlayer, SubSkillType.HERBALISM_HYLIAN_LUCK);
         canGreenTerra = Permissions.greenTerra(mmoPlayer.getPlayer());
         canGreenThumbPlants = RankUtils.hasUnlockedSubskill(mmoPlayer, SubSkillType.HERBALISM_GREEN_THUMB)
-                && (Permissions.greenThumbPlant(mmoPlayer.getPlayer(), Material.WHEAT)
-                || Permissions.greenThumbPlant(mmoPlayer.getPlayer(), Material.CARROT)
-                || Permissions.greenThumbPlant(mmoPlayer.getPlayer(), Material.POTATO)
-                || Permissions.greenThumbPlant(mmoPlayer.getPlayer(), Material.BEETROOT)
-                || Permissions.greenThumbPlant(mmoPlayer.getPlayer(), Material.NETHER_WART)
-                || Permissions.greenThumbPlant(mmoPlayer.getPlayer(), Material.COCOA));
+                && (Permissions.greenThumbPlant(Misc.adaptPlayer(mmoPlayer), Material.WHEAT)
+                || Permissions.greenThumbPlant(Misc.adaptPlayer(mmoPlayer), Material.CARROT)
+                || Permissions.greenThumbPlant(Misc.adaptPlayer(mmoPlayer), Material.POTATO)
+                || Permissions.greenThumbPlant(Misc.adaptPlayer(mmoPlayer), Material.BEETROOT)
+                || Permissions.greenThumbPlant(Misc.adaptPlayer(mmoPlayer), Material.NETHER_WART)
+                || Permissions.greenThumbPlant(Misc.adaptPlayer(mmoPlayer), Material.COCOA));
         canGreenThumbBlocks = RankUtils.hasUnlockedSubskill(mmoPlayer, SubSkillType.HERBALISM_GREEN_THUMB)
-                && (Permissions.greenThumbBlock(mmoPlayer.getPlayer(), Material.DIRT)
-                || Permissions.greenThumbBlock(mmoPlayer.getPlayer(), Material.COBBLESTONE)
-                || Permissions.greenThumbBlock(mmoPlayer.getPlayer(), Material.COBBLESTONE_WALL)
-                || Permissions.greenThumbBlock(mmoPlayer.getPlayer(), Material.STONE_BRICKS));
+                && (Permissions.greenThumbBlock(Misc.adaptPlayer(mmoPlayer), Material.DIRT)
+                || Permissions.greenThumbBlock(Misc.adaptPlayer(mmoPlayer), Material.COBBLESTONE)
+                || Permissions.greenThumbBlock(Misc.adaptPlayer(mmoPlayer), Material.COBBLESTONE_WALL)
+                || Permissions.greenThumbBlock(Misc.adaptPlayer(mmoPlayer), Material.STONE_BRICKS));
         canFarmersDiet = canUseSubskill(mmoPlayer, SubSkillType.HERBALISM_FARMERS_DIET);
-        canDoubleDrop = canUseSubskill(mmoPlayer, SubSkillType.HERBALISM_DOUBLE_DROPS) && !skill.getDoubleDropsDisabled();
+        canDoubleDrop = canUseSubskill(mmoPlayer, SubSkillType.HERBALISM_DOUBLE_DROPS) && !rootSkill.getDoubleDropsDisabled();
         canShroomThumb = canUseSubskill(mmoPlayer, SubSkillType.HERBALISM_SHROOM_THUMB);
     }
 

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/skills/MiningCommand.java

@@ -42,7 +42,7 @@ public class MiningCommand extends SkillCommand {
     protected void dataCalculations(@NotNull OnlineMMOPlayer mmoPlayer, float skillValue) {
         // BLAST MINING
         if (canBlast || canDemoExpert || canBiggerBombs) {
-            MiningManager miningManager = mmoPlayer.getMiningManager();
+            MiningManager miningManager = ((McMMOPlayer) (mmoPlayer)).getMiningManager();
 
             blastMiningRank = miningManager.getBlastMiningTier();
             bonusTNTDrops = miningManager.getDropMultiplier();

+ 4 - 4
src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java

@@ -91,10 +91,10 @@ public class MmoInfoCommand implements TabExecutor {
             /*
              * Skill is only in the old system
              */
-            mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Commands.MmoInfo.Header"));
-            mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Commands.MmoInfo.SubSkillHeader", subSkillName));
-            mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Commands.MmoInfo.DetailsHeader"));
-            mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Commands.MmoInfo.OldSkill"));
+            Misc.adaptPlayer(mmoPlayer).sendMessage(LocaleLoader.getString("Commands.MmoInfo.Header"));
+            Misc.adaptPlayer(mmoPlayer).sendMessage(LocaleLoader.getString("Commands.MmoInfo.SubSkillHeader", subSkillName));
+            Misc.adaptPlayer(mmoPlayer).sendMessage(LocaleLoader.getString("Commands.MmoInfo.DetailsHeader"));
+            Misc.adaptPlayer(mmoPlayer).sendMessage(LocaleLoader.getString("Commands.MmoInfo.OldSkill"));
         }
 
         for(SubSkillType subSkillType : SubSkillType.values())

+ 8 - 8
src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java

@@ -79,13 +79,13 @@ public class RepairCommand extends SkillCommand {
         canSuperRepair = canUseSubskill(mmoPlayer, SubSkillType.REPAIR_SUPER_REPAIR);
         canMasterRepair = canUseSubskill(mmoPlayer, SubSkillType.REPAIR_REPAIR_MASTERY);
         canArcaneForge = canUseSubskill(mmoPlayer, SubSkillType.REPAIR_ARCANE_FORGING);
-        canRepairDiamond = Permissions.repairMaterialType(mmoPlayer.getPlayer(), MaterialType.DIAMOND);
-        canRepairGold = Permissions.repairMaterialType(mmoPlayer.getPlayer(), MaterialType.GOLD);
-        canRepairIron = Permissions.repairMaterialType(mmoPlayer.getPlayer(), MaterialType.IRON);
-        canRepairStone = Permissions.repairMaterialType(mmoPlayer.getPlayer(), MaterialType.STONE);
-        canRepairString = Permissions.repairMaterialType(mmoPlayer.getPlayer(), MaterialType.STRING);
-        canRepairLeather = Permissions.repairMaterialType(mmoPlayer.getPlayer(), MaterialType.LEATHER);
-        canRepairWood = Permissions.repairMaterialType(mmoPlayer.getPlayer(), MaterialType.WOOD);
+        canRepairDiamond = Permissions.repairMaterialType(Misc.adaptPlayer(mmoPlayer), MaterialType.DIAMOND);
+        canRepairGold = Permissions.repairMaterialType(Misc.adaptPlayer(mmoPlayer), MaterialType.GOLD);
+        canRepairIron = Permissions.repairMaterialType(Misc.adaptPlayer(mmoPlayer), MaterialType.IRON);
+        canRepairStone = Permissions.repairMaterialType(Misc.adaptPlayer(mmoPlayer), MaterialType.STONE);
+        canRepairString = Permissions.repairMaterialType(Misc.adaptPlayer(mmoPlayer), MaterialType.STRING);
+        canRepairLeather = Permissions.repairMaterialType(Misc.adaptPlayer(mmoPlayer), MaterialType.LEATHER);
+        canRepairWood = Permissions.repairMaterialType(Misc.adaptPlayer(mmoPlayer), MaterialType.WOOD);
         arcaneBypass = (Permissions.arcaneBypass(mmoPlayer.getPlayer()) || Permissions.hasRepairEnchantBypassPerk(mmoPlayer.getPlayer()));
     }
 
@@ -94,7 +94,7 @@ public class RepairCommand extends SkillCommand {
         List<String> messages = new ArrayList<>();
 
         if (canArcaneForge) {
-            RepairManager repairManager = mmoPlayer.getRepairManager();
+            RepairManager repairManager = ((McMMOPlayer) (mmoPlayer)).getRepairManager();
 
             messages.add(getStatMessage(false, true,
                     SubSkillType.REPAIR_ARCANE_FORGING,

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/skills/SalvageCommand.java

@@ -37,7 +37,7 @@ public class SalvageCommand extends SkillCommand {
     @Override
     protected @NotNull List<String> statsDisplay(@NotNull OnlineMMOPlayer mmoPlayer, float skillValue, boolean hasEndurance, boolean isLucky) {
         List<String> messages = new ArrayList<>();
-        SalvageManager salvageManager = mmoPlayer.getSalvageManager();
+        SalvageManager salvageManager = ((McMMOPlayer) (mmoPlayer)).getSalvageManager();
 
         if (canScrapCollector) {
             messages.add(getStatMessage(false, true,

+ 31 - 26
src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java

@@ -2,6 +2,8 @@ package com.gmail.nossr50.commands.skills;
 
 import com.gmail.nossr50.config.AdvancedConfig;
 import com.gmail.nossr50.config.Config;
+import com.gmail.nossr50.datatypes.skills.CoreSkills;
+import com.gmail.nossr50.util.Misc;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.SubSkillType;
@@ -19,6 +21,7 @@ import com.gmail.nossr50.util.skills.SkillActivationType;
 import com.gmail.nossr50.util.text.StringUtils;
 import com.gmail.nossr50.util.text.TextComponentFactory;
 import com.google.common.collect.ImmutableList;
+import com.neetgames.mcmmo.skill.RootSkill;
 import net.kyori.adventure.text.Component;
 import net.md_5.bungee.api.ChatColor;
 import org.bukkit.command.Command;
@@ -35,7 +38,8 @@ import java.util.Locale;
 import java.util.Set;
 
 public abstract class SkillCommand implements TabExecutor {
-    protected PrimarySkillType skill;
+    protected @NotNull RootSkill rootSkill;
+    protected @NotNull PrimarySkillType primarySkillType;
     private final String skillName;
 
     protected DecimalFormat percent = new DecimalFormat("##0.00%");
@@ -43,10 +47,11 @@ public abstract class SkillCommand implements TabExecutor {
 
     private final CommandExecutor skillGuideCommand;
 
-    public SkillCommand(PrimarySkillType skill) {
-        this.skill = skill;
-        skillName = skill.getName();
-        skillGuideCommand = new SkillGuideCommand(skill);
+    public SkillCommand(@NotNull PrimarySkillType primarySkillType) {
+        this.rootSkill = CoreSkills.getSkill(primarySkillType);
+        this.primarySkillType = primarySkillType;
+        skillName = rootSkill.getSkillName();
+        skillGuideCommand = new SkillGuideCommand(rootSkill);
     }
 
     @Override
@@ -67,11 +72,11 @@ public abstract class SkillCommand implements TabExecutor {
         }
 
         if (args.length == 0) {
-            Player player = mmoPlayer.getPlayer();
+            Player player = Misc.adaptPlayer(mmoPlayer);
 
-            boolean isLucky = Permissions.lucky(player, skill);
+            boolean isLucky = Permissions.lucky(player, rootSkill);
             boolean hasEndurance = (PerksUtils.handleActivationPerks(player, 0, 0) != 0);
-            float skillValue = mmoPlayer.getExperienceManager().getSkillLevel(skill);
+            float skillValue = mmoPlayer.getExperienceHandler().getSkillLevel(rootSkill);
 
             //Send the players a few blank lines to make finding the top of the skill command easier
             if (AdvancedConfig.getInstance().doesSkillCommandSendBlankLines())
@@ -113,7 +118,7 @@ public abstract class SkillCommand implements TabExecutor {
 
 
             if (Config.getInstance().getScoreboardsEnabled() && Config.getInstance().getSkillUseBoard()) {
-                ScoreboardManager.enablePlayerSkillScoreboard(player, skill);
+                ScoreboardManager.enablePlayerSkillScoreboard(player, primarySkillType);
             }
 
             return true;
@@ -125,14 +130,14 @@ public abstract class SkillCommand implements TabExecutor {
         List<String> statsMessages = statsDisplay(mmoPlayer, skillValue, hasEndurance, isLucky);
 
         if (!statsMessages.isEmpty()) {
-            mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Skills.Overhaul.Header", LocaleLoader.getString("Commands.Stats.Self.Overhaul")));
+            Misc.adaptPlayer(mmoPlayer).sendMessage(LocaleLoader.getString("Skills.Overhaul.Header", LocaleLoader.getString("Commands.Stats.Self.Overhaul")));
 
             for (String message : statsMessages) {
-                mmoPlayer.getPlayer().sendMessage(message);
+                Misc.adaptPlayer(mmoPlayer).sendMessage(message);
             }
         }
 
-        mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Guides.Available", skillName, skillName.toLowerCase(Locale.ENGLISH)));
+        Misc.adaptPlayer(mmoPlayer).sendMessage(LocaleLoader.getString("Guides.Available", skillName, skillName.toLowerCase(Locale.ENGLISH)));
     }
 
     private void sendSkillCommandHeader(@NotNull OnlineMMOPlayer mmoPlayer, int skillValue) {
@@ -141,19 +146,19 @@ public abstract class SkillCommand implements TabExecutor {
         ChatColor c2 = ChatColor.RED;
 
 
-        mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Skills.Overhaul.Header", skillName));
+        Misc.adaptPlayer(mmoPlayer).sendMessage(LocaleLoader.getString("Skills.Overhaul.Header", skillName));
 
-        if(!skill.isChildSkill())
+        if(!CoreSkills.isChildSkill(rootSkill))
         {
             /*
              * NON-CHILD SKILLS
              */
 
             //XP GAIN METHOD
-            mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Commands.XPGain.Overhaul", LocaleLoader.getString("Commands.XPGain." + StringUtils.getCapitalized(skill.toString()))));
+            Misc.adaptPlayer(mmoPlayer).sendMessage(LocaleLoader.getString("Commands.XPGain.Overhaul", LocaleLoader.getString("Commands.XPGain." + StringUtils.getCapitalized(rootSkill.toString()))));
 
             //LEVEL
-            mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Effects.Level.Overhaul", skillValue, mmoPlayer.getExperienceManager().getSkillXpValue(skill), mmoPlayer.getExperienceManager().getExperienceToNextLevel(skill)));
+            Misc.adaptPlayer(mmoPlayer).sendMessage(LocaleLoader.getString("Effects.Level.Overhaul", skillValue, mmoPlayer.getExperienceHandler().getSkillXpValue(rootSkill), mmoPlayer.getExperienceHandler().getExperienceToNextLevel(rootSkill)));
 
         } else {
             /*
@@ -161,11 +166,11 @@ public abstract class SkillCommand implements TabExecutor {
              */
 
 
-            Set<PrimarySkillType> parents = FamilyTree.getParents(skill);
+            Set<RootSkill> parents = FamilyTree.getParentSkills(rootSkill);
 
             //TODO: Add JSON here
             /*player.sendMessage(parent.getName() + " - " + LocaleLoader.getString("Effects.Level.Overhaul", mmoPlayer.getSkillLevel(parent), mmoPlayer.getSkillXpLevel(parent), mmoPlayer.getXpToLevel(parent)))*/
-            ArrayList<PrimarySkillType> parentList = new ArrayList<>(parents);
+            ArrayList<RootSkill> parentList = new ArrayList<>(parents);
 
             StringBuilder parentMessage = new StringBuilder();
 
@@ -173,17 +178,17 @@ public abstract class SkillCommand implements TabExecutor {
             {
                 if(i+1 < parentList.size())
                 {
-                    parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", parentList.get(i).getName(), mmoPlayer.getExperienceManager().getSkillLevel(parentList.get(i))));
+                    parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", parentList.get(i).getSkillName(), mmoPlayer.getExperienceHandler().getSkillLevel(parentList.get(i))));
                     parentMessage.append(ChatColor.GRAY).append(", ");
                 } else {
-                    parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", parentList.get(i).getName(), mmoPlayer.getExperienceManager().getSkillLevel(parentList.get(i))));
+                    parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", parentList.get(i).getSkillName(), mmoPlayer.getExperienceHandler().getSkillLevel(parentList.get(i))));
                 }
             }
 
             //XP GAIN METHOD
-            mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Commands.XPGain.Overhaul", LocaleLoader.getString("Commands.XPGain.Child")));
+            Misc.adaptPlayer(mmoPlayer).sendMessage(LocaleLoader.getString("Commands.XPGain.Overhaul", LocaleLoader.getString("Commands.XPGain.Child")));
 
-            mmoPlayer.getPlayer().sendMessage(LocaleLoader.getString("Effects.Child.Overhaul", skillValue, parentMessage.toString()));
+            Misc.adaptPlayer(mmoPlayer).sendMessage(LocaleLoader.getString("Effects.Child.Overhaul", skillValue, parentMessage.toString()));
 
         }
     }
@@ -201,11 +206,11 @@ public abstract class SkillCommand implements TabExecutor {
     }
 
     protected @NotNull String[] getAbilityDisplayValues(@NotNull SkillActivationType skillActivationType, @NotNull OnlineMMOPlayer mmoPlayer, @NotNull SubSkillType subSkill) {
-        return RandomChanceUtil.calculateAbilityDisplayValues(skillActivationType, mmoPlayer.getPlayer(), subSkill);
+        return RandomChanceUtil.calculateAbilityDisplayValues(skillActivationType, Misc.adaptPlayer(mmoPlayer), subSkill);
     }
 
     protected @NotNull String[] calculateLengthDisplayValues(@NotNull OnlineMMOPlayer mmoPlayer, float skillValue) {
-        int maxLength = skill.getSuperAbilityType().getMaxLength();
+        int maxLength = primarySkillType.getSuperAbilityType().getMaxLength();
         int abilityLengthVar = AdvancedConfig.getInstance().getAbilityLength();
         int abilityLengthCap = AdvancedConfig.getInstance().getAbilityLengthCap();
 
@@ -219,7 +224,7 @@ public abstract class SkillCommand implements TabExecutor {
             length = 2 + (int) (Math.min(abilityLengthCap, skillValue) / abilityLengthVar);
         }
 
-        int enduranceLength = PerksUtils.handleActivationPerks(mmoPlayer.getPlayer(), length, maxLength);
+        int enduranceLength = PerksUtils.handleActivationPerks(Misc.adaptPlayer(mmoPlayer), length, maxLength);
 
         if (maxLength != 0) {
             length = Math.min(length, maxLength);
@@ -272,6 +277,6 @@ public abstract class SkillCommand implements TabExecutor {
      * @return true if the player has permission and has the skill unlocked
      */
     protected boolean canUseSubskill(@NotNull OnlineMMOPlayer mmoPlayer, SubSkillType subSkillType) {
-        return Permissions.isSubSkillEnabled(mmoPlayer.getPlayer(), subSkillType) && RankUtils.hasUnlockedSubskill(mmoPlayer, subSkillType);
+        return Permissions.isSubSkillEnabled(Misc.adaptPlayer(mmoPlayer), subSkillType) && RankUtils.hasUnlockedSubskill(mmoPlayer, subSkillType);
     }
 }

+ 6 - 1
src/main/java/com/gmail/nossr50/commands/skills/SkillGuideCommand.java

@@ -1,8 +1,10 @@
 package com.gmail.nossr50.commands.skills;
 
+import com.gmail.nossr50.datatypes.skills.CoreSkills;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.text.StringUtils;
+import com.neetgames.mcmmo.skill.RootSkill;
 import org.bukkit.command.Command;
 import org.bukkit.command.CommandExecutor;
 import org.bukkit.command.CommandSender;
@@ -11,13 +13,16 @@ import org.jetbrains.annotations.NotNull;
 import java.util.ArrayList;
 import java.util.Arrays;
 
+//TODO: Switch to root skill based
 public class SkillGuideCommand implements CommandExecutor {
     private final String header;
+    private final PrimarySkillType skill;
     private final ArrayList<String> guide;
 
     private final String invalidPage = LocaleLoader.getString("Guides.Page.Invalid");
 
-    public SkillGuideCommand(PrimarySkillType skill) {
+    public SkillGuideCommand(@NotNull RootSkill rootSkill) {
+        skill = CoreSkills.getSkill(rootSkill);
         header = LocaleLoader.getString("Guides.Header", skill.getName());
         guide = getGuide(skill);
     }

+ 3 - 3
src/main/java/com/gmail/nossr50/commands/skills/SmeltingCommand.java

@@ -34,7 +34,7 @@ public class SmeltingCommand extends SkillCommand {
     protected void dataCalculations(@NotNull OnlineMMOPlayer mmoPlayer, float skillValue) {
         // FUEL EFFICIENCY
         if (canFuelEfficiency) {
-            burnTimeModifier = String.valueOf(mmoPlayer.getSmeltingManager().getFuelEfficiencyMultiplier());
+            burnTimeModifier = String.valueOf(((McMMOPlayer) (mmoPlayer)).getSmeltingManager().getFuelEfficiencyMultiplier());
         }
 
         // FLUX MINING
@@ -57,7 +57,7 @@ public class SmeltingCommand extends SkillCommand {
         canFuelEfficiency = canUseSubskill(mmoPlayer, SubSkillType.SMELTING_FUEL_EFFICIENCY);
         canSecondSmelt = canUseSubskill(mmoPlayer, SubSkillType.SMELTING_SECOND_SMELT);
         //canFluxMine = canUseSubskill(player, SubSkillType.SMELTING_FLUX_MINING);
-        canUnderstandTheArt = Permissions.vanillaXpBoost(mmoPlayer.getPlayer(), skill) && RankUtils.hasUnlockedSubskill(mmoPlayer, SubSkillType.SMELTING_UNDERSTANDING_THE_ART);
+        canUnderstandTheArt = Permissions.vanillaXpBoost(Misc.adaptPlayer(mmoPlayer), rootSkill) && RankUtils.hasUnlockedSubskill(mmoPlayer, SubSkillType.SMELTING_UNDERSTANDING_THE_ART);
     }
 
     @Override
@@ -81,7 +81,7 @@ public class SmeltingCommand extends SkillCommand {
 
         if (canUnderstandTheArt) {
             messages.add(getStatMessage(false, true, SubSkillType.SMELTING_UNDERSTANDING_THE_ART,
-                    String.valueOf(mmoPlayer.getSmeltingManager().getVanillaXpMultiplier())));
+                    String.valueOf(((McMMOPlayer) (mmoPlayer)).getSmeltingManager().getVanillaXpMultiplier())));
         }
 
         return messages;

+ 3 - 3
src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java

@@ -44,7 +44,7 @@ public class SwordsCommand extends SkillCommand {
 
         // SWORDS_RUPTURE
         if (canBleed) {
-            bleedLength = mmoPlayer.getSwordsManager().getRuptureBleedTicks();
+            bleedLength = ((McMMOPlayer) (mmoPlayer)).getSwordsManager().getRuptureBleedTicks();
 
             String[] bleedStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, mmoPlayer, SubSkillType.SWORDS_RUPTURE);
             bleedChance = bleedStrings[0];
@@ -70,7 +70,7 @@ public class SwordsCommand extends SkillCommand {
     protected @NotNull List<String> statsDisplay(@NotNull OnlineMMOPlayer mmoPlayer, float skillValue, boolean hasEndurance, boolean isLucky) {
         List<String> messages = new ArrayList<>();
 
-        int ruptureTicks = mmoPlayer.getSwordsManager().getRuptureBleedTicks();
+        int ruptureTicks = ((McMMOPlayer) (mmoPlayer)).getSwordsManager().getRuptureBleedTicks();
         double ruptureDamagePlayers =  RankUtils.getRank(mmoPlayer, SubSkillType.SWORDS_RUPTURE) >= 3 ? AdvancedConfig.getInstance().getRuptureDamagePlayer() * 1.5D : AdvancedConfig.getInstance().getRuptureDamagePlayer();
         double ruptureDamageMobs =  RankUtils.getRank(mmoPlayer, SubSkillType.SWORDS_RUPTURE) >= 3 ? AdvancedConfig.getInstance().getRuptureDamageMobs() * 1.5D : AdvancedConfig.getInstance().getRuptureDamageMobs();
 
@@ -98,7 +98,7 @@ public class SwordsCommand extends SkillCommand {
         if(canUseSubskill(mmoPlayer, SubSkillType.SWORDS_STAB))
         {
             messages.add(getStatMessage(SubSkillType.SWORDS_STAB,
-                    String.valueOf(mmoPlayer.getSwordsManager().getStabDamage())));
+                    String.valueOf(((McMMOPlayer) (mmoPlayer)).getSwordsManager().getStabDamage())));
         }
 
         if(canUseSubskill(mmoPlayer, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK)) {

+ 2 - 2
src/main/java/com/gmail/nossr50/commands/skills/TamingCommand.java

@@ -45,7 +45,7 @@ public class TamingCommand extends SkillCommand {
     @Override
     protected void permissionsCheck(@NotNull OnlineMMOPlayer mmoPlayer) {
         canBeastLore = canUseSubskill(mmoPlayer, SubSkillType.TAMING_BEAST_LORE);
-        canCallWild = Permissions.callOfTheWild(mmoPlayer.getPlayer(), EntityType.HORSE) || Permissions.callOfTheWild(mmoPlayer.getPlayer(), EntityType.WOLF) || Permissions.callOfTheWild(mmoPlayer.getPlayer(), EntityType.OCELOT);
+        canCallWild = Permissions.callOfTheWild(Misc.adaptPlayer(mmoPlayer), EntityType.HORSE) || Permissions.callOfTheWild(Misc.adaptPlayer(mmoPlayer), EntityType.WOLF) || Permissions.callOfTheWild(Misc.adaptPlayer(mmoPlayer), EntityType.OCELOT);
         canEnvironmentallyAware = canUseSubskill(mmoPlayer, SubSkillType.TAMING_ENVIRONMENTALLY_AWARE);
         canFastFood = canUseSubskill(mmoPlayer, SubSkillType.TAMING_FAST_FOOD_SERVICE);
         canGore = canUseSubskill(mmoPlayer, SubSkillType.TAMING_GORE);
@@ -96,7 +96,7 @@ public class TamingCommand extends SkillCommand {
     protected @NotNull List<Component> getTextComponents(@NotNull OnlineMMOPlayer mmoPlayer) {
         List<Component> textComponents = new ArrayList<>();
 
-        TextComponentFactory.getSubSkillTextComponents(mmoPlayer, textComponents, this.skill);
+        TextComponentFactory.getSubSkillTextComponents(mmoPlayer, textComponents, this.rootSkill);
 
         return textComponents;
     }

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java

@@ -61,7 +61,7 @@ public class UnarmedCommand extends SkillCommand {
 
         // IRON ARM
         if (canIronArm) {
-            ironArmBonus = mmoPlayer.getUnarmedManager().getSteelArmStyleDamage();
+            ironArmBonus = ((McMMOPlayer) (mmoPlayer)).getUnarmedManager().getSteelArmStyleDamage();
         }
 
         // IRON GRIP

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java

@@ -56,7 +56,7 @@ public class WoodcuttingCommand extends SkillCommand {
     @Override
     protected void permissionsCheck(@NotNull OnlineMMOPlayer mmoPlayer) {
         canTreeFell = RankUtils.hasUnlockedSubskill(mmoPlayer, SubSkillType.WOODCUTTING_TREE_FELLER) && Permissions.treeFeller(mmoPlayer.getPlayer());
-        canDoubleDrop = canUseSubskill(mmoPlayer, SubSkillType.WOODCUTTING_HARVEST_LUMBER) && !skill.getDoubleDropsDisabled() && RankUtils.getRank(mmoPlayer, SubSkillType.WOODCUTTING_HARVEST_LUMBER) >= 1;
+        canDoubleDrop = canUseSubskill(mmoPlayer, SubSkillType.WOODCUTTING_HARVEST_LUMBER) && !rootSkill.getDoubleDropsDisabled() && RankUtils.getRank(mmoPlayer, SubSkillType.WOODCUTTING_HARVEST_LUMBER) >= 1;
         canLeafBlow = canUseSubskill(mmoPlayer, SubSkillType.WOODCUTTING_LEAF_BLOWER);
         canKnockOnWood = canTreeFell && canUseSubskill(mmoPlayer, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD);
         /*canSplinter = canUseSubskill(player, SubSkillType.WOODCUTTING_SPLINTER);

+ 1 - 0
src/main/java/com/gmail/nossr50/config/Config.java

@@ -552,6 +552,7 @@ public class Config extends AutoUpdateConfigLoader {
     }
 
     public int getLevelCap(@NotNull SkillIdentity skillIdentity) {
+
         int cap = config.getInt("Skills." + StringUtils.getCapitalized(skillIdentity.getSkillName()) + ".Level_Cap", 0);
         return (cap <= 0) ? Integer.MAX_VALUE : cap;
     }

+ 31 - 2
src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java

@@ -6,6 +6,7 @@ import com.gmail.nossr50.datatypes.skills.MaterialType;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.alchemy.PotionStage;
 import com.gmail.nossr50.util.text.StringUtils;
+import com.neetgames.mcmmo.skill.RootSkill;
 import org.bukkit.Material;
 import org.bukkit.block.Block;
 import org.bukkit.block.BlockState;
@@ -13,6 +14,7 @@ import org.bukkit.block.data.BlockData;
 import org.bukkit.boss.BarColor;
 import org.bukkit.boss.BarStyle;
 import org.bukkit.entity.EntityType;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -328,6 +330,21 @@ public class ExperienceConfig extends AutoUpdateConfigLoader {
     public boolean getAddExtraDetails() { return config.getBoolean("Experience_Bars.ThisMayCauseLag.AlwaysUpdateTitlesWhenXPIsGained.ExtraDetails", false);}
     public boolean isExperienceBarsEnabled() { return config.getBoolean("Experience_Bars.Enable", true); }
     public boolean isExperienceBarEnabled(PrimarySkillType primarySkillType) { return config.getBoolean("Experience_Bars."+StringUtils.getCapitalized(primarySkillType.toString())+".Enable", true);}
+    public boolean isExperienceBarEnabled(@NotNull RootSkill rootSkill) { return config.getBoolean("Experience_Bars."+StringUtils.getCapitalized(rootSkill.getSkillName())+".Enable", true);}
+
+    public BarColor getExperienceBarColor(@NotNull RootSkill rootSkill)
+    {
+        String colorValueFromConfig = config.getString("Experience_Bars."+StringUtils.getCapitalized(rootSkill.getSkillName())+".Color");
+
+        for(BarColor barColor : BarColor.values())
+        {
+            if(barColor.toString().equalsIgnoreCase(colorValueFromConfig))
+                return barColor;
+        }
+
+        //In case the value is invalid
+        return BarColor.WHITE;
+    }
 
     public BarColor getExperienceBarColor(PrimarySkillType primarySkillType)
     {
@@ -343,8 +360,7 @@ public class ExperienceConfig extends AutoUpdateConfigLoader {
         return BarColor.WHITE;
     }
 
-    public BarStyle getExperienceBarStyle(PrimarySkillType primarySkillType)
-    {
+    public BarStyle getExperienceBarStyle(PrimarySkillType primarySkillType) {
         String colorValueFromConfig = config.getString("Experience_Bars."+StringUtils.getCapitalized(primarySkillType.toString())+".BarStyle");
 
         for(BarStyle barStyle : BarStyle.values())
@@ -357,6 +373,19 @@ public class ExperienceConfig extends AutoUpdateConfigLoader {
         return BarStyle.SOLID;
     }
 
+    public BarStyle getExperienceBarStyle(@NotNull RootSkill rootSkill) {
+        String colorValueFromConfig = config.getString("Experience_Bars."+StringUtils.getCapitalized(rootSkill.getSkillName())+".BarStyle");
+
+        for(BarStyle barStyle : BarStyle.values())
+        {
+            if(barStyle.toString().equalsIgnoreCase(colorValueFromConfig))
+                return barStyle;
+        }
+
+        //In case the value is invalid
+        return BarStyle.SOLID;
+    }
+
     /* Acrobatics */
     public int getDodgeXPModifier() { return config.getInt("Experience_Values.Acrobatics.Dodge", 120); }
     public int getRollXPModifier() { return config.getInt("Experience_Values.Acrobatics.Roll", 80); }

+ 5 - 4
src/main/java/com/gmail/nossr50/database/DatabaseManager.java

@@ -8,6 +8,7 @@ import com.gmail.nossr50.datatypes.player.PlayerProfile;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.neetgames.mcmmo.exceptions.InvalidSkillException;
 import com.neetgames.mcmmo.exceptions.ProfileRetrievalException;
+import com.neetgames.mcmmo.player.MMOPlayerData;
 import org.apache.commons.lang.NullArgumentException;
 import org.bukkit.entity.Player;
 import org.jetbrains.annotations.NotNull;
@@ -85,7 +86,7 @@ public interface DatabaseManager {
      */
     void insertNewUser(@NotNull String playerName, @NotNull UUID uuid) throws Exception;
 
-    @Nullable PlayerProfile queryPlayerDataByPlayer(@NotNull Player player) throws ProfileRetrievalException, NullArgumentException;
+    @Nullable MMOPlayerData queryPlayerDataByPlayer(@NotNull Player player) throws ProfileRetrievalException, NullArgumentException;
 
     /**
      * Load player data (in the form of {@link PlayerProfile}) if player data exists
@@ -95,7 +96,7 @@ public interface DatabaseManager {
      * @param playerName the current player name for this player
      * @return The player's data, or null if not found
      */
-    @Nullable PlayerProfile queryPlayerDataByUUID(@NotNull UUID uuid, @NotNull String playerName) throws ProfileRetrievalException, NullArgumentException;
+    @Nullable MMOPlayerData queryPlayerDataByUUID(@NotNull UUID uuid, @NotNull String playerName) throws ProfileRetrievalException, NullArgumentException;
 
     /**
      * Load player data (in the form of {@link PlayerProfile}) if player data exists
@@ -104,7 +105,7 @@ public interface DatabaseManager {
      * @param playerName the current player name for this player
      * @return The player's data, or null if not found
      */
-    @Nullable PlayerProfile queryPlayerByName(@NotNull String playerName) throws ProfileRetrievalException;
+    @Nullable MMOPlayerData queryPlayerByName(@NotNull String playerName) throws ProfileRetrievalException;
 
     /**
      * This method queries the DB for player data for target player
@@ -117,7 +118,7 @@ public interface DatabaseManager {
      * @param player target player
      * @return {@link PlayerProfile} for the target player
      */
-    @Nullable PlayerProfile initPlayerProfile(@NotNull Player player) throws Exception;
+    @Nullable MMOPlayerData initPlayerProfile(@NotNull Player player) throws Exception;
 
     /**
      * Get all users currently stored in the database.

+ 0 - 459
src/main/java/com/gmail/nossr50/datatypes/experience/ExperienceManager.java

@@ -1,459 +0,0 @@
-package com.gmail.nossr50.datatypes.experience;
-
-import com.gmail.nossr50.config.Config;
-import com.gmail.nossr50.config.experience.ExperienceConfig;
-import com.gmail.nossr50.datatypes.party.Party;
-import com.neetgames.mcmmo.player.OnlineMMOPlayer;
-import com.gmail.nossr50.datatypes.player.PersistentPlayerData;
-import com.gmail.nossr50.datatypes.skills.CoreSkillConstants;
-import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
-import com.gmail.nossr50.mcMMO;
-import com.gmail.nossr50.party.ShareHandler;
-import com.gmail.nossr50.skills.child.FamilyTree;
-import com.gmail.nossr50.util.EventUtils;
-import com.gmail.nossr50.util.experience.ExperienceUtils;
-import com.gmail.nossr50.util.player.NotificationManager;
-import com.gmail.nossr50.util.skills.PerksUtils;
-import com.gmail.nossr50.util.sounds.SoundManager;
-import com.gmail.nossr50.util.sounds.SoundType;
-import com.neetgames.mcmmo.exceptions.UnknownSkillException;
-import com.neetgames.mcmmo.skill.SkillIdentity;
-import org.bukkit.GameMode;
-import org.bukkit.plugin.Plugin;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Set;
-
-public class ExperienceManager {
-
-    private boolean isUsingUnarmed = false;
-
-    private final @NotNull PersistentPlayerData persistentPlayerDataRef;
-    private @Nullable OnlineMMOPlayer mmoPlayer;
-
-    public ExperienceManager(@NotNull OnlineMMOPlayer mmoPlayer) {
-        this.mmoPlayer = mmoPlayer;
-        this.persistentPlayerDataRef = mmoPlayer.getPersistentPlayerData();
-    }
-
-    public ExperienceManager(@NotNull PersistentPlayerData persistentPlayerData) {
-        this.persistentPlayerDataRef = persistentPlayerData;
-    }
-
-    /**
-     * Gets the power level of this player.
-     * A power level is the sum of all skill levels for this player
-     *
-     * @return the power level of the player
-     */
-    public int getPowerLevel() {
-        int powerLevel = 0;
-
-        for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) {
-            powerLevel += getSkillLevel(primarySkillType);
-        }
-
-        return powerLevel;
-    }
-
-    /**
-     * Get the current value of raw XP for a skill
-     * @param primarySkillType target skill
-     * @return the value of raw XP for target skill
-     */
-    public float getSkillXpLevelRaw(@NotNull PrimarySkillType primarySkillType) {
-        return persistentPlayerDataRef.getSkillsExperienceMap().get(primarySkillType);
-    }
-
-    /**
-     * Get the value of XP a player has accumulated in target skill
-     * Child Skills will return 0 (Child Skills will be removed in a future update)
-     * @param skillIdentity target skill
-     * @return the value for XP the player has accumulated in target skill
-     */
-    public int getSkillXpValue(@NotNull SkillIdentity skillIdentity) {
-        if(CoreSkillConstants.isChildSkill(skillIdentity)) {
-            return 0;
-        }
-
-        return (int) Math.floor(getSkillXpLevelRaw(skillIdentity));
-    }
-
-    public void setSkillXpValue(@NotNull SkillIdentity skillIdentity, float xpLevel) {
-        if (CoreSkillConstants.isChildSkill(skillIdentity)) {
-            return;
-        }
-
-        persistentPlayerDataRef.getSkillsExperienceMap().put(skillIdentity, xpLevel);
-    }
-
-    public float levelUp(@NotNull SkillIdentity skillIdentity) {
-        float xpRemoved = getExperienceToNextLevel(skillIdentity);
-
-        setSkillLevel(skillIdentity, getSkillLevel(skillIdentity) + 1);
-        setSkillXpValue(skillIdentity, getSkillXpValue(skillIdentity) - xpRemoved);
-
-        return xpRemoved;
-    }
-
-    /**
-     * Whether or not a player is level capped
-     * If they are at the power level cap, this will return true, otherwise it checks their skill level
-     *
-     * @param skillIdentity
-     * @return
-     */
-    public boolean hasReachedLevelCap(@NotNull SkillIdentity skillIdentity) {
-        if(hasReachedPowerLevelCap())
-            return true;
-
-        return getSkillLevel(skillIdentity) >= Config.getInstance().getLevelCap(skillIdentity);
-    }
-
-    /**
-     * Whether or not a player is power level capped
-     * Compares their power level total to the current set limit
-     * @return true if they have reached the power level cap
-     */
-    public boolean hasReachedPowerLevelCap() {
-        return this.getPowerLevel() >= Config.getInstance().getPowerLevelCap();
-    }
-
-    /**
-     * Begins an experience gain. The amount will be affected by skill modifiers, global rate, perks, and may be shared with the party
-     *
-     * @param skillIdentity Skill being used
-     * @param xp Experience amount to process
-     */
-    public void beginXpGain(@NotNull SkillIdentity skillIdentity, float xp, @NotNull XPGainReason xpGainReason, @NotNull XPGainSource xpGainSource) {
-        if (xp <= 0.0) {
-            return;
-        }
-
-        if (CoreSkillConstants.isChildSkill(skillIdentity)) {
-            Set<SkillIdentity> parentSkills = FamilyTree.getParentSkills(skillIdentity);
-            float splitXp = xp / parentSkills.size();
-
-            for (SkillIdentity parentSkill : parentSkills) {
-                beginXpGain(parentSkill, splitXp, xpGainReason, xpGainSource);
-            }
-
-            return;
-        }
-
-        //TODO: The logic here is so stupid... rewrite later
-
-        // Return if the experience has been shared
-        if (mmoPlayer.getParty() != null && ShareHandler.handleXpShare(xp, mmoPlayer, mmoPlayer.getParty(), skillIdentity, ShareHandler.getSharedXpGainReason(xpGainReason))) {
-            return;
-        }
-
-        beginUnsharedXpGain(skillIdentity, xp, xpGainReason, xpGainSource);
-    }
-
-    /**
-     * Begins an experience gain. The amount will be affected by skill modifiers, global rate and perks
-     *
-     * @param skillIdentity Skill being used
-     * @param xp Experience amount to process
-     */
-    public void beginUnsharedXpGain(@NotNull SkillIdentity skillIdentity, float xp, @NotNull XPGainReason xpGainReason, @NotNull XPGainSource xpGainSource) {
-        if(mmoPlayer.getPlayer().getGameMode() == GameMode.CREATIVE)
-            return;
-
-        ExperienceUtils.applyXpGain(mmoPlayer, skillIdentity, modifyXpGain(skillIdentity, xp), xpGainReason, xpGainSource);
-
-        Party party = mmoPlayer.getParty();
-
-        if (party != null) {
-            if (!Config.getInstance().getPartyXpNearMembersNeeded() || !mcMMO.getPartyManager().getNearMembers(mmoPlayer).isEmpty()) {
-                party.getPartyExperienceManager().applyXpGain(modifyXpGain(skillIdentity, xp));
-            }
-        }
-    }
-
-    public int getSkillLevel(@NotNull SkillIdentity skillIdentity) {
-        return CoreSkillConstants.isChildSkill(skillIdentity) ? getChildSkillLevel(skillIdentity) : getSkillLevel(skillIdentity);
-    }
-
-    /**
-     * Get the amount of Xp remaining before the next level.
-     *
-     * @param skillIdentity Type of skill to check
-     * @return the total amount of Xp until next level
-     */
-    public int getExperienceToNextLevel(@NotNull SkillIdentity skillIdentity) {
-        if(CoreSkillConstants.isChildSkill(skillIdentity)) {
-            return 0;
-        }
-
-        int level = (ExperienceConfig.getInstance().getCumulativeCurveEnabled()) ? getPowerLevel() : getSkillLevel(skillIdentity);
-        FormulaType formulaType = ExperienceConfig.getInstance().getFormulaType();
-
-        return mcMMO.getFormulaManager().getXPtoNextLevel(level, formulaType);
-    }
-
-    private int getChildSkillLevel(@NotNull SkillIdentity skillIdentity) {
-        Set<SkillIdentity> parents = FamilyTree.getParentSkills(skillIdentity);
-        int sum = 0;
-
-        for (SkillIdentity parentIdentity : parents) {
-            sum += getSkillLevel(parentIdentity);
-        }
-
-        return sum / parents.size();
-    }
-
-    /*
-     * Xp Functions
-     */
-
-    /**
-     * Remove Xp from a skill.
-     *
-     * @param skill Type of skill to modify
-     * @param xp Amount of xp to remove
-     */
-    public void removeXp(@NotNull PrimarySkillType skill, int xp) {
-        if (skill.isChildSkill()) {
-            return;
-        }
-
-        setSkillXpValue(skill, getSkillXpValue(skill) - xp);
-    }
-
-    public void removeXp(PrimarySkillType skill, float xp) {
-        if (skill.isChildSkill()) {
-            return;
-        }
-
-        setSkillXpValue(skill, getSkillXpValue(skill) - xp);
-    }
-
-    /**
-     * Modify a primarySkillType level.
-     *
-     * @param primarySkillType Type of primarySkillType to modify
-     * @param level New level value for the primarySkillType
-     */
-    public void setSkillLevel(@NotNull PrimarySkillType primarySkillType, int level) {
-        if (primarySkillType.isChildSkill()) {
-            return;
-        }
-
-        //Don't allow levels to be negative
-        if(level < 0)
-            level = 0;
-
-        setSkillLevel(primarySkillType, level);
-        setSkillXpValue(primarySkillType, 0F);
-    }
-
-    /**
-     * Add levels to a primarySkillType.
-     *
-     * @param primarySkillType Type of primarySkillType to add levels to
-     * @param levels Number of levels to add
-     */
-    public void addLevels(@NotNull PrimarySkillType primarySkillType, int levels) {
-        setSkillLevel(primarySkillType, getSkillLevel(primarySkillType) + levels);
-    }
-
-    /**
-     * Add Experience to a primarySkillType.
-     *
-     * @param primarySkillType Type of primarySkillType to add experience to
-     * @param xp Number of experience to add
-     */
-    public void addXp(@NotNull PrimarySkillType primarySkillType, float xp) {
-        if (primarySkillType.isChildSkill()) {
-            Set<PrimarySkillType> parentSkills = FamilyTree.getParents(primarySkillType);
-            float dividedXP = (xp / parentSkills.size());
-
-            for (PrimarySkillType parentSkill : parentSkills) {
-                setSkillXpValue(parentSkill, getSkillXpValue(parentSkill) + dividedXP);
-            }
-        }
-        else {
-            setSkillXpValue(primarySkillType, getSkillXpValue(primarySkillType) + xp);
-        }
-    }
-
-    /**
-     * Get the registered amount of experience gained
-     * This is used for diminished XP returns
-     *
-     * @return xp Experience amount registered
-     */
-    public float getRegisteredXpGain(@NotNull PrimarySkillType primarySkillType) {
-        float xp = 0F;
-
-        if (get(primarySkillType) != null) { //??
-            xp = rollingSkillsXp.get(primarySkillType);
-        }
-
-        return xp;
-    }
-
-    /**
-     * Register an experience gain
-     * This is used for diminished XP returns
-     *
-     * @param primarySkillType Skill being used
-     * @param xp Experience amount to add
-     */
-    public void registerXpGain(@NotNull PrimarySkillType primarySkillType, float xp) {
-        gainedSkillsXp.add(new SkillXpGain(primarySkillType, xp));
-        rollingSkillsXp.put(primarySkillType, getRegisteredXpGain(primarySkillType) + xp);
-    }
-
-    /**
-     * Remove experience gains older than a given time
-     * This is used for diminished XP returns
-     */
-    public void purgeExpiredXpGains() {
-        SkillXpGain gain;
-        while ((gain = gainedSkillsXp.poll()) != null) {
-            rollingSkillsXp.put(gain.getSkill(), getRegisteredXpGain(gain.getSkill()) - gain.getXp());
-        }
-    }
-
-    /**
-     * Modifies an experience gain using skill modifiers, global rate and perks
-     *
-     * @param skillIdentity Skill being used
-     * @param xp Experience amount to process
-     * @return Modified experience
-     */
-    private float modifyXpGain(@NotNull SkillIdentity skillIdentity, float xp) {
-        if ((skillIdentity.getMaxLevel() <= getSkillLevel(skillIdentity)) || (Config.getInstance().getPowerLevelCap() <= getPowerLevel())) {
-            return 0;
-        }
-
-        xp = (float) (xp / skillIdentity.getXpModifier() * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier());
-
-        return PerksUtils.handleXpPerks(mmoPlayer.getPlayer(), xp, skillIdentity);
-    }
-
-    public double getProgressInCurrentSkillLevel(@NotNull SkillIdentity skillIdentity) throws UnknownSkillException
-    {
-        if(CoreSkillConstants.isChildSkill(skillIdentity)) {
-            return 1.0D;
-        }
-
-        double currentXP = getSkillXpValue(skillIdentity);
-        double maxXP = getExperienceToNextLevel(skillIdentity);
-
-        return (currentXP / maxXP);
-    }
-
-    public void setUsingUnarmed(boolean bool) {
-        isUsingUnarmed = bool;
-    }
-
-    /**
-     * Applies an experience gain
-     *
-     * @param primarySkillType Skill being used
-     * @param xp Experience amount to add
-     */
-    public void applyXpGain(@NotNull PrimarySkillType primarySkillType, float xp, @NotNull XPGainReason xpGainReason, @NotNull XPGainSource xpGainSource) {
-        //Only check for permissions if the player is online, otherwise just assume a command is being executed by an admin or some other means and add the XP
-        if(mmoPlayer != null) {
-            if (!primarySkillType.getPermissions(mmoPlayer.getPlayer())) {
-                return;
-            }
-        }
-
-        if (primarySkillType.isChildSkill()) {
-            Set<PrimarySkillType> parentSkills = FamilyTree.getParents(primarySkillType);
-
-            for (PrimarySkillType parentSkill : parentSkills) {
-                applyXpGain(parentSkill, xp / parentSkills.size(), xpGainReason, xpGainSource);
-            }
-
-            return;
-        }
-
-        if (!EventUtils.handleXpGainEvent(mmoPlayer.getPlayer(), primarySkillType, xp, xpGainReason)) {
-            return;
-        }
-
-        setUsingUnarmed(primarySkillType == PrimarySkillType.UNARMED);
-        updateLevelStats(primarySkillType, xpGainReason, xpGainSource);
-    }
-
-    public void processPostXpEvent(@NotNull PrimarySkillType primarySkillType, @NotNull Plugin plugin, @NotNull XPGainSource xpGainSource)
-    {
-        /*
-         * Everything in this method requires an online player, so if they aren't online we don't waste our time
-         */
-        if(mmoPlayer == null)
-            return;
-
-        //Check if they've reached the power level cap just now
-        if(hasReachedPowerLevelCap()) {
-            NotificationManager.sendPlayerInformationChatOnly(mmoPlayer.getPlayer(), "LevelCap.PowerLevel", String.valueOf(Config.getInstance().getPowerLevelCap()));
-        } else if(hasReachedLevelCap(primarySkillType)) {
-            NotificationManager.sendPlayerInformationChatOnly(mmoPlayer.getPlayer(), "LevelCap.Skill", String.valueOf(Config.getInstance().getLevelCap(primarySkillType)), primarySkillType.getName());
-        }
-
-        //Updates from Party sources
-        if(xpGainSource == XPGainSource.PARTY_MEMBERS && !ExperienceConfig.getInstance().isPartyExperienceBarsEnabled())
-            return;
-
-        //Updates from passive sources (Alchemy, Smelting, etc...)
-        if(xpGainSource == XPGainSource.PASSIVE && !ExperienceConfig.getInstance().isPassiveGainsExperienceBarsEnabled())
-            return;
-
-        mmoPlayer.updateXPBar(primarySkillType, plugin);
-    }
-
-    /**
-     * Updates a players level
-     *
-     * @param primarySkillType The skill to check
-     */
-    public void updateLevelStats(@NotNull PrimarySkillType primarySkillType, @NotNull XPGainReason xpGainReason, @NotNull XPGainSource xpGainSource) {
-        if(hasReachedLevelCap(primarySkillType))
-            return;
-
-        if (getSkillXpLevelRaw(primarySkillType) < getExperienceToNextLevel(primarySkillType)) {
-            processPostXpEvent(primarySkillType, mcMMO.p, xpGainSource);
-            return;
-        }
-
-        int levelsGained = 0;
-        float xpRemoved = 0;
-
-        while (getSkillXpLevelRaw(primarySkillType) >= getExperienceToNextLevel(primarySkillType)) {
-            if (hasReachedLevelCap(primarySkillType)) {
-                setSkillXpValue(primarySkillType, 0);
-                break;
-            }
-
-            xpRemoved += levelUp(primarySkillType);
-            levelsGained++;
-        }
-
-        if (EventUtils.tryLevelChangeEvent(mmoPlayer.getPlayer(), primarySkillType, levelsGained, xpRemoved, true, xpGainReason)) {
-            return;
-        }
-
-        if (Config.getInstance().getLevelUpSoundsEnabled()) {
-            SoundManager.sendSound(mmoPlayer.getPlayer(), mmoPlayer.getPlayer().getLocation(), SoundType.LEVEL_UP);
-        }
-
-        /*
-         * Check to see if the player unlocked any new skills
-         */
-
-        NotificationManager.sendPlayerLevelUpNotification(mmoPlayer, primarySkillType, levelsGained, getSkillLevel(primarySkillType));
-
-        //UPDATE XP BARS
-        processPostXpEvent(primarySkillType, mcMMO.p, xpGainSource);
-    }
-
-
-}

+ 6 - 0
src/main/java/com/gmail/nossr50/datatypes/experience/OfflineExperienceProcessor.java

@@ -0,0 +1,6 @@
+package com.gmail.nossr50.datatypes.experience;
+
+import com.neetgames.mcmmo.experience.ExperienceHandler;
+
+public class OfflineExperienceProcessor implements ExperienceHandler {
+}

+ 379 - 0
src/main/java/com/gmail/nossr50/datatypes/experience/OnlineExperienceProcessor.java

@@ -0,0 +1,379 @@
+package com.gmail.nossr50.datatypes.experience;
+
+import com.gmail.nossr50.config.Config;
+import com.gmail.nossr50.config.experience.ExperienceConfig;
+import com.gmail.nossr50.datatypes.party.Party;
+import com.gmail.nossr50.datatypes.player.McMMOPlayer;
+import com.gmail.nossr50.util.Misc;
+import com.gmail.nossr50.util.Permissions;
+import com.neetgames.mcmmo.experience.ExperienceHandler;
+import com.neetgames.mcmmo.experience.XPGainReason;
+import com.neetgames.mcmmo.experience.XPGainSource;
+import com.neetgames.mcmmo.player.MMOPlayer;
+import com.neetgames.mcmmo.player.MMOPlayerData;
+import com.neetgames.mcmmo.player.OnlineMMOPlayer;
+import com.gmail.nossr50.datatypes.skills.CoreSkills;
+import com.gmail.nossr50.datatypes.skills.RootSkill;
+import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.party.ShareHandler;
+import com.gmail.nossr50.skills.child.FamilyTree;
+import com.gmail.nossr50.util.EventUtils;
+import com.gmail.nossr50.util.experience.ExperienceUtils;
+import com.gmail.nossr50.util.player.NotificationManager;
+import com.gmail.nossr50.util.skills.PerksUtils;
+import com.gmail.nossr50.util.sounds.SoundManager;
+import com.gmail.nossr50.util.sounds.SoundType;
+import com.neetgames.mcmmo.exceptions.UnknownSkillException;
+import com.neetgames.mcmmo.skill.RootSkill;
+import org.bukkit.GameMode;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.Plugin;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+import java.util.Set;
+
+public class OnlineExperienceProcessor implements ExperienceHandler {
+
+    private boolean isUsingUnarmed = false;
+
+    private final @NotNull MMOPlayerData mmoPlayerData;
+    private final @NotNull MMOPlayer mmoPlayer;
+    private final @NotNull Player playerRef;
+
+    public OnlineExperienceProcessor(@NotNull MMOPlayer mmoPlayer, @NotNull Player playerRef) {
+        this.mmoPlayer = mmoPlayer;
+        this.playerRef = playerRef;
+        this.mmoPlayerData = mmoPlayer.getMMOPlayerData();
+    }
+
+    @Override
+    public int getPowerLevel() {
+        int powerLevel = 0;
+
+        Map<RootSkill, Integer> rootSkillLevelMap = mmoPlayerData.getDirtySkillLevelMap().unwrapMap();
+
+        for (RootSkill rootSkill : rootSkillLevelMap.keySet()) {
+            powerLevel += rootSkillLevelMap.get(rootSkill);
+        }
+
+        return powerLevel;
+    }
+
+    @Override
+    public float getSkillXpLevelRaw(@NotNull RootSkill rootSkill) {
+        return mmoPlayerData.getSkillsExperienceMap().get(rootSkill);
+    }
+
+    @Override
+    public int getSkillXpValue(@NotNull RootSkill rootSkill) {
+        if(CoreSkills.isChildSkill(rootSkill)) {
+            return 0;
+        }
+
+        return (int) Math.floor(getSkillXpLevelRaw(rootSkill));
+    }
+
+    @Override
+    public void setSkillXpValue(@NotNull RootSkill rootSkill, float xpLevel) {
+        if (CoreSkills.isChildSkill(rootSkill)) {
+            return;
+        }
+
+        mmoPlayerData.getSkillsExperienceMap().put(rootSkill, xpLevel);
+    }
+
+    @Override
+    public float levelUp(@NotNull RootSkill rootSkill) {
+        float xpRemoved = getExperienceToNextLevel(rootSkill);
+
+        setSkillLevel(rootSkill, getSkillLevel(rootSkill) + 1);
+        setSkillXpValue(rootSkill, getSkillXpValue(rootSkill) - xpRemoved);
+
+        return xpRemoved;
+    }
+
+    @Override
+    public boolean hasReachedLevelCap(@NotNull RootSkill rootSkill) {
+        if(hasReachedPowerLevelCap())
+            return true;
+
+        return getSkillLevel(rootSkill) >= Config.getInstance().getLevelCap(rootSkill);
+    }
+
+    @Override
+    public boolean hasReachedPowerLevelCap() {
+        return this.getPowerLevel() >= Config.getInstance().getPowerLevelCap();
+    }
+
+    @Override
+    public void beginXpGain(@NotNull RootSkill rootSkill, float xp, @NotNull XPGainReason xpGainReason, @NotNull XPGainSource xpGainSource) {
+        if (xp <= 0.0) {
+            return;
+        }
+
+        if (CoreSkills.isChildSkill(rootSkill)) {
+            Set<RootSkill> parentSkills = FamilyTree.getParentSkills(rootSkill);
+            float splitXp = xp / parentSkills.size();
+
+            for (RootSkill parentSkill : parentSkills) {
+                beginXpGain(parentSkill, splitXp, xpGainReason, xpGainSource);
+            }
+
+            return;
+        }
+
+        //TODO: The logic here is so stupid... rewrite later
+
+        // Return if the experience has been shared
+        if (mmoPlayer.getParty() != null && ShareHandler.handleXpShare(xp, mmoPlayer, mmoPlayer.getParty(), rootSkill, ShareHandler.getSharedXpGainReason(xpGainReason))) {
+            return;
+        }
+
+        beginUnsharedXpGain(rootSkill, xp, xpGainReason, xpGainSource);
+    }
+
+    @Override
+    public void beginUnsharedXpGain(@NotNull RootSkill rootSkill, float xp, @NotNull XPGainReason xpGainReason, @NotNull XPGainSource xpGainSource) {
+        if(Misc.adaptPlayer(mmoPlayer).getGameMode() == GameMode.CREATIVE)
+            return;
+
+        ExperienceUtils.applyXpGain(mmoPlayer, rootSkill, modifyXpGain(rootSkill, xp), xpGainReason, xpGainSource);
+
+        Party party = mmoPlayer.getParty();
+
+        if (party != null) {
+            if (!Config.getInstance().getPartyXpNearMembersNeeded() || !mcMMO.getPartyManager().getNearMembers(mmoPlayer).isEmpty()) {
+                party.getPartyExperienceManager().applyXpGain(modifyXpGain(rootSkill, xp));
+            }
+        }
+    }
+
+    @Override
+    public int getSkillLevel(@NotNull RootSkill rootSkill) {
+        return CoreSkills.isChildSkill(rootSkill) ? getChildSkillLevel(rootSkill) : getSkillLevel(rootSkill);
+    }
+
+    @Override
+    public int getExperienceToNextLevel(@NotNull RootSkill rootSkill) {
+        if(CoreSkills.isChildSkill(rootSkill)) {
+            return 0;
+        }
+
+        int level = (ExperienceConfig.getInstance().getCumulativeCurveEnabled()) ? getPowerLevel() : getSkillLevel(rootSkill);
+        FormulaType formulaType = ExperienceConfig.getInstance().getFormulaType();
+
+        return mcMMO.getFormulaManager().getXPtoNextLevel(level, formulaType);
+    }
+
+    @Override
+    public int getChildSkillLevel(@NotNull RootSkill rootSkill) {
+        Set<RootSkill> parents = FamilyTree.getParentSkills(rootSkill);
+        int sum = 0;
+
+        for (RootSkill parentIdentity : parents) {
+            sum += getSkillLevel(parentIdentity);
+        }
+
+        return sum / parents.size();
+    }
+
+    @Override
+    public void removeXp(@NotNull RootSkill skill, int xp) {
+        if (skill.isChildSkill()) {
+            return;
+        }
+
+        setSkillXpValue(skill, getSkillXpValue(skill) - xp);
+    }
+
+    @Override
+    public void removeXp(RootSkill skill, float xp) {
+        if (skill.isChildSkill()) {
+            return;
+        }
+
+        setSkillXpValue(skill, getSkillXpValue(skill) - xp);
+    }
+
+    @Override
+    public void setSkillLevel(@NotNull RootSkill rootSkill, int level) {
+        if (rootSkill.isChildSkill()) {
+            return;
+        }
+
+        //Don't allow levels to be negative
+        if(level < 0)
+            level = 0;
+
+        setSkillLevel(rootSkill, level);
+        setSkillXpValue(rootSkill, 0F);
+    }
+
+    @Override
+    public void addLevels(@NotNull RootSkill rootSkill, int levels) {
+        setSkillLevel(rootSkill, getSkillLevel(rootSkill) + levels);
+    }
+
+    @Override
+    public void addXp(@NotNull RootSkill rootSkill, float xp) {
+        if (rootSkill.isChildSkill()) {
+            Set<RootSkill> parentSkills = FamilyTree.getParents(rootSkill);
+            float dividedXP = (xp / parentSkills.size());
+
+            for (RootSkill parentSkill : parentSkills) {
+                setSkillXpValue(parentSkill, getSkillXpValue(parentSkill) + dividedXP);
+            }
+        }
+        else {
+            setSkillXpValue(rootSkill, getSkillXpValue(rootSkill) + xp);
+        }
+    }
+
+    @Override
+    public float getRegisteredXpGain(@NotNull RootSkill rootSkill) {
+        float xp = 0F;
+
+        if (get(rootSkill) != null) { //??
+            xp = rollingSkillsXp.get(rootSkill);
+        }
+
+        return xp;
+    }
+
+    @Override
+    public void registerXpGain(@NotNull RootSkill rootSkill, float xp) {
+        gainedSkillsXp.add(new SkillXpGain(rootSkill, xp));
+        rollingSkillsXp.put(rootSkill, getRegisteredXpGain(rootSkill) + xp);
+    }
+
+    @Override
+    public void purgeExpiredXpGains() {
+        SkillXpGain gain;
+        while ((gain = gainedSkillsXp.poll()) != null) {
+            rollingSkillsXp.put(gain.getSkill(), getRegisteredXpGain(gain.getSkill()) - gain.getXp());
+        }
+    }
+
+    @Override
+    private float modifyXpGain(@NotNull RootSkill rootSkill, float xp) {
+        if ((rootSkill.getMaxLevel() <= getSkillLevel(rootSkill)) || (Config.getInstance().getPowerLevelCap() <= getPowerLevel())) {
+            return 0;
+        }
+
+        xp = (float) (xp / rootSkill.getXpModifier() * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier());
+
+        return PerksUtils.handleXpPerks(Misc.adaptPlayer(mmoPlayer), xp, rootSkill);
+    }
+
+    @Override
+    public double getProgressInCurrentSkillLevel(@NotNull RootSkill rootSkill) throws UnknownSkillException
+    {
+        if(CoreSkills.isChildSkill(rootSkill)) {
+            return 1.0D;
+        }
+
+        double currentXP = getSkillXpValue(rootSkill);
+        double maxXP = getExperienceToNextLevel(rootSkill);
+
+        return (currentXP / maxXP);
+    }
+
+    @Override
+    public void setUsingUnarmed(boolean bool) {
+        isUsingUnarmed = bool;
+    }
+
+    @Override
+    public void applyXpGain(@NotNull RootSkill rootSkill, float xp, @NotNull XPGainReason xpGainReason, @NotNull XPGainSource xpGainSource) {
+        //Only check for permissions if the player is online, otherwise just assume a command is being executed by an admin or some other means and add the XP
+        if (!Permissions.skillEnabled(mmoPlayer.getPlayer(), CoreSkills.getSkill(rootSkill))) {
+            return;
+        }
+
+        if (CoreSkills.isChildSkill(rootSkill)) {
+            Set<RootSkill> parentSkills = FamilyTree.getParentSkills(rootSkill);
+
+            for (RootSkill parentSkill : parentSkills) {
+                applyXpGain(parentSkill, xp / parentSkills.size(), xpGainReason, xpGainSource);
+            }
+
+            return;
+        }
+
+        if (!EventUtils.handleXpGainEvent(Misc.adaptPlayer(mmoPlayer), rootSkill, xp, xpGainReason)) {
+            return;
+        }
+
+        setUsingUnarmed(rootSkill == CoreSkills.UNARMED_CS);
+        updateLevelStats(rootSkill, xpGainReason, xpGainSource);
+    }
+
+    @Override
+    public void processPostXpEvent(@NotNull RootSkill rootSkill, @NotNull XPGainSource xpGainSource)
+    {
+        /*
+         * Everything in this method requires an online player, so if they aren't online we don't waste our time
+         */
+        if(mmoPlayer == null)
+            return;
+
+        //Check if they've reached the power level cap just now
+        if(hasReachedPowerLevelCap()) {
+            NotificationManager.sendPlayerInformationChatOnly(Misc.adaptPlayer(mmoPlayer), "LevelCap.PowerLevel", String.valueOf(Config.getInstance().getPowerLevelCap()));
+        } else if(hasReachedLevelCap(rootSkill)) {
+            NotificationManager.sendPlayerInformationChatOnly(Misc.adaptPlayer(mmoPlayer), "LevelCap.Skill", String.valueOf(Config.getInstance().getLevelCap(rootSkill)), rootSkill.getName());
+        }
+
+        //Updates from Party sources
+        if(xpGainSource == XPGainSource.PARTY_MEMBERS && !ExperienceConfig.getInstance().isPartyExperienceBarsEnabled())
+            return;
+
+        //Updates from passive sources (Alchemy, Smelting, etc...)
+        if(xpGainSource == XPGainSource.PASSIVE && !ExperienceConfig.getInstance().isPassiveGainsExperienceBarsEnabled())
+            return;
+
+        mmoPlayer.updateXPBar(rootSkill);
+    }
+
+    @Override
+    public void updateLevelStats(@NotNull RootSkill rootSkill, @NotNull XPGainReason xpGainReason, @NotNull XPGainSource xpGainSource) {
+        if(hasReachedLevelCap(rootSkill))
+            return;
+
+        if (getSkillXpLevelRaw(rootSkill) < getExperienceToNextLevel(rootSkill)) {
+            processPostXpEvent(rootSkill, xpGainSource);
+            return;
+        }
+
+        int levelsGained = 0;
+        float xpRemoved = 0;
+
+        while (getSkillXpLevelRaw(rootSkill) >= getExperienceToNextLevel(rootSkill)) {
+            if (hasReachedLevelCap(rootSkill)) {
+                setSkillXpValue(rootSkill, 0);
+                break;
+            }
+
+            xpRemoved += levelUp(rootSkill);
+            levelsGained++;
+        }
+
+        if (EventUtils.tryLevelChangeEvent(Misc.adaptPlayer(mmoPlayer), rootSkill, levelsGained, xpRemoved, true, xpGainReason)) {
+            return;
+        }
+
+        if (Config.getInstance().getLevelUpSoundsEnabled()) {
+            SoundManager.sendSound(Misc.adaptPlayer(mmoPlayer), Misc.adaptPlayer(mmoPlayer).getLocation(), SoundType.LEVEL_UP);
+        }
+
+        /*
+         * Check to see if the player unlocked any new skills
+         */
+
+        NotificationManager.sendPlayerLevelUpNotification(mmoPlayer, rootSkill, levelsGained, getSkillLevel(rootSkill));
+
+        //UPDATE XP BARS
+        processPostXpEvent(rootSkill, xpGainSource);
+    }
+}

+ 0 - 21
src/main/java/com/gmail/nossr50/datatypes/experience/XPGainReason.java

@@ -1,21 +0,0 @@
-package com.gmail.nossr50.datatypes.experience;
-
-public enum XPGainReason {
-    PVP,
-    PVE,
-    VAMPIRISM,
-    SHARED_PVP,
-    SHARED_PVE,
-    COMMAND,
-    UNKNOWN;
-
-    public static XPGainReason getXPGainReason(String reason) {
-        for (XPGainReason type : values()) {
-            if (type.name().equalsIgnoreCase(reason)) {
-                return type;
-            }
-        }
-
-        return null;
-    }
-}

+ 0 - 10
src/main/java/com/gmail/nossr50/datatypes/experience/XPGainSource.java

@@ -1,10 +0,0 @@
-package com.gmail.nossr50.datatypes.experience;
-
-public enum XPGainSource {
-    SELF,
-    VAMPIRISM, //From Vampirism kills
-    PASSIVE, //Smelting, Brewing, etc...
-    PARTY_MEMBERS, //From other members of a party
-    COMMAND,
-    CUSTOM, //Outside Sources
-}

+ 1 - 1
src/main/java/com/gmail/nossr50/datatypes/party/PartyMemberManager.java

@@ -168,7 +168,7 @@ public class PartyMemberManager {
         Party party = mmoPlayer.getParty();
 
         if (party != null) {
-            Player player = mmoPlayer.getPlayer();
+            Player player = Misc.adaptPlayer(mmoPlayer);
             double range = Config.getInstance().getPartyShareRange();
 
             for (PartyMember partyMember : party.getPartyMembers()) {

+ 19 - 28
src/main/java/com/gmail/nossr50/datatypes/player/AbstractMMOPlayer.java

@@ -1,7 +1,10 @@
 package com.gmail.nossr50.datatypes.player;
 
-import com.gmail.nossr50.datatypes.experience.ExperienceManager;
+import com.gmail.nossr50.datatypes.experience.OfflineExperienceProcessor;
+import com.gmail.nossr50.datatypes.experience.OnlineExperienceProcessor;
+import com.neetgames.mcmmo.experience.ExperienceHandler;
 import com.neetgames.mcmmo.player.MMOPlayer;
+import com.neetgames.mcmmo.player.MMOPlayerData;
 import org.bukkit.entity.Player;
 import org.jetbrains.annotations.NotNull;
 
@@ -9,44 +12,32 @@ import java.util.UUID;
 
 public abstract class AbstractMMOPlayer implements MMOPlayer {
     /* All of the persistent data for a player that gets saved and loaded from DB */
-    protected final @NotNull PersistentPlayerData persistentPlayerData; //All persistent data is kept here
+    protected final @NotNull MMOPlayerData mmoPlayerData; //All persistent data is kept here
 
     /* Managers */
-    protected final @NotNull ExperienceManager experienceManager;
+    protected final @NotNull ExperienceHandler experienceHandler;
     protected final @NotNull CooldownManager cooldownManager;
 
     /**
-     * Create a new AbstractMMOPlayer for a {@link Player} with default values
-     *
-     * @param player target player
-     */
-    public AbstractMMOPlayer(@NotNull Player player) {
-        /* New Data */
-        this(player.getUniqueId(), player.getName());
-    }
-
-    /**
-     * Create a new AbstractMMOPlayer for a {@link Player} with default values
+     * Init for online players
+     * This will be used for existing data
      *
-     * @param playerUUID target player's UUID
-     * @param playerName target player's name
+     * @param mmoPlayerData player data
      */
-    public AbstractMMOPlayer(@NotNull UUID playerUUID, @NotNull String playerName) {
-        /* New Data */
-        this.persistentPlayerData = new PersistentPlayerData(playerUUID, playerName);
-        this.experienceManager = new ExperienceManager(persistentPlayerData);
-        this.cooldownManager = new CooldownManager(persistentPlayerData);
+    public AbstractMMOPlayer(@NotNull Player player, @NotNull MMOPlayerData mmoPlayerData) {
+        this.mmoPlayerData = mmoPlayerData;
+        this.experienceHandler = new OnlineExperienceProcessor(mmoPlayerData);
+        this.cooldownManager = new CooldownManager(mmoPlayerData);
     }
 
     /**
-     * Initialize an AbstractMMOPlayer for {@link PersistentPlayerData}
-     * This will be used for existing data
+     * Init for offline players
      *
-     * @param persistentPlayerData target persistent player data
+     * @param mmoPlayerData player data
      */
-    public AbstractMMOPlayer(@NotNull PersistentPlayerData persistentPlayerData) {
-        this.persistentPlayerData = persistentPlayerData;
-        this.experienceManager = new ExperienceManager(persistentPlayerData);
-        this.cooldownManager = new CooldownManager(persistentPlayerData);
+    public AbstractMMOPlayer(@NotNull MMOPlayerData mmoPlayerData) {
+        this.mmoPlayerData = mmoPlayerData;
+        this.experienceHandler = new OfflineExperienceProcessor(mmoPlayerData);
+        this.cooldownManager = new CooldownManager(mmoPlayerData);
     }
 }

+ 39 - 30
src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java

@@ -34,7 +34,9 @@ import com.gmail.nossr50.util.experience.MMOExperienceBarManager;
 import com.gmail.nossr50.util.input.AbilityActivationProcessor;
 import com.gmail.nossr50.util.input.SuperAbilityManager;
 import com.neetgames.mcmmo.exceptions.UnknownSkillException;
+import com.neetgames.mcmmo.player.MMOPlayerData;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
+import com.neetgames.mcmmo.skill.RootSkill;
 import com.neetgames.mcmmo.skill.SkillIdentity;
 import net.kyori.adventure.identity.Identified;
 import net.kyori.adventure.identity.Identity;
@@ -49,6 +51,7 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.UUID;
 
+//TODO: Update javadocs
 public class McMMOPlayer extends PlayerProfile implements OnlineMMOPlayer, Identified {
     private final @NotNull Player player;
     private final @NotNull Identity identity;
@@ -91,15 +94,16 @@ public class McMMOPlayer extends PlayerProfile implements OnlineMMOPlayer, Ident
          * New
          * Player
          */
-        super(player);
+        super(new PersistentPlayerData(player.getUniqueId(), player.getName()));
+
         UUID uuid = player.getUniqueId();
         identity = Identity.identity(uuid);
 
         this.player = player;
         playerMetadata = new FixedMetadataValue(mcMMO.p, player.getName());
-        experienceBarManager = new MMOExperienceBarManager(this, getPersistentPlayerData().getDirtyBarStateMap());
+        experienceBarManager = new MMOExperienceBarManager(this, mmoPlayerData.getBarStateMap());
 
-        superAbilityManager = new SuperAbilityManager(this);
+        superAbilityManager = new SuperAbilityManager(this, mmoPlayerData);
         abilityActivationProcessor = new AbilityActivationProcessor(this);
 
         debugMode = false; //Debug mode helps solve support issues, players can toggle it on or off
@@ -114,7 +118,6 @@ public class McMMOPlayer extends PlayerProfile implements OnlineMMOPlayer, Ident
 
         assignParty();
 
-
         //Update last login
         updateLastLogin();
     }
@@ -122,18 +125,17 @@ public class McMMOPlayer extends PlayerProfile implements OnlineMMOPlayer, Ident
     /**
      * Create a new instance based on existing player data
      * @param player target player
-     * @param persistentPlayerData existing player data
+     * @param mmoPlayerData existing player data
      */
-    public McMMOPlayer(@NotNull Player player, @NotNull PersistentPlayerData persistentPlayerData) {
+    public McMMOPlayer(@NotNull Player player, @NotNull MMOPlayerData mmoPlayerData) {
         /*
          * Existing
          * Player
          */
-        super(persistentPlayerData);
-        UUID uuid = player.getUniqueId();
-        identity = Identity.identity(uuid);
-        playerMetadata = new FixedMetadataValue(mcMMO.p, player.getName());
+        super(mmoPlayerData);
         this.player = player;
+        identity = Identity.identity(player.getUniqueId());
+        playerMetadata = new FixedMetadataValue(mcMMO.p, player.getName());
 
         /*
          * I'm using this method because it makes code shorter and safer (we don't have to add all SkillTypes manually),
@@ -150,9 +152,9 @@ public class McMMOPlayer extends PlayerProfile implements OnlineMMOPlayer, Ident
             mcMMO.p.getPluginLoader().disablePlugin(mcMMO.p);
         }
 
-        superAbilityManager = new SuperAbilityManager(this);
+        superAbilityManager = new SuperAbilityManager(this, mmoPlayerData);
         abilityActivationProcessor = new AbilityActivationProcessor(this);
-        experienceBarManager = new MMOExperienceBarManager(this, persistentPlayerData.getBarStateMap());
+        experienceBarManager = new MMOExperienceBarManager(this, this.mmoPlayerData.getBarStateMap());
 
         debugMode = false; //Debug mode helps solve support issues, players can toggle it on or off
 
@@ -172,7 +174,10 @@ public class McMMOPlayer extends PlayerProfile implements OnlineMMOPlayer, Ident
 
     private void assignParty() {
         if(mcMMO.getPartyManager() != null) {
+            Party queryParty = mcMMO.getPartyManager().queryParty(player.getUniqueId());
 
+            if(queryParty != null)
+                this.playerPartyRef = queryParty;
         }
     }
 
@@ -180,7 +185,7 @@ public class McMMOPlayer extends PlayerProfile implements OnlineMMOPlayer, Ident
      * Update the last login to the current system time
      */
     private void updateLastLogin() {
-        getPersistentPlayerData().setLastLogin(System.currentTimeMillis());
+        mmoPlayerData.setLastLogin(System.currentTimeMillis());
     }
 
     public @NotNull String getPlayerName() {
@@ -555,15 +560,16 @@ public class McMMOPlayer extends PlayerProfile implements OnlineMMOPlayer, Ident
      * Whether or not this player is currently spying on all party chat
      * @return true if this player is currently spying
      */
-    public boolean isPartyChatSpying() {
-        return getPersistentPlayerData().isPartyChatSpying();
+    @Override
+    public boolean isChatSpying() {
+        return mmoPlayerData.isPartyChatSpying();
     }
 
     /**
      * Toggle this player's party chat spying flag
      */
     public void togglePartyChatSpying() {
-        getPersistentPlayerData().togglePartyChatSpying();
+        mmoPlayerData.togglePartyChatSpying();
     }
 
     /**
@@ -606,36 +612,39 @@ public class McMMOPlayer extends PlayerProfile implements OnlineMMOPlayer, Ident
 
     @Override
     public boolean inParty() {
-        return false;
+        return playerPartyRef == null;
     }
 
     @Override
     public boolean isGodMode() {
-        return false;
+        return godMode;
     }
 
-    @Override
-    public boolean isChatSpying() {
-        return false;
+    @Nullable
+    public Location getTeleportCommenceLocation() {
+        return teleportCommence;
     }
 
-    @Override
-    public double getProgressInCurrentSkillLevel(@NotNull SkillIdentity skillIdentity) throws UnknownSkillException {
-        return experienceManager.getProgressInCurrentSkillLevel(skillIdentity);
+    public void setTeleportCommenceLocation(@Nullable Location location) {
+        teleportCommence = location;
+    }
+
+    public void actualizeTeleportCommenceLocation() {
+        teleportCommence = getPlayer().getLocation();
     }
 
     @Override
-    public int getSkillLevel(@NotNull SkillIdentity skillIdentity) throws UnknownSkillException {
-        return experienceManager.getSkillLevel(skillIdentity);
+    public void sendMessage(@NotNull String s) {
+        player.sendMessage(s);
     }
 
     @Override
-    public int getSkillExperience(@NotNull SkillIdentity skillIdentity) throws UnknownSkillException {
-        return experienceManager.getSkillXpValue(skillIdentity);
+    public @NotNull Object getServerAPIPlayerImpl() {
+        return player;
     }
 
     @Override
-    public int getExperienceToNextLevel(@NotNull SkillIdentity skillIdentity) throws UnknownSkillException {
-        return experienceManager.getExperienceToNextLevel(skillIdentity);
+    public void updateXPBar(@NotNull RootSkill rootSkill) {
+        experienceBarManager.updateExperienceBar(rootSkill, mcMMO.p);
     }
 }

+ 2 - 3
src/main/java/com/gmail/nossr50/datatypes/player/PersistentPlayerData.java

@@ -1,8 +1,7 @@
 package com.gmail.nossr50.datatypes.player;
 
 import com.gmail.nossr50.config.AdvancedConfig;
-import com.gmail.nossr50.datatypes.skills.CoreSkillConstants;
-import com.gmail.nossr50.datatypes.skills.SuperAbilityType;
+import com.gmail.nossr50.datatypes.skills.CoreSkills;
 import com.gmail.nossr50.datatypes.validation.NonNullRule;
 import com.gmail.nossr50.datatypes.validation.PositiveIntegerRule;
 import com.gmail.nossr50.datatypes.validation.Validator;
@@ -80,7 +79,7 @@ public class PersistentPlayerData implements MMOPlayerData {
 
         //Core skills
         //TODO: Don't store values for disabled skills
-        for(RootSkill rootSkill : CoreSkillConstants.getImmutableCoreRootSkillSet()) {
+        for(RootSkill rootSkill : CoreSkills.getImmutableCoreRootSkillSet()) {
             skillLevelValues.put(rootSkill, AdvancedConfig.getInstance().getStartingLevel());
             skillExperienceValues.put(rootSkill, 0F);
         }

+ 27 - 138
src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java

@@ -1,174 +1,58 @@
 package com.gmail.nossr50.datatypes.player;
 
-import com.gmail.nossr50.datatypes.experience.ExperienceManager;
-import com.gmail.nossr50.datatypes.party.Party;
-import com.gmail.nossr50.mcMMO;
-import com.neetgames.mcmmo.MobHealthBarType;
+import com.neetgames.mcmmo.exceptions.UnknownSkillException;
+import com.neetgames.mcmmo.experience.ExperienceHandler;
 import com.neetgames.mcmmo.player.MMOPlayerData;
-import com.neetgames.mcmmo.player.OfflineMMOPlayer;
-import com.neetgames.mcmmo.skill.Skill;
-import org.bukkit.entity.Player;
+import com.neetgames.mcmmo.skill.RootSkill;
 import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
 
 import java.util.UUID;
 
 public class PlayerProfile extends AbstractMMOPlayer {
 
-    /**
-     * Create a new {@link PlayerProfile} for a {@link Player} with default values
-     *
-     * @param player target player
-     */
-    public PlayerProfile(@NotNull Player player) {
-        super(player);
-    }
-
-    /**
-     * Create a new {@link PlayerProfile} for a {@link Player} with default values
-     *
-     * @param playerUUID target player's UUID
-     * @param playerName target player's name
-     */
-    public PlayerProfile(@NotNull UUID playerUUID, @NotNull String playerName) {
-        super(playerUUID, playerName);
-    }
-
     /**
      * Initialize an {@link PlayerProfile} for {@link PersistentPlayerData}
      * This will be used for existing data
      *
-     * @param persistentPlayerData target persistent player data
+     * @param mmoPlayerData target persistent player data
      */
-    public PlayerProfile(@NotNull PersistentPlayerData persistentPlayerData) {
-        super(persistentPlayerData);
+    public PlayerProfile(@NotNull MMOPlayerData mmoPlayerData) {
+        super(mmoPlayerData);
     }
 
-    /**
-     * Get the saved player name for this profile
-     * @return the saved player name for this profile
-     */
     @Override
-    public @NotNull String getPlayerName() {
-        return getPersistentPlayerData().getPlayerName();
-    }
-
-    /**
-     * Get the current {@link MobHealthBarType} for this profile
-     * @return the mob health bar setting for this profile
-     */
-    public @NotNull MobHealthBarType getMobHealthBarType() {
-        return getPersistentPlayerData().getMobHealthBarType();
-    }
-
-    /**
-     * Set the {@link MobHealthBarType} for this profile
-     * @param mobHealthbarType desired mob health bar type
-     */
-    public void setMobHealthBarType(@NotNull MobHealthBarType mobHealthbarType) {
-        getPersistentPlayerData().setMobHealthBarType(mobHealthbarType);
-    }
-
-    /**
-     * The number of times scoreboard tips have been shown to this profile
-     * @return the scoreboard tips view count
-     */
-    public int getScoreboardTipsShown() {
-        return getPersistentPlayerData().getScoreboardTipsShown();
-    }
-
-    /**
-     * Replace the scoreboard view count
-     * @param scoreboardTipsShown new value
-     */
-    public void setScoreboardTipsShown(int scoreboardTipsShown) {
-        getPersistentPlayerData().setScoreboardTipsShown(scoreboardTipsShown);
-
-    }
-
-    /**
-     * Increments the scoreboard tip view count by 1
-     */
-    public void increaseTipsShown() {
-        setScoreboardTipsShown(getScoreboardTipsShown() + 1);
-    }
-
-    /**
-     * Retrieves a reference to the {@link PersistentPlayerData} for this profile
-     * @return the persistent data for this profile
-     */
-    public @NotNull PersistentPlayerData getPersistentPlayerData() {
-        return persistentPlayerData;
-    }
-
-    /**
-     * Invert the current value of the party chat spy toggle
-     */
-    public void togglePartyChatSpying() {
-        persistentPlayerData.togglePartyChatSpying();
-    }
-
-    /**
-     * Retrieve the {@link ExperienceManager} for this profile
-     * @return the experience manager for this profile
-     */
-    public @NotNull ExperienceManager getExperienceManager() {
-        return experienceManager;
-    }
-
-    /**
-     * Retrieve the {@link CooldownManager} for this profile
-     * @return the cooldown manager for this profile
-     */
-    public @NotNull CooldownManager getCooldownManager() {
-        return cooldownManager;
-    }
-
-    /**
-     * Attempt to get a party for this PlayerProfile
-     * @return get a party for this PlayerProfile
-     */
-    public @Nullable Party getParty(){
-        //TODO: This can be optimized
-        return mcMMO.getPartyManager().queryParty(persistentPlayerData.getPlayerUUID());
+    public @NotNull UUID getUUID() {
+        return mmoPlayerData.getPlayerUUID();
     }
 
-    /**
-     * Whether or not this player is excluded from leaderboards
-     * @return true if the player is excluded from leaderboards
-     */
-    public boolean isLeaderBoardExcluded() {
-        return persistentPlayerData.isLeaderBoardExcluded();
+    @Override
+    public @NotNull String getPlayerName() {
+        return mmoPlayerData.getPlayerName();
     }
 
-
-    /**
-     * Get the saved {@link UUID} for this profile
-     * @return the saved {@link UUID} for this profile
-     */
     @Override
-    public @NotNull UUID getUUID() {
-        return getPersistentPlayerData().getPlayerUUID();
+    public int getPowerLevel() {
+        return experienceHandler.getPowerLevel();
     }
 
     @Override
-    public int getPowerLevel() {
-        return experienceManager.getPowerLevel();
+    public int getSkillLevel(@NotNull RootSkill rootSkill) throws UnknownSkillException {
+        return experienceHandler.getSkillLevel(rootSkill);
     }
 
     @Override
-    public int getSkillLevel(@NotNull Skill skill) {
-        return 0;
+    public int getSkillExperience(@NotNull RootSkill rootSkill) throws UnknownSkillException {
+        return experienceHandler.getSkillXpValue(rootSkill);
     }
 
     @Override
-    public int getSkillExperience(@NotNull Skill skill) {
-        return persistentPlayerData;
+    public int getExperienceToNextLevel(@NotNull RootSkill rootSkill) throws UnknownSkillException {
+        return experienceHandler.getExperienceToNextLevel(rootSkill);
     }
 
     @Override
-    public int getExperienceToNextLevel() {
-        return 0;
+    public double getProgressInCurrentSkillLevel(@NotNull RootSkill rootSkill) throws UnknownSkillException {
+        return experienceHandler.getProgressInCurrentSkillLevel(rootSkill);
     }
 
     @Override
@@ -176,8 +60,13 @@ public class PlayerProfile extends AbstractMMOPlayer {
         return false;
     }
 
+    @Override
+    public @NotNull ExperienceHandler getExperienceHandler() {
+        return experienceHandler;
+    }
+
     @Override
     public @NotNull MMOPlayerData getMMOPlayerData() {
-        return persistentPlayerData;
+        return mmoPlayerData;
     }
 }

+ 0 - 151
src/main/java/com/gmail/nossr50/datatypes/skills/CoreSkillConstants.java

@@ -1,151 +0,0 @@
-package com.gmail.nossr50.datatypes.skills;
-
-import com.google.common.collect.ImmutableSet;
-import com.neetgames.mcmmo.skill.RootSkill;
-import com.neetgames.mcmmo.skill.Skill;
-import com.neetgames.mcmmo.skill.SkillIdentity;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.HashSet;
-import java.util.Set;
-
-public class CoreSkillConstants {
-
-    private static final @NotNull ImmutableSet<RootSkill> CORE_ROOT_SKILLS_IMMUTABLE_SET;
-    private static final @NotNull ImmutableSet<RootSkill> CORE_CHILD_SKILLS;
-
-    public static final @NotNull CoreRootSkill ACROBATICS, ALCHEMY, ARCHERY, AXES, EXCAVATION,
-            FISHING, HERBALISM, MINING, REPAIR, SALVAGE, SMELTING, SWORDS, TAMING, UNARMED,
-            WOODCUTTING, TRIDENTS, CROSSBOWS;
-
-    public static final @NotNull SkillIdentity ACROBATICS_ID, ALCHEMY_ID, ARCHERY_ID, AXES_ID, EXCAVATION_ID,
-            FISHING_ID, HERBALISM_ID, MINING_ID, REPAIR_ID, SALVAGE_ID, SMELTING_ID, SWORDS_ID, TAMING_ID, UNARMED_ID,
-            WOODCUTTING_ID, TRIDENTS_ID, CROSSBOWS_ID;
-
-    static {
-        HashSet<CoreRootSkill> rootSkillSet = new HashSet<>();
-        HashSet<CoreRootSkill> childSkillSet = new HashSet<>();
-
-        ACROBATICS = new CoreRootSkill("acrobatics");
-        ACROBATICS_ID = ACROBATICS.getSkillIdentity();
-
-        ALCHEMY = new CoreRootSkill("alchemy");
-        ALCHEMY_ID = ALCHEMY.getSkillIdentity();
-
-        ARCHERY = new CoreRootSkill("archery");
-        ARCHERY_ID = ARCHERY.getSkillIdentity();
-
-        AXES = new CoreRootSkill("axes");
-        AXES_ID = AXES.getSkillIdentity();
-
-        EXCAVATION = new CoreRootSkill("excavation");
-        EXCAVATION_ID = EXCAVATION.getSkillIdentity();
-
-        FISHING = new CoreRootSkill("fishing");
-        FISHING_ID = FISHING.getSkillIdentity();
-
-        HERBALISM = new CoreRootSkill("herbalism");
-        HERBALISM_ID = HERBALISM.getSkillIdentity();
-
-        MINING = new CoreRootSkill("mining");
-        MINING_ID = MINING.getSkillIdentity();
-
-        REPAIR = new CoreRootSkill("repair");
-        REPAIR_ID = REPAIR.getSkillIdentity();
-
-        SALVAGE = new CoreRootSkill("salvage");
-        SALVAGE_ID = SALVAGE.getSkillIdentity();
-
-        SMELTING = new CoreRootSkill("smelting");
-        SMELTING_ID = SMELTING.getSkillIdentity();
-
-        SWORDS = new CoreRootSkill("swords");
-        SWORDS_ID = SWORDS.getSkillIdentity();
-
-        TAMING = new CoreRootSkill("taming");
-        TAMING_ID = TAMING.getSkillIdentity();
-
-        UNARMED = new CoreRootSkill("unarmed");
-        UNARMED_ID = UNARMED.getSkillIdentity();
-
-        WOODCUTTING = new CoreRootSkill("woodcutting");
-        WOODCUTTING_ID = WOODCUTTING.getSkillIdentity();
-
-        TRIDENTS = new CoreRootSkill("tridents");
-        TRIDENTS_ID = TRIDENTS.getSkillIdentity();
-
-        CROSSBOWS = new CoreRootSkill("crossbows");
-        CROSSBOWS_ID = CROSSBOWS.getSkillIdentity();
-        
-        //Child skills (soon to be removed)
-        childSkillSet.add(SMELTING);
-        childSkillSet.add(SALVAGE);
-
-        rootSkillSet.add(ACROBATICS);
-        rootSkillSet.add(ALCHEMY);
-        rootSkillSet.add(ARCHERY);
-        rootSkillSet.add(AXES);
-        rootSkillSet.add(EXCAVATION);
-        rootSkillSet.add(FISHING);
-        rootSkillSet.add(HERBALISM);
-        rootSkillSet.add(MINING);
-        rootSkillSet.add(REPAIR);
-        rootSkillSet.add(SALVAGE);
-        rootSkillSet.add(SMELTING);
-        rootSkillSet.add(SWORDS);
-        rootSkillSet.add(TAMING);
-        rootSkillSet.add(UNARMED);
-        rootSkillSet.add(WOODCUTTING);
-        rootSkillSet.add(TRIDENTS);
-        rootSkillSet.add(CROSSBOWS);
-
-        CORE_ROOT_SKILLS_IMMUTABLE_SET = ImmutableSet.copyOf(rootSkillSet);
-        CORE_CHILD_SKILLS = ImmutableSet.copyOf(childSkillSet);
-    }
-
-    /**
-     * Returns a set of built in skills for mcMMO
-     * No guarantees for whether or not the skills are registered or active or inactive
-     *
-     * @return a set of all root skills built into mcMMO
-     */
-    public static @NotNull Set<RootSkill> getImmutableCoreRootSkillSet() {
-        return CORE_ROOT_SKILLS_IMMUTABLE_SET;
-    }
-
-    /**
-     * Returns a set of built in skills for mcMMO which are child skills
-     * No guarantees for whether or not the skills are registered or active or inactive
-     *
-     * @return a set of all "child" root skills for mcMMO
-     * @deprecated child skills will be removed in an upcoming update
-     */
-    @Deprecated
-    public static @NotNull Set<RootSkill> getChildSkills() {
-        return CORE_CHILD_SKILLS;
-    }
-
-    /**
-     * Whether or not a skill is considered a child skill
-     * @param skillIdentity target skill identity
-     * @return true if the skill identity belongs to a core "child" root skill
-     */
-    public static boolean isChildSkill(@NotNull SkillIdentity skillIdentity) {
-        for(RootSkill rootSkill : CORE_CHILD_SKILLS) {
-            if(rootSkill.getSkillIdentity().equals(skillIdentity)) {
-                return true;
-            }
-        }
-        
-        return false;
-    }
-
-    /**
-     * Whether or not a skill is considered a child skill
-     * @param skill target skill
-     * @return true if the skill identity belongs to a core "child" root skill
-     */
-    public static boolean isChildSkill(@NotNull Skill skill) {
-        return isChildSkill(skill.getSkillIdentity());
-    }
-}

+ 224 - 0
src/main/java/com/gmail/nossr50/datatypes/skills/CoreSkills.java

@@ -0,0 +1,224 @@
+package com.gmail.nossr50.datatypes.skills;
+
+import com.google.common.collect.ImmutableSet;
+import com.neetgames.mcmmo.exceptions.InvalidSkillException;
+import com.neetgames.mcmmo.skill.RootSkill;
+import com.neetgames.mcmmo.skill.Skill;
+import com.neetgames.mcmmo.skill.SkillIdentity;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class CoreSkills {
+
+    private static final @NotNull ImmutableSet<RootSkill> CORE_ROOT_SKILLS_IMMUTABLE_SET;
+    private static final @NotNull ImmutableSet<RootSkill> CORE_CHILD_SKILLS;
+
+    public static final @NotNull CoreRootSkill ACROBATICS_CS, ALCHEMY_CS, ARCHERY_CS, AXES_CS, EXCAVATION_CS,
+            FISHING_CS, HERBALISM_CS, MINING_CS, REPAIR_CS, SALVAGE_CS, SMELTING_CS, SWORDS_CS, TAMING_CS, UNARMED_CS,
+            WOODCUTTING_CS, TRIDENTS_CS, CROSSBOWS_CS;
+
+    public static final @NotNull SkillIdentity ACROBATICS_ID, ALCHEMY_ID, ARCHERY_ID, AXES_ID, EXCAVATION_ID,
+            FISHING_ID, HERBALISM_ID, MINING_ID, REPAIR_ID, SALVAGE_ID, SMELTING_ID, SWORDS_ID, TAMING_ID, UNARMED_ID,
+            WOODCUTTING_ID, TRIDENTS_ID, CROSSBOWS_ID;
+
+    private static @NotNull
+    final HackySkillMappings hackySkillMappings = new HackySkillMappings();
+
+    static {
+        HashSet<CoreRootSkill> rootSkillSet = new HashSet<>();
+        HashSet<CoreRootSkill> childSkillSet = new HashSet<>();
+
+        ACROBATICS_CS = new CoreRootSkill("acrobatics");
+        ACROBATICS_ID = ACROBATICS_CS.getSkillIdentity();
+
+        ALCHEMY_CS = new CoreRootSkill("alchemy");
+        ALCHEMY_ID = ALCHEMY_CS.getSkillIdentity();
+
+        ARCHERY_CS = new CoreRootSkill("archery");
+        ARCHERY_ID = ARCHERY_CS.getSkillIdentity();
+
+        AXES_CS = new CoreRootSkill("axes");
+        AXES_ID = AXES_CS.getSkillIdentity();
+
+        EXCAVATION_CS = new CoreRootSkill("excavation");
+        EXCAVATION_ID = EXCAVATION_CS.getSkillIdentity();
+
+        FISHING_CS = new CoreRootSkill("fishing");
+        FISHING_ID = FISHING_CS.getSkillIdentity();
+
+        HERBALISM_CS = new CoreRootSkill("herbalism");
+        HERBALISM_ID = HERBALISM_CS.getSkillIdentity();
+
+        MINING_CS = new CoreRootSkill("mining");
+        MINING_ID = MINING_CS.getSkillIdentity();
+
+        REPAIR_CS = new CoreRootSkill("repair");
+        REPAIR_ID = REPAIR_CS.getSkillIdentity();
+
+        SALVAGE_CS = new CoreRootSkill("salvage");
+        SALVAGE_ID = SALVAGE_CS.getSkillIdentity();
+
+        SMELTING_CS = new CoreRootSkill("smelting");
+        SMELTING_ID = SMELTING_CS.getSkillIdentity();
+
+        SWORDS_CS = new CoreRootSkill("swords");
+        SWORDS_ID = SWORDS_CS.getSkillIdentity();
+
+        TAMING_CS = new CoreRootSkill("taming");
+        TAMING_ID = TAMING_CS.getSkillIdentity();
+
+        UNARMED_CS = new CoreRootSkill("unarmed");
+        UNARMED_ID = UNARMED_CS.getSkillIdentity();
+
+        WOODCUTTING_CS = new CoreRootSkill("woodcutting");
+        WOODCUTTING_ID = WOODCUTTING_CS.getSkillIdentity();
+
+        TRIDENTS_CS = new CoreRootSkill("tridents");
+        TRIDENTS_ID = TRIDENTS_CS.getSkillIdentity();
+
+        CROSSBOWS_CS = new CoreRootSkill("crossbows");
+        CROSSBOWS_ID = CROSSBOWS_CS.getSkillIdentity();
+        
+        //Child skills (soon to be removed)
+        childSkillSet.add(SMELTING_CS);
+        childSkillSet.add(SALVAGE_CS);
+
+        rootSkillSet.add(ACROBATICS_CS);
+        rootSkillSet.add(ALCHEMY_CS);
+        rootSkillSet.add(ARCHERY_CS);
+        rootSkillSet.add(AXES_CS);
+        rootSkillSet.add(EXCAVATION_CS);
+        rootSkillSet.add(FISHING_CS);
+        rootSkillSet.add(HERBALISM_CS);
+        rootSkillSet.add(MINING_CS);
+        rootSkillSet.add(REPAIR_CS);
+        rootSkillSet.add(SALVAGE_CS);
+        rootSkillSet.add(SMELTING_CS);
+        rootSkillSet.add(SWORDS_CS);
+        rootSkillSet.add(TAMING_CS);
+        rootSkillSet.add(UNARMED_CS);
+        rootSkillSet.add(WOODCUTTING_CS);
+        rootSkillSet.add(TRIDENTS_CS);
+        rootSkillSet.add(CROSSBOWS_CS);
+
+        CORE_ROOT_SKILLS_IMMUTABLE_SET = ImmutableSet.copyOf(rootSkillSet);
+        CORE_CHILD_SKILLS = ImmutableSet.copyOf(childSkillSet);
+    }
+
+    /**
+     * Returns a set of built in skills for mcMMO
+     * No guarantees for whether or not the skills are registered or active or inactive
+     *
+     * @return a set of all root skills built into mcMMO
+     */
+    public static @NotNull Set<RootSkill> getImmutableCoreRootSkillSet() {
+        return CORE_ROOT_SKILLS_IMMUTABLE_SET;
+    }
+
+    /**
+     * Returns a set of built in skills for mcMMO which are child skills
+     * No guarantees for whether or not the skills are registered or active or inactive
+     *
+     * @return a set of all "child" root skills for mcMMO
+     * @deprecated child skills will be removed in an upcoming update
+     */
+    @Deprecated
+    public static @NotNull Set<RootSkill> getChildSkills() {
+        return CORE_CHILD_SKILLS;
+    }
+
+    /**
+     * Whether or not a skill is considered a child skill
+     * @param rootSkill target skill
+     * @return true if the skill identity belongs to a core "child" root skill
+     */
+    public static boolean isChildSkill(@NotNull RootSkill rootSkill) {
+        return CORE_CHILD_SKILLS.contains(rootSkill);
+    }
+
+    @Deprecated
+    public static @NotNull RootSkill getSkill(@NotNull PrimarySkillType primarySkillType) {
+        if(!hackySkillMappings.init) {
+            hackySkillMappings.initMappings();
+        }
+
+        return hackySkillMappings.primaryToRootMap.get(primarySkillType);
+    }
+
+    @Deprecated
+    public static @NotNull PrimarySkillType getSkill(@NotNull RootSkill rootSkill) {
+        if(!hackySkillMappings.init) {
+            hackySkillMappings.initMappings();
+        }
+
+        return hackySkillMappings.rootToPrimaryMap.get(rootSkill);
+    }
+
+    protected static class HackySkillMappings {
+        @NotNull Map<PrimarySkillType, RootSkill> primaryToRootMap = new HashMap<>();
+        @NotNull Map<RootSkill, PrimarySkillType> rootToPrimaryMap = new HashMap<>();
+        boolean init = false;
+
+        protected void initMappings() {
+            //TODO: add tests
+            //Can't init these from the get go as PrimarySkillType does some stuff and it would be race condition hell
+            primaryToRootMap.put(PrimarySkillType.ACROBATICS, ACROBATICS_CS);
+            rootToPrimaryMap.put(ACROBATICS_CS, PrimarySkillType.ACROBATICS);
+
+            primaryToRootMap.put(PrimarySkillType.ALCHEMY, ALCHEMY_CS);
+            rootToPrimaryMap.put(ALCHEMY_CS, PrimarySkillType.ALCHEMY);
+
+            primaryToRootMap.put(PrimarySkillType.ARCHERY, ARCHERY_CS);
+            rootToPrimaryMap.put(ARCHERY_CS, PrimarySkillType.ARCHERY);
+
+            primaryToRootMap.put(PrimarySkillType.AXES, AXES_CS);
+            rootToPrimaryMap.put(AXES_CS, PrimarySkillType.AXES);
+
+            primaryToRootMap.put(PrimarySkillType.EXCAVATION, EXCAVATION_CS);
+            rootToPrimaryMap.put(EXCAVATION_CS, PrimarySkillType.EXCAVATION);
+
+            primaryToRootMap.put(PrimarySkillType.FISHING, FISHING_CS);
+            rootToPrimaryMap.put(FISHING_CS, PrimarySkillType.FISHING);
+
+            primaryToRootMap.put(PrimarySkillType.HERBALISM, HERBALISM_CS);
+            rootToPrimaryMap.put(HERBALISM_CS, PrimarySkillType.HERBALISM);
+
+            primaryToRootMap.put(PrimarySkillType.MINING, MINING_CS);
+            rootToPrimaryMap.put(MINING_CS, PrimarySkillType.MINING);
+
+            primaryToRootMap.put(PrimarySkillType.REPAIR, REPAIR_CS);
+            rootToPrimaryMap.put(REPAIR_CS, PrimarySkillType.REPAIR);
+
+            primaryToRootMap.put(PrimarySkillType.SALVAGE, SALVAGE_CS);
+            rootToPrimaryMap.put(SALVAGE_CS, PrimarySkillType.SALVAGE);
+
+            primaryToRootMap.put(PrimarySkillType.SMELTING, SMELTING_CS);
+            rootToPrimaryMap.put(SMELTING_CS, PrimarySkillType.SMELTING);
+
+            primaryToRootMap.put(PrimarySkillType.SWORDS, SWORDS_CS);
+            rootToPrimaryMap.put(SWORDS_CS, PrimarySkillType.SWORDS);
+
+            primaryToRootMap.put(PrimarySkillType.TAMING, TAMING_CS);
+            rootToPrimaryMap.put(TAMING_CS, PrimarySkillType.TAMING);
+
+            primaryToRootMap.put(PrimarySkillType.UNARMED, UNARMED_CS);
+            rootToPrimaryMap.put(UNARMED_CS, PrimarySkillType.UNARMED);
+
+            primaryToRootMap.put(PrimarySkillType.WOODCUTTING, WOODCUTTING_CS);
+            rootToPrimaryMap.put(WOODCUTTING_CS, PrimarySkillType.WOODCUTTING);
+
+            primaryToRootMap.put(PrimarySkillType.TRIDENTS, TRIDENTS_CS);
+            rootToPrimaryMap.put(TRIDENTS_CS, PrimarySkillType.TRIDENTS);
+
+            primaryToRootMap.put(PrimarySkillType.CROSSBOWS, CROSSBOWS_CS);
+            rootToPrimaryMap.put(CROSSBOWS_CS, PrimarySkillType.CROSSBOWS);
+
+            init = true;
+        }
+    }
+}

+ 1 - 1
src/main/java/com/gmail/nossr50/datatypes/skills/SkillRegisterImpl.java

@@ -143,7 +143,7 @@ public class SkillRegisterImpl implements SkillRegister {
     }
 
     private void registerCoreSkills() {
-        for(RootSkill rootSkill : CoreSkillConstants.getImmutableCoreRootSkillSet()) {
+        for(RootSkill rootSkill : CoreSkills.getImmutableCoreRootSkillSet()) {
             mcMMO.p.getLogger().info("Registering core skill: "+rootSkill.getSkillName());
             registerSkill(rootSkill);
         }

+ 9 - 10
src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java

@@ -2,7 +2,6 @@ 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.experience.XPGainReason;
 import com.gmail.nossr50.datatypes.interactions.NotificationType;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.SubSkillType;
@@ -120,7 +119,7 @@ public class Roll extends AcrobaticsSubSkill {
 
         /* Values related to the player */
         OnlineMMOPlayer mmoPlayer = mcMMO.getUserManager().queryPlayer(player);
-        float skillValue = mmoPlayer.getExperienceManager().getSkillLevel(getPrimarySkill());
+        float skillValue = mmoPlayer.getExperienceHandler().getSkillLevel(getPrimarySkill());
         boolean isLucky = Permissions.lucky(player, getPrimarySkill());
 
         String[] rollStrings = RandomChanceUtil.calculateAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.ACROBATICS_ROLL);
@@ -188,7 +187,7 @@ public class Roll extends AcrobaticsSubSkill {
      */
     private double rollCheck(Player player, OnlineMMOPlayer mmoPlayer, double damage) {
 
-        int skillLevel = mmoPlayer.getExperienceManager().getSkillLevel(getPrimarySkill());
+        int skillLevel = mmoPlayer.getExperienceHandler().getSkillLevel(getPrimarySkill());
 
         if (player.isSneaking()) {
             return gracefulRollCheck(player, mmoPlayer, damage, skillLevel);
@@ -203,7 +202,7 @@ public class Roll extends AcrobaticsSubSkill {
             //player.sendMessage(LocaleLoader.getString("Acrobatics.Roll.Text"));
 
             //if (!SkillUtils.cooldownExpired((long) mmoPlayer.getTeleportATS(), Config.getInstance().getXPAfterTeleportCooldown())) {
-            if(!isExploiting(player) && mmoPlayer.getAcrobaticsManager().canGainRollXP())
+            if(!isExploiting(player) && ((McMMOPlayer) (mmoPlayer)).getAcrobaticsManager().canGainRollXP())
                 SkillUtils.applyXpGain(mmoPlayer, getPrimarySkill(), calculateRollXP(player, damage, true), XPGainReason.PVE);
             //}
 
@@ -212,7 +211,7 @@ public class Roll extends AcrobaticsSubSkill {
         }
         else if (!isFatal(player, damage)) {
             //if (!SkillUtils.cooldownExpired((long) mmoPlayer.getTeleportATS(), Config.getInstance().getXPAfterTeleportCooldown())) {
-            if(!isExploiting(player) && mmoPlayer.getAcrobaticsManager().canGainRollXP())
+            if(!isExploiting(player) && ((McMMOPlayer) (mmoPlayer)).getAcrobaticsManager().canGainRollXP())
                 SkillUtils.applyXpGain(mmoPlayer, getPrimarySkill(), calculateRollXP(player, damage, false), XPGainReason.PVE);
             //}
         }
@@ -222,7 +221,7 @@ public class Roll extends AcrobaticsSubSkill {
     }
 
     private int getActivationChance(OnlineMMOPlayer mmoPlayer) {
-        return PerksUtils.handleLuckyPerks(mmoPlayer.getPlayer(), getPrimarySkill());
+        return PerksUtils.handleLuckyPerks(Misc.adaptPlayer(mmoPlayer), getPrimarySkill());
     }
 
     /**
@@ -242,14 +241,14 @@ public class Roll extends AcrobaticsSubSkill {
         {
             NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Acrobatics.Ability.Proc");
             SoundManager.sendCategorizedSound(player, player.getLocation(), SoundType.ROLL_ACTIVATED, SoundCategory.PLAYERS,0.5F);
-            if(!isExploiting(player) && mmoPlayer.getAcrobaticsManager().canGainRollXP())
+            if(!isExploiting(player) && ((McMMOPlayer) (mmoPlayer)).getAcrobaticsManager().canGainRollXP())
                 SkillUtils.applyXpGain(mmoPlayer, getPrimarySkill(), calculateRollXP(player, damage, true), XPGainReason.PVE);
 
             addFallLocation(player);
             return modifiedDamage;
         }
         else if (!isFatal(player, damage)) {
-            if(!isExploiting(player) && mmoPlayer.getAcrobaticsManager().canGainRollXP())
+            if(!isExploiting(player) && ((McMMOPlayer) (mmoPlayer)).getAcrobaticsManager().canGainRollXP())
                 SkillUtils.applyXpGain(mmoPlayer, getPrimarySkill(), calculateRollXP(player, damage, false), XPGainReason.PVE);
             
             addFallLocation(player);
@@ -273,7 +272,7 @@ public class Roll extends AcrobaticsSubSkill {
 
         if (ItemUtils.hasItemInEitherHand(player, Material.ENDER_PEARL) || player.isInsideVehicle()) {
             if(mmoPlayer.isDebugMode()) {
-                mmoPlayer.getPlayer().sendMessage("Acrobatics XP Prevented: Ender Pearl or Inside Vehicle");
+                Misc.adaptPlayer(mmoPlayer).sendMessage("Acrobatics XP Prevented: Ender Pearl or Inside Vehicle");
             }
             return true;
         }
@@ -281,7 +280,7 @@ public class Roll extends AcrobaticsSubSkill {
         if(mcMMO.getUserManager().queryPlayer(player).getAcrobaticsManager().hasFallenInLocationBefore(getBlockLocation(player)))
         {
             if(mmoPlayer.isDebugMode()) {
-                mmoPlayer.getPlayer().sendMessage("Acrobatics XP Prevented: Fallen in location before");
+                Misc.adaptPlayer(mmoPlayer).sendMessage("Acrobatics XP Prevented: Fallen in location before");
             }
 
             return true;

+ 0 - 1
src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerExperienceEvent.java

@@ -1,6 +1,5 @@
 package com.gmail.nossr50.events.experience;
 
-import com.gmail.nossr50.datatypes.experience.XPGainReason;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import org.bukkit.entity.Player;
 import org.bukkit.event.Cancellable;

+ 0 - 1
src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelChangeEvent.java

@@ -1,6 +1,5 @@
 package com.gmail.nossr50.events.experience;
 
-import com.gmail.nossr50.datatypes.experience.XPGainReason;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import org.bukkit.entity.Player;
 

+ 0 - 1
src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelDownEvent.java

@@ -1,6 +1,5 @@
 package com.gmail.nossr50.events.experience;
 
-import com.gmail.nossr50.datatypes.experience.XPGainReason;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import org.bukkit.entity.Player;
 import org.bukkit.event.HandlerList;

+ 0 - 1
src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerLevelUpEvent.java

@@ -1,6 +1,5 @@
 package com.gmail.nossr50.events.experience;
 
-import com.gmail.nossr50.datatypes.experience.XPGainReason;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import org.bukkit.entity.Player;
 import org.bukkit.event.HandlerList;

+ 0 - 1
src/main/java/com/gmail/nossr50/events/experience/McMMOPlayerXpGainEvent.java

@@ -1,6 +1,5 @@
 package com.gmail.nossr50.events.experience;
 
-import com.gmail.nossr50.datatypes.experience.XPGainReason;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import org.bukkit.entity.Player;
 import org.bukkit.event.HandlerList;

+ 10 - 10
src/main/java/com/gmail/nossr50/listeners/BlockListener.java

@@ -226,10 +226,10 @@ public class BlockListener implements Listener {
             return;
 
         if (blockState.getType() == Repair.anvilMaterial && PrimarySkillType.REPAIR.getPermissions(player)) {
-            mmoPlayer.getRepairManager().placedAnvilCheck();
+            ((McMMOPlayer) (mmoPlayer)).getRepairManager().placedAnvilCheck();
         }
         else if (blockState.getType() == Salvage.anvilMaterial && PrimarySkillType.SALVAGE.getPermissions(player)) {
-            mmoPlayer.getSalvageManager().placedAnvilCheck();
+            ((McMMOPlayer) (mmoPlayer)).getSalvageManager().placedAnvilCheck();
         }
     }
 
@@ -313,7 +313,7 @@ public class BlockListener implements Listener {
 
         /* HERBALISM */
         if (BlockUtils.affectedByGreenTerra(blockState)) {
-            HerbalismManager herbalismManager = mmoPlayer.getHerbalismManager();
+            HerbalismManager herbalismManager = ((McMMOPlayer) (mmoPlayer)).getHerbalismManager();
 
             /* Green Terra */
             if (herbalismManager.canActivateAbility()) {
@@ -336,13 +336,13 @@ public class BlockListener implements Listener {
 
         /* MINING */
         else if (BlockUtils.affectedBySuperBreaker(blockState) && ItemUtils.isPickaxe(heldItem) && PrimarySkillType.MINING.getPermissions(player) && !mcMMO.getPlaceStore().isTrue(blockState)) {
-            MiningManager miningManager = mmoPlayer.getMiningManager();
+            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)) {
-            WoodcuttingManager woodcuttingManager = mmoPlayer.getWoodcuttingManager();
+            WoodcuttingManager woodcuttingManager = ((McMMOPlayer) (mmoPlayer)).getWoodcuttingManager();
             if (woodcuttingManager.canUseTreeFeller(heldItem)) {
                 woodcuttingManager.processTreeFeller(blockState);
             }
@@ -357,7 +357,7 @@ public class BlockListener implements Listener {
 
         /* EXCAVATION */
         else if (BlockUtils.affectedByGigaDrillBreaker(blockState) && ItemUtils.isShovel(heldItem) && PrimarySkillType.EXCAVATION.getPermissions(player) && !mcMMO.getPlaceStore().isTrue(blockState)) {
-            ExcavationManager excavationManager = mmoPlayer.getExcavationManager();
+            ExcavationManager excavationManager = ((McMMOPlayer) (mmoPlayer)).getExcavationManager();
             excavationManager.excavationBlockCheck(blockState);
 
             if (mmoPlayer.getSuperAbilityManager().getAbilityMode(SuperAbilityType.GIGA_DRILL_BREAKER)) {
@@ -565,13 +565,13 @@ 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.GREEN_TERRA) && BlockUtils.canMakeMossy(blockState)) {
-            if (mmoPlayer.getHerbalismManager().processGreenTerraBlockConversion(blockState)) {
+            if (((McMMOPlayer) (mmoPlayer)).getHerbalismManager().processGreenTerraBlockConversion(blockState)) {
                 blockState.update(true);
             }
         }
         else if (mmoPlayer.getSuperAbilityManager().getAbilityMode(SuperAbilityType.BERSERK) && (heldItem.getType() == Material.AIR || Config.getInstance().getUnarmedItemsAsUnarmed())) {
-            if (mmoPlayer.getUnarmedManager().canUseBlockCracker() && BlockUtils.affectedByBlockCracker(blockState)) {
-                if (EventUtils.simulateBlockBreak(block, player, true) && mmoPlayer.getUnarmedManager().blockCrackerCheck(blockState)) {
+            if (((McMMOPlayer) (mmoPlayer)).getUnarmedManager().canUseBlockCracker() && BlockUtils.affectedByBlockCracker(blockState)) {
+                if (EventUtils.simulateBlockBreak(block, player, true) && ((McMMOPlayer) (mmoPlayer)).getUnarmedManager().blockCrackerCheck(blockState)) {
                     blockState.update();
                 }
             }
@@ -585,7 +585,7 @@ public class BlockListener implements Listener {
                 }
             }
         }
-        else if (mmoPlayer.getWoodcuttingManager().canUseLeafBlower(heldItem) && BlockUtils.hasWoodcuttingXP(blockState) && EventUtils.simulateBlockBreak(block, player, true)) {
+        else if (((McMMOPlayer) (mmoPlayer)).getWoodcuttingManager().canUseLeafBlower(heldItem) && BlockUtils.hasWoodcuttingXP(blockState) && EventUtils.simulateBlockBreak(block, player, true)) {
             event.setInstaBreak(true);
             SoundManager.sendSound(player, block.getLocation(), SoundType.POP);
         }

+ 2 - 2
src/main/java/com/gmail/nossr50/listeners/EntityListener.java

@@ -197,7 +197,7 @@ public class EntityListener implements Listener {
                     //Process launch event
                     if (Permissions.skillEnabled(player, PrimarySkillType.CROSSBOWS)) {
                         if (mmoPlayer != null) {
-                            mmoPlayer.getCrossbowManager().processProjectileLaunchEvent(event);
+                            ((McMMOPlayer) (mmoPlayer)).getCrossbowManager().processProjectileLaunchEvent(event);
                         }
                     }
 
@@ -411,7 +411,7 @@ public class EntityListener implements Listener {
                     //Deflect checks
                     final OnlineMMOPlayer mmoPlayer = mcMMO.getUserManager().queryPlayer(defendingPlayer);
                     if (mmoPlayer != null) {
-                        UnarmedManager unarmedManager = mmoPlayer.getUnarmedManager();
+                        UnarmedManager unarmedManager = ((McMMOPlayer) (mmoPlayer)).getUnarmedManager();
 
                         if (unarmedManager.canDeflect()) {
                             if (projectile instanceof Arrow && unarmedManager.deflectCheck()) {

+ 5 - 5
src/main/java/com/gmail/nossr50/listeners/PlayerListener.java

@@ -629,7 +629,7 @@ public class PlayerListener implements Listener {
         }
 
         OnlineMMOPlayer mmoPlayer = mcMMO.getUserManager().queryPlayer(player);
-        MiningManager miningManager = mmoPlayer.getMiningManager();
+        MiningManager miningManager = ((McMMOPlayer) (mmoPlayer)).getMiningManager();
         ItemStack heldItem = player.getInventory().getItemInMainHand();
 
         switch (event.getAction()) {
@@ -642,7 +642,7 @@ public class PlayerListener implements Listener {
                             && PrimarySkillType.REPAIR.getPermissions(player)
                             && mcMMO.getRepairableManager().isRepairable(heldItem)
                             && heldItem.getAmount() <= 1) {
-                        RepairManager repairManager = mmoPlayer.getRepairManager();
+                        RepairManager repairManager = ((McMMOPlayer) (mmoPlayer)).getRepairManager();
                         event.setCancelled(true);
 
                         // Make sure the player knows what he's doing when trying to repair an enchanted item
@@ -687,7 +687,7 @@ public class PlayerListener implements Listener {
                 if (!Config.getInstance().getAbilitiesOnlyActivateWhenSneaking() || player.isSneaking()) {
                     /* REPAIR CHECKS */
                     if (type == Repair.anvilMaterial && PrimarySkillType.REPAIR.getPermissions(player) && mcMMO.getRepairableManager().isRepairable(heldItem)) {
-                        RepairManager repairManager = mmoPlayer.getRepairManager();
+                        RepairManager repairManager = ((McMMOPlayer) (mmoPlayer)).getRepairManager();
 
                         // Cancel repairing an enchanted item
                         if (repairManager.checkConfirmation(false)) {
@@ -697,7 +697,7 @@ public class PlayerListener implements Listener {
                     }
                     /* SALVAGE CHECKS */
                     else if (type == Salvage.anvilMaterial && PrimarySkillType.SALVAGE.getPermissions(player) && mcMMO.getSalvageableManager().isSalvageable(heldItem)) {
-                        SalvageManager salvageManager = mmoPlayer.getSalvageManager();
+                        SalvageManager salvageManager = ((McMMOPlayer) (mmoPlayer)).getSalvageManager();
 
                         // Cancel salvaging an enchanted item
                         if (salvageManager.checkConfirmation(false)) {
@@ -759,7 +759,7 @@ public class PlayerListener implements Listener {
                     player.setVelocity(player.getEyeLocation().getDirection().multiply(10));
                 }
 
-                mmoPlayer.getFishingManager().setFishingRodCastTimestamp();
+                ((McMMOPlayer) (mmoPlayer)).getFishingManager().setFishingRodCastTimestamp();
             }
         }
 

+ 7 - 8
src/main/java/com/gmail/nossr50/listeners/SelfListener.java

@@ -2,7 +2,6 @@ package com.gmail.nossr50.listeners;
 
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.config.experience.ExperienceConfig;
-import com.gmail.nossr50.datatypes.experience.XPGainReason;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.events.experience.McMMOPlayerLevelUpEvent;
@@ -85,8 +84,8 @@ public class SelfListener implements Listener {
         PrimarySkillType primarySkillType = event.getSkill();
 
         if(mmoPlayer.isDebugMode()) {
-            mmoPlayer.getPlayer().sendMessage(event.getSkill().toString() + " XP Gained");
-            mmoPlayer.getPlayer().sendMessage("Incoming Raw XP: "+event.getRawXpGained());
+            Misc.adaptPlayer(mmoPlayer).sendMessage(event.getSkill().toString() + " XP Gained");
+            Misc.adaptPlayer(mmoPlayer).sendMessage("Incoming Raw XP: "+event.getRawXpGained());
         }
 
         //WorldGuard XP Check
@@ -103,7 +102,7 @@ public class SelfListener implements Listener {
                     event.setCancelled(true);
 
                     if(mmoPlayer.isDebugMode()) {
-                        mmoPlayer.getPlayer().sendMessage("No WG XP Flag - New Raw XP: "+event.getRawXpGained());
+                        Misc.adaptPlayer(mmoPlayer).sendMessage("No WG XP Flag - New Raw XP: "+event.getRawXpGained());
                     }
                 }
             }
@@ -122,7 +121,7 @@ public class SelfListener implements Listener {
             //Give some bonus XP for low levels
             if(PlayerLevelUtils.qualifiesForEarlyGameBoost(mmoPlayer, primarySkillType))
             {
-                earlyGameBonusXP += (mmoPlayer.getExperienceManager().getExperienceToNextLevel(primarySkillType) * 0.05);
+                earlyGameBonusXP += (mmoPlayer.getExperienceHandler().getExperienceToNextLevel(primarySkillType) * 0.05);
                 event.setRawXpGained(event.getRawXpGained() + earlyGameBonusXP);
             }
         }
@@ -131,7 +130,7 @@ public class SelfListener implements Listener {
 
         if (threshold <= 0 || !ExperienceConfig.getInstance().getDiminishedReturnsEnabled()) {
             if(mmoPlayer.isDebugMode()) {
-                mmoPlayer.getPlayer().sendMessage("Final Raw XP: "+event.getRawXpGained());
+                Misc.adaptPlayer(mmoPlayer).sendMessage("Final Raw XP: "+event.getRawXpGained());
             }
             // Diminished returns is turned off
             return;
@@ -151,7 +150,7 @@ public class SelfListener implements Listener {
         float guaranteedMinimum = ExperienceConfig.getInstance().getDiminishedReturnsCap() * rawXp;
 
         float modifiedThreshold = (float) (threshold / primarySkillType.getXpModifier() * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier());
-        float difference = (mmoPlayer.getExperienceManager().getRegisteredXpGain(primarySkillType) - modifiedThreshold) / modifiedThreshold;
+        float difference = (mmoPlayer.getExperienceHandler().getRegisteredXpGain(primarySkillType) - modifiedThreshold) / modifiedThreshold;
 
         if (difference > 0) {
 //            System.out.println("Total XP Earned: " + mmoPlayer.getProfile().getRegisteredXpGain(primarySkillType) + " / Threshold value: " + threshold);
@@ -179,7 +178,7 @@ public class SelfListener implements Listener {
         }
 
         if(mmoPlayer.isDebugMode()) {
-            mmoPlayer.getPlayer().sendMessage("Final Raw XP: "+event.getRawXpGained());
+            Misc.adaptPlayer(mmoPlayer).sendMessage("Final Raw XP: "+event.getRawXpGained());
         }
     }
 

+ 12 - 12
src/main/java/com/gmail/nossr50/party/PartyManager.java

@@ -54,7 +54,7 @@ public final class PartyManager {
      */
     public @Nullable Party queryParty(@NotNull UUID playerUUID) {
         for(Party party : parties.values()) {
-            if(party.hasMember(playerUUID)) {
+            if(party.getPartyMemberManager().hasMember(playerUUID)) {
                 return party;
             }
         }
@@ -114,7 +114,7 @@ public final class PartyManager {
      * @return true if the party was joined successfully, false otherwise
      */
     public boolean changeOrJoinParty(@NotNull OnlineMMOPlayer mmoPlayer, @NotNull String newPartyName) {
-        Player player = mmoPlayer.getPlayer();
+        Player player = Misc.adaptPlayer(mmoPlayer);
 
         if (inParty(mmoPlayer)) {
             Party oldParty = mmoPlayer.getParty();
@@ -171,7 +171,7 @@ public final class PartyManager {
         Party party = mmoPlayer.getParty();
 
         if (party != null) {
-            Player player = mmoPlayer.getPlayer();
+            Player player = Misc.adaptPlayer(mmoPlayer);
             double range = Config.getInstance().getPartyShareRange();
 
             for (PartyMember member : party.getPartyMembers()) {
@@ -189,7 +189,7 @@ public final class PartyManager {
         Party party = mmoPlayer.getParty();
 
         if (party != null) {
-            Player player = mmoPlayer.getPlayer();
+            Player player = Misc.adaptPlayer(mmoPlayer);
             double range = Config.getInstance().getPartyShareRange();
 
             for (Player member : party.getVisibleMembers(player)) {
@@ -359,7 +359,7 @@ public final class PartyManager {
      * @param mmoPlayer The player to remove
      */
     public void removeFromParty(OnlineMMOPlayer mmoPlayer) {
-        removeFromParty(mmoPlayer.getPlayer(), mmoPlayer.getParty());
+        removeFromParty(Misc.adaptPlayer(mmoPlayer), mmoPlayer.getParty());
         processPartyLeaving(mmoPlayer);
     }
 
@@ -396,7 +396,7 @@ public final class PartyManager {
      * @param password The password for this party, null if there was no password
      */
     public void createParty(OnlineMMOPlayer mmoPlayer, String partyName, String password) {
-        Player player = mmoPlayer.getPlayer();
+        Player player = Misc.adaptPlayer(mmoPlayer);
 
         Party party = new Party(new PartyLeader(player.getUniqueId(), player.getName()), partyName.replace(".", ""), password);
 
@@ -451,7 +451,7 @@ public final class PartyManager {
 
         // Check if the party still exists, it might have been disbanded
         if (!parties.contains(invite)) {
-            NotificationManager.sendPlayerInformation(mmoPlayer.getPlayer(), NotificationType.PARTY_MESSAGE, "Party.Disband");
+            NotificationManager.sendPlayerInformation(Misc.adaptPlayer(mmoPlayer), NotificationType.PARTY_MESSAGE, "Party.Disband");
             return;
         }
 
@@ -460,11 +460,11 @@ public final class PartyManager {
          */
         if(Config.getInstance().getPartyMaxSize() > 0 && invite.getMembers().size() >= Config.getInstance().getPartyMaxSize())
         {
-            NotificationManager.sendPlayerInformation(mmoPlayer.getPlayer(), NotificationType.PARTY_MESSAGE, "Commands.Party.PartyFull.InviteAccept", invite.getPartyName(), String.valueOf(Config.getInstance().getPartyMaxSize()));
+            NotificationManager.sendPlayerInformation(Misc.adaptPlayer(mmoPlayer), NotificationType.PARTY_MESSAGE, "Commands.Party.PartyFull.InviteAccept", invite.getPartyName(), String.valueOf(Config.getInstance().getPartyMaxSize()));
             return;
         }
 
-        NotificationManager.sendPlayerInformation(mmoPlayer.getPlayer(), NotificationType.PARTY_MESSAGE, "Commands.Party.Invite.Accepted", invite.getPartyName());
+        NotificationManager.sendPlayerInformation(Misc.adaptPlayer(mmoPlayer), NotificationType.PARTY_MESSAGE, "Commands.Party.Invite.Accepted", invite.getPartyName());
         mmoPlayer.removePartyInvite();
         addToParty(mmoPlayer, invite);
     }
@@ -476,7 +476,7 @@ public final class PartyManager {
      */
     public void acceptAllianceInvite(OnlineMMOPlayer mmoPlayer) {
         Party invite = mmoPlayer.getPartyAllianceInvite();
-        Player player = mmoPlayer.getPlayer();
+        Player player = Misc.adaptPlayer(mmoPlayer);
 
         // Check if the party still exists, it might have been disbanded
         if (!parties.contains(invite)) {
@@ -536,7 +536,7 @@ public final class PartyManager {
      * @param party The party
      */
     public void addToParty(OnlineMMOPlayer mmoPlayer, Party party) {
-        Player player = mmoPlayer.getPlayer();
+        Player player = Misc.adaptPlayer(mmoPlayer);
         String playerName = player.getName();
 
         informPartyMembersJoin(party, playerName);
@@ -591,7 +591,7 @@ public final class PartyManager {
     public boolean canInvite(OnlineMMOPlayer mmoPlayer) {
         Party party = mmoPlayer.getParty();
 
-        return !party.isLocked() || party.getLeader().getUniqueId().equals(mmoPlayer.getPlayer().getUniqueId());
+        return !party.isLocked() || party.getLeader().getUniqueId().equals(mmoPlayer.getUUID());
     }
 
     /**

+ 1 - 3
src/main/java/com/gmail/nossr50/party/ShareHandler.java

@@ -2,8 +2,6 @@ package com.gmail.nossr50.party;
 
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.config.party.ItemWeightConfig;
-import com.gmail.nossr50.datatypes.experience.XPGainReason;
-import com.gmail.nossr50.datatypes.experience.XPGainSource;
 import com.gmail.nossr50.datatypes.party.ItemShareType;
 import com.gmail.nossr50.datatypes.party.Party;
 import com.gmail.nossr50.datatypes.party.ShareMode;
@@ -55,7 +53,7 @@ public final class ShareHandler {
                 continue;
             }
 
-            partyMember.getExperienceManager().beginUnsharedXpGain(primarySkillType, splitXp, xpGainReason, XPGainSource.PARTY_MEMBERS);
+            partyMember.getExperienceHandler().beginUnsharedXpGain(primarySkillType, splitXp, xpGainReason, XPGainSource.PARTY_MEMBERS);
         }
 
         return true;

+ 3 - 2
src/main/java/com/gmail/nossr50/runnables/items/ChimaeraWingWarmup.java

@@ -1,6 +1,7 @@
 package com.gmail.nossr50.runnables.items;
 
 import com.gmail.nossr50.config.Config;
+import com.gmail.nossr50.datatypes.player.McMMOPlayer;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.ChimaeraWing;
@@ -13,9 +14,9 @@ import org.bukkit.inventory.ItemStack;
 import org.bukkit.scheduler.BukkitRunnable;
 
 public class ChimaeraWingWarmup extends BukkitRunnable {
-    private final OnlineMMOPlayer mmoPlayer;
+    private final McMMOPlayer mmoPlayer;
 
-    public ChimaeraWingWarmup(OnlineMMOPlayer mmoPlayer) {
+    public ChimaeraWingWarmup(McMMOPlayer mmoPlayer) {
         this.mmoPlayer = mmoPlayer;
     }
 

+ 7 - 5
src/main/java/com/gmail/nossr50/runnables/items/TeleportationWarmup.java

@@ -1,6 +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.mcMMO;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.EventUtils;
@@ -13,20 +15,20 @@ import org.bukkit.entity.Player;
 import org.bukkit.scheduler.BukkitRunnable;
 
 public class TeleportationWarmup extends BukkitRunnable {
-    private final OnlineMMOPlayer mmoPlayer;
-    private final OnlineMMOPlayer mcMMOTarget;
+    private final McMMOPlayer mmoPlayer;
+    private final McMMOPlayer mcMMOTarget;
 
-    public TeleportationWarmup(OnlineMMOPlayer mmoPlayer, OnlineMMOPlayer mcMMOTarget) {
+    public TeleportationWarmup(McMMOPlayer mmoPlayer, McMMOPlayer mcMMOTarget) {
         this.mmoPlayer = mmoPlayer;
         this.mcMMOTarget = mcMMOTarget;
     }
 
     @Override
     public void run() {
-        Player teleportingPlayer = mmoPlayer.getPlayer();
+        Player teleportingPlayer = Misc.adaptPlayer(mmoPlayer);
         Player targetPlayer = mcMMOTarget.getPlayer();
         Location previousLocation = mmoPlayer.getTeleportCommenceLocation();
-        Location newLocation = mmoPlayer.getPlayer().getLocation();
+        Location newLocation = Misc.adaptPlayer(mmoPlayer).getLocation();
         long recentlyHurt = mmoPlayer.getRecentlyHurtTimestamp();
 
         mmoPlayer.setTeleportCommenceLocation(null);

+ 9 - 4
src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java

@@ -1,6 +1,10 @@
 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.PersistentPlayerData;
+import com.gmail.nossr50.datatypes.player.PersistentPlayerDataBuilder;
+import com.neetgames.mcmmo.player.MMOPlayerData;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.datatypes.player.PlayerProfile;
 import com.gmail.nossr50.locale.LocaleLoader;
@@ -42,8 +46,9 @@ public class PlayerProfileLoadingTask extends BukkitRunnable {
         }
 
         try {
-            PlayerProfile profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(player.getUniqueId());
-            new ApplySuccessfulProfile(new OnlineMMOPlayer(player, profile)).runTask(mcMMO.p);
+            MMOPlayerData mmoPlayerData = mcMMO.getDatabaseManager().queryPlayerDataByPlayer(player);
+            McMMOPlayer mmoPlayer = new McMMOPlayer(player, player.getUniqueId(), player.getName());
+            new ApplySuccessfulProfile(new McMMOPlayer(player, )).runTask(mcMMO.p);
             EventUtils.callPlayerProfileLoadEvent(player, profile);
             return;
 
@@ -70,9 +75,9 @@ public class PlayerProfileLoadingTask extends BukkitRunnable {
     }
 
     private class ApplySuccessfulProfile extends BukkitRunnable {
-        private final OnlineMMOPlayer mmoPlayer;
+        private final McMMOPlayer mmoPlayer;
 
-        private ApplySuccessfulProfile(OnlineMMOPlayer mmoPlayer) {
+        private ApplySuccessfulProfile(McMMOPlayer mmoPlayer) {
             this.mmoPlayer = mmoPlayer;
         }
 

+ 3 - 3
src/main/java/com/gmail/nossr50/runnables/skills/AbilityCooldownTask.java

@@ -17,13 +17,13 @@ public class AbilityCooldownTask extends BukkitRunnable {
 
     @Override
     public void run() {
-        if (!mmoPlayer.getPlayer().isOnline() || mmoPlayer.getSuperAbilityManager().getAbilityInformed(ability)) {
+        if (!Misc.adaptPlayer(mmoPlayer).isOnline() || mmoPlayer.getSuperAbilityManager().getAbilityInformed(ability)) {
             return;
         }
 
         mmoPlayer.getSuperAbilityManager().setAbilityInformed(ability, true);
 
-        NotificationManager.sendPlayerInformation(mmoPlayer.getPlayer(), NotificationType.ABILITY_REFRESHED, ability.getAbilityRefresh());
-        //mmoPlayer.getPlayer().sendMessage(ability.getAbilityRefresh());
+        NotificationManager.sendPlayerInformation(Misc.adaptPlayer(mmoPlayer), NotificationType.ABILITY_REFRESHED, ability.getAbilityRefresh());
+        //Misc.adaptPlayer(mmoPlayer).sendMessage(ability.getAbilityRefresh());
     }
 }

+ 1 - 1
src/main/java/com/gmail/nossr50/runnables/skills/AbilityDisableTask.java

@@ -32,7 +32,7 @@ public class AbilityDisableTask extends BukkitRunnable {
             return;
         }
 
-        Player player = mmoPlayer.getPlayer();
+        Player player = Misc.adaptPlayer(mmoPlayer);
 
         switch (ability) {
             case SUPER_BREAKER:

+ 5 - 2
src/main/java/com/gmail/nossr50/runnables/skills/AlchemyBrewTask.java

@@ -1,5 +1,6 @@
 package com.gmail.nossr50.runnables.skills;
 
+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.events.skills.alchemy.McMMOPlayerBrewEvent;
@@ -9,6 +10,7 @@ import com.gmail.nossr50.skills.alchemy.Alchemy;
 import com.gmail.nossr50.skills.alchemy.AlchemyPotionBrewer;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.Permissions;
+import com.neetgames.mcmmo.player.OnlineMMOPlayer;
 import org.bukkit.Location;
 import org.bukkit.Material;
 import org.bukkit.block.BlockState;
@@ -36,12 +38,13 @@ public class AlchemyBrewTask extends BukkitRunnable {
         brewSpeed = DEFAULT_BREW_SPEED;
         brewTimer = DEFAULT_BREW_TICKS;
 
+        OnlineMMOPlayer mmoPlayer = mcMMO.getUserManager().queryPlayer(player);
         if (player != null
                 && !Misc.isNPCEntityExcludingVillagers(player)
                 && Permissions.isSubSkillEnabled(player, SubSkillType.ALCHEMY_CATALYSIS)
-                && mcMMO.getUserManager().queryPlayer(player) != null) {
+                && mmoPlayer != null) {
 
-            double catalysis = mcMMO.getUserManager().queryPlayer(player).getAlchemyManager().calculateBrewSpeed(Permissions.lucky(player, PrimarySkillType.ALCHEMY));
+            double catalysis = ((McMMOPlayer) mmoPlayer).getAlchemyManager().calculateBrewSpeed(Permissions.lucky(player, PrimarySkillType.ALCHEMY));
 
             McMMOPlayerCatalysisEvent event = new McMMOPlayerCatalysisEvent(player, catalysis);
             mcMMO.p.getServer().getPluginManager().callEvent(event);

+ 0 - 2
src/main/java/com/gmail/nossr50/runnables/skills/AwardCombatXpTask.java

@@ -1,7 +1,5 @@
 package com.gmail.nossr50.runnables.skills;
 
-import com.gmail.nossr50.datatypes.experience.XPGainReason;
-import com.gmail.nossr50.datatypes.experience.XPGainSource;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import org.bukkit.entity.LivingEntity;

+ 1 - 1
src/main/java/com/gmail/nossr50/runnables/skills/DelayedHerbalismXPCheckTask.java

@@ -18,6 +18,6 @@ public class DelayedHerbalismXPCheckTask extends BukkitRunnable {
 
     @Override
     public void run() {
-        mmoPlayer.getHerbalismManager().awardXPForBlockSnapshots(chorusBlocks);
+        ((McMMOPlayer) (mmoPlayer)).getHerbalismManager().awardXPForBlockSnapshots(chorusBlocks);
     }
 }

+ 6 - 7
src/main/java/com/gmail/nossr50/runnables/skills/ExperienceBarHideTask.java

@@ -1,20 +1,19 @@
 package com.gmail.nossr50.runnables.skills;
 
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
-import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.util.experience.MMOExperienceBarManager;
+import com.neetgames.mcmmo.skill.RootSkill;
 import org.bukkit.scheduler.BukkitRunnable;
 
 public class ExperienceBarHideTask extends BukkitRunnable {
     public final OnlineMMOPlayer mmoPlayer;
-    public final PrimarySkillType primarySkillType;
+    public final RootSkill rootSkill;
     public final MMOExperienceBarManager MMOExperienceBarManagerRef;
 
-    public ExperienceBarHideTask(MMOExperienceBarManager MMOExperienceBarManagerRef, OnlineMMOPlayer mmoPlayer, PrimarySkillType primarySkillType)
-    {
+    public ExperienceBarHideTask(MMOExperienceBarManager MMOExperienceBarManagerRef, OnlineMMOPlayer mmoPlayer, RootSkill rootSkill) {
         this.MMOExperienceBarManagerRef = MMOExperienceBarManagerRef;
         this.mmoPlayer = mmoPlayer;
-        this.primarySkillType = primarySkillType;
+        this.rootSkill = rootSkill;
     }
 
     /**
@@ -33,7 +32,7 @@ public class ExperienceBarHideTask extends BukkitRunnable {
         if(MMOExperienceBarManagerRef == null || mmoPlayer == null)
             return;
 
-        MMOExperienceBarManagerRef.hideExperienceBar(primarySkillType);
-        MMOExperienceBarManagerRef.clearTask(primarySkillType);
+        MMOExperienceBarManagerRef.hideExperienceBar(rootSkill);
+        MMOExperienceBarManagerRef.clearTask(rootSkill);
     }
 }

+ 1 - 1
src/main/java/com/gmail/nossr50/runnables/skills/SkillUnlockNotificationTask.java

@@ -35,7 +35,7 @@ public class SkillUnlockNotificationTask extends BukkitRunnable {
      */
     @Override
     public void run() {
-        //mmoPlayer.getPlayer().sendTitle(subSkillType.getLocaleName(), "Rank "+rank, 7, 20, 7);
+        //Misc.adaptPlayer(mmoPlayer).sendTitle(subSkillType.getLocaleName(), "Rank "+rank, 7, 20, 7);
         NotificationManager.sendPlayerUnlockNotification(mmoPlayer, subSkillType);
     }
 }

+ 1 - 1
src/main/java/com/gmail/nossr50/runnables/skills/ToolLowerTask.java

@@ -25,7 +25,7 @@ public class ToolLowerTask extends BukkitRunnable {
         mmoPlayer.getSuperAbilityManager().setAbilityToolPrime(tool, false);
 
         if (Config.getInstance().getAbilityMessagesEnabled()) {
-            NotificationManager.sendPlayerInformation(mmoPlayer.getPlayer(), NotificationType.TOOL, tool.getLowerToolLocaleKey());
+            NotificationManager.sendPlayerInformation(Misc.adaptPlayer(mmoPlayer), NotificationType.TOOL, tool.getLowerToolLocaleKey());
         }
     }
 }

+ 2 - 4
src/main/java/com/gmail/nossr50/skills/SkillManager.java

@@ -1,7 +1,5 @@
 package com.gmail.nossr50.skills;
 
-import com.gmail.nossr50.datatypes.experience.XPGainReason;
-import com.gmail.nossr50.datatypes.experience.XPGainSource;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import org.bukkit.entity.Entity;
@@ -18,11 +16,11 @@ public abstract class SkillManager {
     }
 
     public Player getPlayer() {
-        return mmoPlayer.getPlayer();
+        return Misc.adaptPlayer(mmoPlayer);
     }
 
     public int getSkillLevel() {
-        return mmoPlayer.getExperienceManager().getSkillLevel(skill);
+        return mmoPlayer.getExperienceHandler().getSkillLevel(skill);
     }
 
     /**

+ 0 - 1
src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java

@@ -2,7 +2,6 @@ package com.gmail.nossr50.skills.acrobatics;
 
 import com.gmail.nossr50.config.experience.ExperienceConfig;
 import com.gmail.nossr50.datatypes.LimitedSizeList;
-import com.gmail.nossr50.datatypes.experience.XPGainReason;
 import com.gmail.nossr50.datatypes.interactions.NotificationType;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;

+ 0 - 2
src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyManager.java

@@ -2,8 +2,6 @@ package com.gmail.nossr50.skills.alchemy;
 
 import com.gmail.nossr50.config.experience.ExperienceConfig;
 import com.gmail.nossr50.config.skills.alchemy.PotionConfig;
-import com.gmail.nossr50.datatypes.experience.XPGainReason;
-import com.gmail.nossr50.datatypes.experience.XPGainSource;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.SubSkillType;

+ 16 - 12
src/main/java/com/gmail/nossr50/skills/child/FamilyTree.java

@@ -1,7 +1,9 @@
 package com.gmail.nossr50.skills.child;
 
-import com.gmail.nossr50.datatypes.skills.CoreSkillConstants;
+import com.gmail.nossr50.datatypes.skills.CoreSkills;
+import com.gmail.nossr50.mcMMO;
 import com.neetgames.mcmmo.exceptions.UnknownSkillException;
+import com.neetgames.mcmmo.skill.RootSkill;
 import com.neetgames.mcmmo.skill.SkillIdentity;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -14,27 +16,29 @@ public class FamilyTree {
     /*
      * Hacky crap, will remove later
      */
+    private static @Nullable Set<RootSkill> smeltingParents;
+    private static @Nullable Set<RootSkill> salvageParents;
 
-    private static @Nullable Set<SkillIdentity> smeltingParents;
-    private static @Nullable Set<SkillIdentity> salvageParents;
-
-    public static @NotNull Set<SkillIdentity> getParentSkills(@NotNull SkillIdentity skillIdentity) throws UnknownSkillException {
-        if(CoreSkillConstants.isChildSkill(skillIdentity)) {
+    public static @NotNull Set<RootSkill> getParentSkills(@NotNull RootSkill rootSkill) throws UnknownSkillException {
+        if(CoreSkills.isChildSkill(rootSkill)) {
             if(smeltingParents == null || salvageParents == null) {
                 smeltingParents = new HashSet<>();
                 salvageParents = new HashSet<>();
 
-                smeltingParents.add(CoreSkillConstants.MINING_ID);
-                smeltingParents.add(CoreSkillConstants.REPAIR_ID);
+                smeltingParents.add(CoreSkills.MINING_CS);
+                smeltingParents.add(CoreSkills.REPAIR_CS);
 
-                salvageParents.add(CoreSkillConstants.FISHING_ID);
-                salvageParents.add(CoreSkillConstants.REPAIR_ID);
+                salvageParents.add(CoreSkills.FISHING_CS);
+                salvageParents.add(CoreSkills.REPAIR_CS);
             }
 
-            if(skillIdentity.equals(CoreSkillConstants.SALVAGE_ID)) {
+            if(rootSkill.equals(CoreSkills.SALVAGE_CS)) {
                 return salvageParents;
-            } else {
+            } else if (rootSkill.equals(CoreSkills.SMELTING_CS)) {
                 return smeltingParents;
+            } else {
+                mcMMO.p.getLogger().severe("root skill argument is not a child skill! " + rootSkill.toString());
+                throw new UnknownSkillException();
             }
 
         } else {

+ 3 - 3
src/main/java/com/gmail/nossr50/skills/crossbows/CrossbowManager.java

@@ -52,8 +52,8 @@ public class CrossbowManager extends SkillManager {
      */
     public void processProjectileLaunchEvent(ProjectileLaunchEvent projectileLaunchEvent) {
         //Testing
-        if(Permissions.isSubSkillEnabled(mmoPlayer.getPlayer(), SubSkillType.CROSSBOWS_SUPER_SHOTGUN)) {
-            if(RankUtils.hasUnlockedSubskill(mmoPlayer.getPlayer(), SubSkillType.CROSSBOWS_SUPER_SHOTGUN)) {
+        if(Permissions.isSubSkillEnabled(Misc.adaptPlayer(mmoPlayer), SubSkillType.CROSSBOWS_SUPER_SHOTGUN)) {
+            if(RankUtils.hasUnlockedSubskill(Misc.adaptPlayer(mmoPlayer), SubSkillType.CROSSBOWS_SUPER_SHOTGUN)) {
                 superShotgunProcessing(projectileLaunchEvent);
             }
         }
@@ -79,7 +79,7 @@ public class CrossbowManager extends SkillManager {
     }
 
     public int getSuperShotgunAdditionalArrowCount() {
-        switch(RankUtils.getRank(mmoPlayer.getPlayer(), SubSkillType.CROSSBOWS_SUPER_SHOTGUN)) {
+        switch(RankUtils.getRank(Misc.adaptPlayer(mmoPlayer), SubSkillType.CROSSBOWS_SUPER_SHOTGUN)) {
             case 1:
                 return 9;
             case 2:

+ 0 - 1
src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java

@@ -2,7 +2,6 @@ package com.gmail.nossr50.skills.excavation;
 
 import com.gmail.nossr50.api.ItemSpawnReason;
 import com.gmail.nossr50.config.Config;
-import com.gmail.nossr50.datatypes.experience.XPGainReason;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.SubSkillType;

+ 21 - 22
src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java

@@ -5,7 +5,6 @@ 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.TreasureConfig;
-import com.gmail.nossr50.datatypes.experience.XPGainReason;
 import com.gmail.nossr50.datatypes.interactions.NotificationType;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
@@ -292,38 +291,38 @@ public class FishingManager extends SkillManager {
             }
 
             if(mmoPlayer.isDebugMode()) {
-                mmoPlayer.getPlayer().sendMessage(ChatColor.GOLD + "Master Angler Debug");
+                Misc.adaptPlayer(mmoPlayer).sendMessage(ChatColor.GOLD + "Master Angler Debug");
 
                 if(badValuesFix) {
-                    mmoPlayer.getPlayer().sendMessage(ChatColor.RED + "Bad values were applied and corrected, check your configs, max wait should never be lower than min wait.");
+                    Misc.adaptPlayer(mmoPlayer).sendMessage(ChatColor.RED + "Bad values were applied and corrected, check your configs, max wait should never be lower than min wait.");
                 }
 
-                mmoPlayer.getPlayer().sendMessage("ALLOW STACK WITH LURE: " + masterAnglerCompatibilityLayer.getApplyLure(fishHook));
-                mmoPlayer.getPlayer().sendMessage("MIN TICK REDUCTION: " + minWaitReduction);
-                mmoPlayer.getPlayer().sendMessage("MAX TICK REDUCTION: " + maxWaitReduction);
-                mmoPlayer.getPlayer().sendMessage("BOAT BONUS: " + boatBonus);
+                Misc.adaptPlayer(mmoPlayer).sendMessage("ALLOW STACK WITH LURE: " + masterAnglerCompatibilityLayer.getApplyLure(fishHook));
+                Misc.adaptPlayer(mmoPlayer).sendMessage("MIN TICK REDUCTION: " + minWaitReduction);
+                Misc.adaptPlayer(mmoPlayer).sendMessage("MAX TICK REDUCTION: " + maxWaitReduction);
+                Misc.adaptPlayer(mmoPlayer).sendMessage("BOAT BONUS: " + boatBonus);
 
                 if(boatBonus) {
-                    mmoPlayer.getPlayer().sendMessage("BOAT MAX TICK REDUCTION: " + maxWaitReduction);
-                    mmoPlayer.getPlayer().sendMessage("BOAT MIN TICK REDUCTION: " + maxWaitReduction);
+                    Misc.adaptPlayer(mmoPlayer).sendMessage("BOAT MAX TICK REDUCTION: " + maxWaitReduction);
+                    Misc.adaptPlayer(mmoPlayer).sendMessage("BOAT MIN TICK REDUCTION: " + maxWaitReduction);
                 }
 
-                mmoPlayer.getPlayer().sendMessage("");
+                Misc.adaptPlayer(mmoPlayer).sendMessage("");
 
-                mmoPlayer.getPlayer().sendMessage(ChatColor.DARK_AQUA + "BEFORE MASTER ANGLER WAS APPLIED");
-                mmoPlayer.getPlayer().sendMessage("Original Max Wait Ticks: " + maxWaitTicks);
-                mmoPlayer.getPlayer().sendMessage("Original Min Wait Ticks: " + minWaitTicks);
-                mmoPlayer.getPlayer().sendMessage("");
+                Misc.adaptPlayer(mmoPlayer).sendMessage(ChatColor.DARK_AQUA + "BEFORE MASTER ANGLER WAS APPLIED");
+                Misc.adaptPlayer(mmoPlayer).sendMessage("Original Max Wait Ticks: " + maxWaitTicks);
+                Misc.adaptPlayer(mmoPlayer).sendMessage("Original Min Wait Ticks: " + minWaitTicks);
+                Misc.adaptPlayer(mmoPlayer).sendMessage("");
 
-                mmoPlayer.getPlayer().sendMessage(ChatColor.DARK_AQUA + "AFTER MASTER ANGLER WAS APPLIED");
-                mmoPlayer.getPlayer().sendMessage("Current Max Wait Ticks: " + reducedMaxWaitTime);
-                mmoPlayer.getPlayer().sendMessage("Current Min Wait Ticks: " + reducedMinWaitTime);
+                Misc.adaptPlayer(mmoPlayer).sendMessage(ChatColor.DARK_AQUA + "AFTER MASTER ANGLER WAS APPLIED");
+                Misc.adaptPlayer(mmoPlayer).sendMessage("Current Max Wait Ticks: " + reducedMaxWaitTime);
+                Misc.adaptPlayer(mmoPlayer).sendMessage("Current Min Wait Ticks: " + reducedMinWaitTime);
 
-                mmoPlayer.getPlayer().sendMessage("");
+                Misc.adaptPlayer(mmoPlayer).sendMessage("");
 
-                mmoPlayer.getPlayer().sendMessage(ChatColor.DARK_AQUA + "Caps / Limits (edit in advanced.yml)");
-                mmoPlayer.getPlayer().sendMessage("Lowest possible max wait ticks " + bonusCapMax);
-                mmoPlayer.getPlayer().sendMessage("Lowest possible min wait ticks " + bonusCapMin);
+                Misc.adaptPlayer(mmoPlayer).sendMessage(ChatColor.DARK_AQUA + "Caps / Limits (edit in advanced.yml)");
+                Misc.adaptPlayer(mmoPlayer).sendMessage("Lowest possible max wait ticks " + bonusCapMax);
+                Misc.adaptPlayer(mmoPlayer).sendMessage("Lowest possible min wait ticks " + bonusCapMin);
             }
 
             masterAnglerCompatibilityLayer.setMaxWaitTime(fishHook, reducedMaxWaitTime);
@@ -337,7 +336,7 @@ public class FishingManager extends SkillManager {
     }
 
     public boolean isInBoat() {
-        return mmoPlayer.getPlayer().isInsideVehicle() && mmoPlayer.getPlayer().getVehicle() instanceof Boat;
+        return Misc.adaptPlayer(mmoPlayer).isInsideVehicle() && Misc.adaptPlayer(mmoPlayer).getVehicle() instanceof Boat;
     }
 
     public int getMasterAnglerTickMaxWaitReduction(int masterAnglerRank, boolean boatBonus, int emulatedLureBonus) {

+ 3 - 5
src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java

@@ -5,8 +5,6 @@ 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;
-import com.gmail.nossr50.datatypes.experience.XPGainReason;
-import com.gmail.nossr50.datatypes.experience.XPGainSource;
 import com.gmail.nossr50.datatypes.interactions.NotificationType;
 import com.gmail.nossr50.datatypes.meta.RecentlyReplantedCropMeta;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
@@ -388,7 +386,7 @@ public class HerbalismManager extends SkillManager {
         }
 
         if(mmoPlayer.isDebugMode()) {
-            mmoPlayer.getPlayer().sendMessage("Plants processed: "+brokenPlants.size());
+            Misc.adaptPlayer(mmoPlayer).sendMessage("Plants processed: "+brokenPlants.size());
         }
 
         //Reward XP
@@ -439,8 +437,8 @@ public class HerbalismManager extends SkillManager {
         }
 
         if(mmoPlayer.isDebugMode()) {
-            mmoPlayer.getPlayer().sendMessage("Chorus Plants checked for XP: "+brokenPlants.size());
-            mmoPlayer.getPlayer().sendMessage("Valid Chorus Plant XP Gains: "+blocksGivingXP);
+            Misc.adaptPlayer(mmoPlayer).sendMessage("Chorus Plants checked for XP: "+brokenPlants.size());
+            Misc.adaptPlayer(mmoPlayer).sendMessage("Valid Chorus Plant XP Gains: "+blocksGivingXP);
         }
 
         //Reward XP

+ 0 - 1
src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java

@@ -4,7 +4,6 @@ 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.experience.XPGainReason;
 import com.gmail.nossr50.datatypes.interactions.NotificationType;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;

+ 0 - 1
src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java

@@ -3,7 +3,6 @@ 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.experience.XPGainReason;
 import com.gmail.nossr50.datatypes.interactions.NotificationType;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;

+ 0 - 2
src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java

@@ -1,8 +1,6 @@
 package com.gmail.nossr50.skills.smelting;
 
 import com.gmail.nossr50.config.Config;
-import com.gmail.nossr50.datatypes.experience.XPGainReason;
-import com.gmail.nossr50.datatypes.experience.XPGainSource;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.SubSkillType;

+ 0 - 1
src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java

@@ -3,7 +3,6 @@ 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.experience.XPGainReason;
 import com.gmail.nossr50.datatypes.interactions.NotificationType;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;

+ 0 - 1
src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java

@@ -3,7 +3,6 @@ package com.gmail.nossr50.skills.woodcutting;
 import com.gmail.nossr50.api.ItemSpawnReason;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.config.experience.ExperienceConfig;
-import com.gmail.nossr50.datatypes.experience.XPGainReason;
 import com.gmail.nossr50.datatypes.interactions.NotificationType;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;

+ 3 - 2
src/main/java/com/gmail/nossr50/util/ChimaeraWing.java

@@ -2,6 +2,7 @@ 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.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.mcMMO;
@@ -112,7 +113,7 @@ public final class ChimaeraWing {
 
         if (warmup > 0) {
             NotificationManager.sendPlayerInformation(player, NotificationType.ITEM_MESSAGE, "Teleport.Commencing", String.valueOf(warmup));
-            new ChimaeraWingWarmup(mmoPlayer).runTaskLater(mcMMO.p, 20 * warmup);
+            new ChimaeraWingWarmup((McMMOPlayer) mmoPlayer).runTaskLater(mcMMO.p, 20 * warmup);
         }
         else {
             chimaeraExecuteTeleport();
@@ -120,7 +121,7 @@ public final class ChimaeraWing {
     }
 
     public static void chimaeraExecuteTeleport() {
-        Player player = mmoPlayer.getPlayer();
+        Player player = Misc.adaptPlayer(mmoPlayer);
 
         if (Config.getInstance().getChimaeraUseBedSpawn() && player.getBedSpawnLocation() != null) {
             player.teleport(player.getBedSpawnLocation());

+ 1 - 3
src/main/java/com/gmail/nossr50/util/EventUtils.java

@@ -1,8 +1,6 @@
 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.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.datatypes.player.PlayerProfile;
@@ -224,7 +222,7 @@ public final class EventUtils {
         if (isCancelled) {
             PlayerProfile profile = mcMMO.getUserManager().queryPlayer(player);
 
-            profile.getExperienceManager().setSkillLevel(skill, profile.getSkillLevel(skill) - (isLevelUp ? levelsChanged : -levelsChanged));
+            profile.getExperienceHandler().setSkillLevel(skill, profile.getSkillLevel(skill) - (isLevelUp ? levelsChanged : -levelsChanged));
             profile.addXp(skill, xpRemoved);
         }
 

+ 5 - 5
src/main/java/com/gmail/nossr50/util/HardcoreManager.java

@@ -41,8 +41,8 @@ public final class HardcoreManager {
                 continue;
             }
 
-            int playerSkillLevel = playerProfile.getExperienceManager().getSkillLevel(primarySkillType);
-            int playerSkillXpLevel = playerProfile.getExperienceManager().getSkillXpValue(primarySkillType);
+            int playerSkillLevel = playerProfile.getExperienceHandler().getSkillLevel(primarySkillType);
+            int playerSkillXpLevel = playerProfile.getExperienceHandler().getSkillXpValue(primarySkillType);
 
             if (playerSkillLevel <= 0 || playerSkillLevel <= levelThreshold) {
                 levelChanged.put(primarySkillType.toString(), 0);
@@ -93,8 +93,8 @@ public final class HardcoreManager {
                 continue;
             }
 
-            int killerSkillLevel = killerProfile.getExperienceManager().getSkillLevel(primarySkillType);
-            int victimSkillLevel = victimProfile.getExperienceManager().getSkillLevel(primarySkillType);
+            int killerSkillLevel = killerProfile.getExperienceHandler().getSkillLevel(primarySkillType);
+            int victimSkillLevel = victimProfile.getExperienceHandler().getSkillLevel(primarySkillType);
 
             if (victimSkillLevel <= 0 || victimSkillLevel < killerSkillLevel / 2 || victimSkillLevel <= levelThreshold) {
                 levelChanged.put(primarySkillType.toString(), 0);
@@ -102,7 +102,7 @@ public final class HardcoreManager {
                 continue;
             }
 
-            int victimSkillXpLevel = victimProfile.getExperienceManager().getSkillXpValue(primarySkillType);
+            int victimSkillXpLevel = victimProfile.getExperienceHandler().getSkillXpValue(primarySkillType);
 
             double statsStolen = victimSkillLevel * (vampirismStatLeechPercentage * 0.01D);
             int levelsStolen = (int) statsStolen;

+ 5 - 1
src/main/java/com/gmail/nossr50/util/Misc.java

@@ -308,7 +308,7 @@ public final class Misc {
      * @return true if the player is the party leader
      */
     public static boolean isPartyLeader(@NotNull OnlineMMOPlayer mmoPlayer) {
-        return mmoPlayer.getParty().getLeader().getUniqueId().equals(mmoPlayer.getPlayer().getUniqueId());
+        return mcMMO.getPartyManager().queryParty(mmoPlayer.getUUID()).getPartyMemberManager().getPartyLeader().getUniqueId().equals(mmoPlayer.getUUID());
     }
 
 //    public static void spawnExperienceOrb(@NotNull Location location, int orbAmount, int experienceValue) {
@@ -325,6 +325,10 @@ public final class Misc {
         experienceOrb.setExperience(experienceValue);
     }
 
+    public static @NotNull Player adaptPlayer(@NotNull OnlineMMOPlayer onlineMMOPlayer) {
+        return (Player) onlineMMOPlayer.getServerAPIPlayerImpl();
+    }
+
     private static class SpawnOrbTask extends BukkitRunnable {
         private final Location location;
         private int orbExpValue;

+ 2 - 0
src/main/java/com/gmail/nossr50/util/Permissions.java

@@ -7,6 +7,7 @@ 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.mcMMO;
+import com.neetgames.mcmmo.skill.RootSkill;
 import org.bukkit.Material;
 import org.bukkit.Server;
 import org.bukkit.World;
@@ -115,6 +116,7 @@ public final class Permissions {
     public static boolean hasSalvageEnchantBypassPerk(Permissible permissible) { return permissible.hasPermission("mcmmo.perks.bypass.salvageenchant"); }
 
     public static boolean lucky(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.perks.lucky." + skill.toString().toLowerCase(Locale.ENGLISH)); }
+    public static boolean lucky(Permissible permissible, RootSkill rootSkill) { return permissible.hasPermission("mcmmo.perks.lucky." + rootSkill.getSkillName().toLowerCase(Locale.ENGLISH)); }
 
     /* XP PERKS */
     public static boolean quadrupleXp(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.perks.xp.quadruple." + skill.toString().toLowerCase(Locale.ENGLISH)); }

+ 2 - 2
src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java

@@ -79,7 +79,7 @@ public final class CommandUtils {
      */
     public static boolean checkPlayerExistence(CommandSender sender, String playerName, OnlineMMOPlayer mmoPlayer) {
         if (mmoPlayer != null) {
-            if (CommandUtils.hidden(sender, mmoPlayer.getPlayer(), false)) {
+            if (CommandUtils.hidden(sender, Misc.adaptPlayer(mmoPlayer), false)) {
                 sender.sendMessage(LocaleLoader.getString("Commands.Offline"));
                 return false;
             }
@@ -200,7 +200,7 @@ public final class CommandUtils {
         if (skill.isChildSkill()) {
             return LocaleLoader.getString("Skills.ChildStats", LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".Listener") + " ", profile.getSkillLevel(skill));
         }
-        if (profile.getExperienceManager().getSkillLevel(skill) == Config.getInstance().getLevelCap(skill)){
+        if (profile.getExperienceHandler().getSkillLevel(skill) == Config.getInstance().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));

+ 19 - 16
src/main/java/com/gmail/nossr50/util/experience/ExperienceBarWrapper.java

@@ -1,11 +1,14 @@
 package com.gmail.nossr50.util.experience;
 
 import com.gmail.nossr50.config.experience.ExperienceConfig;
+import com.gmail.nossr50.datatypes.player.McMMOPlayer;
+import com.gmail.nossr50.datatypes.skills.CoreSkills;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.util.player.PlayerLevelUtils;
 import com.gmail.nossr50.util.text.StringUtils;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
-import com.neetgames.mcmmo.skill.SkillIdentity;
+import com.neetgames.mcmmo.skill.RootSkill;
+import org.bukkit.Bukkit;
 import org.bukkit.boss.BarColor;
 import org.bukkit.boss.BarStyle;
 import org.bukkit.boss.BossBar;
@@ -19,9 +22,9 @@ import java.util.List;
  */
 public class ExperienceBarWrapper {
 
-    private final @NotNull SkillIdentity skillIdentity; //Primary Skill
+    private final @NotNull RootSkill rootSkill; //Primary Skill
     private @NotNull BossBar bossBar;
-    protected final @NotNull OnlineMMOPlayer onlineMMOPlayer;
+    protected final @NotNull McMMOPlayer mmoPlayer;
     private int lastLevelUpdated;
 
     /*
@@ -30,14 +33,14 @@ public class ExperienceBarWrapper {
     protected String niceSkillName;
     protected String title;
 
-    public ExperienceBarWrapper(@NotNull SkillIdentity skillIdentity, @NotNull OnlineMMOPlayer onlineMMOPlayer) {
-        this.onlineMMOPlayer = onlineMMOPlayer;
-        this.skillIdentity = skillIdentity;
+    public ExperienceBarWrapper(@NotNull RootSkill rootSkill, @NotNull McMMOPlayer mmoPlayer) {
+        this.mmoPlayer = mmoPlayer;
+        this.rootSkill = rootSkill;
         title = "";
         lastLevelUpdated = 0;
 
         //These vars are stored to help reduce operations involving strings
-        niceSkillName = StringUtils.getCapitalized(skillIdentity.toString());
+        niceSkillName = StringUtils.getCapitalized(rootSkill.toString());
 
         //Create the bar
         initBar();
@@ -56,7 +59,7 @@ public class ExperienceBarWrapper {
     private String getTitleTemplate() {
         //If they are using extra details
 
-        if(ExperienceConfig.getInstance().isEarlyGameBoostEnabled() && PlayerLevelUtils.qualifiesForEarlyGameBoost(onlineMMOPlayer, skillIdentity)) {
+        if(ExperienceConfig.getInstance().isEarlyGameBoostEnabled() && PlayerLevelUtils.qualifiesForEarlyGameBoost(mmoPlayer, rootSkill)) {
                 return LocaleLoader.getString("XPBar.Template.EarlyGameBoost");
         } else if(ExperienceConfig.getInstance().getAddExtraDetails())
             return LocaleLoader.getString("XPBar.Complex.Template", LocaleLoader.getString("XPBar."+niceSkillName, getLevel()), getCurrentXP(), getMaxXP(), getPowerLevel(), getPercentageOfLevel());
@@ -65,16 +68,16 @@ public class ExperienceBarWrapper {
     }
 
     private int getLevel() {
-        return onlineMMOPlayer.getSkillLevel(skillIdentity);
+        return mmoPlayer.getSkillLevel(rootSkill);
     }
     private int getCurrentXP() {
-        return onlineMMOPlayer.getSkillExperience(skillIdentity);
+        return mmoPlayer.getSkillExperience(rootSkill);
     }
     private int getMaxXP() {
-        return onlineMMOPlayer.getExperienceToNextLevel(skillIdentity);
+        return mmoPlayer.getExperienceToNextLevel(rootSkill);
     }
-    private int getPowerLevel() { return onlineMMOPlayer.getPowerLevel(); }
-    private int getPercentageOfLevel() { return (int) (onlineMMOPlayer.getProgressInCurrentSkillLevel(skillIdentity) * 100); }
+    private int getPowerLevel() { return mmoPlayer.getPowerLevel(); }
+    private int getPercentageOfLevel() { return (int) (mmoPlayer.getProgressInCurrentSkillLevel(rootSkill) * 100); }
 
     public String getTitle() {
         return bossBar.getTitle();
@@ -111,10 +114,10 @@ public class ExperienceBarWrapper {
             bossBar.setProgress(v);
 
         //Check player level
-        if(ExperienceConfig.getInstance().isEarlyGameBoostEnabled() && PlayerLevelUtils.qualifiesForEarlyGameBoost(mmoPlayer, skillIdentity)) {
+        if(ExperienceConfig.getInstance().isEarlyGameBoostEnabled() && PlayerLevelUtils.qualifiesForEarlyGameBoost(mmoPlayer, rootSkill)) {
            setColor(BarColor.YELLOW);
         } else {
-            setColor(ExperienceConfig.getInstance().getExperienceBarColor(skillIdentity));
+            setColor(ExperienceConfig.getInstance().getExperienceBarColor(rootSkill));
         }
 
         //Every time progress updates we need to check for a title update
@@ -154,7 +157,7 @@ public class ExperienceBarWrapper {
 
     private void createBossBar()
     {
-        bossBar = mmoPlayer.getPlayer().getServer().createBossBar(title, ExperienceConfig.getInstance().getExperienceBarColor(skillIdentity), ExperienceConfig.getInstance().getExperienceBarStyle(skillIdentity));
+        bossBar = Bukkit.getServer().createBossBar(title, ExperienceConfig.getInstance().getExperienceBarColor(rootSkill), ExperienceConfig.getInstance().getExperienceBarStyle(rootSkill));
         bossBar.addPlayer(mmoPlayer.getPlayer());
     }
 }

+ 3 - 5
src/main/java/com/gmail/nossr50/util/experience/ExperienceUtils.java

@@ -1,7 +1,5 @@
 package com.gmail.nossr50.util.experience;
 
-import com.gmail.nossr50.datatypes.experience.XPGainReason;
-import com.gmail.nossr50.datatypes.experience.XPGainSource;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import org.bukkit.plugin.Plugin;
@@ -17,11 +15,11 @@ public class ExperienceUtils {
      * @param xp Experience amount to add
      */
     public static void applyXpGain(@NotNull OnlineMMOPlayer mmoPlayer, @NotNull PrimarySkillType primarySkillType, float xp, @NotNull XPGainReason xpGainReason, @NotNull XPGainSource xpGainSource) {
-        mmoPlayer.getExperienceManager().applyXpGain(primarySkillType, xp, xpGainReason, xpGainSource);
+        mmoPlayer.getExperienceHandler().applyXpGain(primarySkillType, xp, xpGainReason, xpGainSource);
     }
 
     public static void processPostXpEvent(@NotNull OnlineMMOPlayer mmoPlayer, @NotNull PrimarySkillType primarySkillType, @NotNull Plugin plugin, @NotNull XPGainSource xpGainSource) {
-        mmoPlayer.getExperienceManager().processPostXpEvent(primarySkillType, plugin, xpGainSource);
+        mmoPlayer.getExperienceHandler().processPostXpEvent(primarySkillType, plugin, xpGainSource);
     }
 
     /**
@@ -30,6 +28,6 @@ public class ExperienceUtils {
      * @param primarySkillType The skill to check
      */
     public static void updateLevelStats(@NotNull OnlineMMOPlayer mmoPlayer, @NotNull PrimarySkillType primarySkillType, @NotNull XPGainReason xpGainReason, @NotNull XPGainSource xpGainSource) {
-        mmoPlayer.getExperienceManager().updateLevelStats(primarySkillType, xpGainReason, xpGainSource);
+        mmoPlayer.getExperienceHandler().updateLevelStats(primarySkillType, xpGainReason, xpGainSource);
     }
 }

+ 57 - 59
src/main/java/com/gmail/nossr50/util/experience/MMOExperienceBarManager.java

@@ -1,18 +1,17 @@
 package com.gmail.nossr50.util.experience;
 
 import com.gmail.nossr50.config.experience.ExperienceConfig;
+import com.gmail.nossr50.datatypes.player.McMMOPlayer;
+import com.gmail.nossr50.util.Misc;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
-import com.gmail.nossr50.datatypes.skills.CoreSkillConstants;
-import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
+import com.gmail.nossr50.datatypes.skills.CoreSkills;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.runnables.skills.ExperienceBarHideTask;
 import com.gmail.nossr50.util.player.NotificationManager;
 import com.neetgames.mcmmo.skill.*;
 import org.bukkit.plugin.Plugin;
 import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
 
-import java.util.EnumMap;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -21,17 +20,16 @@ import java.util.Map;
  * Each ExperienceBarManager only manages a single player
  */
 public class MMOExperienceBarManager {
-    private final OnlineMMOPlayer mmoPlayer;
+    private final McMMOPlayer mmoPlayer;
 
     int delaySeconds = 3;
 
-    private @NotNull final Map<SkillIdentity, SkillBossBarState> barStateMapRef;
+    private @NotNull final Map<RootSkill, SkillBossBarState> barStateMapRef;
 
-    private @NotNull final HashMap<SkillIdentity, ExperienceBarWrapper> experienceBars;
-    private @NotNull final HashMap<SkillIdentity, ExperienceBarHideTask> experienceBarHideTaskHashMap;
+    private @NotNull final Map<RootSkill, ExperienceBarWrapper> experienceBars;
+    private @NotNull final Map<RootSkill, ExperienceBarHideTask> experienceBarHideTaskHashMap;
 
-
-    public MMOExperienceBarManager(@NotNull OnlineMMOPlayer mmoPlayer, @NotNull Map<SkillIdentity, SkillBossBarState> barStateMapRef)
+    public MMOExperienceBarManager(@NotNull McMMOPlayer mmoPlayer, @NotNull Map<RootSkill, SkillBossBarState> barStateMapRef)
     {
         this.mmoPlayer = mmoPlayer;
         this.barStateMapRef = barStateMapRef;
@@ -48,8 +46,8 @@ public class MMOExperienceBarManager {
     }
 
     private void syncBarStates() {
-        for(Map.Entry<SkillIdentity, SkillBossBarState> entry : barStateMapRef.entrySet()) {
-            SkillIdentity key = entry.getKey();
+        for(Map.Entry<RootSkill, SkillBossBarState> entry : barStateMapRef.entrySet()) {
+            RootSkill key = entry.getKey();
             SkillBossBarState barState = entry.getValue();
 
             switch(barState) {
@@ -67,130 +65,130 @@ public class MMOExperienceBarManager {
         barStateMapRef.putAll(generateDefaultBarStateMap());
     }
 
-    public void updateExperienceBar(@NotNull SkillIdentity skillIdentity, @NotNull Plugin plugin)
+    public void updateExperienceBar(@NotNull RootSkill rootSkill, @NotNull Plugin plugin)
     {
-        if(isBarDisabled(skillIdentity))
+        if(isBarDisabled(rootSkill))
             return;
 
         //Init Bar
-        if(experienceBars.get(skillIdentity) == null)
-            experienceBars.put(skillIdentity, new ExperienceBarWrapper(skillIdentity, mmoPlayer.getPersistentPlayerData()));
+        if(experienceBars.get(rootSkill) == null)
+            experienceBars.put(rootSkill, new ExperienceBarWrapper(rootSkill, mmoPlayer));
 
         //Get Bar
-        ExperienceBarWrapper experienceBarWrapper = experienceBars.get(skillIdentity);
+        ExperienceBarWrapper experienceBarWrapper = experienceBars.get(rootSkill);
 
         //Update Progress
-        experienceBarWrapper.setProgress(mmoPlayer.getExperienceManager().getProgressInCurrentSkillLevel(skillIdentity));
+        experienceBarWrapper.setProgress(mmoPlayer.getExperienceHandler().getProgressInCurrentSkillLevel(rootSkill));
 
         //Show Bar
         experienceBarWrapper.showExperienceBar();
 
         //Setup Hide Bar Task
-        if(experienceBarHideTaskHashMap.get(skillIdentity) != null)
+        if(experienceBarHideTaskHashMap.get(rootSkill) != null)
         {
-            experienceBarHideTaskHashMap.get(skillIdentity).cancel();
+            experienceBarHideTaskHashMap.get(rootSkill).cancel();
         }
 
-        scheduleHideTask(skillIdentity, plugin);
+        scheduleHideTask(rootSkill, plugin);
     }
 
-    private boolean isBarDisabled(PrimarySkillType primarySkillType) {
-        return barStateMapRef.get(primarySkillType) == BarState.DISABLED
+    private boolean isBarDisabled(@NotNull RootSkill rootSkill) {
+        return barStateMapRef.get(rootSkill) == SkillBossBarState.DISABLED
                 //Config checks
                 || !ExperienceConfig.getInstance().isExperienceBarsEnabled()
-                || !ExperienceConfig.getInstance().isExperienceBarEnabled(primarySkillType);
+                || !ExperienceConfig.getInstance().isExperienceBarEnabled(rootSkill);
     }
 
-    private boolean isBarAlwaysVisible(PrimarySkillType primarySkillType) {
-        return barStateMapRef.get(primarySkillType) == BarState.ALWAYS_ON;
+    private boolean isBarAlwaysVisible(@NotNull RootSkill rootSkill) {
+        return barStateMapRef.get(rootSkill) == SkillBossBarState.ALWAYS_ON;
     }
 
-    private void scheduleHideTask(PrimarySkillType primarySkillType, Plugin plugin) {
-        if(isBarAlwaysVisible(primarySkillType))
+    private void scheduleHideTask(@NotNull RootSkill rootSkill, @NotNull Plugin plugin) {
+        if(isBarAlwaysVisible(rootSkill))
             return;
 
-        ExperienceBarHideTask experienceBarHideTask = new ExperienceBarHideTask(this, mmoPlayer, primarySkillType);
-        experienceBarHideTask.runTaskLater(plugin, 20* delaySeconds);
-        experienceBarHideTaskHashMap.put(primarySkillType, experienceBarHideTask);
+        ExperienceBarHideTask experienceBarHideTask = new ExperienceBarHideTask(this, mmoPlayer, rootSkill);
+        experienceBarHideTask.runTaskLater(plugin, 20 * delaySeconds);
+        experienceBarHideTaskHashMap.put(rootSkill, experienceBarHideTask);
     }
 
-    public void hideExperienceBar(PrimarySkillType primarySkillType)
+    public void hideExperienceBar(@NotNull RootSkill rootSkill)
     {
-        if(experienceBars.containsKey(primarySkillType))
-            experienceBars.get(primarySkillType).hideExperienceBar();
+        if(experienceBars.containsKey(rootSkill))
+            experienceBars.get(rootSkill).hideExperienceBar();
     }
 
-    public void clearTask(PrimarySkillType primarySkillType)
+    public void clearTask(@NotNull RootSkill rootSkill)
     {
-        experienceBarHideTaskHashMap.remove(primarySkillType);
+        experienceBarHideTaskHashMap.remove(rootSkill);
     }
 
     public void disableAllBars() {
-        for(PrimarySkillType primarySkillType : PrimarySkillType.values()) {
-            xpBarSettingToggle(XPBarSettingTarget.HIDE, primarySkillType);
+        for(RootSkill rootSkill : mcMMO.p.getSkillRegister().getRootSkills()) {
+            xpBarSettingToggle(SkillBossBarSetting.HIDE, rootSkill);
         }
 
-        NotificationManager.sendPlayerInformationChatOnlyPrefixed(mmoPlayer.getPlayer(), "Commands.XPBar.DisableAll");
+        NotificationManager.sendPlayerInformationChatOnlyPrefixed(Misc.adaptPlayer(mmoPlayer), "Commands.XPBar.DisableAll");
     }
 
-    public void xpBarSettingToggle(@NotNull SkillBossBarSetting skillBossBarSetting, @Nullable SkillIdentity skillIdentity) {
+    public void xpBarSettingToggle(@NotNull SkillBossBarSetting skillBossBarSetting, @NotNull RootSkill rootSkill) {
         switch(skillBossBarSetting) {
             case SHOW:
-                barStateMapRef.put(skillIdentity, SkillBossBarState.ALWAYS_ON);
+                barStateMapRef.put(rootSkill, SkillBossBarState.ALWAYS_ON);
 
                 //Remove lingering tasks
-                if(experienceBarHideTaskHashMap.containsKey(skillIdentity)) {
-                    experienceBarHideTaskHashMap.get(skillIdentity).cancel();
+                if(experienceBarHideTaskHashMap.containsKey(rootSkill)) {
+                    experienceBarHideTaskHashMap.get(rootSkill).cancel();
                 }
 
-                updateExperienceBar(skillIdentity, mcMMO.p);
+                updateExperienceBar(rootSkill, mcMMO.p);
                 break;
             case HIDE:
-                barStateMapRef.put(skillIdentity, SkillBossBarState.DISABLED);
+                barStateMapRef.put(rootSkill, SkillBossBarState.DISABLED);
 
                 //Remove lingering tasks
-                if(experienceBarHideTaskHashMap.containsKey(skillIdentity)) {
-                    experienceBarHideTaskHashMap.get(skillIdentity).cancel();
+                if(experienceBarHideTaskHashMap.containsKey(rootSkill)) {
+                    experienceBarHideTaskHashMap.get(rootSkill).cancel();
                 }
 
-                hideExperienceBar(skillIdentity);
+                hideExperienceBar(rootSkill);
                 break;
             case RESET:
                 resetBarSettings();
                 break;
         }
 
-        informPlayer(skillBossBarSetting, skillIdentity);
+        informPlayer(skillBossBarSetting, rootSkill);
     }
 
     private void resetBarSettings() {
         barStateMapRef.putAll(generateDefaultBarStateMap());
     }
 
-    private void informPlayer(@NotNull SkillBossBarSetting settingTarget, @Nullable PrimarySkillType skillType) {
+    private void informPlayer(@NotNull SkillBossBarSetting settingTarget, @NotNull RootSkill rootSkill) {
         //Inform player of setting change
         if(settingTarget != SkillBossBarSetting.RESET) {
-            NotificationManager.sendPlayerInformationChatOnlyPrefixed(mmoPlayer.getPlayer(), "Commands.XPBar.SettingChanged", skillType.getName(), settingTarget.toString());
+            NotificationManager.sendPlayerInformationChatOnlyPrefixed(Misc.adaptPlayer(mmoPlayer), "Commands.XPBar.SettingChanged", rootSkill.getSkillName(), settingTarget.toString());
         } else {
-            NotificationManager.sendPlayerInformationChatOnlyPrefixed(mmoPlayer.getPlayer(), "Commands.XPBar.Reset");
+            NotificationManager.sendPlayerInformationChatOnlyPrefixed(Misc.adaptPlayer(mmoPlayer), "Commands.XPBar.Reset");
         }
     }
 
-    public static @NotNull HashMap<SkillIdentity, SkillBossBarState> generateDefaultBarStateMap() {
-        HashMap<SkillIdentity, SkillBossBarState> barStateMap = new HashMap<>();
+    public static @NotNull Map<RootSkill, SkillBossBarState> generateDefaultBarStateMap() {
+        HashMap<RootSkill, SkillBossBarState> barStateMap = new HashMap<>();
 
         setBarStateDefaults(barStateMap);
 
         return barStateMap;
     }
 
-    public static void setBarStateDefaults(HashMap<SkillIdentity, SkillBossBarState> barStateHashMap) {
-        for(RootSkill rootSkill : CoreSkillConstants.getImmutableCoreRootSkillSet()) {
+    public static void setBarStateDefaults(@NotNull Map<RootSkill, SkillBossBarState> barStateHashMap) {
+        for(RootSkill rootSkill : CoreSkills.getImmutableCoreRootSkillSet()) {
 
-            if(CoreSkillConstants.isChildSkill(rootSkill.getSkillIdentity())) {
-                barStateHashMap.put(rootSkill.getSkillIdentity(), SkillBossBarState.DISABLED);
+            if(CoreSkills.isChildSkill(rootSkill)) {
+                barStateHashMap.put(rootSkill, SkillBossBarState.DISABLED);
             } else {
-                barStateHashMap.put(rootSkill.getSkillIdentity(), SkillBossBarState.NORMAL);
+                barStateHashMap.put(rootSkill, SkillBossBarState.NORMAL);
             }
         }
     }

+ 4 - 4
src/main/java/com/gmail/nossr50/util/input/AbilityActivationProcessor.java

@@ -31,7 +31,7 @@ public class AbilityActivationProcessor {
 
     public AbilityActivationProcessor(OnlineMMOPlayer mmoPlayer) {
         this.mmoPlayer = mmoPlayer;
-        this.player = mmoPlayer.getPlayer();
+        this.player = Misc.adaptPlayer(mmoPlayer);
     }
 
     /**
@@ -98,7 +98,7 @@ public class AbilityActivationProcessor {
         }
 
         /* GREEN THUMB CHECK */
-        HerbalismManager herbalismManager = mmoPlayer.getHerbalismManager();
+        HerbalismManager herbalismManager = ((McMMOPlayer) (mmoPlayer)).getHerbalismManager();
 
         if (getHeldItem().getType() == Material.BONE_MEAL) {
             switch (blockState.getType()) {
@@ -157,7 +157,7 @@ public class AbilityActivationProcessor {
         //TODO: This is strange, why is this needed?
         //TODO: This is strange, why is this needed?
         /* BLAST MINING CHECK */
-        MiningManager miningManager = mmoPlayer.getMiningManager();
+        MiningManager miningManager = ((McMMOPlayer) (mmoPlayer)).getMiningManager();
         if (miningManager.canDetonate()) {
             miningManager.remoteDetonation();
         }
@@ -178,7 +178,7 @@ public class AbilityActivationProcessor {
 
         /* CALL OF THE WILD CHECKS */
         Material type = getHeldItem().getType();
-        TamingManager tamingManager = mmoPlayer.getTamingManager();
+        TamingManager tamingManager = ((McMMOPlayer) (mmoPlayer)).getTamingManager();
 
         if (type == Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.WOLF.getConfigEntityTypeEntry())) {
             tamingManager.summonWolf();

+ 10 - 10
src/main/java/com/gmail/nossr50/util/input/SuperAbilityManager.java

@@ -3,8 +3,8 @@ package com.gmail.nossr50.util.input;
 import com.gmail.nossr50.config.AdvancedConfig;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.datatypes.interactions.NotificationType;
-import com.neetgames.mcmmo.player.OnlineMMOPlayer;
-import com.gmail.nossr50.datatypes.player.PersistentPlayerData;
+import com.gmail.nossr50.datatypes.player.McMMOPlayer;
+import com.neetgames.mcmmo.player.MMOPlayerData;
 import com.gmail.nossr50.datatypes.skills.AbilityToolType;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.SuperAbilityType;
@@ -28,7 +28,7 @@ import java.util.Map;
 
 public class SuperAbilityManager {
 
-    private final OnlineMMOPlayer mmoPlayer;
+    private final McMMOPlayer mmoPlayer;
     private final Player player;
 
     private final Map<SuperAbilityType, Boolean> superAbilityState = new HashMap<>();
@@ -37,12 +37,12 @@ public class SuperAbilityManager {
     private boolean abilityActivationPermission = true;
 
     private final Map<AbilityToolType, Boolean> toolMode = new HashMap<>();
-    private final PersistentPlayerData persistentPlayerData;
+    private final MMOPlayerData mmoPlayerData;
 
-    public SuperAbilityManager(@NotNull OnlineMMOPlayer mmoPlayer, @NotNull PersistentPlayerData persistentPlayerData) {
+    public SuperAbilityManager(@NotNull McMMOPlayer mmoPlayer, @NotNull MMOPlayerData mmoPlayerData) {
         this.mmoPlayer = mmoPlayer;
-        this.persistentPlayerData = persistentPlayerData;
-        this.player = mmoPlayer.getPlayer();
+        this.mmoPlayerData = mmoPlayerData;
+        this.player = Misc.adaptPlayer(mmoPlayer);
 
         for (SuperAbilityType superAbilityType : SuperAbilityType.values()) {
             superAbilityState.put(superAbilityType, false);
@@ -55,7 +55,7 @@ public class SuperAbilityManager {
     }
 
     public void processAbilityActivation(PrimarySkillType skill) {
-        Player player = mmoPlayer.getPlayer();
+        Player player = Misc.adaptPlayer(mmoPlayer);
 
         if (!skill.getPermissions(player)) {
             return;
@@ -243,7 +243,7 @@ public class SuperAbilityManager {
     }
 
     public void resetCooldowns() {
-        this.persistentPlayerData.resetCooldowns();
+        this.mmoPlayerData.resetCooldowns();
     }
 
     /**
@@ -336,7 +336,7 @@ public class SuperAbilityManager {
      */
     public int calculateTimeRemaining(SuperAbilityType superAbilityType) {
         long deactivatedTimestamp = mmoPlayer.getAbilityDATS(superAbilityType) * Misc.TIME_CONVERSION_FACTOR;
-        return (int) (((deactivatedTimestamp + (PerksUtils.handleCooldownPerks(mmoPlayer.getPlayer(), superAbilityType.getCooldown()) * Misc.TIME_CONVERSION_FACTOR)) - System.currentTimeMillis()) / Misc.TIME_CONVERSION_FACTOR);
+        return (int) (((deactivatedTimestamp + (PerksUtils.handleCooldownPerks(Misc.adaptPlayer(mmoPlayer), superAbilityType.getCooldown()) * Misc.TIME_CONVERSION_FACTOR)) - System.currentTimeMillis()) / Misc.TIME_CONVERSION_FACTOR);
     }
 
 }

+ 24 - 20
src/main/java/com/gmail/nossr50/util/player/NotificationManager.java

@@ -4,8 +4,9 @@ import com.gmail.nossr50.config.AdvancedConfig;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.datatypes.interactions.NotificationType;
 import com.gmail.nossr50.datatypes.notifications.SensitiveCommandType;
+import com.gmail.nossr50.datatypes.skills.CoreSkills;
+import com.gmail.nossr50.util.Misc;
 import com.neetgames.mcmmo.player.OnlineMMOPlayer;
-import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.events.skills.McMMOPlayerNotificationEvent;
 import com.gmail.nossr50.locale.LocaleLoader;
@@ -15,6 +16,7 @@ import com.gmail.nossr50.util.sounds.SoundManager;
 import com.gmail.nossr50.util.sounds.SoundType;
 import com.gmail.nossr50.util.text.McMMOMessageType;
 import com.gmail.nossr50.util.text.TextComponentFactory;
+import com.neetgames.mcmmo.skill.RootSkill;
 import net.kyori.adventure.audience.Audience;
 import net.kyori.adventure.audience.MessageType;
 import net.kyori.adventure.identity.Identity;
@@ -71,16 +73,15 @@ public class NotificationManager {
      * @param key Locale Key for the string to use with this event
      * @param values values to be injected into the locale string
      */
-    public static void sendNearbyPlayersInformation(@NotNull Player targetPlayer, @NotNull NotificationType notificationType, @NotNull String key, String... values)
-    {
+    public static void sendNearbyPlayersInformation(@NotNull Player targetPlayer, @NotNull NotificationType notificationType, @NotNull String key, String... values) {
         sendPlayerInformation(targetPlayer, notificationType, key, values);
     }
 
-    public static void sendPlayerInformationChatOnly(@NotNull Player player, @NotNull String key, String... values)
-    {
+    public static void sendPlayerInformationChatOnly(@NotNull Player player, @NotNull String key, String... values) {
         OnlineMMOPlayer mmoPlayer = mcMMO.getUserManager().queryPlayer(player);
 
-        if(mmoPlayer == null || !mmoPlayer.hasSkillChatNotifications())
+        //Don't send chat notifications if they are disabled
+        if(mmoPlayer != null && !mmoPlayer.hasSkillChatNotifications())
             return;
 
         String preColoredString = LocaleLoader.getString(key, (Object[]) values);
@@ -91,7 +92,8 @@ public class NotificationManager {
     {
         OnlineMMOPlayer mmoPlayer = mcMMO.getUserManager().queryPlayer(player);
 
-        if(mmoPlayer == null || !mmoPlayer.hasSkillChatNotifications())
+        //Don't send chat notifications if they are disabled
+        if(mmoPlayer != null && !mmoPlayer.hasSkillChatNotifications())
             return;
 
         String preColoredString = LocaleLoader.getString(key, (Object[]) values);
@@ -99,9 +101,11 @@ public class NotificationManager {
         player.sendMessage(prefixFormattedMessage);
     }
 
-    public static void sendPlayerInformation(@NotNull Player player, @NotNull NotificationType notificationType, @NotNull String key, String... values)
-    {
-        if(mcMMO.getUserManager().queryPlayer(player) == null || !mcMMO.getUserManager().queryPlayer(player).hasSkillChatNotifications())
+    public static void sendPlayerInformation(@NotNull Player player, @NotNull NotificationType notificationType, @NotNull String key, String... values) {
+        OnlineMMOPlayer mmoPlayer = mcMMO.getUserManager().queryPlayer(player);
+
+        //Don't send chat notifications if they are disabled
+        if(mmoPlayer != null && !mmoPlayer.hasSkillChatNotifications())
             return;
 
         McMMOMessageType destination = AdvancedConfig.getInstance().doesNotificationUseActionBar(notificationType) ? McMMOMessageType.ACTION_BAR : McMMOMessageType.SYSTEM;
@@ -133,7 +137,7 @@ public class NotificationManager {
         }
     }
 
-    private static McMMOPlayerNotificationEvent checkNotificationEvent(Player player, NotificationType notificationType, McMMOMessageType destination, Component message) {
+    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));
@@ -146,20 +150,20 @@ public class NotificationManager {
     /**
      * Handles sending level up notifications to a mmoPlayer
      * @param mmoPlayer target mmoPlayer
-     * @param skillName skill that leveled up
+     * @param rootSkill skill that leveled up
      * @param newLevel new level of that skill
      */
-    public static void sendPlayerLevelUpNotification(OnlineMMOPlayer mmoPlayer, PrimarySkillType skillName, int levelsGained, int newLevel)
+    public static void sendPlayerLevelUpNotification(@NotNull OnlineMMOPlayer mmoPlayer, @NotNull RootSkill rootSkill, int levelsGained, int newLevel)
     {
         if(!mmoPlayer.hasSkillChatNotifications())
             return;
 
         McMMOMessageType destination = AdvancedConfig.getInstance().doesNotificationUseActionBar(NotificationType.LEVEL_UP_MESSAGE) ? McMMOMessageType.ACTION_BAR : McMMOMessageType.SYSTEM;
 
-        Component levelUpTextComponent = TextComponentFactory.getNotificationLevelUpTextComponent(skillName, levelsGained, newLevel);
-        McMMOPlayerNotificationEvent customEvent = checkNotificationEvent(mmoPlayer.getPlayer(), NotificationType.LEVEL_UP_MESSAGE, destination, levelUpTextComponent);
+        Component levelUpTextComponent = TextComponentFactory.getNotificationLevelUpTextComponent(CoreSkills.getSkill(rootSkill), levelsGained, newLevel);
+        McMMOPlayerNotificationEvent customEvent = checkNotificationEvent(Misc.adaptPlayer(mmoPlayer), NotificationType.LEVEL_UP_MESSAGE, destination, levelUpTextComponent);
 
-        sendNotification(mmoPlayer.getPlayer(), customEvent);
+        sendNotification(Misc.adaptPlayer(mmoPlayer), customEvent);
     }
 
     public static void broadcastTitle(@NotNull Server server, @NotNull String title, @NotNull String subtitle, int i1, int i2, int i3)
@@ -176,16 +180,16 @@ public class NotificationManager {
             return;
 
         //CHAT MESSAGE
-        mcMMO.getAudiences().player(mmoPlayer.getPlayer()).sendMessage(Identity.nil(), TextComponentFactory.getSubSkillUnlockedNotificationComponents(mmoPlayer, subSkillType));
+        mcMMO.getAudiences().player(Misc.adaptPlayer(mmoPlayer)).sendMessage(Identity.nil(), TextComponentFactory.getSubSkillUnlockedNotificationComponents(mmoPlayer, subSkillType));
 
         //Unlock Sound Effect
-        SoundManager.sendCategorizedSound(mmoPlayer.getPlayer(), mmoPlayer.getPlayer().getLocation(), SoundType.SKILL_UNLOCKED, SoundCategory.MASTER);
+        SoundManager.sendCategorizedSound(Misc.adaptPlayer(mmoPlayer), Misc.adaptPlayer(mmoPlayer).getLocation(), SoundType.SKILL_UNLOCKED, SoundCategory.MASTER);
 
         //ACTION BAR MESSAGE
         /*if(AdvancedConfig.getInstance().doesNotificationUseActionBar(NotificationType.SUBSKILL_UNLOCKED))
-            mmoPlayer.getPlayer().spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(LocaleLoader.getString("JSON.SkillUnlockMessage",
+            Misc.adaptPlayer(mmoPlayer).spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(LocaleLoader.getString("JSON.SkillUnlockMessage",
                     subSkillType.getLocaleName(),
-                    String.valueOf(RankUtils.getRank(mmoPlayer.getPlayer(),
+                    String.valueOf(RankUtils.getRank(Misc.adaptPlayer(mmoPlayer),
                             subSkillType)))));*/
     }
 

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است