Browse Source

Add a newUser test

nossr50 4 years ago
parent
commit
d9e195f63a

+ 2 - 0
Changelog.txt

@@ -5,6 +5,8 @@ Version 2.1.189
     Rewrote how FlatFileDatabase verifies data integrity
     Rewrote how FlatFileDatabase verifies data integrity
     (API) Added com.gmail.nossr50.database.DatabaseManager.loadPlayerProfile(org.bukkit.OfflinePlayer)
     (API) Added com.gmail.nossr50.database.DatabaseManager.loadPlayerProfile(org.bukkit.OfflinePlayer)
     (API) Deprecated com.gmail.nossr50.database.DatabaseManager.loadPlayerProfile(java.util.UUID, java.lang.String)
     (API) Deprecated com.gmail.nossr50.database.DatabaseManager.loadPlayerProfile(java.util.UUID, java.lang.String)
+    (API) Removed com.gmail.nossr50.database.DatabaseManager.newUser(java.lang.String, java.util.UUID)
+    (API) Added
     Added unit tests for FlatFileDatabaseManager (see notes)
     Added unit tests for FlatFileDatabaseManager (see notes)
     Fixed a bug where FlatFileDatabaseManager didn't properly upgrade older database entries to the newest schema
     Fixed a bug where FlatFileDatabaseManager didn't properly upgrade older database entries to the newest schema
     The setting to disable the mcMMO user block tracker has been moved from our "hidden config" to persistent_data.yml
     The setting to disable the mcMMO user block tracker has been moved from our "hidden config" to persistent_data.yml

+ 6 - 0
pom.xml

@@ -220,6 +220,12 @@
         <!-- ... -->
         <!-- ... -->
     </repositories>
     </repositories>
     <dependencies>
     <dependencies>
+        <dependency>
+            <groupId>com.github.seeseemelk</groupId>
+            <artifactId>MockBukkit-v1.16</artifactId>
+            <version>0.25.0</version>
+            <scope>test</scope>
+        </dependency>
         <dependency>
         <dependency>
             <groupId>co.aikar</groupId>
             <groupId>co.aikar</groupId>
             <artifactId>acf-bukkit</artifactId> <!-- Don't forget to replace this -->
             <artifactId>acf-bukkit</artifactId> <!-- Don't forget to replace this -->

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

@@ -76,11 +76,11 @@ public interface DatabaseManager {
 
 
     /**
     /**
      * Add a new user to the database.
      * 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
      * @param uuid The uuid of the player to be added to the database
+     * @return
      */
      */
-    void newUser(String playerName, UUID uuid);
+    @NotNull PlayerProfile newUser(String playerName, UUID uuid);
 
 
     @NotNull PlayerProfile newUser(@NotNull Player player);
     @NotNull PlayerProfile newUser(@NotNull Player player);
 
 
@@ -101,11 +101,13 @@ public interface DatabaseManager {
      * Load a player from the database.
      * Load a player from the database.
      * @param uuid The uuid of the player to load from the database
      * @param uuid The uuid of the player to load from the database
      * @return The player's data, or an unloaded PlayerProfile if not found
      * @return The player's data, or an unloaded PlayerProfile if not found
-     * @deprecated Use {@link DatabaseManager#loadPlayerProfile(org.bukkit.OfflinePlayer)} if possible
+     * @deprecated Use {@link DatabaseManager#loadPlayerProfile(org.bukkit.OfflinePlayer)} or {@link DatabaseManager#loadPlayerProfile(java.util.UUID)} if possible
      */
      */
     @Deprecated
     @Deprecated
     @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid, @Nullable String playerName);
     @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid, @Nullable String playerName);
 
 
+    @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid);
+
     /**
     /**
      * Get all users currently stored in the database.
      * Get all users currently stored in the database.
      *
      *

+ 75 - 127
src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java

@@ -31,7 +31,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
     private final @NotNull Logger logger;
     private final @NotNull Logger logger;
     private final long purgeTime;
     private final long purgeTime;
     private final int startingLevel;
     private final int startingLevel;
-    private boolean testing;
+    private final boolean testing;
 
 
     private final long UPDATE_WAIT_TIME = 600000L; // 10 minutes
     private final long UPDATE_WAIT_TIME = 600000L; // 10 minutes
     private final @NotNull File usersFile;
     private final @NotNull File usersFile;
@@ -97,6 +97,8 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
                     logger.info("Detected "+flatFileDataFlags.size() + " data entries which need correction.");
                     logger.info("Detected "+flatFileDataFlags.size() + " data entries which need correction.");
                 }
                 }
             }
             }
+
+            updateLeaderboards();
         }
         }
     }
     }
 
 
@@ -193,29 +195,31 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
                     String name = character[USERNAME_INDEX];
                     String name = character[USERNAME_INDEX];
                     long lastPlayed = 0;
                     long lastPlayed = 0;
                     boolean rewrite = false;
                     boolean rewrite = false;
+
                     try {
                     try {
-                        lastPlayed = Long.parseLong(character[37]) * Misc.TIME_CONVERSION_FACTOR;
-                    }
-                    catch (NumberFormatException e) {
+                        lastPlayed = Long.parseLong(character[OVERHAUL_LAST_LOGIN]);
+                    } catch (NumberFormatException e) {
                         e.printStackTrace();
                         e.printStackTrace();
                     }
                     }
-                    if (lastPlayed == 0) {
+
+                    if (lastPlayed == -1) {
                         OfflinePlayer player = mcMMO.p.getServer().getOfflinePlayer(name);
                         OfflinePlayer player = mcMMO.p.getServer().getOfflinePlayer(name);
-                        lastPlayed = player.getLastPlayed();
-                        rewrite = true;
+
+                        if(player.getLastPlayed() != 0) {
+                            lastPlayed = player.getLastPlayed();
+                            rewrite = true;
+                        }
                     }
                     }
 
 
                     if (currentTime - lastPlayed > purgeTime) {
                     if (currentTime - lastPlayed > purgeTime) {
                         removedPlayers++;
                         removedPlayers++;
-                    }
-                    else {
+                    } else {
                         if (rewrite) {
                         if (rewrite) {
                             // Rewrite their data with a valid time
                             // Rewrite their data with a valid time
-                            character[37] = Long.toString(lastPlayed);
+                            character[OVERHAUL_LAST_LOGIN] = Long.toString(lastPlayed);
                             String newLine = org.apache.commons.lang.StringUtils.join(character, ":");
                             String newLine = org.apache.commons.lang.StringUtils.join(character, ":");
                             writer.append(newLine).append("\r\n");
                             writer.append(newLine).append("\r\n");
-                        }
-                        else {
+                        } else {
                             writer.append(line).append("\r\n");
                             writer.append(line).append("\r\n");
                         }
                         }
                     }
                     }
@@ -421,51 +425,52 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
         }
         }
     }
     }
 
 
-    private void writeUserToLine(PlayerProfile profile, @NotNull String playerName, @Nullable UUID uuid, StringBuilder writer) {
+    public void writeUserToLine(@NotNull PlayerProfile profile, @NotNull String playerName, @Nullable UUID uuid, @NotNull Appendable writer) throws IOException {
         writer.append(playerName).append(":");
         writer.append(playerName).append(":");
-        writer.append(profile.getSkillLevel(PrimarySkillType.MINING)).append(":");
-        writer.append(":");
-        writer.append(":");
-        writer.append(profile.getSkillXpLevel(PrimarySkillType.MINING)).append(":");
-        writer.append(profile.getSkillLevel(PrimarySkillType.WOODCUTTING)).append(":");
-        writer.append(profile.getSkillXpLevel(PrimarySkillType.WOODCUTTING)).append(":");
-        writer.append(profile.getSkillLevel(PrimarySkillType.REPAIR)).append(":");
-        writer.append(profile.getSkillLevel(PrimarySkillType.UNARMED)).append(":");
-        writer.append(profile.getSkillLevel(PrimarySkillType.HERBALISM)).append(":");
-        writer.append(profile.getSkillLevel(PrimarySkillType.EXCAVATION)).append(":");
-        writer.append(profile.getSkillLevel(PrimarySkillType.ARCHERY)).append(":");
-        writer.append(profile.getSkillLevel(PrimarySkillType.SWORDS)).append(":");
-        writer.append(profile.getSkillLevel(PrimarySkillType.AXES)).append(":");
-        writer.append(profile.getSkillLevel(PrimarySkillType.ACROBATICS)).append(":");
-        writer.append(profile.getSkillXpLevel(PrimarySkillType.REPAIR)).append(":");
-        writer.append(profile.getSkillXpLevel(PrimarySkillType.UNARMED)).append(":");
-        writer.append(profile.getSkillXpLevel(PrimarySkillType.HERBALISM)).append(":");
-        writer.append(profile.getSkillXpLevel(PrimarySkillType.EXCAVATION)).append(":");
-        writer.append(profile.getSkillXpLevel(PrimarySkillType.ARCHERY)).append(":");
-        writer.append(profile.getSkillXpLevel(PrimarySkillType.SWORDS)).append(":");
-        writer.append(profile.getSkillXpLevel(PrimarySkillType.AXES)).append(":");
-        writer.append(profile.getSkillXpLevel(PrimarySkillType.ACROBATICS)).append(":");
-        writer.append(":");
-        writer.append(profile.getSkillLevel(PrimarySkillType.TAMING)).append(":");
-        writer.append(profile.getSkillXpLevel(PrimarySkillType.TAMING)).append(":");
-        writer.append((int) profile.getAbilityDATS(SuperAbilityType.BERSERK)).append(":");
-        writer.append((int) profile.getAbilityDATS(SuperAbilityType.GIGA_DRILL_BREAKER)).append(":");
-        writer.append((int) profile.getAbilityDATS(SuperAbilityType.TREE_FELLER)).append(":");
-        writer.append((int) profile.getAbilityDATS(SuperAbilityType.GREEN_TERRA)).append(":");
-        writer.append((int) profile.getAbilityDATS(SuperAbilityType.SERRATED_STRIKES)).append(":");
-        writer.append((int) profile.getAbilityDATS(SuperAbilityType.SKULL_SPLITTER)).append(":");
-        writer.append((int) profile.getAbilityDATS(SuperAbilityType.SUPER_BREAKER)).append(":");
-        writer.append(":");
-        writer.append(profile.getSkillLevel(PrimarySkillType.FISHING)).append(":");
-        writer.append(profile.getSkillXpLevel(PrimarySkillType.FISHING)).append(":");
-        writer.append((int) profile.getAbilityDATS(SuperAbilityType.BLAST_MINING)).append(":");
-        writer.append(System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR).append(":");
+        writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.MINING))).append(":");
+        writer.append(IGNORED).append(":");
+        writer.append(IGNORED).append(":");
+        writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.MINING))).append(":");
+        writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.WOODCUTTING))).append(":");
+        writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.WOODCUTTING))).append(":");
+        writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.REPAIR))).append(":");
+        writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.UNARMED))).append(":");
+        writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.HERBALISM))).append(":");
+        writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.EXCAVATION))).append(":");
+        writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ARCHERY))).append(":");
+        writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.SWORDS))).append(":");
+        writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.AXES))).append(":");
+        writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ACROBATICS))).append(":");
+        writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.REPAIR))).append(":");
+        writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.UNARMED))).append(":");
+        writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.HERBALISM))).append(":");
+        writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.EXCAVATION))).append(":");
+        writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ARCHERY))).append(":");
+        writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.SWORDS))).append(":");
+        writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.AXES))).append(":");
+        writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ACROBATICS))).append(":");
+        writer.append(IGNORED).append(":");
+        writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.TAMING))).append(":");
+        writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.TAMING))).append(":");
+        writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.BERSERK))).append(":");
+        writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.GIGA_DRILL_BREAKER))).append(":");
+        writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.TREE_FELLER))).append(":");
+        writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.GREEN_TERRA))).append(":");
+        writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SERRATED_STRIKES))).append(":");
+        writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SKULL_SPLITTER))).append(":");
+        writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SUPER_BREAKER))).append(":");
+        writer.append(IGNORED).append(":");
+        writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.FISHING))).append(":");
+        writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.FISHING))).append(":");
+        writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.BLAST_MINING))).append(":");
+        writer.append(IGNORED).append(":"); //Legacy last login
         writer.append(IGNORED).append(":"); //mob health bar
         writer.append(IGNORED).append(":"); //mob health bar
-        writer.append(profile.getSkillLevel(PrimarySkillType.ALCHEMY)).append(":");
-        writer.append(profile.getSkillXpLevel(PrimarySkillType.ALCHEMY)).append(":");
+        writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ALCHEMY))).append(":");
+        writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ALCHEMY))).append(":");
         writer.append(uuid != null ? uuid.toString() : "NULL").append(":");
         writer.append(uuid != null ? uuid.toString() : "NULL").append(":");
-        writer.append(profile.getScoreboardTipsShown()).append(":");
-        writer.append(profile.getUniqueData(UniqueDataType.CHIMAERA_WING_DATS)).append(":");
+        writer.append(String.valueOf(profile.getScoreboardTipsShown())).append(":");
+        writer.append(String.valueOf(profile.getUniqueData(UniqueDataType.CHIMAERA_WING_DATS))).append(":");
+        writer.append(String.valueOf(profile.getLastLogin())).append(":"); //overhaul last login
         writer.append("\r\n");
         writer.append("\r\n");
     }
     }
 
 
@@ -498,81 +503,21 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
     }
     }
 
 
     public @NotNull PlayerProfile newUser(@NotNull Player player) {
     public @NotNull PlayerProfile newUser(@NotNull Player player) {
-        newUser(player.getName(), player.getUniqueId());
-        return new PlayerProfile(player.getName(), player.getUniqueId(), true);
+        return new PlayerProfile(player.getName(), player.getUniqueId(), true, startingLevel);
     }
     }
 
 
-    public void newUser(String playerName, UUID uuid) {
-        BufferedWriter out = null;
+    public @NotNull PlayerProfile newUser(@NotNull String playerName, @NotNull UUID uuid) {
+        PlayerProfile playerProfile = new PlayerProfile(playerName, uuid, true, startingLevel);
+
         synchronized (fileWritingLock) {
         synchronized (fileWritingLock) {
-            try {
-                // Open the file to write the player
-                out = new BufferedWriter(new FileWriter(usersFilePath, true));
-
-                String startingLevelStr = startingLevel + ":";
-
-                // Add the player to the end
-                out.append(playerName).append(":");
-                out.append(startingLevelStr); // Mining
-                out.append(":");
-                out.append(":");
-                out.append("0:"); // Xp
-                out.append(startingLevelStr); // Woodcutting
-                out.append("0:"); // WoodCuttingXp
-                out.append(startingLevelStr); // Repair
-                out.append(startingLevelStr); // Unarmed
-                out.append(startingLevelStr); // Herbalism
-                out.append(startingLevelStr); // Excavation
-                out.append(startingLevelStr); // Archery
-                out.append(startingLevelStr); // Swords
-                out.append(startingLevelStr); // Axes
-                out.append(startingLevelStr); // Acrobatics
-                out.append("0:"); // RepairXp
-                out.append("0:"); // UnarmedXp
-                out.append("0:"); // HerbalismXp
-                out.append("0:"); // ExcavationXp
-                out.append("0:"); // ArcheryXp
-                out.append("0:"); // SwordsXp
-                out.append("0:"); // AxesXp
-                out.append("0:"); // AcrobaticsXp
-                out.append(":");
-                out.append(startingLevelStr); // Taming
-                out.append("0:"); // TamingXp
-                out.append("0:"); // DATS
-                out.append("0:"); // DATS
-                out.append("0:"); // DATS
-                out.append("0:"); // DATS
-                out.append("0:"); // DATS
-                out.append("0:"); // DATS
-                out.append("0:"); // DATS
-                out.append(":");
-                out.append(startingLevelStr); // Fishing
-                out.append("0:"); // FishingXp
-                out.append("0:"); // Blast Mining
-                out.append(String.valueOf(System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR)).append(":"); // LastLogin
-                out.append(IGNORED).append(":"); // Mob Healthbar HUD
-                out.append(startingLevelStr); // Alchemy
-                out.append("0:"); // AlchemyXp
-                out.append(uuid != null ? uuid.toString() : "NULL").append(":"); // UUID
-                out.append("0:"); // Scoreboard tips shown
-                // Add more in the same format as the line above
-
-                out.newLine();
-            }
-            catch (Exception e) {
+            try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(usersFilePath, true))) {
+                writeUserToLine(playerProfile, playerName, uuid, bufferedWriter);
+            } catch (Exception e) {
                 e.printStackTrace();
                 e.printStackTrace();
             }
             }
-            finally {
-                if (out != null) {
-                    try {
-                        out.close();
-                    }
-                    catch (IOException e) {
-                        // Ignore
-                    }
-                }
-            }
         }
         }
+
+        return playerProfile;
     }
     }
 
 
     public @NotNull PlayerProfile loadPlayerProfile(@NotNull OfflinePlayer offlinePlayer) {
     public @NotNull PlayerProfile loadPlayerProfile(@NotNull OfflinePlayer offlinePlayer) {
@@ -587,6 +532,10 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
         return loadPlayerByUUID(uuid, playerName, false);
         return loadPlayerByUUID(uuid, playerName, false);
     }
     }
 
 
+    public @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid) {
+        return loadPlayerByUUID(uuid, null, false);
+    }
+
     private @NotNull PlayerProfile loadPlayerByUUID(@NotNull UUID uuid, @Nullable String playerName, boolean isOnline) {
     private @NotNull PlayerProfile loadPlayerByUUID(@NotNull UUID uuid, @Nullable String playerName, boolean isOnline) {
         BufferedReader in = null;
         BufferedReader in = null;
 
 
@@ -700,7 +649,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
         }
         }
 
 
         //Return a new blank profile
         //Return a new blank profile
-        return new PlayerProfile(playerName, null);
+        return new PlayerProfile(playerName, new UUID(0, 0), startingLevel);
     }
     }
 
 
     private @NotNull PlayerProfile grabUnloadedProfile(@NotNull UUID uuid, @Nullable String playerName) {
     private @NotNull PlayerProfile grabUnloadedProfile(@NotNull UUID uuid, @Nullable String playerName) {
@@ -708,7 +657,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
             playerName = ""; //No name for you boy!
             playerName = ""; //No name for you boy!
         }
         }
 
 
-        return new PlayerProfile(playerName, uuid);
+        return new PlayerProfile(playerName, uuid, 0);
     }
     }
 
 
     public void convertUsers(DatabaseManager destination) {
     public void convertUsers(DatabaseManager destination) {
@@ -731,8 +680,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
 
 
                     try {
                     try {
                         destination.saveUser(loadFromLine(character));
                         destination.saveUser(loadFromLine(character));
-                    }
-                    catch (Exception e) {
+                    } catch (Exception e) {
                         e.printStackTrace();
                         e.printStackTrace();
                     }
                     }
                     convertedUsers++;
                     convertedUsers++;

+ 17 - 10
src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java

@@ -1,6 +1,7 @@
 package com.gmail.nossr50.database;
 package com.gmail.nossr50.database;
 
 
 import com.gmail.nossr50.api.exceptions.InvalidSkillException;
 import com.gmail.nossr50.api.exceptions.InvalidSkillException;
+import com.gmail.nossr50.config.AdvancedConfig;
 import com.gmail.nossr50.datatypes.MobHealthbarType;
 import com.gmail.nossr50.datatypes.MobHealthbarType;
 import com.gmail.nossr50.datatypes.database.DatabaseType;
 import com.gmail.nossr50.datatypes.database.DatabaseType;
 import com.gmail.nossr50.datatypes.database.PlayerStat;
 import com.gmail.nossr50.datatypes.database.PlayerStat;
@@ -491,19 +492,19 @@ public final class SQLDatabaseManager implements DatabaseManager {
         return skills;
         return skills;
     }
     }
 
 
-    public void newUser(String playerName, UUID uuid) {
+    public @NotNull PlayerProfile newUser(String playerName, UUID uuid) {
         Connection connection = null;
         Connection connection = null;
 
 
         try {
         try {
             connection = getConnection(PoolIdentifier.MISC);
             connection = getConnection(PoolIdentifier.MISC);
             newUser(connection, playerName, uuid);
             newUser(connection, playerName, uuid);
-        }
-        catch (SQLException ex) {
+        } catch (SQLException ex) {
             printErrors(ex);
             printErrors(ex);
-        }
-        finally {
+        } finally {
             tryClose(connection);
             tryClose(connection);
         }
         }
+
+        return new PlayerProfile(playerName, uuid, true, mcMMO.p.getAdvancedConfig().getStartingLevel());
     }
     }
 
 
     @Override
     @Override
@@ -513,7 +514,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
             int id = newUser(connection, player.getName(), player.getUniqueId());
             int id = newUser(connection, player.getName(), player.getUniqueId());
 
 
             if (id == -1) {
             if (id == -1) {
-                return new PlayerProfile(player.getName(), player.getUniqueId(), false);
+                return new PlayerProfile(player.getName(), player.getUniqueId(), false, mcMMO.p.getAdvancedConfig().getStartingLevel());
             } else {
             } else {
                 return loadPlayerProfile(player.getUniqueId(), player.getName());
                 return loadPlayerProfile(player.getUniqueId(), player.getName());
             }
             }
@@ -521,7 +522,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
             e.printStackTrace();
             e.printStackTrace();
         }
         }
 
 
-        return new PlayerProfile(player.getName(), player.getUniqueId(), false);
+        return new PlayerProfile(player.getName(), player.getUniqueId(), false, mcMMO.p.getAdvancedConfig().getStartingLevel());
     }
     }
 
 
     private int newUser(Connection connection, String playerName, UUID uuid) {
     private int newUser(Connection connection, String playerName, UUID uuid) {
@@ -567,7 +568,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
             return loadPlayerFromDB(null, playerName);
             return loadPlayerFromDB(null, playerName);
         } catch (RuntimeException e) {
         } catch (RuntimeException e) {
             e.printStackTrace();
             e.printStackTrace();
-            return new PlayerProfile(playerName, false);
+            return new PlayerProfile(playerName, false, mcMMO.p.getAdvancedConfig().getStartingLevel());
         }
         }
     }
     }
 
 
@@ -575,6 +576,12 @@ public final class SQLDatabaseManager implements DatabaseManager {
         return loadPlayerFromDB(uuid, playerName);
         return loadPlayerFromDB(uuid, playerName);
     }
     }
 
 
+    @Override
+    public @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid) {
+        return loadPlayerFromDB(uuid, null);
+    }
+
+
     private PlayerProfile loadPlayerFromDB(@Nullable UUID uuid, @Nullable String playerName) throws RuntimeException {
     private PlayerProfile loadPlayerFromDB(@Nullable UUID uuid, @Nullable String playerName) throws RuntimeException {
         if(uuid == null && playerName == null) {
         if(uuid == null && playerName == null) {
             throw new RuntimeException("Error looking up player, both UUID and playerName are null and one must not be.");
             throw new RuntimeException("Error looking up player, both UUID and playerName are null and one must not be.");
@@ -590,7 +597,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
 
 
             if (id == -1) {
             if (id == -1) {
             // There is no such user
             // There is no such user
-                return new PlayerProfile(playerName, false);
+                return new PlayerProfile(playerName, mcMMO.p.getAdvancedConfig().getStartingLevel());
             }
             }
             // There is such a user
             // There is such a user
             writeMissingRows(connection, id);
             writeMissingRows(connection, id);
@@ -659,7 +666,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
         }
         }
 
 
         //Return empty profile
         //Return empty profile
-        return new PlayerProfile(playerName, false);
+        return new PlayerProfile(playerName, mcMMO.p.getAdvancedConfig().getStartingLevel());
     }
     }
 
 
     public void convertUsers(DatabaseManager destination) {
     public void convertUsers(DatabaseManager destination) {

+ 14 - 10
src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java

@@ -43,11 +43,13 @@ public class PlayerProfile {
     private final Map<PrimarySkillType, Float> rollingSkillsXp = new EnumMap<PrimarySkillType, Float>(PrimarySkillType.class);
     private final Map<PrimarySkillType, Float> rollingSkillsXp = new EnumMap<PrimarySkillType, Float>(PrimarySkillType.class);
 
 
     @Deprecated
     @Deprecated
-    public PlayerProfile(String playerName) {
-        this(playerName, null);
+    //TODO: Add deprecated constructor w/o startinglevel
+    public PlayerProfile(String playerName, int startingLevel) {
+        this(playerName, null, startingLevel);
     }
     }
 
 
-    public PlayerProfile(String playerName, UUID uuid) {
+    //TODO: Add deprecated constructor w/o startinglevel
+    public PlayerProfile(String playerName, UUID uuid, int startingLevel) {
         this.uuid = uuid;
         this.uuid = uuid;
         this.playerName = playerName;
         this.playerName = playerName;
 
 
@@ -58,9 +60,7 @@ public class PlayerProfile {
         }
         }
 
 
         for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) {
         for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) {
-            int startingLvl = mcMMO.p != null ? mcMMO.p.getAdvancedConfig().getStartingLevel() : 0; //TODO: Setup the mock since this was to avoid setting up a mock in a test
-
-            skills.put(primarySkillType, startingLvl);
+            skills.put(primarySkillType, startingLevel);
             skillsXp.put(primarySkillType, 0F);
             skillsXp.put(primarySkillType, 0F);
         }
         }
 
 
@@ -70,13 +70,13 @@ public class PlayerProfile {
     }
     }
 
 
     @Deprecated
     @Deprecated
-    public PlayerProfile(@NotNull String playerName, boolean isLoaded) {
-        this(playerName);
+    public PlayerProfile(@NotNull String playerName, boolean isLoaded, int startingLvl) {
+        this(playerName, startingLvl);
         this.loaded = isLoaded;
         this.loaded = isLoaded;
     }
     }
 
 
-    public PlayerProfile(@NotNull String playerName, UUID uuid, boolean isLoaded) {
-        this(playerName, uuid);
+    public PlayerProfile(@NotNull String playerName, UUID uuid, boolean isLoaded, int startingLvl) {
+        this(playerName, uuid, startingLvl);
         this.loaded = isLoaded;
         this.loaded = isLoaded;
     }
     }
 
 
@@ -167,6 +167,10 @@ public class PlayerProfile {
             return lastLogin;
             return lastLogin;
     }
     }
 
 
+    public void updateLastLogin() {
+        this.lastLogin = System.currentTimeMillis();
+    }
+
     public String getPlayerName() {
     public String getPlayerName() {
         return playerName;
         return playerName;
     }
     }

+ 9 - 0
src/main/java/com/gmail/nossr50/mcMMO.java

@@ -59,8 +59,10 @@ import org.bukkit.Bukkit;
 import org.bukkit.entity.Player;
 import org.bukkit.entity.Player;
 import org.bukkit.event.HandlerList;
 import org.bukkit.event.HandlerList;
 import org.bukkit.metadata.FixedMetadataValue;
 import org.bukkit.metadata.FixedMetadataValue;
+import org.bukkit.plugin.PluginDescriptionFile;
 import org.bukkit.plugin.PluginManager;
 import org.bukkit.plugin.PluginManager;
 import org.bukkit.plugin.java.JavaPlugin;
 import org.bukkit.plugin.java.JavaPlugin;
+import org.bukkit.plugin.java.JavaPluginLoader;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.annotations.Nullable;
 
 
@@ -168,6 +170,13 @@ public class mcMMO extends JavaPlugin {
         p = this;
         p = this;
     }
     }
 
 
+
+    protected mcMMO(JavaPluginLoader loader, PluginDescriptionFile description, File dataFolder, File file)
+    {
+        super(loader, description, dataFolder, file);
+    }
+
+
     /**
     /**
      * Things to be run when the plugin is enabled.
      * Things to be run when the plugin is enabled.
      */
      */

+ 2 - 0
src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java

@@ -92,6 +92,8 @@ public class PlayerProfileLoadingTask extends BukkitRunnable {
                 return;
                 return;
             }
             }
 
 
+            mcMMOPlayer.getProfile().updateLastLogin();
+
             mcMMOPlayer.setupPartyData();
             mcMMOPlayer.setupPartyData();
             UserManager.track(mcMMOPlayer);
             UserManager.track(mcMMOPlayer);
             mcMMOPlayer.actualizeRespawnATS();
             mcMMOPlayer.actualizeRespawnATS();

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

@@ -86,7 +86,7 @@ public final class CommandUtils {
             return true;
             return true;
         }
         }
 
 
-        PlayerProfile profile = new PlayerProfile(playerName, false);
+        PlayerProfile profile = new PlayerProfile(playerName, false, 0);
 
 
         if (unloadedProfile(sender, profile)) {
         if (unloadedProfile(sender, profile)) {
             return false;
             return false;

+ 59 - 2
src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java

@@ -6,14 +6,20 @@ import com.gmail.nossr50.datatypes.player.PlayerProfile;
 import com.gmail.nossr50.datatypes.player.UniqueDataType;
 import com.gmail.nossr50.datatypes.player.UniqueDataType;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.SuperAbilityType;
 import com.gmail.nossr50.datatypes.skills.SuperAbilityType;
+import com.gmail.nossr50.mcMMO;
+import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask;
 import com.gmail.nossr50.util.skills.SkillTools;
 import com.gmail.nossr50.util.skills.SkillTools;
 import com.google.common.io.Files;
 import com.google.common.io.Files;
+import org.bukkit.entity.Player;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.annotations.Nullable;
 import org.junit.After;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor;
 import org.powermock.modules.junit4.PowerMockRunner;
 import org.powermock.modules.junit4.PowerMockRunner;
 
 
 import java.io.*;
 import java.io.*;
@@ -26,9 +32,10 @@ import static org.junit.Assert.*;
 
 
 
 
 //TODO: Test update leaderboards
 //TODO: Test update leaderboards
-@RunWith(PowerMockRunner.class)
 public class FlatFileDatabaseManagerTest {
 public class FlatFileDatabaseManagerTest {
 
 
+    public mcMMO plugin;
+
     public static final @NotNull String TEST_FILE_NAME = "test.mcmmo.users";
     public static final @NotNull String TEST_FILE_NAME = "test.mcmmo.users";
     public static final @NotNull String BAD_FILE_LINE_ONE = "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:";
     public static final @NotNull String BAD_FILE_LINE_ONE = "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:";
     public static final @NotNull String BAD_DATA_FILE_LINE_TWENTY_THREE = "nossr51:baddata:::baddata:baddata:640:baddata:1000:1000:1000:baddata:baddata:baddata:baddata:16:0:500:20273:0:0:0:0::1000:0:0:baddata:1593543012:0:0:0:0::1000:0:0:baddata:IGNORED:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1:0:";
     public static final @NotNull String BAD_DATA_FILE_LINE_TWENTY_THREE = "nossr51:baddata:::baddata:baddata:640:baddata:1000:1000:1000:baddata:baddata:baddata:baddata:16:0:500:20273:0:0:0:0::1000:0:0:baddata:1593543012:0:0:0:0::1000:0:0:baddata:IGNORED:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1:0:";
@@ -137,7 +144,7 @@ public class FlatFileDatabaseManagerTest {
         //Make a Profile to save and check to see if it worked
         //Make a Profile to save and check to see if it worked
         UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3");
         UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3");
         String playerName = "nossr50";
         String playerName = "nossr50";
-        PlayerProfile testProfile = new PlayerProfile(playerName, uuid);
+        PlayerProfile testProfile = new PlayerProfile(playerName, uuid, 0);
         //The above profile should be "zero" initialized
         //The above profile should be "zero" initialized
 
 
         //Save the zero version and see if it looks correct
         //Save the zero version and see if it looks correct
@@ -208,6 +215,56 @@ public class FlatFileDatabaseManagerTest {
         testHealthyDataProfileValues(playerName, uuid, profile);
         testHealthyDataProfileValues(playerName, uuid, profile);
     }
     }
 
 
+    @Test
+    public void testNewUser() {
+        //We will test that new user values line up with our expectations
+        UUID uuid = new UUID(0, 1);
+        String playerName = "nossr50";
+
+        int newUserTestStartingLvl = 1337;
+        db = new FlatFileDatabaseManager(new File(tempDir.getPath() + File.separator + TEST_FILE_NAME), logger, PURGE_TIME, newUserTestStartingLvl, true);
+        db.checkFileHealthAndStructure();
+
+        PlayerProfile playerProfile = db.newUser(playerName, uuid);
+
+        assertTrue(playerProfile.isLoaded());
+        assertEquals(playerName, playerProfile.getPlayerName());
+        assertEquals(uuid, playerProfile.getUniqueId());
+
+        PlayerProfile retrievedFromDisk = db.loadPlayerProfile(uuid);
+        assertTrue(retrievedFromDisk.isLoaded());
+        assertEquals(playerName, retrievedFromDisk.getPlayerName());
+        assertEquals(uuid, retrievedFromDisk.getUniqueId());
+
+        //Checking a new user for being "zero" initialized
+        checkNewUserValues(playerProfile, newUserTestStartingLvl);
+        checkNewUserValues(retrievedFromDisk, newUserTestStartingLvl);
+
+        //TODO: Should we do any dupe checking? Probably not needed as it would be caught on the next load
+        db.newUser("disco", new UUID(3, 3));
+        db.newUser("dingus", new UUID(3, 4));
+        db.newUser("duped_dingus", new UUID(3, 4));
+    }
+
+    private void checkNewUserValues(@NotNull PlayerProfile playerProfile, int startingLevel) {
+        //Checking a new user for being zero initialized
+        for(PrimarySkillType primarySkillType : PrimarySkillType.values()) {
+            if(SkillTools.isChildSkill(primarySkillType))
+                continue;
+
+            assertEquals(startingLevel, playerProfile.getSkillLevel(primarySkillType));
+            assertEquals(0, playerProfile.getSkillXpLevelRaw(primarySkillType), 0);
+        }
+
+        for(SuperAbilityType superAbilityType : SuperAbilityType.values()) {
+            assertEquals(0, playerProfile.getAbilityDATS(superAbilityType));
+        }
+
+        assertTrue(playerProfile.getLastLogin() > 0);
+        assertEquals(playerProfile.getChimaerWingDATS(), 0);
+        assertEquals(playerProfile.getScoreboardTipsShown(), 0);
+    }
+
     @Test
     @Test
     public void testLoadByUUID() {
     public void testLoadByUUID() {
         File dbFile = prepareDatabaseTestResource(DB_HEALTHY);
         File dbFile = prepareDatabaseTestResource(DB_HEALTHY);