Browse Source

WIP of reworking classes involved in querying data, also some work done to the party code rewrite

nossr50 4 years ago
parent
commit
cf245b02a5
62 changed files with 636 additions and 637 deletions
  1. 4 1
      Changelog.txt
  2. 16 16
      src/main/java/com/gmail/nossr50/api/AbilityAPI.java
  3. 1 1
      src/main/java/com/gmail/nossr50/api/DatabaseAPI.java
  4. 3 3
      src/main/java/com/gmail/nossr50/api/ExperienceAPI.java
  5. 9 9
      src/main/java/com/gmail/nossr50/api/PartyAPI.java
  6. 4 0
      src/main/java/com/gmail/nossr50/api/exceptions/NullPartyException.java
  7. 7 0
      src/main/java/com/gmail/nossr50/api/exceptions/ProfileRetrievalException.java
  8. 1 1
      src/main/java/com/gmail/nossr50/commands/McnotifyCommand.java
  9. 70 52
      src/main/java/com/gmail/nossr50/commands/chat/ChatCommand.java
  10. 1 1
      src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java
  11. 9 4
      src/main/java/com/gmail/nossr50/commands/database/DatabaseRemovePlayerCommand.java
  12. 2 2
      src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java
  13. 2 2
      src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java
  14. 2 2
      src/main/java/com/gmail/nossr50/commands/party/PartyAcceptCommand.java
  15. 2 2
      src/main/java/com/gmail/nossr50/commands/party/PartyChangeOwnerCommand.java
  16. 2 2
      src/main/java/com/gmail/nossr50/commands/party/PartyChangePasswordCommand.java
  17. 4 4
      src/main/java/com/gmail/nossr50/commands/party/PartyCommand.java
  18. 2 2
      src/main/java/com/gmail/nossr50/commands/party/PartyCreateCommand.java
  19. 2 2
      src/main/java/com/gmail/nossr50/commands/party/PartyDisbandCommand.java
  20. 2 2
      src/main/java/com/gmail/nossr50/commands/party/PartyInfoCommand.java
  21. 2 2
      src/main/java/com/gmail/nossr50/commands/party/PartyInviteCommand.java
  22. 3 3
      src/main/java/com/gmail/nossr50/commands/party/PartyKickCommand.java
  23. 2 2
      src/main/java/com/gmail/nossr50/commands/party/PartyRenameCommand.java
  24. 2 2
      src/main/java/com/gmail/nossr50/commands/party/PartyXpShareCommand.java
  25. 2 2
      src/main/java/com/gmail/nossr50/commands/party/teleport/PtpAcceptCommand.java
  26. 8 8
      src/main/java/com/gmail/nossr50/commands/party/teleport/PtpCommand.java
  27. 1 1
      src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java
  28. 1 1
      src/main/java/com/gmail/nossr50/commands/skills/RepairCommand.java
  29. 1 1
      src/main/java/com/gmail/nossr50/commands/skills/UnarmedCommand.java
  30. 37 0
      src/main/java/com/gmail/nossr50/database/AbstractDatabaseManager.java
  31. 39 16
      src/main/java/com/gmail/nossr50/database/DatabaseManager.java
  32. 154 228
      src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java
  33. 16 27
      src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java
  34. 0 8
      src/main/java/com/gmail/nossr50/datatypes/party/PartyFeature.java
  35. 4 5
      src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java
  36. 12 12
      src/main/java/com/gmail/nossr50/listeners/BlockListener.java
  37. 15 15
      src/main/java/com/gmail/nossr50/listeners/EntityListener.java
  38. 6 6
      src/main/java/com/gmail/nossr50/listeners/InventoryListener.java
  39. 20 20
      src/main/java/com/gmail/nossr50/listeners/PlayerListener.java
  40. 3 3
      src/main/java/com/gmail/nossr50/listeners/SelfListener.java
  41. 19 10
      src/main/java/com/gmail/nossr50/party/PartyManager.java
  42. 1 1
      src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java
  43. 18 20
      src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java
  44. 2 2
      src/main/java/com/gmail/nossr50/runnables/skills/AlchemyBrewTask.java
  45. 3 3
      src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyPotionBrewer.java
  46. 2 2
      src/main/java/com/gmail/nossr50/skills/mining/BlastMining.java
  47. 2 2
      src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java
  48. 1 1
      src/main/java/com/gmail/nossr50/util/ChimaeraWing.java
  49. 12 12
      src/main/java/com/gmail/nossr50/util/EventUtils.java
  50. 5 5
      src/main/java/com/gmail/nossr50/util/HardcoreManager.java
  51. 1 1
      src/main/java/com/gmail/nossr50/util/HolidayManager.java
  52. 2 2
      src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java
  53. 5 5
      src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java
  54. 6 6
      src/main/java/com/gmail/nossr50/util/player/NotificationManager.java
  55. 12 0
      src/main/java/com/gmail/nossr50/util/player/PartyUtils.java
  56. 50 73
      src/main/java/com/gmail/nossr50/util/player/UserManager.java
  57. 2 2
      src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java
  58. 14 14
      src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java
  59. 2 2
      src/main/java/com/gmail/nossr50/util/skills/PerksUtils.java
  60. 1 1
      src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java
  61. 2 2
      src/main/java/com/gmail/nossr50/util/skills/SmeltingTracker.java
  62. 1 1
      src/main/resources/locale/locale_en_US.properties

+ 4 - 1
Changelog.txt

@@ -29,7 +29,6 @@ Version 2.2.000
     New permission node 'mcmmo.ability.crossbows.crossbowslimitbreak'
     New permission node 'mcmmo.ability.crossbows.coneofdeath'
 
-
     The Party system has some new features, and a lot of bad features were removed completely, read the notes
     Parties can no longer have passwords (see notes)
     Parties can no longer be locked (see notes)
@@ -63,6 +62,10 @@ Version 2.2.000
     Added new locale string 'Crossbows.SubSkill.CrossbowsLimitBreak.Description'
     Added new locale string 'Crossbows.SubSkill.CrossbowsLimitBreak.Stat'
 
+    Added new locale string 'Commands.MissingProfile'
+    Removed locale string 'Commands.Offline'
+
+
     Player Power Levels no longer need to pass permission checks when summing skills
     Minor improvements to how player data is serialized
     SMP mod settings removed from config.yml (this is a legacy feature and didn't really do anything anymore)

+ 16 - 16
src/main/java/com/gmail/nossr50/api/AbilityAPI.java

@@ -11,35 +11,35 @@ public final class AbilityAPI {
     private AbilityAPI() {}
 
     public static boolean berserkEnabled(Player player) {
-        return mcMMO.getUserManager().getPlayer(player).getSuperAbilityManager().getAbilityMode(SuperAbilityType.BERSERK);
+        return mcMMO.getUserManager().queryMcMMOPlayer(player).getSuperAbilityManager().getAbilityMode(SuperAbilityType.BERSERK);
     }
 
     public static boolean gigaDrillBreakerEnabled(Player player) {
-        return mcMMO.getUserManager().getPlayer(player).getSuperAbilityManager().getAbilityMode(SuperAbilityType.GIGA_DRILL_BREAKER);
+        return mcMMO.getUserManager().queryMcMMOPlayer(player).getSuperAbilityManager().getAbilityMode(SuperAbilityType.GIGA_DRILL_BREAKER);
     }
 
     public static boolean greenTerraEnabled(Player player) {
-        return mcMMO.getUserManager().getPlayer(player).getSuperAbilityManager().getAbilityMode(SuperAbilityType.GREEN_TERRA);
+        return mcMMO.getUserManager().queryMcMMOPlayer(player).getSuperAbilityManager().getAbilityMode(SuperAbilityType.GREEN_TERRA);
     }
 
     public static boolean serratedStrikesEnabled(Player player) {
-        return mcMMO.getUserManager().getPlayer(player).getSuperAbilityManager().getAbilityMode(SuperAbilityType.SERRATED_STRIKES);
+        return mcMMO.getUserManager().queryMcMMOPlayer(player).getSuperAbilityManager().getAbilityMode(SuperAbilityType.SERRATED_STRIKES);
     }
 
     public static boolean skullSplitterEnabled(Player player) {
-        return mcMMO.getUserManager().getPlayer(player).getSuperAbilityManager().getAbilityMode(SuperAbilityType.SKULL_SPLITTER);
+        return mcMMO.getUserManager().queryMcMMOPlayer(player).getSuperAbilityManager().getAbilityMode(SuperAbilityType.SKULL_SPLITTER);
     }
 
     public static boolean superBreakerEnabled(Player player) {
-        return mcMMO.getUserManager().getPlayer(player).getSuperAbilityManager().getAbilityMode(SuperAbilityType.SUPER_BREAKER);
+        return mcMMO.getUserManager().queryMcMMOPlayer(player).getSuperAbilityManager().getAbilityMode(SuperAbilityType.SUPER_BREAKER);
     }
 
     public static boolean treeFellerEnabled(Player player) {
-        return mcMMO.getUserManager().getPlayer(player).getSuperAbilityManager().getAbilityMode(SuperAbilityType.TREE_FELLER);
+        return mcMMO.getUserManager().queryMcMMOPlayer(player).getSuperAbilityManager().getAbilityMode(SuperAbilityType.TREE_FELLER);
     }
 
     public static boolean isAnyAbilityEnabled(Player player) {
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
         for (SuperAbilityType ability : SuperAbilityType.values()) {
             if (mmoPlayer.getSuperAbilityManager().getAbilityMode(ability)) {
@@ -51,35 +51,35 @@ public final class AbilityAPI {
     }
 
     public static void resetCooldowns(Player player) {
-        mcMMO.getUserManager().getPlayer(player).getPersistentPlayerData().resetCooldowns();
+        mcMMO.getUserManager().queryMcMMOPlayer(player).getPersistentPlayerData().resetCooldowns();
     }
 
     public static void setBerserkCooldown(Player player, long cooldown) {
-        mcMMO.getUserManager().getPlayer(player).getPersistentPlayerData().setAbilityDATS(SuperAbilityType.BERSERK, cooldown);
+        mcMMO.getUserManager().queryMcMMOPlayer(player).getPersistentPlayerData().setAbilityDATS(SuperAbilityType.BERSERK, cooldown);
     }
 
     public static void setGigaDrillBreakerCooldown(Player player, long cooldown) {
-        mcMMO.getUserManager().getPlayer(player).getPersistentPlayerData().setAbilityDATS(SuperAbilityType.GIGA_DRILL_BREAKER, cooldown);
+        mcMMO.getUserManager().queryMcMMOPlayer(player).getPersistentPlayerData().setAbilityDATS(SuperAbilityType.GIGA_DRILL_BREAKER, cooldown);
     }
 
     public static void setGreenTerraCooldown(Player player, long cooldown) {
-        mcMMO.getUserManager().getPlayer(player).getPersistentPlayerData().setAbilityDATS(SuperAbilityType.GREEN_TERRA, cooldown);
+        mcMMO.getUserManager().queryMcMMOPlayer(player).getPersistentPlayerData().setAbilityDATS(SuperAbilityType.GREEN_TERRA, cooldown);
     }
 
     public static void setSerratedStrikesCooldown(Player player, long cooldown) {
-        mcMMO.getUserManager().getPlayer(player).getPersistentPlayerData().setAbilityDATS(SuperAbilityType.SERRATED_STRIKES, cooldown);
+        mcMMO.getUserManager().queryMcMMOPlayer(player).getPersistentPlayerData().setAbilityDATS(SuperAbilityType.SERRATED_STRIKES, cooldown);
     }
 
     public static void setSkullSplitterCooldown(Player player, long cooldown) {
-        mcMMO.getUserManager().getPlayer(player).getPersistentPlayerData().setAbilityDATS(SuperAbilityType.SKULL_SPLITTER, cooldown);
+        mcMMO.getUserManager().queryMcMMOPlayer(player).getPersistentPlayerData().setAbilityDATS(SuperAbilityType.SKULL_SPLITTER, cooldown);
     }
 
     public static void setSuperBreakerCooldown(Player player, long cooldown) {
-        mcMMO.getUserManager().getPlayer(player).getPersistentPlayerData().setAbilityDATS(SuperAbilityType.SUPER_BREAKER, cooldown);
+        mcMMO.getUserManager().queryMcMMOPlayer(player).getPersistentPlayerData().setAbilityDATS(SuperAbilityType.SUPER_BREAKER, cooldown);
     }
 
     public static void setTreeFellerCooldown(Player player, long cooldown) {
-        mcMMO.getUserManager().getPlayer(player).getPersistentPlayerData().setAbilityDATS(SuperAbilityType.TREE_FELLER, cooldown);
+        mcMMO.getUserManager().queryMcMMOPlayer(player).getPersistentPlayerData().setAbilityDATS(SuperAbilityType.TREE_FELLER, cooldown);
     }
 
     public static boolean isBleeding(LivingEntity entity) {

+ 1 - 1
src/main/java/com/gmail/nossr50/api/DatabaseAPI.java

@@ -22,7 +22,7 @@ public class DatabaseAPI {
      * @return true if the player exists in the DB, false if they do not
      */
     public boolean doesPlayerExistInDB(UUID uuid) {
-        PlayerProfile playerProfile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid);
+        PlayerProfile playerProfile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(uuid);
 
         return playerProfile.isLoaded();
     }

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

@@ -1144,7 +1144,7 @@ public final class ExperienceAPI {
     }
 
     private static PlayerProfile getOfflineProfile(UUID uuid) {
-        PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid);
+        PlayerProfile profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(uuid);
 
         if (profile == null) {
             throw new InvalidPlayerException();
@@ -1156,7 +1156,7 @@ public final class ExperienceAPI {
     @Deprecated
     private static PlayerProfile getOfflineProfile(String playerName) {
         UUID uuid = mcMMO.p.getServer().getOfflinePlayer(playerName).getUniqueId();
-        PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid);
+        PlayerProfile profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(uuid);
 
         if (profile == null) {
             throw new InvalidPlayerException();
@@ -1217,6 +1217,6 @@ public final class ExperienceAPI {
             throw new McMMOPlayerNotFoundException(player);
         }
 
-        return mcMMO.getUserManager().getPlayer(player);
+        return mcMMO.getUserManager().queryMcMMOPlayer(player);
     }
 }

+ 9 - 9
src/main/java/com/gmail/nossr50/api/PartyAPI.java

@@ -26,7 +26,7 @@ public final class PartyAPI {
             return null;
         }
 
-        return mcMMO.getUserManager().getPlayer(player).getParty().getName();
+        return mcMMO.getUserManager().queryMcMMOPlayer(player).getParty().getName();
     }
 
     /**
@@ -38,10 +38,10 @@ public final class PartyAPI {
      * @return true if the player is in a party, false otherwise
      */
     public static boolean inParty(Player player) {
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
             return false;
 
-        return mcMMO.getUserManager().getPlayer(player).inParty();
+        return mcMMO.getUserManager().queryMcMMOPlayer(player).inParty();
     }
 
     /**
@@ -80,7 +80,7 @@ public final class PartyAPI {
     @Deprecated
     public static void addToParty(Player player, String partyName) {
         //Check if player profile is loaded
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
             return;
 
         Party party = mcMMO.getPartyManager().getParty(partyName);
@@ -95,7 +95,7 @@ public final class PartyAPI {
             }
         }
 
-        mcMMO.getPartyManager().addToParty(mcMMO.getUserManager().getPlayer(player), party);
+        mcMMO.getPartyManager().addToParty(mcMMO.getUserManager().queryMcMMOPlayer(player), party);
     }
 
     /**
@@ -120,7 +120,7 @@ public final class PartyAPI {
     //TODO: bypasslimit not used?
     public static void addToParty(Player player, String partyName, boolean bypassLimit) {
         //Check if player profile is loaded
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
             return;
 
         Party party = mcMMO.getPartyManager().getParty(partyName);
@@ -129,7 +129,7 @@ public final class PartyAPI {
             party = new Party(new PartyLeader(player.getUniqueId(), player.getName()), partyName);
         }
 
-        mcMMO.getPartyManager().addToParty(mcMMO.getUserManager().getPlayer(player), party);
+        mcMMO.getPartyManager().addToParty(mcMMO.getUserManager().queryMcMMOPlayer(player), party);
     }
 
     /**
@@ -141,10 +141,10 @@ public final class PartyAPI {
      */
     public static void removeFromParty(Player player) {
         //Check if player profile is loaded
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
             return;
 
-        mcMMO.getPartyManager().removeFromParty(mcMMO.getUserManager().getPlayer(player));
+        mcMMO.getPartyManager().removeFromParty(mcMMO.getUserManager().queryMcMMOPlayer(player));
     }
 
     /**

+ 4 - 0
src/main/java/com/gmail/nossr50/api/exceptions/NullPartyException.java

@@ -0,0 +1,4 @@
+package com.gmail.nossr50.api.exceptions;
+
+public class NullPartyException extends RuntimeException {
+}

+ 7 - 0
src/main/java/com/gmail/nossr50/api/exceptions/ProfileRetrievalException.java

@@ -0,0 +1,7 @@
+package com.gmail.nossr50.api.exceptions;
+
+public class ProfileRetrievalException extends RuntimeException {
+    public ProfileRetrievalException(String message) {
+        super(message);
+    }
+}

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

@@ -21,7 +21,7 @@ public class McnotifyCommand implements TabExecutor {
         }
 
         if (args.length == 0) {
-            McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer((Player) sender);
+            McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer((Player) sender);
 
             //Not Loaded yet
             if (mmoPlayer == null)

+ 70 - 52
src/main/java/com/gmail/nossr50/commands/chat/ChatCommand.java

@@ -2,13 +2,14 @@ package com.gmail.nossr50.commands.chat;
 
 import com.gmail.nossr50.chat.ChatManager;
 import com.gmail.nossr50.chat.ChatManagerFactory;
-import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.datatypes.chat.ChatMode;
+import com.gmail.nossr50.datatypes.party.Party;
 import com.gmail.nossr50.datatypes.party.PartyFeature;
 import com.gmail.nossr50.datatypes.player.McMMOPlayer;
 import com.gmail.nossr50.locale.LocaleLoader;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.util.commands.CommandUtils;
+import com.gmail.nossr50.util.player.PartyUtils;
 import com.google.common.collect.ImmutableList;
 import org.bukkit.command.Command;
 import org.bukkit.command.CommandSender;
@@ -32,58 +33,72 @@ public abstract class ChatCommand implements TabExecutor {
     @Override
     public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
         McMMOPlayer mmoPlayer;
+        Player player;
 
-        switch (args.length) {
-            case 0:
-                if (CommandUtils.noConsoleUsage(sender)) {
-                    return true;
-                }
-
-                if (!CommandUtils.hasPlayerDataKey(sender)) {
-                    return true;
-                }
-
-                mmoPlayer = mcMMO.getUserManager().getPlayer(sender.getName());
-
-                if (mmoPlayer.isChatEnabled(chatMode)) {
-                    disableChatMode(mmoPlayer, sender);
-                }
-                else {
-                    enableChatMode(mmoPlayer, sender);
-                }
+        if(sender instanceof Player) {
+            player = (Player) sender;
 
+            if (!CommandUtils.hasPlayerDataKey(sender)) {
                 return true;
+            } else {
+                mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
+
+                switch (args.length) {
+                    case 0:
+                        if (CommandUtils.noConsoleUsage(sender)) {
+                            return true;
+                        }
+
+                        if (!CommandUtils.hasPlayerDataKey(sender)) {
+                            return true;
+                        }
+
+                        if (mmoPlayer.isChatEnabled(chatMode)) {
+                            disableChatMode(mmoPlayer, sender);
+                        }
+                        else {
+                            enableChatMode(mmoPlayer, sender);
+                        }
 
-            case 1:
-                if (CommandUtils.shouldEnableToggle(args[0])) {
-                    if (CommandUtils.noConsoleUsage(sender)) {
                         return true;
-                    }
-                    if (!CommandUtils.hasPlayerDataKey(sender)) {
-                        return true;
-                    }
-
-                    enableChatMode(mcMMO.getUserManager().getPlayer(sender.getName()), sender);
-                    return true;
-                }
 
-                if (CommandUtils.shouldDisableToggle(args[0])) {
-                    if (CommandUtils.noConsoleUsage(sender)) {
-                        return true;
-                    }
-                    if (!CommandUtils.hasPlayerDataKey(sender)) {
+                    case 1:
+                        if (CommandUtils.shouldEnableToggle(args[0])) {
+                            if (CommandUtils.noConsoleUsage(sender)) {
+                                return true;
+                            }
+                            if (!CommandUtils.hasPlayerDataKey(sender)) {
+                                return true;
+                            }
+
+                            enableChatMode(mcMMO.getUserManager().queryMcMMOPlayer(player), sender);
+                            return true;
+                        }
+
+                        if (CommandUtils.shouldDisableToggle(args[0])) {
+                            if (CommandUtils.noConsoleUsage(sender)) {
+                                return true;
+                            }
+                            if (!CommandUtils.hasPlayerDataKey(sender)) {
+                                return true;
+                            }
+
+                            disableChatMode(mcMMO.getUserManager().queryMcMMOPlayer(player), sender);
+                            return true;
+                        }
+
+                        // Fallthrough
+
+                    default:
+                        handleChatSending(sender, args);
                         return true;
-                    }
-
-                    disableChatMode(mcMMO.getUserManager().getPlayer(sender.getName()), sender);
-                    return true;
                 }
 
-                // Fallthrough
 
-            default:
-                handleChatSending(sender, args);
-                return true;
+            }
+        } else {
+            sender.sendMessage(LocaleLoader.getString("Commands.NoConsole"));
+            return true;
         }
     }
 
@@ -111,17 +126,20 @@ public abstract class ChatCommand implements TabExecutor {
         return (sender instanceof Player) ? ((Player) sender).getDisplayName() : LocaleLoader.getString("Commands.Chat.Console");
     }
 
-    protected abstract void handleChatSending(CommandSender sender, String[] args);
+    protected abstract void handleChatSending(CommandSender sender, @NotNull String[] args);
 
-    private void enableChatMode(McMMOPlayer mmoPlayer, CommandSender sender) {
-        if (chatMode == ChatMode.PARTY && mmoPlayer.getParty() == null) {
-            sender.sendMessage(LocaleLoader.getString("Commands.Party.None"));
-            return;
-        }
+    private void enableChatMode(@NotNull McMMOPlayer mmoPlayer, @NotNull CommandSender sender) {
+        if (chatMode == ChatMode.PARTY) {
+            Party party = mmoPlayer.getParty();
+            if(party == null) {
+                sender.sendMessage(LocaleLoader.getString("Commands.Party.None"));
+                return;
+            }
 
-        if (chatMode == ChatMode.PARTY && (mmoPlayer.getParty().getLevel() < Config.getInstance().getPartyFeatureUnlockLevel(PartyFeature.CHAT))) {
-            sender.sendMessage(LocaleLoader.getString("Party.Feature.Disabled.1"));
-            return;
+            if(PartyUtils.isAllowed(party, PartyFeature.CHAT)) {
+                sender.sendMessage(LocaleLoader.getString("Party.Feature.Disabled.1"));
+                return;
+            }
         }
 
         mmoPlayer.enableChat(chatMode);

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

@@ -58,7 +58,7 @@ public class ConvertDatabaseCommand implements CommandExecutor {
             }
 
             for (Player player : mcMMO.p.getServer().getOnlinePlayers()) {
-                PlayerProfile profile = oldDatabase.loadPlayerProfile(player.getUniqueId());
+                PlayerProfile profile = oldDatabase.queryPlayerDataByUUID(player.getUniqueId());
 
                 if(profile == null)
                     continue;

+ 9 - 4
src/main/java/com/gmail/nossr50/commands/database/McremoveCommand.java → src/main/java/com/gmail/nossr50/commands/database/DatabaseRemovePlayerCommand.java

@@ -8,6 +8,7 @@ import org.bukkit.Bukkit;
 import org.bukkit.command.Command;
 import org.bukkit.command.CommandSender;
 import org.bukkit.command.TabExecutor;
+import org.bukkit.entity.Player;
 import org.bukkit.util.StringUtil;
 import org.jetbrains.annotations.NotNull;
 
@@ -15,20 +16,24 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
 
-public class McremoveCommand implements TabExecutor {
+public class DatabaseRemovePlayerCommand implements TabExecutor {
     @Override
     public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
         if (args.length == 1) {
             String playerName = CommandUtils.getMatchedPlayerName(args[0]);
 
-            if (mcMMO.getUserManager().getOfflinePlayer(playerName) == null && CommandUtils.unloadedProfile(sender, mcMMO.getDatabaseManager().loadPlayerProfile(playerName, false))) {
+            if (mcMMO.getUserManager().getOfflinePlayer(playerName) == null
+                    && CommandUtils.hasNoProfile(sender, mcMMO.getDatabaseManager().queryPlayerDataByUUID(playerName, false))) {
+                sender.sendMessage(LocaleLoader.getString("Commands.Offline"));
                 return true;
             }
 
             UUID uuid = null;
 
-            if (Bukkit.getPlayer(playerName) != null) {
-                uuid = Bukkit.getPlayer(playerName).getUniqueId();
+            Player targetPlayer = Bukkit.getPlayer(playerName);
+
+            if (targetPlayer != null) {
+                uuid = targetPlayer.getUniqueId();
             }
 
             if (mcMMO.getDatabaseManager().removeUser(playerName, uuid)) {

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

@@ -98,9 +98,9 @@ public abstract class ExperienceCommand implements TabExecutor {
                     if (player != null) {
                         uuid = player.getUniqueId();
                     }
-                    PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName, uuid, false);
+                    PlayerProfile profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(playerName, uuid, false);
 
-                    if (CommandUtils.unloadedProfile(sender, profile)) {
+                    if (CommandUtils.hasNoProfile(sender, profile)) {
                         return true;
                     }
 

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

@@ -82,9 +82,9 @@ public class SkillresetCommand implements TabExecutor {
                     if (player != null) {
                         uuid = player.getUniqueId();
                     }
-                    PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName, uuid, false);
+                    PlayerProfile profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(playerName, uuid, false);
 
-                    if (CommandUtils.unloadedProfile(sender, profile)) {
+                    if (CommandUtils.hasNoProfile(sender, profile)) {
                         return true;
                     }
 

+ 2 - 2
src/main/java/com/gmail/nossr50/commands/party/PartyAcceptCommand.java

@@ -16,12 +16,12 @@ public class PartyAcceptCommand implements CommandExecutor {
             Player player = (Player) sender;
 
             //Check if player profile is loaded
-            if (mcMMO.getUserManager().getPlayer(player) == null) {
+            if (mcMMO.getUserManager().queryMcMMOPlayer(player) == null) {
                 sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad"));
                 return true;
             }
 
-            McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+            McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
 
             if (!mmoPlayer.hasPartyInvite()) {

+ 2 - 2
src/main/java/com/gmail/nossr50/commands/party/PartyChangeOwnerCommand.java

@@ -15,12 +15,12 @@ public class PartyChangeOwnerCommand implements CommandExecutor {
     @Override
     public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
         if (args.length == 2) {//Check if player profile is loaded
-            if (mcMMO.getUserManager().getPlayer((Player) sender) == null) {
+            if (mcMMO.getUserManager().queryMcMMOPlayer((Player) sender) == null) {
                 sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad"));
                 return true;
             }
 
-            Party playerParty = mcMMO.getUserManager().getPlayer((Player) sender).getParty();
+            Party playerParty = mcMMO.getUserManager().queryMcMMOPlayer((Player) sender).getParty();
             String targetName = CommandUtils.getMatchedPlayerName(args[1]);
             OfflinePlayer target = mcMMO.p.getServer().getOfflinePlayer(targetName);
 

+ 2 - 2
src/main/java/com/gmail/nossr50/commands/party/PartyChangePasswordCommand.java

@@ -12,13 +12,13 @@ import org.jetbrains.annotations.NotNull;
 public class PartyChangePasswordCommand implements CommandExecutor {
     @Override
     public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
-        if(mcMMO.getUserManager().getPlayer((Player) sender) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer((Player) sender) == null)
         {
             sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad"));
             return true;
         }
 
-        Party party = mcMMO.getUserManager().getPlayer((Player) sender).getParty();
+        Party party = mcMMO.getUserManager().queryMcMMOPlayer((Player) sender).getParty();
 
         switch (args.length) {
             case 1:

+ 4 - 4
src/main/java/com/gmail/nossr50/commands/party/PartyCommand.java

@@ -69,13 +69,13 @@ public class PartyCommand implements TabExecutor {
             return true;
         }
 
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
         {
             player.sendMessage(LocaleLoader.getString("Profile.PendingLoad"));
             return true;
         }
 
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
         if (args.length < 1) {
             if (!mcMMO.getPartyManager().mmoPlayer.inParty()) {
@@ -189,13 +189,13 @@ public class PartyCommand implements TabExecutor {
                             Player player = (Player) sender;
 
                             //Not Loaded
-                            if(mcMMO.getUserManager().getPlayer(player) == null)
+                            if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
                             {
                                 sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad"));
                                 return ImmutableList.of();
                             }
 
-                            Party party = mcMMO.getUserManager().getPlayer(player).getParty();
+                            Party party = mcMMO.getUserManager().queryMcMMOPlayer(player).getParty();
 
                             playerNames = party.getOnlinePlayerNames(player);
                             return StringUtil.copyPartialMatches(args[1], playerNames, new ArrayList<>(playerNames.size()));

+ 2 - 2
src/main/java/com/gmail/nossr50/commands/party/PartyCreateCommand.java

@@ -16,9 +16,9 @@ public class PartyCreateCommand implements CommandExecutor {
             case 2:
             case 3:
                 Player player = (Player) sender;
-                McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+                McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
-                if(mcMMO.getUserManager().getPlayer(player) == null)
+                if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
                 {
                     player.sendMessage(LocaleLoader.getString("Profile.PendingLoad"));
                     return true;

+ 2 - 2
src/main/java/com/gmail/nossr50/commands/party/PartyDisbandCommand.java

@@ -15,12 +15,12 @@ public class PartyDisbandCommand implements CommandExecutor {
     @Override
     public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
         if (args.length == 1) {
-            if (mcMMO.getUserManager().getPlayer((Player) sender) == null) {
+            if (mcMMO.getUserManager().queryMcMMOPlayer((Player) sender) == null) {
                 sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad"));
                 return true;
             }
 
-            Party playerParty = mcMMO.getUserManager().getPlayer((Player) sender).getParty();
+            Party playerParty = mcMMO.getUserManager().queryMcMMOPlayer((Player) sender).getParty();
             String partyName = playerParty.getPartyName();
 
             for (PartyMember member : playerParty.getPartyMembers()) {

+ 2 - 2
src/main/java/com/gmail/nossr50/commands/party/PartyInfoCommand.java

@@ -21,13 +21,13 @@ public class PartyInfoCommand implements CommandExecutor {
         switch (args.length) {
             case 0:
             case 1:
-                if(mcMMO.getUserManager().getPlayer((Player) sender) == null)
+                if(mcMMO.getUserManager().queryMcMMOPlayer((Player) sender) == null)
                 {
                     sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad"));
                     return true;
                 }
                 Player player = (Player) sender;
-                McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+                McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
                 Party party = mmoPlayer.getParty();
 
                 displayPartyHeader(player, party);

+ 2 - 2
src/main/java/com/gmail/nossr50/commands/party/PartyInviteCommand.java

@@ -25,13 +25,13 @@ public class PartyInviteCommand implements CommandExecutor {
 
             Player target = mcMMOTarget.getPlayer();
 
-            if (mcMMO.getUserManager().getPlayer((Player) sender) == null) {
+            if (mcMMO.getUserManager().queryMcMMOPlayer((Player) sender) == null) {
                 sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad"));
                 return true;
             }
 
             Player player = (Player) sender;
-            McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+            McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
             String playerName = player.getName();
 
             if (player.equals(target)) {

+ 3 - 3
src/main/java/com/gmail/nossr50/commands/party/PartyKickCommand.java

@@ -16,12 +16,12 @@ public class PartyKickCommand implements CommandExecutor {
     @Override
     public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
         if (args.length == 2) {
-            if (mcMMO.getUserManager().getPlayer((Player) sender) == null) {
+            if (mcMMO.getUserManager().queryMcMMOPlayer((Player) sender) == null) {
                 sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad"));
                 return true;
             }
 
-            Party playerParty = mcMMO.getUserManager().getPlayer((Player) sender).getParty();
+            Party playerParty = mcMMO.getUserManager().queryMcMMOPlayer((Player) sender).getParty();
             String targetName = CommandUtils.getMatchedPlayerName(args[1]);
 
             if (!playerParty.hasMember(targetName)) {
@@ -39,7 +39,7 @@ public class PartyKickCommand implements CommandExecutor {
                     return true;
                 }
 
-                mcMMO.getPartyManager().processPartyLeaving(mcMMO.getUserManager().getPlayer(onlineTarget));
+                mcMMO.getPartyManager().processPartyLeaving(mcMMO.getUserManager().queryMcMMOPlayer(onlineTarget));
                 onlineTarget.sendMessage(LocaleLoader.getString("Commands.Party.Kick", partyName));
             }
 

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

@@ -16,12 +16,12 @@ public class PartyRenameCommand implements CommandExecutor {
     @Override
     public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
         if (args.length == 2) {
-            if (mcMMO.getUserManager().getPlayer((Player) sender) == null) {
+            if (mcMMO.getUserManager().queryMcMMOPlayer((Player) sender) == null) {
                 sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad"));
                 return true;
             }
 
-            McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer((Player) sender);
+            McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer((Player) sender);
             Party playerParty = mmoPlayer.getParty();
 
             String oldPartyName = playerParty.getPartyName();

+ 2 - 2
src/main/java/com/gmail/nossr50/commands/party/PartyXpShareCommand.java

@@ -17,13 +17,13 @@ import org.jetbrains.annotations.NotNull;
 public class PartyXpShareCommand implements CommandExecutor {
     @Override
     public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
-        if(mcMMO.getUserManager().getPlayer((Player) sender) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer((Player) sender) == null)
         {
             sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad"));
             return true;
         }
 
-        Party party = mcMMO.getUserManager().getPlayer((Player) sender).getParty();
+        Party party = mcMMO.getUserManager().queryMcMMOPlayer((Player) sender).getParty();
 
         if (party.getLevel() < Config.getInstance().getPartyFeatureUnlockLevel(PartyFeature.XP_SHARE)) {
             sender.sendMessage(LocaleLoader.getString("Party.Feature.Disabled.5"));

+ 2 - 2
src/main/java/com/gmail/nossr50/commands/party/teleport/PtpAcceptCommand.java

@@ -21,14 +21,14 @@ public class PtpAcceptCommand implements CommandExecutor {
             return true;
         }
 
-        if(mcMMO.getUserManager().getPlayer((Player) sender) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer((Player) sender) == null)
         {
             sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad"));
             return true;
         }
 
         Player player = (Player) sender;
-        PartyTeleportRecord ptpRecord = mcMMO.getUserManager().getPlayer(player).getPartyTeleportRecord();
+        PartyTeleportRecord ptpRecord = mcMMO.getUserManager().queryMcMMOPlayer(player).getPartyTeleportRecord();
 
         if (!ptpRecord.hasRequest()) {
             player.sendMessage(LocaleLoader.getString("Commands.ptp.NoRequests"));

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

@@ -59,13 +59,13 @@ public class PtpCommand implements TabExecutor {
             return true;
         }
 
-        if(mcMMO.getUserManager().getPlayer((Player) sender) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer((Player) sender) == null)
         {
             sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad"));
             return true;
         }
 
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
         if (!mmoPlayer.inParty()) {
             sender.sendMessage(LocaleLoader.getString("Commands.Party.None"));
@@ -133,13 +133,13 @@ public class PtpCommand implements TabExecutor {
             List<String> matches = StringUtil.copyPartialMatches(args[0], TELEPORT_SUBCOMMANDS, new ArrayList<>(TELEPORT_SUBCOMMANDS.size()));
 
             if (matches.size() == 0) {
-                if (mcMMO.getUserManager().getPlayer((Player) sender) == null) {
+                if (mcMMO.getUserManager().queryMcMMOPlayer((Player) sender) == null) {
                     sender.sendMessage(LocaleLoader.getString("Profile.PendingLoad"));
                     return ImmutableList.of();
                 }
 
                 Player player = (Player) sender;
-                McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+                McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
                 if (!mmoPlayer.inParty()) {
                     return ImmutableList.of();
@@ -228,20 +228,20 @@ public class PtpCommand implements TabExecutor {
     }
 
     protected static void handleTeleportWarmup(Player teleportingPlayer, Player targetPlayer) {
-        if(mcMMO.getUserManager().getPlayer(targetPlayer) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(targetPlayer) == null)
         {
             targetPlayer.sendMessage(LocaleLoader.getString("Profile.PendingLoad"));
             return;
         }
 
-        if(mcMMO.getUserManager().getPlayer(teleportingPlayer) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(teleportingPlayer) == null)
         {
             teleportingPlayer.sendMessage(LocaleLoader.getString("Profile.PendingLoad"));
             return;
         }
 
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(teleportingPlayer);
-        McMMOPlayer mcMMOTarget = mcMMO.getUserManager().getPlayer(targetPlayer);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(teleportingPlayer);
+        McMMOPlayer mcMMOTarget = mcMMO.getUserManager().queryMcMMOPlayer(targetPlayer);
 
         long warmup = Config.getInstance().getPTPCommandWarmup();
 

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

@@ -29,7 +29,7 @@ public class InspectCommand implements TabExecutor {
 
             // If the mmoPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process.
             if (mmoPlayer == null) {
-                PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName, false); // Temporary Profile
+                PlayerProfile profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(playerName, false); // Temporary Profile
 
                 if (!CommandUtils.isLoaded(sender, profile)) {
                     return true;

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

@@ -93,7 +93,7 @@ public class RepairCommand extends SkillCommand {
         List<String> messages = new ArrayList<>();
 
         if (canArcaneForge) {
-            RepairManager repairManager = mcMMO.getUserManager().getPlayer(player).getRepairManager();
+            RepairManager repairManager = mcMMO.getUserManager().queryMcMMOPlayer(player).getRepairManager();
 
             messages.add(getStatMessage(false, true,
                     SubSkillType.REPAIR_ARCANE_FORGING,

+ 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 = mcMMO.getUserManager().getPlayer(player).getUnarmedManager().getSteelArmStyleDamage();
+            ironArmBonus = mcMMO.getUserManager().queryMcMMOPlayer(player).getUnarmedManager().getSteelArmStyleDamage();
         }
 
         // IRON GRIP

+ 37 - 0
src/main/java/com/gmail/nossr50/database/AbstractDatabaseManager.java

@@ -0,0 +1,37 @@
+package com.gmail.nossr50.database;
+
+import com.gmail.nossr50.api.exceptions.ProfileRetrievalException;
+import com.gmail.nossr50.datatypes.player.PersistentPlayerDataBuilder;
+import com.gmail.nossr50.datatypes.player.PlayerProfile;
+import com.gmail.nossr50.mcMMO;
+import org.apache.commons.lang.NullArgumentException;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public abstract class AbstractDatabaseManager implements DatabaseManager {
+    @Override
+    public @Nullable PlayerProfile initPlayerProfile(@NotNull Player player) throws Exception {
+        //First we attempt to load the player data
+        try {
+            PlayerProfile playerProfile = queryPlayerDataByUUID(player.getUniqueId(), player.getName());
+            if(playerProfile != null) {
+                return playerProfile;
+            }
+            //If we fail to load the player data due to either missing data for the player or corrupted/invalid data, we create a new profile for this player
+        } catch (ProfileRetrievalException | NullArgumentException e) {
+            mcMMO.p.getLogger().info("Making new player data in DB for user name:"+player.getName().toString()+", uuid:" + player.getUniqueId().toString());
+            //Add data for this player into DB with default values
+            //TODO: have this use the PersistentPlayerData object created below to initialize defaults
+            insertNewUser(player.getName(), player.getUniqueId());
+            //Construct player data object
+            PersistentPlayerDataBuilder persistentPlayerDataBuilder = new PersistentPlayerDataBuilder();
+            //Return player profile
+            return new PlayerProfile(persistentPlayerDataBuilder.buildNewPlayerData(player.getUniqueId(), player.getName()));
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        return null; //Some critical failure happened
+    }
+}

+ 39 - 16
src/main/java/com/gmail/nossr50/database/DatabaseManager.java

@@ -1,12 +1,19 @@
 package com.gmail.nossr50.database;
 
+import com.gmail.nossr50.api.exceptions.ProfileRetrievalException;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.datatypes.database.DatabaseType;
 import com.gmail.nossr50.datatypes.database.PlayerStat;
 import com.gmail.nossr50.datatypes.player.MMODataSnapshot;
 import com.gmail.nossr50.datatypes.player.PlayerProfile;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
+import org.apache.commons.lang.NullArgumentException;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
+import java.io.IOException;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
@@ -31,24 +38,24 @@ public interface DatabaseManager {
      * Remove a user from the database.
      *
      * @param playerName The name of the user to remove
-     * @param uuid player UUID, can be null
+     * @param uuid uuid of player to remove, can be null
      * @return true if the user was successfully removed, false otherwise
      */
-    boolean removeUser(String playerName, UUID uuid);
+    boolean removeUser(@NotNull String playerName, @Nullable UUID uuid);
 
     /**
      * Removes any cache used for faster lookups
      * Currently only used for SQL
      * @param uuid target UUID to cleanup
      */
-    void removeCache(UUID uuid);
+    void removeCache(@NotNull UUID uuid);
 
     /**
      * Save a user to the database.
      *
      * @param mmoDataSnapshot Snapshot of player data to save
      */
-    boolean saveUser(MMODataSnapshot mmoDataSnapshot);
+    boolean saveUser(@NotNull MMODataSnapshot mmoDataSnapshot);
 
     /**
     * Retrieve leaderboard info.
@@ -58,7 +65,7 @@ public interface DatabaseManager {
     * @param statsPerPage The number of stats per page
     * @return the requested leaderboard information
     */
-    List<PlayerStat> readLeaderboard(PrimarySkillType skill, int pageNumber, int statsPerPage);
+    @NotNull List<PlayerStat> readLeaderboard(@NotNull PrimarySkillType skill, int pageNumber, int statsPerPage);
 
     /**
      * Retrieve rank info into a HashMap from PrimarySkillType to the rank.
@@ -69,38 +76,54 @@ public interface DatabaseManager {
      * @param playerName The name of the user to retrieve the rankings for
      * @return the requested rank information
      */
-    Map<PrimarySkillType, Integer> readRank(String playerName);
+    @NotNull Map<PrimarySkillType, Integer> readRank(@NotNull String playerName);
 
     /**
      * Add a new user to the database.
-     *
-     * @param playerName The name of the player to be added to the database
+     *  @param playerName The name of the player to be added to the database
      * @param uuid The uuid of the player to be added to the database
      */
-    void newUser(String playerName, UUID uuid);
+    void insertNewUser(@NotNull String playerName, @NotNull UUID uuid) throws Exception;
+
+    @Nullable PlayerProfile queryPlayerDataByPlayer(@NotNull Player player) throws ProfileRetrievalException, NullArgumentException;
 
     /**
-     * Load a player from the database.
+     * Load player data (in the form of {@link PlayerProfile}) if player data exists
+     * Returns null if it doesn't
      *
      * @param uuid The uuid of the player to load from the database
-     * @return The player's data, or an unloaded PlayerProfile if not found
+     * @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;
+
+    /**
+     * This method queries the DB for player data for target player
+     * If it fails to find data for this player, or if it does find data but the data is corrupted,
+     *  it will then proceed to make brand new data for the target player, which will be saved to the DB during the next save
+     *
+     * This method will return null for all other errors, which indicates a problem with the DB, in which case mcMMO
+     *  will try to load the player data periodically, but that isn't handled in this method
+     *
+     * @param player target player
+     * @return {@link PlayerProfile} for the target player
      */
-    PlayerProfile loadPlayerProfile(UUID uuid);
+    @Nullable PlayerProfile initPlayerProfile(@NotNull Player player) throws Exception;
 
     /**
      * Get all users currently stored in the database.
      *
      * @return list of playernames
      */
-    List<String> getStoredUsers();
+    @NotNull List<String> getStoredUsers();
 
     /**
      * Convert all users from this database to the provided database using
-     * {@link #saveUser(PlayerProfile)}.
+     * {@link #saveUser(MMODataSnapshot)}.
      *
      * @param destination The DatabaseManager to save to
      */
-    void convertUsers(DatabaseManager destination);
+    void convertUsers(@NotNull DatabaseManager destination);
 
 //    boolean saveUserUUID(String userName, UUID uuid);
 
@@ -111,7 +134,7 @@ public interface DatabaseManager {
      *
      * @return The type of database
      */
-    DatabaseType getDatabaseType();
+    @NotNull DatabaseType getDatabaseType();
 
     /**
      * Called when the plugin disables

+ 154 - 228
src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java

@@ -1,5 +1,6 @@
 package com.gmail.nossr50.database;
 
+import com.gmail.nossr50.api.exceptions.ProfileRetrievalException;
 import com.gmail.nossr50.config.AdvancedConfig;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.datatypes.MobHealthBarType;
@@ -18,13 +19,15 @@ import com.gmail.nossr50.util.skills.SkillUtils;
 import com.google.common.collect.ImmutableMap;
 import org.apache.commons.lang.NullArgumentException;
 import org.bukkit.OfflinePlayer;
+import org.bukkit.entity.Player;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.io.*;
 import java.util.*;
 
-public final class FlatFileDatabaseManager implements DatabaseManager {
+public final class FlatFileDatabaseManager extends AbstractDatabaseManager {
+    public static final String FLATFILE_SPLIT_CHARACTER_REGEX = ":";
     private final HashMap<PrimarySkillType, List<PlayerStat>> playerStatHash = new HashMap<>();
     private final List<PlayerStat> powerLevels = new ArrayList<>();
     private long lastUpdate = 0;
@@ -190,7 +193,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
         mcMMO.p.getLogger().info("Purged " + removedPlayers + " users from the database.");
     }
 
-    public boolean removeUser(String playerName, UUID uuid) {
+    public boolean removeUser(String playerName, @Nullable UUID uuid) {
         //NOTE: UUID is unused for FlatFile for this interface implementation
         boolean worked = false;
 
@@ -247,7 +250,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
     }
 
     @Override
-    public void removeCache(UUID uuid) {
+    public void removeCache(@NotNull UUID uuid) {
         //Not used in FlatFile
     }
 
@@ -428,7 +431,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
         writer.append("\r\n");
     }
 
-    public List<PlayerStat> readLeaderboard(PrimarySkillType skill, int pageNumber, int statsPerPage) {
+    public @NotNull List<PlayerStat> readLeaderboard(@NotNull PrimarySkillType skill, int pageNumber, int statsPerPage) {
         updateLeaderboards();
         List<PlayerStat> statsList = skill == null ? powerLevels : playerStatHash.get(skill);
         int fromIndex = (Math.max(pageNumber, 1) - 1) * statsPerPage;
@@ -436,7 +439,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
         return statsList.subList(Math.min(fromIndex, statsList.size()), Math.min(fromIndex + statsPerPage, statsList.size()));
     }
 
-    public Map<PrimarySkillType, Integer> readRank(String playerName) {
+    public @NotNull Map<PrimarySkillType, Integer> readRank(@NotNull String playerName) {
         updateLeaderboards();
 
         Map<PrimarySkillType, Integer> skills = new HashMap<>();
@@ -450,7 +453,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
         return skills;
     }
 
-    public void newUser(String playerName, UUID uuid) {
+    public void insertNewUser(@NotNull String playerName, @NotNull UUID uuid) {
         BufferedWriter out = null;
         synchronized (fileWritingLock) {
             try {
@@ -557,14 +560,73 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
         }
     }
 
-    public PlayerProfile loadPlayerProfile(UUID uuid) {
-        return loadPlayerProfile("", uuid, false);
+    public @Nullable PlayerProfile queryPlayerDataByName(@NotNull String playerName) {
+        BufferedReader bufferedReader = null;
+        String usersFilePath = mcMMO.getUsersFilePath();
+
+        //Retrieve player
+        synchronized (fileWritingLock) {
+            try {
+                // Open the user file
+                bufferedReader = new BufferedReader(new FileReader(usersFilePath));
+                String currentLine;
+
+                while ((currentLine = bufferedReader.readLine()) != null) {
+                    // Split the data which is stored as a string with : as break points
+                    String[] stringDataArray = currentLine.split(FLATFILE_SPLIT_CHARACTER_REGEX);
+
+                    //Search for matching name
+                    if (!stringDataArray[FlatFileMappings.USERNAME].equalsIgnoreCase(playerName)) {
+                        continue;
+                    }
+
+                    //We found our player, load the data
+                    return loadFromLine(stringDataArray);
+                }
+
+                throw new ProfileRetrievalException("Couldn't find a matching player in the database! Using name matching - " + playerName);
+            }
+            catch (Exception e) {
+                e.printStackTrace();
+            }
+
+            //Cleanup resource leaks
+            finally {
+                if (bufferedReader != null) {
+                    try {
+                        bufferedReader.close();
+                    }
+                    catch (IOException e) {
+                        // Ignore
+                    }
+                }
+            }
+        }
+
+        //Theoretically this statement should never be reached
+        mcMMO.p.getLogger().severe("Critical failure in execution of loading player from DB, contact the devs!");
+        return null;
+    }
+
+    public @Nullable PlayerProfile queryPlayerDataByPlayer(@NotNull Player player) throws ProfileRetrievalException, NullArgumentException {
+        return queryPlayerDataByUUID(player.getUniqueId(), player.getName());
     }
 
-    public @Nullable PlayerProfile loadPlayerProfile(@NotNull String playerName, @Nullable UUID uuid, boolean createNewPlayer) {
+    /**
+     * Queries by UUID will always have the current player name included as this method only gets executed when players join the server
+     * The name will be used to update player names in the DB if the name has changed
+     * There exists scenarios where players can share the same name in the DB, there is no code to account for this currently
+     * @param uuid uuid to match
+     * @param playerName used to overwrite playername values in the database if an existing value that is not equal to this one is found
+     * @return the player profile if retrieved successfully, otherwise null
+     * @throws ProfileRetrievalException
+     * @throws NullArgumentException
+     */
+    public @Nullable PlayerProfile queryPlayerDataByUUID(@NotNull UUID uuid, @NotNull String playerName) throws ProfileRetrievalException, NullArgumentException {
         BufferedReader bufferedReader = null;
         String usersFilePath = mcMMO.getUsersFilePath();
 
+        //Retrieve player
         synchronized (fileWritingLock) {
             try {
                 // Open the user file
@@ -572,48 +634,32 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
                 String currentLine;
 
                 while ((currentLine = bufferedReader.readLine()) != null) {
-                    // Find if the currentLine contains the player we want.
-                    String[] stringDataArray = currentLine.split(":");
+                    // Split the data which is stored as a string with : as break points
+                    String[] stringDataArray = currentLine.split(FLATFILE_SPLIT_CHARACTER_REGEX);
 
-                    // Compare names because we don't have a valid uuid for that player even
-                    // if input uuid is not null
-                    if (stringDataArray[FlatFileMappings.UUID_INDEX].equalsIgnoreCase("NULL")) {
-                        if (!stringDataArray[FlatFileMappings.USERNAME].equalsIgnoreCase(playerName)) {
-                            continue;
-                        }
-                    }
-                    // If input uuid is not null then we should compare uuids
-                    else if ((uuid != null && !stringDataArray[FlatFileMappings.UUID_INDEX].equalsIgnoreCase(uuid.toString())) || (uuid == null && !stringDataArray[FlatFileMappings.USERNAME].equalsIgnoreCase(playerName))) {
+                    //Search for matching UUID
+                    if (!stringDataArray[FlatFileMappings.UUID_INDEX].equalsIgnoreCase(uuid.toString())) {
                         continue;
                     }
 
-                    // Update playerName bufferedReader database after name change
+                    //If the player has changed their name, we need to update it too
                     if (!stringDataArray[FlatFileMappings.USERNAME].equalsIgnoreCase(playerName)) {
                         mcMMO.p.getLogger().info("Name change detected: " + stringDataArray[FlatFileMappings.USERNAME] + " => " + playerName);
                         stringDataArray[FlatFileMappings.USERNAME] = playerName;
                     }
 
+                    //We found our player, load the data
                     return loadFromLine(stringDataArray);
                 }
 
-                // Didn't find the player, createNewPlayer a new one
-                if (createNewPlayer) {
-                    if(uuid != null) {
-                        newUser(playerName, uuid);
-                        PersistentPlayerDataBuilder persistentPlayerDataBuilder = new PersistentPlayerDataBuilder();
-                        return new PlayerProfile(persistentPlayerDataBuilder.buildNewPlayerData(uuid, playerName));
-                    } else {
-                        throw new NullArgumentException("playerUUID");
-                    }
-
-                }
+                throw new ProfileRetrievalException("Couldn't find a matching player in the database! - "+playerName+", "+uuid.toString());
             }
             catch (Exception e) {
                 e.printStackTrace();
             }
+
+            //Cleanup resource leaks
             finally {
-                // I have no idea why it's necessary to inline tryClose() here, but it removes
-                // a resource leak warning, and I'm trusting the compiler on this one.
                 if (bufferedReader != null) {
                     try {
                         bufferedReader.close();
@@ -625,10 +671,12 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
             }
         }
 
+        //Theoretically this statement should never be reached
+        mcMMO.p.getLogger().severe("Critical failure in execution of loading player from DB, contact the devs!");
         return null;
     }
 
-    public void convertUsers(DatabaseManager destination) {
+    public void convertUsers(@NotNull DatabaseManager destination) {
         BufferedReader in = null;
         String usersFilePath = mcMMO.getUsersFilePath();
         int convertedUsers = 0;
@@ -674,127 +722,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
         }
     }
 
-//    public boolean saveUserUUID(String userName, UUID uuid) {
-//        boolean worked = false;
-//
-//        int i = 0;
-//        BufferedReader in = null;
-//        FileWriter out = null;
-//        String usersFilePath = mcMMO.getUsersFilePath();
-//
-//        synchronized (fileWritingLock) {
-//            try {
-//                in = new BufferedReader(new FileReader(usersFilePath));
-//                StringBuilder writer = new StringBuilder();
-//                String line;
-//
-//                while ((line = in.readLine()) != null) {
-//                    String[] character = line.split(":");
-//                    if (!worked && character[USERNAME].equalsIgnoreCase(userName)) {
-//                        if (character.length < 42) {
-//                            mcMMO.p.getLogger().severe("Could not update UUID for " + userName + "!");
-//                            mcMMO.p.getLogger().severe("Database entry is invalid.");
-//                            continue;
-//                        }
-//
-//                        line = line.replace(character[UUID_INDEX], uuid.toString());
-//                        worked = true;
-//                    }
-//
-//                    i++;
-//                    writer.append(line).append("\r\n");
-//                }
-//
-//                out = new FileWriter(usersFilePath); // Write out the new file
-//                out.write(writer.toString());
-//            }
-//            catch (Exception e) {
-//                mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString());
-//            }
-//            finally {
-//                mcMMO.p.getLogger().info(i + " entries written while saving UUID for " + userName);
-//                if (in != null) {
-//                    try {
-//                        in.close();
-//                    }
-//                    catch (IOException e) {
-//                        // Ignore
-//                    }
-//                }
-//                if (out != null) {
-//                    try {
-//                        out.close();
-//                    }
-//                    catch (IOException e) {
-//                        // Ignore
-//                    }
-//                }
-//            }
-//        }
-//
-//        return worked;
-//    }
-//
-//    public boolean saveUserUUIDs(Map<String, UUID> fetchedUUIDs) {
-//        BufferedReader in = null;
-//        FileWriter out = null;
-//        String usersFilePath = mcMMO.getUsersFilePath();
-//        int i = 0;
-//
-//        synchronized (fileWritingLock) {
-//            try {
-//                in = new BufferedReader(new FileReader(usersFilePath));
-//                StringBuilder writer = new StringBuilder();
-//                String line;
-//
-//                while (((line = in.readLine()) != null)) {
-//                    String[] character = line.split(":");
-//                    if (!fetchedUUIDs.isEmpty() && fetchedUUIDs.containsKey(character[USERNAME])) {
-//                        if (character.length < 42) {
-//                            mcMMO.p.getLogger().severe("Could not update UUID for " + character[USERNAME] + "!");
-//                            mcMMO.p.getLogger().severe("Database entry is invalid.");
-//                            continue;
-//                        }
-//
-//                        character[UUID_INDEX] = fetchedUUIDs.remove(character[USERNAME]).toString();
-//                        line = org.apache.commons.lang.StringUtils.join(character, ":") + ":";
-//                    }
-//
-//                    i++;
-//                    writer.append(line).append("\r\n");
-//                }
-//
-//                out = new FileWriter(usersFilePath); // Write out the new file
-//                out.write(writer.toString());
-//            }
-//            catch (Exception e) {
-//                mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString());
-//            }
-//            finally {
-//                mcMMO.p.getLogger().info(i + " entries written while saving UUID batch");
-//                if (in != null) {
-//                    try {
-//                        in.close();
-//                    }
-//                    catch (IOException e) {
-//                        // Ignore
-//                    }
-//                }
-//                if (out != null) {
-//                    try {
-//                        out.close();
-//                    }
-//                    catch (IOException e) {
-//                        // Ignore
-//                    }
-//                }
-//            }
-//        }
-//
-//        return true;
-//    }
-
-    public List<String> getStoredUsers() {
+    public @NotNull List<String> getStoredUsers() {
         ArrayList<String> users = new ArrayList<>();
         BufferedReader in = null;
         String usersFilePath = mcMMO.getUsersFilePath();
@@ -1333,73 +1261,72 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
         }
     }
 
-    private @Nullable PlayerProfile loadFromLine(String[] subString) {
+    private @Nullable PlayerProfile loadFromLine(@NotNull String[] dataStrSplit) {
         PersistentPlayerDataBuilder playerDataBuilder = new PersistentPlayerDataBuilder();
 
-        EnumMap<PrimarySkillType, Integer>   skillLevelMap     = getSkillMapFromLine(subString);      // Skill levels
+        EnumMap<PrimarySkillType, Integer>   skillLevelMap     = getSkillMapFromLine(dataStrSplit);      // Skill levels
         EnumMap<PrimarySkillType, Float>     skillExperienceValueMap   = new EnumMap<PrimarySkillType, Float>(PrimarySkillType.class);     // Skill & XP
         EnumMap<SuperAbilityType, Integer> skillAbilityDeactivationTimeStamp = new EnumMap<SuperAbilityType, Integer>(SuperAbilityType.class); // Ability & Cooldown
         EnumMap<UniqueDataType, Integer> uniquePlayerDataMap = new EnumMap<UniqueDataType, Integer>(UniqueDataType.class);
         EnumMap<PrimarySkillType, MMOExperienceBarManager.BarState> xpBarStateMap = new EnumMap<PrimarySkillType, MMOExperienceBarManager.BarState>(PrimarySkillType.class);
-        MobHealthBarType mobHealthbarType;
+//        MobHealthBarType mobHealthbarType;
         int scoreboardTipsShown;
 
-        skillExperienceValueMap.put(PrimarySkillType.TAMING, (float) Integer.parseInt(subString[FlatFileMappings.EXP_TAMING]));
-        skillExperienceValueMap.put(PrimarySkillType.MINING, (float) Integer.parseInt(subString[FlatFileMappings.EXP_MINING]));
-        skillExperienceValueMap.put(PrimarySkillType.REPAIR, (float) Integer.parseInt(subString[FlatFileMappings.EXP_REPAIR]));
-        skillExperienceValueMap.put(PrimarySkillType.WOODCUTTING, (float) Integer.parseInt(subString[FlatFileMappings.EXP_WOODCUTTING]));
-        skillExperienceValueMap.put(PrimarySkillType.UNARMED, (float) Integer.parseInt(subString[FlatFileMappings.EXP_UNARMED]));
-        skillExperienceValueMap.put(PrimarySkillType.HERBALISM, (float) Integer.parseInt(subString[FlatFileMappings.EXP_HERBALISM]));
-        skillExperienceValueMap.put(PrimarySkillType.EXCAVATION, (float) Integer.parseInt(subString[FlatFileMappings.EXP_EXCAVATION]));
-        skillExperienceValueMap.put(PrimarySkillType.ARCHERY, (float) Integer.parseInt(subString[FlatFileMappings.EXP_ARCHERY]));
-        skillExperienceValueMap.put(PrimarySkillType.SWORDS, (float) Integer.parseInt(subString[FlatFileMappings.EXP_SWORDS]));
-        skillExperienceValueMap.put(PrimarySkillType.AXES, (float) Integer.parseInt(subString[FlatFileMappings.EXP_AXES]));
-        skillExperienceValueMap.put(PrimarySkillType.ACROBATICS, (float) Integer.parseInt(subString[FlatFileMappings.EXP_ACROBATICS]));
-        skillExperienceValueMap.put(PrimarySkillType.FISHING, (float) Integer.parseInt(subString[FlatFileMappings.EXP_FISHING]));
-        skillExperienceValueMap.put(PrimarySkillType.ALCHEMY, (float) Integer.parseInt(subString[FlatFileMappings.EXP_ALCHEMY]));
-        skillExperienceValueMap.put(PrimarySkillType.TRIDENTS, (float) Integer.parseInt(subString[FlatFileMappings.EXP_TRIDENTS]));
-        skillExperienceValueMap.put(PrimarySkillType.CROSSBOWS, (float) Integer.parseInt(subString[FlatFileMappings.EXP_CROSSBOWS]));
+        skillExperienceValueMap.put(PrimarySkillType.TAMING, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_TAMING]));
+        skillExperienceValueMap.put(PrimarySkillType.MINING, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_MINING]));
+        skillExperienceValueMap.put(PrimarySkillType.REPAIR, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_REPAIR]));
+        skillExperienceValueMap.put(PrimarySkillType.WOODCUTTING, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_WOODCUTTING]));
+        skillExperienceValueMap.put(PrimarySkillType.UNARMED, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_UNARMED]));
+        skillExperienceValueMap.put(PrimarySkillType.HERBALISM, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_HERBALISM]));
+        skillExperienceValueMap.put(PrimarySkillType.EXCAVATION, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_EXCAVATION]));
+        skillExperienceValueMap.put(PrimarySkillType.ARCHERY, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_ARCHERY]));
+        skillExperienceValueMap.put(PrimarySkillType.SWORDS, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_SWORDS]));
+        skillExperienceValueMap.put(PrimarySkillType.AXES, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_AXES]));
+        skillExperienceValueMap.put(PrimarySkillType.ACROBATICS, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_ACROBATICS]));
+        skillExperienceValueMap.put(PrimarySkillType.FISHING, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_FISHING]));
+        skillExperienceValueMap.put(PrimarySkillType.ALCHEMY, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_ALCHEMY]));
+        skillExperienceValueMap.put(PrimarySkillType.TRIDENTS, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_TRIDENTS]));
+        skillExperienceValueMap.put(PrimarySkillType.CROSSBOWS, (float) Integer.parseInt(dataStrSplit[FlatFileMappings.EXP_CROSSBOWS]));
 
         //Set Skill XP
 
         // Taming - Unused
-        skillAbilityDeactivationTimeStamp.put(SuperAbilityType.SUPER_BREAKER, Integer.valueOf(subString[FlatFileMappings.COOLDOWN_SUPER_BREAKER]));
+        skillAbilityDeactivationTimeStamp.put(SuperAbilityType.SUPER_BREAKER, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_SUPER_BREAKER]));
         // Repair - Unused
-        skillAbilityDeactivationTimeStamp.put(SuperAbilityType.TREE_FELLER, Integer.valueOf(subString[FlatFileMappings.COOLDOWN_TREE_FELLER]));
-        skillAbilityDeactivationTimeStamp.put(SuperAbilityType.BERSERK, Integer.valueOf(subString[FlatFileMappings.COOLDOWN_BERSERK]));
-        skillAbilityDeactivationTimeStamp.put(SuperAbilityType.GREEN_TERRA, Integer.valueOf(subString[FlatFileMappings.COOLDOWN_GREEN_TERRA]));
-        skillAbilityDeactivationTimeStamp.put(SuperAbilityType.GIGA_DRILL_BREAKER, Integer.valueOf(subString[FlatFileMappings.COOLDOWN_GIGA_DRILL_BREAKER]));
-        skillAbilityDeactivationTimeStamp.put(SuperAbilityType.SERRATED_STRIKES, Integer.valueOf(subString[FlatFileMappings.COOLDOWN_SERRATED_STRIKES]));
-        skillAbilityDeactivationTimeStamp.put(SuperAbilityType.SKULL_SPLITTER, Integer.valueOf(subString[FlatFileMappings.COOLDOWN_SKULL_SPLITTER]));
+        skillAbilityDeactivationTimeStamp.put(SuperAbilityType.TREE_FELLER, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_TREE_FELLER]));
+        skillAbilityDeactivationTimeStamp.put(SuperAbilityType.BERSERK, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_BERSERK]));
+        skillAbilityDeactivationTimeStamp.put(SuperAbilityType.GREEN_TERRA, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_GREEN_TERRA]));
+        skillAbilityDeactivationTimeStamp.put(SuperAbilityType.GIGA_DRILL_BREAKER, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_GIGA_DRILL_BREAKER]));
+        skillAbilityDeactivationTimeStamp.put(SuperAbilityType.SERRATED_STRIKES, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_SERRATED_STRIKES]));
+        skillAbilityDeactivationTimeStamp.put(SuperAbilityType.SKULL_SPLITTER, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_SKULL_SPLITTER]));
         // Acrobatics - Unused
-        skillAbilityDeactivationTimeStamp.put(SuperAbilityType.BLAST_MINING, Integer.valueOf(subString[FlatFileMappings.COOLDOWN_BLAST_MINING]));
-        skillAbilityDeactivationTimeStamp.put(SuperAbilityType.ARCHERY_SUPER, Integer.valueOf(subString[FlatFileMappings.COOLDOWN_ARCHERY_SUPER_1]));
-        skillAbilityDeactivationTimeStamp.put(SuperAbilityType.SUPER_SHOTGUN, Integer.valueOf(subString[FlatFileMappings.COOLDOWN_CROSSBOWS_SUPER_1]));
-        skillAbilityDeactivationTimeStamp.put(SuperAbilityType.TRIDENT_SUPER, Integer.valueOf(subString[FlatFileMappings.COOLDOWN_TRIDENTS_SUPER_1]));
-
+        skillAbilityDeactivationTimeStamp.put(SuperAbilityType.BLAST_MINING, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_BLAST_MINING]));
+        skillAbilityDeactivationTimeStamp.put(SuperAbilityType.ARCHERY_SUPER, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_ARCHERY_SUPER_1]));
+        skillAbilityDeactivationTimeStamp.put(SuperAbilityType.SUPER_SHOTGUN, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_CROSSBOWS_SUPER_1]));
+        skillAbilityDeactivationTimeStamp.put(SuperAbilityType.TRIDENT_SUPER, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_TRIDENTS_SUPER_1]));
 
 
-        try {
-            mobHealthbarType = MobHealthBarType.valueOf(subString[FlatFileMappings.HEALTHBAR]);
-        }
-        catch (Exception e) {
-            mobHealthbarType = Config.getInstance().getMobHealthbarDefault();
-        }
+//        try {
+//            mobHealthbarType = MobHealthBarType.valueOf(dataStrSplit[FlatFileMappings.HEALTHBAR]);
+//        }
+//        catch (Exception e) {
+//            mobHealthbarType = Config.getInstance().getMobHealthbarDefault();
+//        }
 
 
+        //Sometimes players are retrieved by name
         UUID playerUUID;
 
         try {
-            playerUUID = UUID.fromString(subString[FlatFileMappings.UUID_INDEX]);
+            playerUUID = UUID.fromString(dataStrSplit[FlatFileMappings.UUID_INDEX]);
         }
         catch (Exception e) {
             mcMMO.p.getLogger().severe("UUID not found for data entry, skipping entry");
             return null;
         }
 
-
         try {
-            scoreboardTipsShown = Integer.parseInt(subString[FlatFileMappings.SCOREBOARD_TIPS]);
+            scoreboardTipsShown = Integer.parseInt(dataStrSplit[FlatFileMappings.SCOREBOARD_TIPS]);
         }
         catch (Exception e) {
             scoreboardTipsShown = 0;
@@ -1407,59 +1334,58 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
 
 
         try {
-            uniquePlayerDataMap.put(UniqueDataType.CHIMAERA_WING_DATS, Integer.valueOf(subString[FlatFileMappings.COOLDOWN_CHIMAERA_WING]));
+            uniquePlayerDataMap.put(UniqueDataType.CHIMAERA_WING_DATS, Integer.valueOf(dataStrSplit[FlatFileMappings.COOLDOWN_CHIMAERA_WING]));
         }
         catch (Exception e) {
             uniquePlayerDataMap.put(UniqueDataType.CHIMAERA_WING_DATS, 0);
         }
 
-
         try {
-            xpBarStateMap.put(PrimarySkillType.ACROBATICS, SkillUtils.asBarState(subString[FlatFileMappings.BARSTATE_ACROBATICS]));
-            xpBarStateMap.put(PrimarySkillType.ALCHEMY, SkillUtils.asBarState(subString[FlatFileMappings.BARSTATE_ALCHEMY]));
-            xpBarStateMap.put(PrimarySkillType.ARCHERY, SkillUtils.asBarState(subString[FlatFileMappings.BARSTATE_ARCHERY]));
-            xpBarStateMap.put(PrimarySkillType.AXES, SkillUtils.asBarState(subString[FlatFileMappings.BARSTATE_AXES]));
-            xpBarStateMap.put(PrimarySkillType.EXCAVATION, SkillUtils.asBarState(subString[FlatFileMappings.BARSTATE_EXCAVATION]));
-            xpBarStateMap.put(PrimarySkillType.FISHING, SkillUtils.asBarState(subString[FlatFileMappings.BARSTATE_FISHING]));
-            xpBarStateMap.put(PrimarySkillType.HERBALISM, SkillUtils.asBarState(subString[FlatFileMappings.BARSTATE_HERBALISM]));
-            xpBarStateMap.put(PrimarySkillType.MINING, SkillUtils.asBarState(subString[FlatFileMappings.BARSTATE_MINING]));
-            xpBarStateMap.put(PrimarySkillType.REPAIR, SkillUtils.asBarState(subString[FlatFileMappings.BARSTATE_REPAIR]));
-            xpBarStateMap.put(PrimarySkillType.SALVAGE, SkillUtils.asBarState(subString[FlatFileMappings.BARSTATE_SALVAGE]));
-            xpBarStateMap.put(PrimarySkillType.SMELTING, SkillUtils.asBarState(subString[FlatFileMappings.BARSTATE_SMELTING]));
-            xpBarStateMap.put(PrimarySkillType.SWORDS, SkillUtils.asBarState(subString[FlatFileMappings.BARSTATE_SWORDS]));
-            xpBarStateMap.put(PrimarySkillType.TAMING, SkillUtils.asBarState(subString[FlatFileMappings.BARSTATE_TAMING]));
-            xpBarStateMap.put(PrimarySkillType.UNARMED, SkillUtils.asBarState(subString[FlatFileMappings.BARSTATE_UNARMED]));
-            xpBarStateMap.put(PrimarySkillType.WOODCUTTING, SkillUtils.asBarState(subString[FlatFileMappings.BARSTATE_WOODCUTTING]));
-            xpBarStateMap.put(PrimarySkillType.TRIDENTS, SkillUtils.asBarState(subString[FlatFileMappings.BARSTATE_TRIDENTS]));
-            xpBarStateMap.put(PrimarySkillType.CROSSBOWS, SkillUtils.asBarState(subString[FlatFileMappings.BARSTATE_CROSSBOWS]));
+            xpBarStateMap.put(PrimarySkillType.ACROBATICS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_ACROBATICS]));
+            xpBarStateMap.put(PrimarySkillType.ALCHEMY, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_ALCHEMY]));
+            xpBarStateMap.put(PrimarySkillType.ARCHERY, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_ARCHERY]));
+            xpBarStateMap.put(PrimarySkillType.AXES, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_AXES]));
+            xpBarStateMap.put(PrimarySkillType.EXCAVATION, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_EXCAVATION]));
+            xpBarStateMap.put(PrimarySkillType.FISHING, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_FISHING]));
+            xpBarStateMap.put(PrimarySkillType.HERBALISM, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_HERBALISM]));
+            xpBarStateMap.put(PrimarySkillType.MINING, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_MINING]));
+            xpBarStateMap.put(PrimarySkillType.REPAIR, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_REPAIR]));
+            xpBarStateMap.put(PrimarySkillType.SALVAGE, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_SALVAGE]));
+            xpBarStateMap.put(PrimarySkillType.SMELTING, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_SMELTING]));
+            xpBarStateMap.put(PrimarySkillType.SWORDS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_SWORDS]));
+            xpBarStateMap.put(PrimarySkillType.TAMING, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_TAMING]));
+            xpBarStateMap.put(PrimarySkillType.UNARMED, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_UNARMED]));
+            xpBarStateMap.put(PrimarySkillType.WOODCUTTING, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_WOODCUTTING]));
+            xpBarStateMap.put(PrimarySkillType.TRIDENTS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_TRIDENTS]));
+            xpBarStateMap.put(PrimarySkillType.CROSSBOWS, SkillUtils.asBarState(dataStrSplit[FlatFileMappings.BARSTATE_CROSSBOWS]));
 
         } catch (Exception e) {
             xpBarStateMap = MMOExperienceBarManager.generateDefaultBarStateMap();
         }
 
-        //Build Player Data
-        playerDataBuilder.setSkillLevelValues(skillLevelMap)
-            .setSkillExperienceValues(skillExperienceValueMap)
-            .setAbilityDeactivationTimestamps(skillAbilityDeactivationTimeStamp)
-            .setMobHealthBarType(mobHealthbarType)
-            .setPlayerUUID(playerUUID)
-            .setScoreboardTipsShown(scoreboardTipsShown)
-            .setUniquePlayerData(uniquePlayerDataMap)
-            .setBarStateMap(xpBarStateMap);
+
 
         PersistentPlayerData persistentPlayerData;
 
         try {
+            //Set Player Data
+            playerDataBuilder.setSkillLevelValues(skillLevelMap)
+                    .setSkillExperienceValues(skillExperienceValueMap)
+                    .setAbilityDeactivationTimestamps(skillAbilityDeactivationTimeStamp)
+//                    .setMobHealthBarType(mobHealthbarType)
+                    .setPlayerUUID(playerUUID)
+                    .setScoreboardTipsShown(scoreboardTipsShown)
+                    .setUniquePlayerData(uniquePlayerDataMap)
+                    .setBarStateMap(xpBarStateMap);
+
+            //Build Data
             persistentPlayerData = playerDataBuilder.build();
+            return new PlayerProfile(persistentPlayerData);
         } catch (Exception e) {
             mcMMO.p.getLogger().severe("Critical failure when trying to construct persistent player data!");
             e.printStackTrace();
             return null;
         }
-
-
-//        return new PlayerProfile(subString[USERNAME], playerUUID, skillLevelMap, skillExperienceValueMap, skillAbilityDeactivationTimeStamp, mobHealthbarType, scoreboardTipsShown, uniquePlayerDataMap, xpBarStateMap);
-        return new PlayerProfile(persistentPlayerData);
     }
 
     private EnumMap<PrimarySkillType, Integer> getSkillMapFromLine(String[] stringDataArray) {
@@ -1484,7 +1410,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
         return skillLevelsMap;
     }
 
-    public DatabaseType getDatabaseType() {
+    public @NotNull DatabaseType getDatabaseType() {
         return DatabaseType.FLATFILE;
     }
 

+ 16 - 27
src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java

@@ -1,5 +1,6 @@
 package com.gmail.nossr50.database;
 
+import com.gmail.nossr50.api.exceptions.ProfileRetrievalException;
 import com.gmail.nossr50.config.Config;
 import com.gmail.nossr50.datatypes.MobHealthBarType;
 import com.gmail.nossr50.datatypes.database.DatabaseType;
@@ -13,6 +14,7 @@ import com.gmail.nossr50.runnables.database.UUIDUpdateAsyncTask;
 import com.gmail.nossr50.util.Misc;
 import com.gmail.nossr50.util.experience.MMOExperienceBarManager;
 import com.gmail.nossr50.util.skills.SkillUtils;
+import org.apache.commons.lang.NullArgumentException;
 import org.apache.tomcat.jdbc.pool.DataSource;
 import org.apache.tomcat.jdbc.pool.PoolProperties;
 import org.bukkit.entity.Player;
@@ -24,7 +26,7 @@ import java.sql.*;
 import java.util.*;
 import java.util.concurrent.locks.ReentrantLock;
 
-public final class SQLDatabaseManager implements DatabaseManager {
+public final class SQLDatabaseManager extends AbstractDatabaseManager {
     private static final String ALL_QUERY_VERSION = "total";
     private final String tablePrefix = Config.getInstance().getMySQLTablePrefix();
 
@@ -179,7 +181,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
         mcMMO.p.getLogger().info("Purged " + purged + " users from the database.");
     }
 
-    public boolean removeUser(String playerName, UUID uuid) {
+    public boolean removeUser(String playerName, @Nullable UUID uuid) {
         boolean success = false;
         Connection connection = null;
         PreparedStatement statement = null;
@@ -220,7 +222,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
         cachedUserIDs.remove(uuid);
     }
 
-    public boolean saveUser(MMODataSnapshot dataSnapshot) {
+    public boolean saveUser(@NotNull MMODataSnapshot dataSnapshot) {
         boolean success = true;
         PreparedStatement statement = null;
         Connection connection = null;
@@ -401,7 +403,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
         return success;
     }
 
-    public List<PlayerStat> readLeaderboard(PrimarySkillType skill, int pageNumber, int statsPerPage) {
+    public @NotNull List<PlayerStat> readLeaderboard(@NotNull PrimarySkillType skill, int pageNumber, int statsPerPage) {
         List<PlayerStat> stats = new ArrayList<>();
 
         String query = skill == null ? ALL_QUERY_VERSION : skill.name().toLowerCase(Locale.ENGLISH);
@@ -440,7 +442,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
         return stats;
     }
 
-    public Map<PrimarySkillType, Integer> readRank(String playerName) {
+    public @NotNull Map<PrimarySkillType, Integer> readRank(@NotNull String playerName) {
         Map<PrimarySkillType, Integer> skills = new HashMap<>();
 
         ResultSet resultSet = null;
@@ -536,7 +538,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
         return skills;
     }
 
-    public void newUser(String playerName, UUID uuid) {
+    public void insertNewUser(@NotNull String playerName, @NotNull UUID uuid) {
         Connection connection = null;
 
         try {
@@ -589,25 +591,12 @@ public final class SQLDatabaseManager implements DatabaseManager {
         return -1;
     }
 
-//    @Deprecated
-//    public PlayerProfile loadPlayerProfile(String playerName, boolean create) {
-//        return loadPlayerProfile(playerName, null);
-//    }
-
-    public @Nullable PlayerProfile loadPlayerProfile(UUID uuid) {
-        return loadPlayerProfile(null, "", uuid);
-    }
-
-    public @Nullable PlayerProfile loadPlayerProfile(String playerName) {
-        return loadPlayerProfile(null, playerName, null);
-    }
-
-    public @Nullable PlayerProfile loadPlayerProfile(String playerName, UUID uuid, boolean create) {
-        return loadPlayerProfile(null, playerName, uuid);
+    @Override
+    public @Nullable PlayerProfile queryPlayerDataByPlayer(@NotNull Player player) throws ProfileRetrievalException, NullArgumentException {
     }
 
-    public @NotNull PlayerProfile loadPlayerProfile(Player player) {
-        return loadPlayerProfile(player, player.getName(), player.getUniqueId());
+    @Override
+    public @Nullable PlayerProfile queryPlayerDataByUUID(@NotNull UUID uuid, @NotNull String playerName) throws ProfileRetrievalException, NullArgumentException {
     }
 
     private @Nullable PlayerProfile loadPlayerProfile(@Nullable Player player, @NotNull String playerName, @Nullable UUID playerUUID) {
@@ -685,7 +674,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
         return null;
     }
 
-    public void convertUsers(DatabaseManager destination) {
+    public void convertUsers(@NotNull DatabaseManager destination) {
         PreparedStatement statement = null;
         Connection connection = null;
         ResultSet resultSet = null;
@@ -815,7 +804,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
 //        }
 //    }
 
-    public List<String> getStoredUsers() {
+    public @NotNull List<String> getStoredUsers() {
         ArrayList<String> users = new ArrayList<>();
 
         Statement statement = null;
@@ -1341,7 +1330,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
         mcMMO.p.getLogger().severe("VendorError: " + ex.getErrorCode());
     }
 
-    public DatabaseType getDatabaseType() {
+    public @NotNull DatabaseType getDatabaseType() {
         return DatabaseType.SQL;
     }
 
@@ -1743,7 +1732,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
     }
 
     @Override
-    public void removeCache(UUID uuid) {
+    public void removeCache(@NotNull UUID uuid) {
         cachedUserIDs.remove(uuid);
     }
 }

+ 0 - 8
src/main/java/com/gmail/nossr50/datatypes/party/PartyFeature.java

@@ -10,8 +10,6 @@ import org.bukkit.entity.Player;
 public enum PartyFeature {
     CHAT,
     TELEPORT,
-    ALLIANCE,
-    ITEM_SHARE,
     XP_SHARE;
 
     public String getLocaleString() {
@@ -31,12 +29,6 @@ public enum PartyFeature {
             case TELEPORT:
                 partySubCommandType = PartySubCommandType.TELEPORT;
                 break;
-            case ALLIANCE:
-                partySubCommandType = PartySubCommandType.ALLIANCE;
-                break;
-            case ITEM_SHARE:
-                partySubCommandType = PartySubCommandType.ITEMSHARE;
-                break;
             case XP_SHARE:
                 partySubCommandType = PartySubCommandType.XPSHARE;
                 break;

+ 4 - 5
src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java

@@ -21,7 +21,6 @@ import com.gmail.nossr50.util.skills.SkillUtils;
 import com.gmail.nossr50.util.sounds.SoundManager;
 import com.gmail.nossr50.util.sounds.SoundType;
 import net.kyori.adventure.text.TextComponent;
-import net.md_5.bungee.api.chat.ComponentBuilder;
 import org.bukkit.Location;
 import org.bukkit.Material;
 import org.bukkit.SoundCategory;
@@ -119,7 +118,7 @@ public class Roll extends AcrobaticsSubSkill {
         String rollChance, rollChanceLucky, gracefulRollChance, gracefulRollChanceLucky;
 
         /* Values related to the player */
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
         float skillValue = mmoPlayer.getExperienceManager().getSkillLevel(getPrimarySkill());
         boolean isLucky = Permissions.lucky(player, getPrimarySkill());
 
@@ -269,7 +268,7 @@ public class Roll extends AcrobaticsSubSkill {
             return false;
         }
 
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
         if (ItemUtils.hasItemInEitherHand(player, Material.ENDER_PEARL) || player.isInsideVehicle()) {
             if(mmoPlayer.isDebugMode()) {
@@ -278,7 +277,7 @@ public class Roll extends AcrobaticsSubSkill {
             return true;
         }
 
-        if(mcMMO.getUserManager().getPlayer(player).getAcrobaticsManager().hasFallenInLocationBefore(getBlockLocation(player)))
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player).getAcrobaticsManager().hasFallenInLocationBefore(getBlockLocation(player)))
         {
             if(mmoPlayer.isDebugMode()) {
                 mmoPlayer.getPlayer().sendMessage("Acrobatics XP Prevented: Fallen in location before");
@@ -420,7 +419,7 @@ public class Roll extends AcrobaticsSubSkill {
 
     public void addFallLocation(Player player)
     {
-        mcMMO.getUserManager().getPlayer(player).getAcrobaticsManager().addLocationToFallMap(getBlockLocation(player));
+        mcMMO.getUserManager().queryMcMMOPlayer(player).getAcrobaticsManager().addLocationToFallMap(getBlockLocation(player));
     }
 
     public Location getBlockLocation(Player player)

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

@@ -218,7 +218,7 @@ public class BlockListener implements Listener {
             return;
         }
 
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
         if(mmoPlayer == null)
             return;
@@ -314,7 +314,7 @@ public class BlockListener implements Listener {
             return;
         }
 
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
         //Check if profile is loaded
         if(mmoPlayer == null) {
@@ -408,7 +408,7 @@ public class BlockListener implements Listener {
         }
 
         //Profile not loaded
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
         {
             return;
         }
@@ -417,7 +417,7 @@ public class BlockListener implements Listener {
         ItemStack heldItem = player.getInventory().getItemInMainHand();
 
         if (ItemUtils.isSword(heldItem)) {
-            HerbalismManager herbalismManager = mcMMO.getUserManager().getPlayer(player).getHerbalismManager();
+            HerbalismManager herbalismManager = mcMMO.getUserManager().queryMcMMOPlayer(player).getHerbalismManager();
 
             if (herbalismManager.canUseHylianLuck()) {
                 if (herbalismManager.processHylianLuck(blockState)) {
@@ -471,7 +471,7 @@ public class BlockListener implements Listener {
             return;
         }
 
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
         //Profile not loaded
         if(mmoPlayer == null)
@@ -557,10 +557,10 @@ public class BlockListener implements Listener {
             return;
         }
 
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
         //Profile not loaded
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
         {
             return;
         }
@@ -604,10 +604,10 @@ public class BlockListener implements Listener {
     @EventHandler(priority = EventPriority.MONITOR)
     public void onBlockDamageCleanup(BlockDamageEvent event) {
         Player player = event.getPlayer();
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
         //Profile not loaded
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
         {
             return;
         }
@@ -625,19 +625,19 @@ public class BlockListener implements Listener {
     //TODO: Convert into locale strings
     private void debugStickDump(Player player, BlockState blockState) {
         //Profile not loaded
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
         {
             return;
         }
 
-        if(mcMMO.getUserManager().getPlayer(player).isDebugMode())
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player).isDebugMode())
         {
             if(mcMMO.getPlaceStore().isTrue(blockState))
                 player.sendMessage("[mcMMO DEBUG] This block is not natural and does not reward treasures/XP");
             else
             {
                 player.sendMessage("[mcMMO DEBUG] This block is considered natural by mcMMO");
-                mcMMO.getUserManager().getPlayer(player).getExcavationManager().printExcavationDebug(player, blockState);
+                mcMMO.getUserManager().queryMcMMOPlayer(player).getExcavationManager().printExcavationDebug(player, blockState);
             }
 
             if(WorldGuardUtils.isWorldGuardLoaded())

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

@@ -170,7 +170,7 @@ public class EntityListener implements Listener {
 
             //Crossbow only
             if(isCrossbow) {
-                McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+                McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
                 //Process launch event
                 if(Permissions.skillEnabled(player, PrimarySkillType.CROSSBOWS)) {
@@ -428,7 +428,7 @@ public class EntityListener implements Listener {
                     }
 
                     //Deflect checks
-                    final McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(defendingPlayer);
+                    final McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(defendingPlayer);
                     if (mmoPlayer != null) {
                         UnarmedManager unarmedManager = mmoPlayer.getUnarmedManager();
 
@@ -584,7 +584,7 @@ public class EntityListener implements Listener {
                 return;
             }
 
-            McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+            McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
             //Profile not loaded
             if(mmoPlayer == null)
@@ -622,12 +622,12 @@ public class EntityListener implements Listener {
                 Wolf wolf = (Wolf) pet;
 
                 //Profile not loaded
-                if(mcMMO.getUserManager().getPlayer(player) == null)
+                if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
                 {
                     return;
                 }
 
-                TamingManager tamingManager = mcMMO.getUserManager().getPlayer(player).getTamingManager();
+                TamingManager tamingManager = mcMMO.getUserManager().queryMcMMOPlayer(player).getTamingManager();
 
                 switch (cause) {
                     case CONTACT:
@@ -825,7 +825,7 @@ public class EntityListener implements Listener {
         }
 
         //Profile not loaded
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
         {
             return;
         }
@@ -837,7 +837,7 @@ public class EntityListener implements Listener {
                 return;
         }
 
-        MiningManager miningManager = mcMMO.getUserManager().getPlayer(player).getMiningManager();
+        MiningManager miningManager = mcMMO.getUserManager().queryMcMMOPlayer(player).getMiningManager();
 
         if (miningManager.canUseBiggerBombs()) {
             event.setRadius(miningManager.biggerBombs(event.getRadius()));
@@ -878,12 +878,12 @@ public class EntityListener implements Listener {
         }
 
         //Profile not loaded
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
         {
             return;
         }
 
-        MiningManager miningManager = mcMMO.getUserManager().getPlayer(player).getMiningManager();
+        MiningManager miningManager = mcMMO.getUserManager().queryMcMMOPlayer(player).getMiningManager();
 
         if (miningManager.canUseBlastMining()) {
             miningManager.blastMiningDropProcessing(event.getYield(), event);
@@ -912,7 +912,7 @@ public class EntityListener implements Listener {
         Player player = (Player) entity;
 
         //Profile not loaded
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
         {
             return;
         }
@@ -977,7 +977,7 @@ public class EntityListener implements Listener {
                                * 1000
                                */
                 if (Permissions.isSubSkillEnabled(player, SubSkillType.HERBALISM_FARMERS_DIET)) {
-                    event.setFoodLevel(mcMMO.getUserManager().getPlayer(player).getHerbalismManager().farmersDiet(newFoodLevel));
+                    event.setFoodLevel(mcMMO.getUserManager().queryMcMMOPlayer(player).getHerbalismManager().farmersDiet(newFoodLevel));
                 }
                 return;
 
@@ -989,7 +989,7 @@ public class EntityListener implements Listener {
                                     */
             case POTATO: /* RESTORES 1/2 HUNGER - RESTORES 2 HUNGER @ 1000 */
                 if (Permissions.isSubSkillEnabled(player, SubSkillType.HERBALISM_FARMERS_DIET)) {
-                    event.setFoodLevel(mcMMO.getUserManager().getPlayer(player).getHerbalismManager().farmersDiet(newFoodLevel));
+                    event.setFoodLevel(mcMMO.getUserManager().queryMcMMOPlayer(player).getHerbalismManager().farmersDiet(newFoodLevel));
                 }
                 return;
             case COD:
@@ -999,7 +999,7 @@ public class EntityListener implements Listener {
             case COOKED_SALMON:
 
                 if (Permissions.isSubSkillEnabled(player, SubSkillType.FISHING_FISHERMANS_DIET)) {
-                    event.setFoodLevel(mcMMO.getUserManager().getPlayer(player).getFishingManager().handleFishermanDiet(newFoodLevel));
+                    event.setFoodLevel(mcMMO.getUserManager().queryMcMMOPlayer(player).getFishingManager().handleFishermanDiet(newFoodLevel));
                 }
                 return;
 
@@ -1041,12 +1041,12 @@ public class EntityListener implements Listener {
         entity.setMetadata(mcMMO.entityMetadataKey, mcMMO.metadataValue);
 
         //Profile not loaded
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
         {
             return;
         }
 
-        mcMMO.getUserManager().getPlayer(player).getTamingManager().awardTamingXP(entity);
+        mcMMO.getUserManager().queryMcMMOPlayer(player).getTamingManager().awardTamingXP(entity);
     }
 
     /**

+ 6 - 6
src/main/java/com/gmail/nossr50/listeners/InventoryListener.java

@@ -66,13 +66,13 @@ public class InventoryListener implements Listener {
                 }
 
                 //Profile doesn't exist
-                if(mcMMO.getUserManager().getOfflinePlayer(offlinePlayer) == null)
+                if(mcMMO.getUserManager().queryMcMMOPlayer(offlinePlayer) == null)
                 {
                     return;
                 }
 
 
-                boolean debugMode = player.isOnline() && mcMMO.getUserManager().getPlayer(player).isDebugMode();
+                boolean debugMode = player.isOnline() && mcMMO.getUserManager().queryMcMMOPlayer(player).isDebugMode();
 
                 if(debugMode) {
                     player.sendMessage("FURNACE FUEL EFFICIENCY DEBUG REPORT");
@@ -81,7 +81,7 @@ public class InventoryListener implements Listener {
                     player.sendMessage("Burn Length before Fuel Efficiency is applied - "+event.getBurnTime());
                 }
 
-                event.setBurnTime(mcMMO.getUserManager().getPlayer(player).getSmeltingManager().fuelEfficiency(event.getBurnTime()));
+                event.setBurnTime(mcMMO.getUserManager().queryMcMMOPlayer(player).getSmeltingManager().fuelEfficiency(event.getBurnTime()));
 
                 if(debugMode) {
                     player.sendMessage("New Furnace Burn Length (after applying fuel efficiency) "+event.getBurnTime());
@@ -111,7 +111,7 @@ public class InventoryListener implements Listener {
 
             if(offlinePlayer != null) {
 
-                McMMOPlayer offlineProfile = mcMMO.getUserManager().getOfflinePlayer(offlinePlayer);
+                McMMOPlayer offlineProfile = mcMMO.getUserManager().queryMcMMOPlayer(offlinePlayer);
 
                 //Profile doesn't exist
                 if(offlineProfile != null) {
@@ -148,13 +148,13 @@ public class InventoryListener implements Listener {
             }
 
             //Profile not loaded
-            if(mcMMO.getUserManager().getPlayer(player) == null)
+            if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
             {
                 return;
             }
 
             int xpToDrop = event.getExpToDrop();
-            int exp = mcMMO.getUserManager().getPlayer(player).getSmeltingManager().vanillaXPBoost(xpToDrop);
+            int exp = mcMMO.getUserManager().queryMcMMOPlayer(player).getSmeltingManager().vanillaXPBoost(xpToDrop);
             event.setExpToDrop(exp);
         }
     }

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

@@ -91,12 +91,12 @@ public class PlayerListener implements Listener {
         }
 
         //Profile not loaded
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
         {
             return;
         }
 
-        mcMMO.getUserManager().getPlayer(player).actualizeTeleportATS();
+        mcMMO.getUserManager().queryMcMMOPlayer(player).actualizeTeleportATS();
     }
     /**
      * Handle PlayerDeathEvents at the lowest priority.
@@ -201,12 +201,12 @@ public class PlayerListener implements Listener {
         }
 
         //Profile not loaded
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
         {
             return;
         }
 
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
         mmoPlayer.checkGodMode();
         mmoPlayer.checkParty();
@@ -272,12 +272,12 @@ public class PlayerListener implements Listener {
         }
 
         //Profile not loaded
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
         {
             return;
         }
 
-        FishingManager fishingManager = mcMMO.getUserManager().getPlayer(player).getFishingManager();
+        FishingManager fishingManager = mcMMO.getUserManager().queryMcMMOPlayer(player).getFishingManager();
 
         switch (event.getState()) {
             case CAUGHT_FISH:
@@ -350,13 +350,13 @@ public class PlayerListener implements Listener {
         }
 
         //Profile not loaded
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
         {
             return;
         }
 
         Entity caught = event.getCaught();
-        FishingManager fishingManager = mcMMO.getUserManager().getPlayer(player).getFishingManager();
+        FishingManager fishingManager = mcMMO.getUserManager().queryMcMMOPlayer(player).getFishingManager();
 
         //Track the hook
         if(ExperienceConfig.getInstance().isFishingExploitingPrevented())
@@ -445,12 +445,12 @@ public class PlayerListener implements Listener {
             }
 
             //Profile not loaded
-            if(mcMMO.getUserManager().getPlayer(player) == null)
+            if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
             {
                 return;
             }
 
-            McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+            McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
             Item drop = event.getItem();
             ItemStack dropStack = drop.getItemStack();
@@ -507,13 +507,13 @@ public class PlayerListener implements Listener {
         }
 
         //Profile not loaded
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
         {
             return;
         }
 
         //No need for null checks here
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
         //TODO: There's an issue with using Async saves on player quit
         //TODO: Basically there are conditions in which an async task does not execute fast enough to save the data if the server shutdown shortly after this task was scheduled
         mcMMO.getUserManager().saveUserWithDelay(mmoPlayer.getPersistentPlayerData(), false, 20);
@@ -564,12 +564,12 @@ public class PlayerListener implements Listener {
         }
 
         //Profile not loaded
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
         {
             return;
         }
 
-        mcMMO.getUserManager().getPlayer(player).actualizeRespawnATS();
+        mcMMO.getUserManager().queryMcMMOPlayer(player).actualizeRespawnATS();
     }
 
     /**
@@ -611,12 +611,12 @@ public class PlayerListener implements Listener {
         }
 
         //Profile not loaded
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
         {
             return;
         }
 
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
         MiningManager miningManager = mmoPlayer.getMiningManager();
         ItemStack heldItem = player.getInventory().getItemInMainHand();
 
@@ -645,7 +645,7 @@ public class PlayerListener implements Listener {
                             && RankUtils.hasUnlockedSubskill(player, SubSkillType.SALVAGE_SCRAP_COLLECTOR)
                             && mcMMO.getSalvageableManager().isSalvageable(heldItem)
                             && heldItem.getAmount() <= 1) {
-                                SalvageManager salvageManager = mcMMO.getUserManager().getPlayer(player).getSalvageManager();
+                                SalvageManager salvageManager = mcMMO.getUserManager().queryMcMMOPlayer(player).getSalvageManager();
                                 event.setCancelled(true);
 
                                 // Make sure the player knows what he's doing when trying to salvage an enchanted item
@@ -727,12 +727,12 @@ public class PlayerListener implements Listener {
         }
 
         //Profile not loaded
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
         {
             return;
         }
 
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
         ItemStack heldItem = player.getInventory().getItemInMainHand();
 
         //Spam Fishing Detection
@@ -767,7 +767,7 @@ public class PlayerListener implements Listener {
             return;
         }
 
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getOfflinePlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
         if (mmoPlayer == null) {
             mcMMO.p.debug(player.getName() + "is chatting, but is currently not logged in to the server.");

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

@@ -38,14 +38,14 @@ public class SelfListener implements Listener {
             {
                 int previousLevelGained = event.getSkillLevel() - i;
                 //Send player skill unlock notifications
-                RankUtils.executeSkillUnlockNotifications(plugin, mcMMO.getUserManager().getPlayer(player), event.getSkill(), previousLevelGained);
+                RankUtils.executeSkillUnlockNotifications(plugin, mcMMO.getUserManager().queryMcMMOPlayer(player), event.getSkill(), previousLevelGained);
             }
 
         for(int i = 0; i < event.getLevelsGained(); i++)
         {
             int previousLevelGained = event.getSkillLevel() - i;
             //Send player skill unlock notifications
-            RankUtils.executeSkillUnlockNotifications(plugin, mcMMO.getUserManager().getPlayer(player), event.getSkill(), previousLevelGained);
+            RankUtils.executeSkillUnlockNotifications(plugin, mcMMO.getUserManager().queryMcMMOPlayer(player), event.getSkill(), previousLevelGained);
         }
 
         //Reset the delay timer
@@ -81,7 +81,7 @@ public class SelfListener implements Listener {
     @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
     public void onPlayerXpGain(McMMOPlayerXpGainEvent event) {
         Player player = event.getPlayer();
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
         PrimarySkillType primarySkillType = event.getSkill();
 
         if(mmoPlayer.isDebugMode()) {

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

@@ -40,6 +40,15 @@ public final class PartyManager {
         parties = new HashMap<>();
     }
 
+    /**
+     * Get the level of a party
+     * @param party target party
+     * @return the level value of the target party
+     */
+    public int getPartyLevel(@NotNull Party party) {
+        return party.getPartyExperienceManager().getLevel();
+    }
+
     /**
      * Check if a party with a given name already exists.
      *
@@ -95,19 +104,19 @@ public final class PartyManager {
      */
     public boolean inSameParty(Player firstPlayer, Player secondPlayer) {
         //Profile not loaded
-        if(mcMMO.getUserManager().getPlayer(firstPlayer) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(firstPlayer) == null)
         {
             return false;
         }
 
         //Profile not loaded
-        if(mcMMO.getUserManager().getPlayer(secondPlayer) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(secondPlayer) == null)
         {
             return false;
         }
 
-        Party firstParty = mcMMO.getUserManager().getPlayer(firstPlayer).getParty();
-        Party secondParty = mcMMO.getUserManager().getPlayer(secondPlayer).getParty();
+        Party firstParty = mcMMO.getUserManager().queryMcMMOPlayer(firstPlayer).getParty();
+        Party secondParty = mcMMO.getUserManager().queryMcMMOPlayer(secondPlayer).getParty();
 
         if (firstParty == null || secondParty == null) {
             return false;
@@ -261,12 +270,12 @@ public final class PartyManager {
      */
     public Party getParty(Player player) {
         //Profile not loaded
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
         {
             return null;
         }
 
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
         return mmoPlayer.getParty();
     }
@@ -328,12 +337,12 @@ public final class PartyManager {
         //TODO: Potential issues with unloaded profile?
         for (Player member : party.getPartyMembers()) {
             //Profile not loaded
-            if(mcMMO.getUserManager().getPlayer(member) == null)
+            if(mcMMO.getUserManager().queryMcMMOPlayer(member) == null)
             {
                 continue;
             }
 
-            processPartyLeaving(mcMMO.getUserManager().getPlayer(member));
+            processPartyLeaving(mcMMO.getUserManager().queryMcMMOPlayer(member));
         }
 
         // Disband the alliance between the disbanded party and it's ally
@@ -679,7 +688,7 @@ public final class PartyManager {
             Party party = new Party(partyName);
 
             String leaderName = partiesFile.getString(partyName + ".Leader");
-            PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(leaderName, false);
+            PlayerProfile profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(leaderName, false);
 
             if (!profile.isLoaded()) {
                 mcMMO.p.getLogger().warning("Could not find UUID in database for party leader " + leaderName + " in party " + partyName);
@@ -708,7 +717,7 @@ public final class PartyManager {
             LinkedHashMap<UUID, String> members = party.getMembers();
 
             for (String memberName : partiesFile.getStringList(partyName + ".Members")) {
-                PlayerProfile memberProfile = mcMMO.getDatabaseManager().loadPlayerProfile(memberName, false);
+                PlayerProfile memberProfile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(memberName, false);
 
                 if (!memberProfile.isLoaded()) {
                     mcMMO.p.getLogger().warning("Could not find UUID in database for party member " + memberName + " in party " + partyName);

+ 1 - 1
src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java

@@ -31,7 +31,7 @@ public class FormulaConversionTask extends BukkitRunnable {
 
             // If the mmoPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process.
             if (mmoPlayer == null) {
-                profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName, false);
+                profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(playerName, false);
 
                 if (!profile.isLoaded()) {
                     mcMMO.p.debug("Profile not loaded.");

+ 18 - 20
src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java

@@ -41,33 +41,32 @@ public class PlayerProfileLoadingTask extends BukkitRunnable {
             return;
         }
 
-        PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(player.getName(), player.getUniqueId(), true);
-
-        // If successful, schedule the apply
-        if (profile.isLoaded()) {
+        try {
+            PlayerProfile profile = mcMMO.getDatabaseManager().queryPlayerDataByUUID(player.getUniqueId());
             new ApplySuccessfulProfile(new McMMOPlayer(player, profile)).runTask(mcMMO.p);
             EventUtils.callPlayerProfileLoadEvent(player, profile);
             return;
-        }
 
-        // Print errors to console/logs if we're failing at least 2 times in a row to load the profile
-        if (attempt >= 3)
-        {
-            //Log the error
-            mcMMO.p.getLogger().severe(LocaleLoader.getString("Profile.Loading.FailureNotice",
-                    player.getName(), String.valueOf(attempt)));
+        } catch () {
+            // Print errors to console/logs if we're failing at least 2 times in a row to load the profile
+            if (attempt >= 3)
+            {
+                //Log the error
+                mcMMO.p.getLogger().severe(LocaleLoader.getString("Profile.Loading.FailureNotice",
+                        player.getName(), String.valueOf(attempt)));
 
-            //Notify the admins
-            mcMMO.p.getServer().broadcast(LocaleLoader.getString("Profile.Loading.FailureNotice", player.getName()), Server.BROADCAST_CHANNEL_ADMINISTRATIVE);
+                //Notify the admins
+                mcMMO.p.getServer().broadcast(LocaleLoader.getString("Profile.Loading.FailureNotice", player.getName()), Server.BROADCAST_CHANNEL_ADMINISTRATIVE);
 
-            //Notify the player
-            player.sendMessage(LocaleLoader.getString("Profile.Loading.FailurePlayer", String.valueOf(attempt)).split("\n"));
-        }
+                //Notify the player
+                player.sendMessage(LocaleLoader.getString("Profile.Loading.FailurePlayer", String.valueOf(attempt)).split("\n"));
+            }
 
-        // Increment attempt counter and try
-        attempt++;
+            // Increment attempt counter and try
+            attempt++;
 
-        new PlayerProfileLoadingTask(player, attempt).runTaskLaterAsynchronously(mcMMO.p, (100 + (attempt * 100)));
+            new PlayerProfileLoadingTask(player, attempt).runTaskLaterAsynchronously(mcMMO.p, (100 + (attempt * 100)));
+        }
     }
 
     private class ApplySuccessfulProfile extends BukkitRunnable {
@@ -86,7 +85,6 @@ public class PlayerProfileLoadingTask extends BukkitRunnable {
                 return;
             }
 
-            mmoPlayer.setupPartyData();
             mcMMO.getUserManager().track(mmoPlayer);
             mmoPlayer.actualizeRespawnATS();
 

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

@@ -39,9 +39,9 @@ public class AlchemyBrewTask extends BukkitRunnable {
         if (player != null
                 && !Misc.isNPCEntityExcludingVillagers(player)
                 && Permissions.isSubSkillEnabled(player, SubSkillType.ALCHEMY_CATALYSIS)
-                && mcMMO.getUserManager().getPlayer(player) != null) {
+                && mcMMO.getUserManager().queryMcMMOPlayer(player) != null) {
 
-            double catalysis = mcMMO.getUserManager().getPlayer(player).getAlchemyManager().calculateBrewSpeed(Permissions.lucky(player, PrimarySkillType.ALCHEMY));
+            double catalysis = mcMMO.getUserManager().queryMcMMOPlayer(player).getAlchemyManager().calculateBrewSpeed(Permissions.lucky(player, PrimarySkillType.ALCHEMY));
 
             McMMOPlayerCatalysisEvent event = new McMMOPlayerCatalysisEvent(player, catalysis);
             mcMMO.p.getServer().getPluginManager().callEvent(event);

+ 3 - 3
src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyPotionBrewer.java

@@ -92,12 +92,12 @@ public final class AlchemyPotionBrewer {
     }
 
     private static List<ItemStack> getValidIngredients(Player player) {
-        if(player == null || mcMMO.getUserManager().getPlayer(player) == null)
+        if(player == null || mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
         {
             return PotionConfig.getInstance().getIngredients(1);
         }
 
-        return PotionConfig.getInstance().getIngredients(!Permissions.isSubSkillEnabled(player, SubSkillType.ALCHEMY_CONCOCTIONS) ? 1 : mcMMO.getUserManager().getPlayer(player).getAlchemyManager().getTier());
+        return PotionConfig.getInstance().getIngredients(!Permissions.isSubSkillEnabled(player, SubSkillType.ALCHEMY_CONCOCTIONS) ? 1 : mcMMO.getUserManager().queryMcMMOPlayer(player).getAlchemyManager().getTier());
     }
 
     public static void finishBrewing(BlockState brewingStand, Player player, boolean forced) {
@@ -148,7 +148,7 @@ public final class AlchemyPotionBrewer {
 
                 //TODO: hmm
                 if (mcMMO.getUserManager().hasPlayerDataKey(player)) {
-                    mcMMO.getUserManager().getPlayer(player).getAlchemyManager().handlePotionBrewSuccesses(potionStage, 1);
+                    mcMMO.getUserManager().queryMcMMOPlayer(player).getAlchemyManager().handlePotionBrewSuccesses(potionStage, 1);
                 }
             }
         }

+ 2 - 2
src/main/java/com/gmail/nossr50/skills/mining/BlastMining.java

@@ -102,12 +102,12 @@ public class BlastMining {
             return false;
         }
 
-        if(mcMMO.getUserManager().getPlayer(defender) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(defender) == null)
         {
             return false;
         }
 
-        MiningManager miningManager =  mcMMO.getUserManager().getPlayer(defender).getMiningManager();
+        MiningManager miningManager =  mcMMO.getUserManager().queryMcMMOPlayer(defender).getMiningManager();
 
         if (!miningManager.canUseDemolitionsExpertise()) {
             return false;

+ 2 - 2
src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java

@@ -105,13 +105,13 @@ public class UnarmedManager extends SkillManager {
                 return;
             }
 
-            if(mcMMO.getUserManager().getPlayer(defender) == null)
+            if(mcMMO.getUserManager().queryMcMMOPlayer(defender) == null)
                 return;
 
             Item item = Misc.dropItem(defender.getLocation(), defender.getInventory().getItemInMainHand());
 
             if (item != null && AdvancedConfig.getInstance().getDisarmProtected()) {
-                item.setMetadata(mcMMO.disarmedItemKey, mcMMO.getUserManager().getPlayer(defender).getPlayerMetadata());
+                item.setMetadata(mcMMO.disarmedItemKey, mcMMO.getUserManager().queryMcMMOPlayer(defender).getPlayerMetadata());
             }
 
             defender.getInventory().setItemInMainHand(new ItemStack(Material.AIR));

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

@@ -51,7 +51,7 @@ public final class ChimaeraWing {
             return;
         }
 
-        mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
         //Not loaded
         if(mmoPlayer == null)

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

@@ -73,7 +73,7 @@ public class EventUtils {
      */
     public static McMMOPlayer getMcMMOPlayer(Entity entity)
     {
-        return mcMMO.getUserManager().getPlayer((Player)entity);
+        return mcMMO.getUserManager().queryMcMMOPlayer((Player)entity);
     }
 
     /**
@@ -121,7 +121,7 @@ public class EventUtils {
                 return true;
             }
 
-            McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+            McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
             if(mmoPlayer == null)
             {
@@ -199,7 +199,7 @@ public class EventUtils {
         boolean isCancelled = event.isCancelled();
 
         if (isCancelled) {
-            PlayerProfile profile = mcMMO.getUserManager().getPlayer(player);
+            PlayerProfile profile = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
             profile.getExperienceManager().setSkillLevel(skill, profile.getSkillLevel(skill) - (isLevelUp ? levelsChanged : -levelsChanged));
             profile.addXp(skill, xpRemoved);
@@ -215,7 +215,7 @@ public class EventUtils {
         boolean isCancelled = event.isCancelled();
 
         if (isCancelled) {
-            PlayerProfile profile = mcMMO.getUserManager().getPlayer(player);
+            PlayerProfile profile = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
             profile.modifySkill(skill, profile.getSkillLevel(skill) - (isLevelUp ? levelsChanged : -levelsChanged));
             profile.addXp(skill, xpRemoved);
@@ -250,7 +250,7 @@ public class EventUtils {
     }
 
     public static void handlePartyTeleportEvent(Player teleportingPlayer, Player targetPlayer) {
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(teleportingPlayer);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(teleportingPlayer);
 
         if(mmoPlayer == null)
             return;
@@ -305,15 +305,15 @@ public class EventUtils {
         boolean isCancelled = event.isCancelled();
 
         if (!isCancelled) {
-            mcMMO.getUserManager().getPlayer(player).addXp(skill, event.getRawXpGained());
-            mcMMO.getUserManager().getPlayer(player).registerXpGain(skill, event.getRawXpGained());
+            mcMMO.getUserManager().queryMcMMOPlayer(player).addXp(skill, event.getRawXpGained());
+            mcMMO.getUserManager().queryMcMMOPlayer(player).registerXpGain(skill, event.getRawXpGained());
         }
 
         return !isCancelled;
     }
 
     public static boolean handleStatsLossEvent(Player player, HashMap<String, Integer> levelChanged, HashMap<String, Float> experienceChanged) {
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
             return true;
 
         McMMOPlayerStatLossEvent event = new McMMOPlayerStatLossEvent(player, levelChanged, experienceChanged);
@@ -324,7 +324,7 @@ public class EventUtils {
         if (!isCancelled) {
             levelChanged = event.getLevelChanged();
             experienceChanged = event.getExperienceChanged();
-            PlayerProfile playerProfile = mcMMO.getUserManager().getPlayer(player);
+            PlayerProfile playerProfile = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
             for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) {
                 String skillName = primarySkillType.toString();
@@ -363,17 +363,17 @@ public class EventUtils {
             HashMap<String, Integer> levelChangedVictim = eventVictim.getLevelChanged();
             HashMap<String, Float> experienceChangedVictim = eventVictim.getExperienceChanged();
 
-            McMMOPlayer killerPlayer = mcMMO.getUserManager().getPlayer(killer);
+            McMMOPlayer killerPlayer = mcMMO.getUserManager().queryMcMMOPlayer(killer);
 
             //Not loaded
             if(killerPlayer == null)
                 return true;
 
             //Not loaded
-            if(mcMMO.getUserManager().getPlayer(victim) == null)
+            if(mcMMO.getUserManager().queryMcMMOPlayer(victim) == null)
                 return true;
 
-            PlayerProfile victimProfile = mcMMO.getUserManager().getPlayer(victim);
+            PlayerProfile victimProfile = mcMMO.getUserManager().queryMcMMOPlayer(victim);
 
             for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) {
                 String skillName = primarySkillType.toString();

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

@@ -25,10 +25,10 @@ public final class HardcoreManager {
         double statLossPercentage = Config.getInstance().getHardcoreDeathStatPenaltyPercentage();
         int levelThreshold = Config.getInstance().getHardcoreDeathStatPenaltyLevelThreshold();
 
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
             return;
 
-        PlayerProfile playerProfile = mcMMO.getUserManager().getPlayer(player);
+        PlayerProfile playerProfile = mcMMO.getUserManager().queryMcMMOPlayer(player);
         int totalLevelsLost = 0;
 
         HashMap<String, Integer> levelChanged = new HashMap<>();
@@ -76,11 +76,11 @@ public final class HardcoreManager {
         double vampirismStatLeechPercentage = Config.getInstance().getHardcoreVampirismStatLeechPercentage();
         int levelThreshold = Config.getInstance().getHardcoreVampirismLevelThreshold();
 
-        if(mcMMO.getUserManager().getPlayer(killer) == null || mcMMO.getUserManager().getPlayer(victim) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(killer) == null || mcMMO.getUserManager().queryMcMMOPlayer(victim) == null)
             return;
 
-        PlayerProfile killerProfile = mcMMO.getUserManager().getPlayer(killer);
-        PlayerProfile victimProfile = mcMMO.getUserManager().getPlayer(victim);
+        PlayerProfile killerProfile = mcMMO.getUserManager().queryMcMMOPlayer(killer);
+        PlayerProfile victimProfile = mcMMO.getUserManager().queryMcMMOPlayer(victim);
         int totalLevelsStolen = 0;
 
         HashMap<String, Integer> levelChanged = new HashMap<>();

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

@@ -367,7 +367,7 @@ public final class HolidayManager {
         if(!Config.getInstance().isAprilFoolsAllowed())
             return;
 
-        final McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        final McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
         if (mmoPlayer == null) return;
 
         int levelTotal = Misc.getRandom().nextInt(1 + mmoPlayer.getSkillLevel(PrimarySkillType.MINING)) + 1;

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

@@ -8,7 +8,7 @@ import com.gmail.nossr50.commands.chat.AdminChatCommand;
 import com.gmail.nossr50.commands.chat.McChatSpy;
 import com.gmail.nossr50.commands.chat.PartyChatCommand;
 import com.gmail.nossr50.commands.database.McpurgeCommand;
-import com.gmail.nossr50.commands.database.McremoveCommand;
+import com.gmail.nossr50.commands.database.DatabaseRemovePlayerCommand;
 import com.gmail.nossr50.commands.database.MmoshowdbCommand;
 import com.gmail.nossr50.commands.experience.AddlevelsCommand;
 import com.gmail.nossr50.commands.experience.AddxpCommand;
@@ -298,7 +298,7 @@ public final class CommandRegistrationManager {
         command.setPermission("mcmmo.commands.mcremove");
         command.setPermissionMessage(permissionsMessage);
         command.setUsage(LocaleLoader.getString("Commands.Usage.1", "mcremove", "<" + LocaleLoader.getString("Commands.Usage.Player") + ">"));
-        command.setExecutor(new McremoveCommand());
+        command.setExecutor(new DatabaseRemovePlayerCommand());
     }
 
     private static void registerMmoshowdbCommand() {

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

@@ -87,7 +87,7 @@ public final class CommandUtils {
 
         PlayerProfile profile = new PlayerProfile(playerName, false);
 
-        if (unloadedProfile(sender, profile)) {
+        if (hasNoProfile(sender, profile)) {
             return false;
         }
 
@@ -95,12 +95,12 @@ public final class CommandUtils {
         return false;
     }
 
-    public static boolean unloadedProfile(CommandSender sender, PlayerProfile profile) {
+    public static boolean hasNoProfile(CommandSender sender, PlayerProfile profile) {
         if (profile.isLoaded()) {
             return false;
         }
 
-        sender.sendMessage(LocaleLoader.getString("Commands.Offline"));
+
         return true;
     }
 
@@ -215,10 +215,10 @@ public final class CommandUtils {
     }
 
     private static void printGroupedSkillData(Player inspect, CommandSender display, String header, List<PrimarySkillType> skillGroup) {
-        if(mcMMO.getUserManager().getPlayer(inspect) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(inspect) == null)
             return;
 
-        PlayerProfile profile = mcMMO.getUserManager().getPlayer(inspect);
+        PlayerProfile profile = mcMMO.getUserManager().queryMcMMOPlayer(inspect);
 
         List<String> displayData = new ArrayList<>();
         displayData.add(header);

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

@@ -35,7 +35,7 @@ public class NotificationManager {
      */
     public static void sendPlayerInformation(Player player, NotificationType notificationType, String key)
     {
-        if(mcMMO.getUserManager().getPlayer(player) == null || !mcMMO.getUserManager().getPlayer(player).hasSkillChatNotifications())
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null || !mcMMO.getUserManager().queryMcMMOPlayer(player).hasSkillChatNotifications())
             return;
 
         McMMOMessageType destination = AdvancedConfig.getInstance().doesNotificationUseActionBar(notificationType) ? McMMOMessageType.ACTION_BAR : McMMOMessageType.SYSTEM;
@@ -49,10 +49,10 @@ public class NotificationManager {
 
     public static boolean doesPlayerUseNotifications(Player player)
     {
-        if(mcMMO.getUserManager().getPlayer(player) == null)
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null)
             return false;
         else
-            return mcMMO.getUserManager().getPlayer(player).hasSkillChatNotifications();
+            return mcMMO.getUserManager().queryMcMMOPlayer(player).hasSkillChatNotifications();
     }
 
     /**
@@ -71,7 +71,7 @@ public class NotificationManager {
 
     public static void sendPlayerInformationChatOnly(Player player, String key, String... values)
     {
-        if(mcMMO.getUserManager().getPlayer(player) == null || !mcMMO.getUserManager().getPlayer(player).hasSkillChatNotifications())
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null || !mcMMO.getUserManager().queryMcMMOPlayer(player).hasSkillChatNotifications())
             return;
 
         String preColoredString = LocaleLoader.getString(key, (Object[]) values);
@@ -80,7 +80,7 @@ public class NotificationManager {
 
     public static void sendPlayerInformationChatOnlyPrefixed(Player player, String key, String... values)
     {
-        if(mcMMO.getUserManager().getPlayer(player) == null || !mcMMO.getUserManager().getPlayer(player).hasSkillChatNotifications())
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null || !mcMMO.getUserManager().queryMcMMOPlayer(player).hasSkillChatNotifications())
             return;
 
         String preColoredString = LocaleLoader.getString(key, (Object[]) values);
@@ -90,7 +90,7 @@ public class NotificationManager {
 
     public static void sendPlayerInformation(Player player, NotificationType notificationType, String key, String... values)
     {
-        if(mcMMO.getUserManager().getPlayer(player) == null || !mcMMO.getUserManager().getPlayer(player).hasSkillChatNotifications())
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) == null || !mcMMO.getUserManager().queryMcMMOPlayer(player).hasSkillChatNotifications())
             return;
 
         McMMOMessageType destination = AdvancedConfig.getInstance().doesNotificationUseActionBar(notificationType) ? McMMOMessageType.ACTION_BAR : McMMOMessageType.SYSTEM;

+ 12 - 0
src/main/java/com/gmail/nossr50/util/player/PartyUtils.java

@@ -0,0 +1,12 @@
+package com.gmail.nossr50.util.player;
+
+import com.gmail.nossr50.config.Config;
+import com.gmail.nossr50.datatypes.party.Party;
+import com.gmail.nossr50.datatypes.party.PartyFeature;
+import org.jetbrains.annotations.NotNull;
+
+public class PartyUtils {
+    public static boolean isAllowed(@NotNull Party party, @NotNull PartyFeature partyFeature) {
+        return party.getPartyExperienceManager().getLevel() >= Config.getInstance().getPartyFeatureUnlockLevel(partyFeature);
+    }
+}

+ 50 - 73
src/main/java/com/gmail/nossr50/util/player/UserManager.java

@@ -9,19 +9,23 @@ import com.gmail.nossr50.runnables.player.PersistentPlayerDataSaveTask;
 import com.gmail.nossr50.runnables.skills.BleedTimerTask;
 import com.gmail.nossr50.util.scoreboards.ScoreboardManager;
 import com.google.common.collect.ImmutableList;
+import org.bukkit.Bukkit;
 import org.bukkit.OfflinePlayer;
 import org.bukkit.entity.Entity;
 import org.bukkit.entity.Player;
 import org.bukkit.metadata.FixedMetadataValue;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.UUID;
 
 //TODO: Add per world handling
 public final class UserManager {
 
-    private final HashSet<McMMOPlayer> playerDataSet; //Used to track players for sync saves on shutdown
+    private final @NotNull HashSet<McMMOPlayer> playerDataSet; //Used to track players for sync saves on shutdown
 
     public UserManager() {
         this.playerDataSet = new HashSet<>();
@@ -32,13 +36,13 @@ public final class UserManager {
      *
      * @param mmoPlayer the player profile to start tracking
      */
-    public void track(McMMOPlayer mmoPlayer) {
+    public void track(@NotNull McMMOPlayer mmoPlayer) {
         mmoPlayer.getPlayer().setMetadata(mcMMO.playerDataKey, new FixedMetadataValue(mcMMO.p, mmoPlayer));
 
         playerDataSet.add(mmoPlayer); //for sync saves on shutdown
     }
 
-    public void cleanupPlayer(McMMOPlayer mmoPlayer) {
+    public void cleanupPlayer(@NotNull McMMOPlayer mmoPlayer) {
         playerDataSet.remove(mmoPlayer);
     }
 
@@ -47,8 +51,8 @@ public final class UserManager {
      *
      * @param player The Player object
      */
-    public void remove(Player player) {
-        McMMOPlayer mmoPlayer = getPlayer(player);
+    public void remove(@NotNull Player player) {
+        McMMOPlayer mmoPlayer = queryMcMMOPlayer(player);
         mmoPlayer.cleanup();
         player.removeMetadata(mcMMO.playerDataKey, mcMMO.p);
 
@@ -66,12 +70,12 @@ public final class UserManager {
         playerDataSet.clear(); //Clear sync save tracking
     }
 
-    public Collection<McMMOPlayer> getPlayers() {
+    public @NotNull Collection<McMMOPlayer> getPlayers() {
         Collection<McMMOPlayer> playerCollection = new ArrayList<>();
 
         for (Player player : mcMMO.p.getServer().getOnlinePlayers()) {
             if (hasPlayerDataKey(player)) {
-                playerCollection.add(getPlayer(player));
+                playerCollection.add(queryMcMMOPlayer(player));
             }
         }
 
@@ -84,19 +88,40 @@ public final class UserManager {
      * @param playerName The name of the player whose McMMOPlayer to retrieve
      * @return the player's McMMOPlayer object
      */
-    public McMMOPlayer getPlayer(String playerName) {
+    public @Nullable McMMOPlayer queryMcMMOPlayer(@NotNull UUID playerUUID) {
         return retrieveMcMMOPlayer(playerName, false);
     }
 
-    public McMMOPlayer getOfflinePlayer(OfflinePlayer player) {
-        if (player instanceof Player) {
-            return getPlayer((Player) player);
-        }
+    /**
+     * Attempts to find a player in the database by name alone
+     * @param playerName target player name
+     * @return will return a valid McMMOPlayer if one is found, otherwise returns null
+     */
+    public @Nullable OfflinePlayer findPlayer(@NotNull String playerName) {
+
+    }
+
+    public @Nullable McMMOPlayer queryMcMMOPlayer(@NotNull OfflinePlayer offlinePlayer) {
+        return queryMcMMOPlayer(offlinePlayer.getUniqueId());
+    }
 
-        return retrieveMcMMOPlayer(player.getName(), true);
+    /**
+     * Used to grab a player by name alone
+     * @param playerName
+     * @return
+     */
+    @Deprecated
+    public @Nullable McMMOPlayer queryMcMMOPlayer(@NotNull String playerName) {
+        OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(playerName);
+
+        if(offlinePlayer != null) {
+            return retrieveMcMMOPlayer(offlinePlayer);
+        } else {
+            return null;
+        }
     }
 
-    public McMMOPlayer getOfflinePlayer(String playerName) {
+    public @Nullable McMMOPlayer getOfflinePlayer(String playerName) {
         return retrieveMcMMOPlayer(playerName, true);
     }
 
@@ -105,7 +130,7 @@ public final class UserManager {
      * @param player target player
      * @return McMMOPlayer object for this player, null if Player has not been loaded
      */
-    public McMMOPlayer getPlayer(Player player) {
+    public @Nullable McMMOPlayer queryMcMMOPlayer(@NotNull Player player) {
         //Avoid Array Index out of bounds
         if(player != null && player.hasMetadata(mcMMO.playerDataKey))
             return (McMMOPlayer) player.getMetadata(mcMMO.playerDataKey).get(0).value();
@@ -113,7 +138,7 @@ public final class UserManager {
             return null;
     }
 
-    private McMMOPlayer retrieveMcMMOPlayer(String playerName, boolean offlineValid) {
+    private @Nullable McMMOPlayer retrieveMcMMOPlayer(@NotNull String playerName, boolean offlineValid) {
         Player player = mcMMO.p.getServer().getPlayerExact(playerName);
 
         if (player == null) {
@@ -124,79 +149,31 @@ public final class UserManager {
             return null;
         }
 
-        return getPlayer(player);
+        return queryMcMMOPlayer(player);
     }
 
     public boolean hasPlayerDataKey(Entity entity) {
         return entity != null && entity.hasMetadata(mcMMO.playerDataKey);
     }
 
-    public MMODataSnapshot createPlayerDataSnapshot(PersistentPlayerData persistentPlayerData) {
+    public @NotNull MMODataSnapshot createPlayerDataSnapshot(@NotNull PersistentPlayerData persistentPlayerData) {
         return new MMODataSnapshot(persistentPlayerData);
     }
 
-    public void saveUserImmediately(PersistentPlayerData persistentPlayerData, boolean useSync) {
+    public void saveUserImmediately(@NotNull PersistentPlayerData persistentPlayerData, boolean useSync) {
         if(useSync)
             scheduleSyncSave(createPlayerDataSnapshot(persistentPlayerData)); //Execute sync saves immediately
         else
             scheduleAsyncSaveDelay(createPlayerDataSnapshot(persistentPlayerData), 0);
     }
 
-    public void saveUserWithDelay(PersistentPlayerData persistentPlayerData, boolean useSync, int delayTicks) {
+    public void saveUserWithDelay(@NotNull PersistentPlayerData persistentPlayerData, boolean useSync, int delayTicks) {
         if(useSync)
             scheduleSyncSaveDelay(createPlayerDataSnapshot(persistentPlayerData), delayTicks); //Execute sync saves immediately
         else
             scheduleAsyncSaveDelay(createPlayerDataSnapshot(persistentPlayerData), delayTicks);
     }
 
-//    public void save(boolean useSync) {
-//        if (!changed || !loaded) {
-//            saveAttempts = 0;
-//            return;
-//        }
-//
-//        // TODO should this part be synchronized?
-//        PlayerProfile profileCopy = new PlayerProfile(playerName, uuid,
-//                experienceManager.copyPrimarySkillLevelsMap(),
-//                experienceManager.copyPrimarySkillExperienceValuesMap(),
-//                ImmutableMap.copyOf(abilityDATS),
-//                mobHealthbarType,
-//                scoreboardTipsShown,
-//                ImmutableMap.copyOf(uniquePlayerData),
-//                ImmutableMap.copyOf(xpBarState));
-//
-//        changed = !mcMMO.getDatabaseManager().saveUser(profileCopy);
-//
-//        if (changed) {
-//            mcMMO.p.getLogger().severe("PlayerProfile saving failed for player: " + playerName + " " + uuid);
-//
-//            if(saveAttempts > 0)
-//            {
-//                mcMMO.p.getLogger().severe("Attempted to save profile for player "+getPlayerName()
-//                        + " resulted in failure. "+saveAttempts+" have been made so far.");
-//            }
-//
-//            if(saveAttempts < 10)
-//            {
-//                saveAttempts++;
-//
-//                if(useSync)
-//                    scheduleSyncSave(); //Execute sync saves immediately
-//                else
-//                    scheduleAsyncSaveDelay();
-//
-//            } else {
-//                mcMMO.p.getLogger().severe("mcMMO has failed to save the profile for "
-//                        +getPlayerName()+" numerous times." +
-//                        " mcMMO will now stop attempting to save this profile." +
-//                        " Check your console for errors and inspect your DB for issues.");
-//            }
-//
-//        } else {
-//            saveAttempts = 0;
-//        }
-//    }
-
     /**
      * Save all users ON THIS THREAD.
      */
@@ -226,7 +203,7 @@ public final class UserManager {
      *
      * @param syncSave if true, data is saved synchronously
      */
-    public void logout(McMMOPlayer mmoPlayer, boolean syncSave) {
+    public void logout(@NotNull McMMOPlayer mmoPlayer, boolean syncSave) {
         BleedTimerTask.bleedOut(mmoPlayer.getPlayer());
 
         //TODO: There is a possibility that async saves don't execute in time if the server is told to shutdown
@@ -247,19 +224,19 @@ public final class UserManager {
     }
 
 
-    public void scheduleAsyncSave(MMODataSnapshot mmoDataSnapshot) {
+    public void scheduleAsyncSave(@NotNull MMODataSnapshot mmoDataSnapshot) {
         new PersistentPlayerDataSaveTask(mmoDataSnapshot).runTaskAsynchronously(mcMMO.p);
     }
 
-    public void scheduleSyncSave(MMODataSnapshot mmoDataSnapshot) {
+    public void scheduleSyncSave(@NotNull MMODataSnapshot mmoDataSnapshot) {
         new PersistentPlayerDataSaveTask(mmoDataSnapshot).runTask(mcMMO.p);
     }
 
-    public void scheduleAsyncSaveDelay(MMODataSnapshot mmoDataSnapshot, int delayTicks) {
+    public void scheduleAsyncSaveDelay(@NotNull MMODataSnapshot mmoDataSnapshot, int delayTicks) {
         new PersistentPlayerDataSaveTask(mmoDataSnapshot).runTaskLaterAsynchronously(mcMMO.p, delayTicks);
     }
 
-    public void scheduleSyncSaveDelay(MMODataSnapshot mmoDataSnapshot, int delayTicks) {
+    public void scheduleSyncSaveDelay(@NotNull MMODataSnapshot mmoDataSnapshot, int delayTicks) {
         new PersistentPlayerDataSaveTask(mmoDataSnapshot).runTaskLater(mcMMO.p, delayTicks);
     }
 }

+ 2 - 2
src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java

@@ -205,7 +205,7 @@ public class ScoreboardWrapper {
         if(mcMMO.getUserManager().getPlayer(playerName) == null)
             return;
 
-        PlayerProfile profile = mcMMO.getUserManager().getPlayer(player);
+        PlayerProfile profile = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
         if (profile.getScoreboardTipsShown() >= Config.getInstance().getTipsAmount()) {
             return;
@@ -433,7 +433,7 @@ public class ScoreboardWrapper {
             return;
         }
 
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
         if(mmoPlayer == null)
             return;

+ 14 - 14
src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java

@@ -47,7 +47,7 @@ public final class CombatUtils {
             return;
         }
 
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
         //Make sure the profiles been loaded
         if(mmoPlayer == null) {
@@ -95,7 +95,7 @@ public final class CombatUtils {
             return;
         }
 
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
         //Make sure the profiles been loaded
         if(mmoPlayer == null) {
@@ -144,7 +144,7 @@ public final class CombatUtils {
         double finalDamage = initialDamage;
         Map<DamageModifier, Double> modifiers = getModifiers(event);
 
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
         //Make sure the profiles been loaded
         if(mmoPlayer == null) {
@@ -193,7 +193,7 @@ public final class CombatUtils {
         double initialDamage = event.getDamage();
         double finalDamage = initialDamage;
 
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
         //Make sure the profiles been loaded
         if(mmoPlayer == null) {
@@ -233,7 +233,7 @@ public final class CombatUtils {
         double finalDamage = initialDamage;
 
         if(master != null && master.isOnline() && master.isValid()) {
-            McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(master);
+            McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(master);
 
             //Make sure the profiles been loaded
             if(mmoPlayer == null) {
@@ -265,7 +265,7 @@ public final class CombatUtils {
     private static void processArcheryCombat(LivingEntity target, Player player, EntityDamageByEntityEvent event, Projectile arrow) {
         double initialDamage = event.getDamage();
 
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
         //Make sure the profiles been loaded
         if(mmoPlayer == null) {
@@ -307,7 +307,7 @@ public final class CombatUtils {
     private static void processCrossbowCombat(LivingEntity target, Player player, EntityDamageByEntityEvent event, Projectile arrow) {
         double initialDamage = event.getDamage();
 
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
         //Make sure the profiles been loaded
         if(mmoPlayer == null) {
@@ -319,7 +319,7 @@ public final class CombatUtils {
         double finalDamage = event.getDamage();
 
         if (target instanceof Player && PrimarySkillType.UNARMED.getPVPEnabled()) {
-            UnarmedManager unarmedManager = mcMMO.getUserManager().getPlayer((Player) target).getUnarmedManager();
+            UnarmedManager unarmedManager = mcMMO.getUserManager().queryMcMMOPlayer((Player) target).getUnarmedManager();
 
             if (unarmedManager.canDeflect()) {
                 event.setCancelled(unarmedManager.deflectCheck());
@@ -359,7 +359,7 @@ public final class CombatUtils {
                 return;
             }
 
-            McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+            McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
             AcrobaticsManager acrobaticsManager = mmoPlayer.getAcrobaticsManager();
 
             if (acrobaticsManager.canDodge(target)) {
@@ -390,7 +390,7 @@ public final class CombatUtils {
 
             if (target instanceof Tameable) {
                 if (heldItem.getType() == Material.BONE) {
-                    TamingManager tamingManager = mcMMO.getUserManager().getPlayer(player).getTamingManager();
+                    TamingManager tamingManager = mcMMO.getUserManager().queryMcMMOPlayer(player).getTamingManager();
 
                     if (tamingManager.canUseBeastLore()) {
                         tamingManager.beastLore(target);
@@ -483,7 +483,7 @@ public final class CombatUtils {
 
 
                 if (target.getType() != EntityType.CREEPER && !Misc.isNPCEntityExcludingVillagers(player) && PrimarySkillType.TAMING.getPermissions(player)) {
-                    McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+                    McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
                     if(mmoPlayer == null) {
                         return;
@@ -752,7 +752,7 @@ public final class CombatUtils {
                         NotificationManager.sendPlayerInformation((Player)entity, NotificationType.SUBSKILL_MESSAGE, "Swords.Combat.SS.Struck");
                     }
 
-                    mcMMO.getUserManager().getPlayer(attacker).getSwordsManager().ruptureCheck(target);
+                    mcMMO.getUserManager().queryMcMMOPlayer(attacker).getSwordsManager().ruptureCheck(target);
                     break;
 
                 case AXES:
@@ -875,10 +875,10 @@ public final class CombatUtils {
             Player defender = (Player) entity;
 
             //TODO: NPC Interaction?
-            if(mcMMO.getUserManager().getPlayer(defender) == null)
+            if(mcMMO.getUserManager().queryMcMMOPlayer(defender) == null)
                 return true;
 
-            if (!defender.getWorld().getPVP() || defender == player || mcMMO.getUserManager().getPlayer(defender).getGodMode()) {
+            if (!defender.getWorld().getPVP() || defender == player || mcMMO.getUserManager().queryMcMMOPlayer(defender).getGodMode()) {
                 return false;
             }
 

+ 2 - 2
src/main/java/com/gmail/nossr50/util/skills/PerksUtils.java

@@ -49,7 +49,7 @@ public final class PerksUtils {
         double modifier = 1.0F;
 
         if (Permissions.customXpBoost(player, skill)) {
-            if(mcMMO.getUserManager().getPlayer(player) != null && mcMMO.getUserManager().getPlayer(player).isDebugMode()) {
+            if(mcMMO.getUserManager().queryMcMMOPlayer(player) != null && mcMMO.getUserManager().queryMcMMOPlayer(player).isDebugMode()) {
                 player.sendMessage(ChatColor.GOLD + "[DEBUG] " + ChatColor.DARK_GRAY + "XP Perk Multiplier IS CUSTOM! ");
             }
 
@@ -76,7 +76,7 @@ public final class PerksUtils {
 
         float modifiedXP = (float) (xp * modifier);
 
-        if(mcMMO.getUserManager().getPlayer(player) != null && mcMMO.getUserManager().getPlayer(player).isDebugMode()) {
+        if(mcMMO.getUserManager().queryMcMMOPlayer(player) != null && mcMMO.getUserManager().queryMcMMOPlayer(player).isDebugMode()) {
             player.sendMessage(ChatColor.GOLD + "[DEBUG] " + ChatColor.RESET + "XP Perk Multiplier - " + ChatColor.GOLD + modifier);
             player.sendMessage(ChatColor.GOLD + "[DEBUG] " + ChatColor.RESET + "Original XP before perk boosts " + ChatColor.RED + (double) xp);
             player.sendMessage(ChatColor.GOLD + "[DEBUG] " + ChatColor.RESET + "XP AFTER PERKS " + ChatColor.DARK_RED + modifiedXP);

+ 1 - 1
src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java

@@ -181,7 +181,7 @@ public class SkillUtils {
                 }
             }
 
-            McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+            McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
             //Not Loaded
             if(mmoPlayer == null)

+ 2 - 2
src/main/java/com/gmail/nossr50/util/skills/SmeltingTracker.java

@@ -21,7 +21,7 @@ public class SmeltingTracker {
 
     private void changeFurnaceOwnership(Furnace furnace, Player player) {
 
-        McMMOPlayer mmoPlayer = mcMMO.getUserManager().getPlayer(player);
+        McMMOPlayer mmoPlayer = mcMMO.getUserManager().queryMcMMOPlayer(player);
 
         /*
             Debug output
@@ -52,7 +52,7 @@ public class SmeltingTracker {
         OfflinePlayer furnaceOwner = getFurnaceOwner(furnace);
 
         if(furnaceOwner != null && furnaceOwner.isOnline()) {
-            McMMOPlayer furnaceOwnerProfile = mcMMO.getUserManager().getPlayer(furnaceOwner.getPlayer());
+            McMMOPlayer furnaceOwnerProfile = mcMMO.getUserManager().queryMcMMOPlayer(furnaceOwner.getPlayer());
 
             if(furnaceOwnerProfile != null) {
                 if(furnaceOwnerProfile.isDebugMode()) {

+ 1 - 1
src/main/resources/locale/locale_en_US.properties

@@ -654,7 +654,7 @@ Commands.ModDescription=[[GREEN]]- Read brief mod description
 Commands.NoConsole=This command does not support console usage.
 Commands.Notifications.Off=Ability notifications toggled [[RED]]off
 Commands.Notifications.On=Ability notifications toggled [[GREEN]]on
-Commands.Offline=This command does not work for offline players.
+Commands.MissingProfile=No profile found for this player.
 Commands.NotLoaded=Player profile is not loaded yet.
 Commands.Party.Status=[[DARK_GRAY]]NAME: [[WHITE]]{0} {1} [[DARK_GRAY]]LEVEL: [[DARK_AQUA]]{2}
 Commands.Party.Status.Alliance=[[DARK_GRAY]]ALLY: [[WHITE]]{0}