From 37610f76ceb3accd7ca353e2f9242a87855d4a54 Mon Sep 17 00:00:00 2001 From: Riley Park Date: Wed, 3 Mar 2021 21:56:44 -0800 Subject: [PATCH 01/33] Deploy to repository --- pom.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pom.xml b/pom.xml index 9c3b05df6..360fd26c2 100755 --- a/pom.xml +++ b/pom.xml @@ -16,6 +16,16 @@ GitHub jar + + + neetgames + https://nexus.neetgames.com/repository/maven-releases/ + + + neetgames + https://nexus.neetgames.com/repository/maven-snapshots/ + + ${project.artifactId} ${basedir}/src/main/java From 5baccd626fbe9e0afdf296d49578151c36e348d3 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 4 Mar 2021 15:17:48 -0800 Subject: [PATCH 02/33] 2.1.176 - Small hotfix before bringing down endgame --- Changelog.txt | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index a0da56a3d..0152c7b63 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,5 +1,5 @@ Version 2.1.176 - Added another measure to prevent item stacks from reaching 65 from double smelt + Another fix for Double Smelt bringing item stack size to illegal values Version 2.1.175 Fixed a bug where mcMMO would occasionally give a 65 item stack from a double smelt on a furnace diff --git a/pom.xml b/pom.xml index 360fd26c2..6da24ef72 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.176-SNAPSHOT + 2.1.176 mcMMO https://github.com/mcMMO-Dev/mcMMO From a425ebcd106cb0e6a106ebe92c4129f2d7653f8f Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 5 Mar 2021 14:03:31 -0800 Subject: [PATCH 03/33] Add magma blocks to the things wolves avoid --- Changelog.txt | 3 +++ pom.xml | 2 +- src/main/java/com/gmail/nossr50/listeners/EntityListener.java | 1 + .../java/com/gmail/nossr50/skills/taming/TamingManager.java | 2 +- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 0152c7b63..16cd6453b 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,6 @@ +Version 2.1.177 + Environmentally aware will now protect Wolves from Magma blocks + Version 2.1.176 Another fix for Double Smelt bringing item stack size to illegal values diff --git a/pom.xml b/pom.xml index 6da24ef72..cae199ec1 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.176 + 2.1.177-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index 1d05c5eb6..f354bd404 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -573,6 +573,7 @@ public class EntityListener implements Listener { switch (cause) { case CONTACT: case FIRE: + case HOT_FLOOR: case LAVA: if (tamingManager.canUseEnvironmentallyAware()) { tamingManager.processEnvironmentallyAware(wolf, event.getDamage()); diff --git a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java index 6a902dd43..eb42b9899 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java @@ -261,7 +261,7 @@ public class TamingManager extends SkillManager { player.sendMessage(message); } - public void processEnvironmentallyAware(Wolf wolf, double damage) { + public void processEnvironmentallyAware(@NotNull Wolf wolf, double damage) { if (damage > wolf.getHealth()) { return; } From 72264205d097c3e2c20eec06f775a1de9a02ba73 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 5 Mar 2021 14:27:53 -0800 Subject: [PATCH 04/33] Update player names immediately when change is detected --- Changelog.txt | 1 + .../database/FlatfileDatabaseManager.java | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 16cd6453b..abede221e 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,5 +1,6 @@ Version 2.1.177 Environmentally aware will now protect Wolves from Magma blocks + Fixed a bug where mcMMO would fail to update a players name when it detected a name change Version 2.1.176 Another fix for Double Smelt bringing item stack size to illegal values diff --git a/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java index 4c9753373..a00553eb5 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java @@ -14,6 +14,7 @@ import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.database.UUIDUpdateAsyncTask; import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.text.StringUtils; import org.bukkit.OfflinePlayer; import org.jetbrains.annotations.NotNull; @@ -477,6 +478,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager { } public PlayerProfile loadPlayerProfile(String playerName, UUID uuid, boolean create) { + boolean updateRequired = false; BufferedReader in = null; String usersFilePath = mcMMO.getUsersFilePath(); @@ -504,11 +506,12 @@ public final class FlatfileDatabaseManager implements DatabaseManager { // Update playerName in database after name change if (!character[USERNAME].equalsIgnoreCase(playerName)) { - mcMMO.p.debug("Name change detected: " + character[USERNAME] + " => " + playerName); +// mcMMO.p.debug("Name change detected: " + character[USERNAME] + " => " + playerName); character[USERNAME] = playerName; + updateRequired = true; //Flag profile to update } - return loadFromLine(character); + return loadFromLine(character, updateRequired); } // Didn't find the player, create a new one @@ -563,7 +566,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager { String[] character = line.split(":"); try { - destination.saveUser(loadFromLine(character)); + destination.saveUser(loadFromLine(character, false)); } catch (Exception e) { e.printStackTrace(); @@ -1146,7 +1149,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager { } } - private PlayerProfile loadFromLine(String[] character) { + private PlayerProfile loadFromLine(@NotNull String[] character, boolean updateRequired) { Map skills = getSkillMapFromLine(character); // Skill levels Map skillsXp = new EnumMap<>(PrimarySkillType.class); // Skill & XP Map skillsDATS = new EnumMap<>(SuperAbilityType.class); // Ability & Cooldown @@ -1212,6 +1215,13 @@ public final class FlatfileDatabaseManager implements DatabaseManager { uniquePlayerDataMap.put(UniqueDataType.CHIMAERA_WING_DATS, 0); } + PlayerProfile playerProfile = new PlayerProfile(character[USERNAME], uuid, skills, skillsXp, skillsDATS, mobHealthbarType, scoreboardTipsShown, uniquePlayerDataMap); + + if(updateRequired) { + playerProfile.markProfileDirty(); + playerProfile.scheduleSyncSave(); //Save profile since fields have changed + } + return new PlayerProfile(character[USERNAME], uuid, skills, skillsXp, skillsDATS, mobHealthbarType, scoreboardTipsShown, uniquePlayerDataMap); } From b59d1afdb41a69dbb9df95b3bfb086109ffbce74 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 5 Mar 2021 14:48:05 -0800 Subject: [PATCH 05/33] Vanished players are treated as if they are offline for inspect command Fixed #4444 --- Changelog.txt | 5 +++++ .../commands/player/InspectCommand.java | 19 +++++++++++++------ .../util/scoreboards/ScoreboardManager.java | 19 ++++++++++++++++++- .../util/scoreboards/ScoreboardWrapper.java | 12 ++++++++++++ 4 files changed, 48 insertions(+), 7 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index abede221e..98c5994af 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,6 +1,11 @@ Version 2.1.177 Environmentally aware will now protect Wolves from Magma blocks Fixed a bug where mcMMO would fail to update a players name when it detected a name change + mcMMO will treat vanished players as if they are offline when using the inspect command on them now (see notes) + + NOTES: + A few changes were made to the inspect command, it used to reject you when used on vanished players, now it will be processed as if they are offline. + Additionally if you do inspect a vanished player, it will not use their display name (consistent with offline players) as that would give them away for being online Version 2.1.176 Another fix for Double Smelt bringing item stack size to illegal values diff --git a/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java b/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java index 3e54ffa8b..a65fa1cf2 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java @@ -36,7 +36,9 @@ public class InspectCommand implements TabExecutor { return true; } - if (Config.getInstance().getScoreboardsEnabled() && sender instanceof Player && Config.getInstance().getInspectUseBoard()) { + if (Config.getInstance().getScoreboardsEnabled() + && sender instanceof Player + && Config.getInstance().getInspectUseBoard()) { ScoreboardManager.enablePlayerInspectScoreboard((Player) sender, profile); if (!Config.getInstance().getInspectUseChat()) { @@ -63,16 +65,21 @@ public class InspectCommand implements TabExecutor { } else { Player target = mcMMOPlayer.getPlayer(); + boolean isVanished = false; if (CommandUtils.hidden(sender, target, Permissions.inspectHidden(sender))) { - sender.sendMessage(LocaleLoader.getString("Inspect.Offline")); - return true; - } else if (CommandUtils.tooFar(sender, target, Permissions.inspectFar(sender))) { + isVanished = true; + } + + //Only distance check players who are online and not vanished + if (!isVanished && CommandUtils.tooFar(sender, target, Permissions.inspectFar(sender))) { return true; } - if (Config.getInstance().getScoreboardsEnabled() && sender instanceof Player && Config.getInstance().getInspectUseBoard()) { - ScoreboardManager.enablePlayerInspectScoreboard((Player) sender, mcMMOPlayer.getProfile()); + if (Config.getInstance().getScoreboardsEnabled() + && sender instanceof Player + && Config.getInstance().getInspectUseBoard()) { + ScoreboardManager.enablePlayerInspectScoreboard((Player) sender, mcMMOPlayer); if (!Config.getInstance().getInspectUseChat()) { return true; diff --git a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java index ad32306ae..e6358ee2d 100644 --- a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java +++ b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java @@ -21,6 +21,7 @@ import org.bukkit.entity.Player; import org.bukkit.scoreboard.DisplaySlot; import org.bukkit.scoreboard.Objective; import org.bukkit.scoreboard.Scoreboard; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -327,7 +328,7 @@ public class ScoreboardManager { changeScoreboard(wrapper, Config.getInstance().getStatsScoreboardTime()); } - public static void enablePlayerInspectScoreboard(Player player, PlayerProfile targetProfile) { + public static void enablePlayerInspectScoreboard(@NotNull Player player, @NotNull PlayerProfile targetProfile) { ScoreboardWrapper wrapper = getWrapper(player); if(wrapper == null) { @@ -343,6 +344,22 @@ public class ScoreboardManager { } } + public static void enablePlayerInspectScoreboard(@NotNull Player player, @NotNull McMMOPlayer targetMcMMOPlayer) { + ScoreboardWrapper wrapper = getWrapper(player); + + if(wrapper == null) { + setupPlayer(player); + wrapper = getWrapper(player); + } + + if(wrapper != null) { + wrapper.setOldScoreboard(); + wrapper.setTypeInspectStats(targetMcMMOPlayer); + + changeScoreboard(wrapper, Config.getInstance().getInspectScoreboardTime()); + } + } + public static void enablePlayerCooldownScoreboard(Player player) { ScoreboardWrapper wrapper = getWrapper(player); diff --git a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java index 56c7650dc..ad61aede0 100644 --- a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java +++ b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java @@ -25,6 +25,7 @@ import org.bukkit.scoreboard.DisplaySlot; import org.bukkit.scoreboard.Objective; import org.bukkit.scoreboard.Score; import org.bukkit.scoreboard.Scoreboard; +import org.jetbrains.annotations.NotNull; import java.util.List; import java.util.Map; @@ -322,6 +323,17 @@ public class ScoreboardWrapper { loadObjective(LocaleLoader.getString("Scoreboard.Header.PlayerInspect", targetPlayer)); } + public void setTypeInspectStats(@NotNull McMMOPlayer mcMMOPlayer) { + this.sidebarType = SidebarType.STATS_BOARD; + targetPlayer = mcMMOPlayer.getPlayer().getName(); + targetProfile = mcMMOPlayer.getProfile(); + + targetSkill = null; + leaderboardPage = -1; + + loadObjective(LocaleLoader.getString("Scoreboard.Header.PlayerInspect", targetPlayer)); + } + public void setTypeCooldowns() { this.sidebarType = SidebarType.COOLDOWNS_BOARD; From 31076e6ba96a7dced8fac7032c17a0b2cc789871 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 5 Mar 2021 14:54:11 -0800 Subject: [PATCH 06/33] Change PlayerFishEvent priority to HIGH instead of HIGHEST --- Changelog.txt | 1 + src/main/java/com/gmail/nossr50/listeners/PlayerListener.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Changelog.txt b/Changelog.txt index 98c5994af..121562136 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -2,6 +2,7 @@ Version 2.1.177 Environmentally aware will now protect Wolves from Magma blocks Fixed a bug where mcMMO would fail to update a players name when it detected a name change mcMMO will treat vanished players as if they are offline when using the inspect command on them now (see notes) + mcMMO now listens to PlayerFishEvent at HIGH event priority instead of HIGHEST NOTES: A few changes were made to the inspect command, it used to reject you when used on vanished players, now it will be processed as if they are offline. diff --git a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java index 0261adabc..340c8cac0 100644 --- a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java @@ -258,7 +258,7 @@ public class PlayerListener implements Listener { * * @param event The event to modify */ - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onPlayerFishHighest(PlayerFishEvent event) { /* WORLD BLACKLIST CHECK */ if(WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld())) From 92efd5976083c9b0d7fb36e26dd8500b93a8d826 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 5 Mar 2021 15:13:14 -0800 Subject: [PATCH 07/33] Better compatibility with other fishing plugins Fixes #4428 --- Changelog.txt | 3 ++ .../McMMOReplaceVanillaTreasureEvent.java | 41 +++++++++++++++++++ .../nossr50/listeners/PlayerListener.java | 13 +++++- 3 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/events/McMMOReplaceVanillaTreasureEvent.java diff --git a/Changelog.txt b/Changelog.txt index 121562136..566a3e035 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3,10 +3,13 @@ Version 2.1.177 Fixed a bug where mcMMO would fail to update a players name when it detected a name change mcMMO will treat vanished players as if they are offline when using the inspect command on them now (see notes) mcMMO now listens to PlayerFishEvent at HIGH event priority instead of HIGHEST + Changed how vanilla treasures are overridden (AIR instead of SALMON) + (API) Added McMMOReplaceVanillaTreasureEvent -- see notes NOTES: A few changes were made to the inspect command, it used to reject you when used on vanished players, now it will be processed as if they are offline. Additionally if you do inspect a vanished player, it will not use their display name (consistent with offline players) as that would give them away for being online + McMMOReplaceVanillaTreasureEvent is an event which is fired when mcMMO replaces a vanilla treasure with a Salmon if the server config file is set to override vanilla treasures, this causes some issues for other fishing plugins so this event helps those plugins be more compatible Version 2.1.176 Another fix for Double Smelt bringing item stack size to illegal values diff --git a/src/main/java/com/gmail/nossr50/events/McMMOReplaceVanillaTreasureEvent.java b/src/main/java/com/gmail/nossr50/events/McMMOReplaceVanillaTreasureEvent.java new file mode 100644 index 000000000..6553bf1c1 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/events/McMMOReplaceVanillaTreasureEvent.java @@ -0,0 +1,41 @@ +package com.gmail.nossr50.events; + +import org.bukkit.entity.Item; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +public class McMMOReplaceVanillaTreasureEvent extends Event { + private @NotNull ItemStack replacementItemStack; + private final @NotNull Item originalItem; + + public McMMOReplaceVanillaTreasureEvent(@NotNull Item originalItem, @NotNull ItemStack replacementItemStack) { + this.originalItem = originalItem; + this.replacementItemStack = replacementItemStack; + } + + /** Rest of file is required boilerplate for custom events **/ + private static final @NotNull HandlerList handlers = new HandlerList(); + + @Override + public @NotNull HandlerList getHandlers() { + return handlers; + } + + public static @NotNull HandlerList getHandlerList() { + return handlers; + } + + public @NotNull ItemStack getReplacementItemStack() { + return replacementItemStack; + } + + public void setReplacementItemStack(@NotNull ItemStack replacementItemStack) { + this.replacementItemStack = replacementItemStack; + } + + public @NotNull Item getOriginalItem() { + return originalItem; + } +} diff --git a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java index 340c8cac0..707658235 100644 --- a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java @@ -8,6 +8,7 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.subskills.taming.CallOfTheWildType; +import com.gmail.nossr50.events.McMMOReplaceVanillaTreasureEvent; import com.gmail.nossr50.events.fake.FakePlayerAnimationEvent; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; @@ -291,12 +292,20 @@ public class PlayerListener implements Listener { if(event.getCaught() != null) { Item fishingCatch = (Item) event.getCaught(); - if (Config.getInstance(). getFishingOverrideTreasures() && + if (Config.getInstance().getFishingOverrideTreasures() && fishingCatch.getItemStack().getType() != Material.SALMON && fishingCatch.getItemStack().getType() != Material.COD && fishingCatch.getItemStack().getType() != Material.TROPICAL_FISH && fishingCatch.getItemStack().getType() != Material.PUFFERFISH) { - fishingCatch.setItemStack(new ItemStack(Material.SALMON, 1)); + + ItemStack replacementCatch = new ItemStack(Material.AIR); + + McMMOReplaceVanillaTreasureEvent replaceVanillaTreasureEvent = new McMMOReplaceVanillaTreasureEvent(fishingCatch, replacementCatch); + Bukkit.getPluginManager().callEvent(replaceVanillaTreasureEvent); + + //Replace + replacementCatch = replaceVanillaTreasureEvent.getReplacementItemStack(); + fishingCatch.setItemStack(replacementCatch); } if (Permissions.vanillaXpBoost(player, PrimarySkillType.FISHING)) { From 5e35a65fbf6f59628c2b2d8823ca46315f3c2487 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 5 Mar 2021 15:17:41 -0800 Subject: [PATCH 08/33] 2.1.177 --- pom.xml | 2 +- .../com/gmail/nossr50/database/FlatfileDatabaseManager.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index cae199ec1..19bee8b55 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.177-SNAPSHOT + 2.1.177 mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java index a00553eb5..efa77fb9a 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java @@ -14,7 +14,6 @@ import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.database.UUIDUpdateAsyncTask; import com.gmail.nossr50.util.Misc; -import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.text.StringUtils; import org.bukkit.OfflinePlayer; import org.jetbrains.annotations.NotNull; From 89c368e481fecdd7e375b6dc46e08c20eb706905 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 5 Mar 2021 15:39:23 -0800 Subject: [PATCH 09/33] changelog tweaks --- Changelog.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 566a3e035..a798cd303 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3,13 +3,13 @@ Version 2.1.177 Fixed a bug where mcMMO would fail to update a players name when it detected a name change mcMMO will treat vanished players as if they are offline when using the inspect command on them now (see notes) mcMMO now listens to PlayerFishEvent at HIGH event priority instead of HIGHEST - Changed how vanilla treasures are overridden (AIR instead of SALMON) + Changed how vanilla fishing treasures are overridden (AIR instead of SALMON) (API) Added McMMOReplaceVanillaTreasureEvent -- see notes NOTES: A few changes were made to the inspect command, it used to reject you when used on vanished players, now it will be processed as if they are offline. Additionally if you do inspect a vanished player, it will not use their display name (consistent with offline players) as that would give them away for being online - McMMOReplaceVanillaTreasureEvent is an event which is fired when mcMMO replaces a vanilla treasure with a Salmon if the server config file is set to override vanilla treasures, this causes some issues for other fishing plugins so this event helps those plugins be more compatible + McMMOReplaceVanillaTreasureEvent is an event which is fired when mcMMO replaces a vanilla treasure with AIR if the server config file is set to override vanilla treasures, this causes some issues for other fishing plugins so this event helps those plugins be more compatible Version 2.1.176 Another fix for Double Smelt bringing item stack size to illegal values From 12d0a220daac7b855f627f01f977e9a017baac51 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 5 Mar 2021 20:14:48 -0800 Subject: [PATCH 10/33] 2.1.178 --- Changelog.txt | 6 ++++++ pom.xml | 2 +- .../java/com/gmail/nossr50/listeners/PlayerListener.java | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index a798cd303..80254b1b8 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,9 @@ +Version 2.1.178 + Item replacement in vanilla fishing override back to SALMON from AIR (see notes) + + NOTES: + Apparently can't set items to AIR, my bad. I'll look into another solution for fishing plugin compatibility soon. + Version 2.1.177 Environmentally aware will now protect Wolves from Magma blocks Fixed a bug where mcMMO would fail to update a players name when it detected a name change diff --git a/pom.xml b/pom.xml index 19bee8b55..5bdb6cb7c 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.177 + 2.1.178 mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java index 707658235..b32083055 100644 --- a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java @@ -298,7 +298,7 @@ public class PlayerListener implements Listener { fishingCatch.getItemStack().getType() != Material.TROPICAL_FISH && fishingCatch.getItemStack().getType() != Material.PUFFERFISH) { - ItemStack replacementCatch = new ItemStack(Material.AIR); + ItemStack replacementCatch = new ItemStack(Material.SALMON, 1); McMMOReplaceVanillaTreasureEvent replaceVanillaTreasureEvent = new McMMOReplaceVanillaTreasureEvent(fishingCatch, replacementCatch); Bukkit.getPluginManager().callEvent(replaceVanillaTreasureEvent); From 8e5f2b804bf54b2c74004f4eeb007402db702be3 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 7 Mar 2021 14:20:40 -0800 Subject: [PATCH 11/33] dev mode --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5bdb6cb7c..c52ee9a2b 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.178 + 2.1.179-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO From f9097087fea194267e92cebacbcfe52c7ef89687 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 7 Mar 2021 14:28:47 -0800 Subject: [PATCH 12/33] Fixed a bug where player levels were wiped on FlatFile database if players changed nicknames --- Changelog.txt | 7 +++++++ .../database/FlatfileDatabaseManager.java | 21 ++++++++++--------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 80254b1b8..9f22ab842 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,10 @@ +Version 2.1.179 + Fixed a bug for FlatFile databases where some players with changed nicknames would have their levels not loaded upon login (possibly wiping their data) + + NOTES: + Players affected by this bug (introduced in 2.1.177) may have their data lost, but this patch reverts the change which caused this bug. + I suspect their data isn't lost and may be restored after this patch is loaded up, however if it is lost mcMMO makes regular backups so you can load one of those (check /plugins/mcMMO/) or manually edit their levels via MMOEDIT as a solution of sorts. + Version 2.1.178 Item replacement in vanilla fishing override back to SALMON from AIR (see notes) diff --git a/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java index efa77fb9a..afd53ecc7 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java @@ -477,7 +477,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager { } public PlayerProfile loadPlayerProfile(String playerName, UUID uuid, boolean create) { - boolean updateRequired = false; +// boolean updateRequired = false; BufferedReader in = null; String usersFilePath = mcMMO.getUsersFilePath(); @@ -505,12 +505,13 @@ public final class FlatfileDatabaseManager implements DatabaseManager { // Update playerName in database after name change if (!character[USERNAME].equalsIgnoreCase(playerName)) { -// mcMMO.p.debug("Name change detected: " + character[USERNAME] + " => " + playerName); + //TODO: A proper fix for changed names + mcMMO.p.debug("Name change detected: " + character[USERNAME] + " => " + playerName); character[USERNAME] = playerName; - updateRequired = true; //Flag profile to update +// updateRequired = true; //Flag profile to update } - return loadFromLine(character, updateRequired); + return loadFromLine(character); } // Didn't find the player, create a new one @@ -565,7 +566,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager { String[] character = line.split(":"); try { - destination.saveUser(loadFromLine(character, false)); + destination.saveUser(loadFromLine(character)); } catch (Exception e) { e.printStackTrace(); @@ -1148,7 +1149,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager { } } - private PlayerProfile loadFromLine(@NotNull String[] character, boolean updateRequired) { + private PlayerProfile loadFromLine(@NotNull String[] character) { Map skills = getSkillMapFromLine(character); // Skill levels Map skillsXp = new EnumMap<>(PrimarySkillType.class); // Skill & XP Map skillsDATS = new EnumMap<>(SuperAbilityType.class); // Ability & Cooldown @@ -1216,10 +1217,10 @@ public final class FlatfileDatabaseManager implements DatabaseManager { PlayerProfile playerProfile = new PlayerProfile(character[USERNAME], uuid, skills, skillsXp, skillsDATS, mobHealthbarType, scoreboardTipsShown, uniquePlayerDataMap); - if(updateRequired) { - playerProfile.markProfileDirty(); - playerProfile.scheduleSyncSave(); //Save profile since fields have changed - } +// if(updateRequired) { +// playerProfile.markProfileDirty(); +// playerProfile.scheduleSyncSave(); //Save profile since fields have changed +// } return new PlayerProfile(character[USERNAME], uuid, skills, skillsXp, skillsDATS, mobHealthbarType, scoreboardTipsShown, uniquePlayerDataMap); } From 935ab22477c7924c5093ddbef92b03c7b69a179f Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 7 Mar 2021 14:33:22 -0800 Subject: [PATCH 13/33] 2.1.179 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c52ee9a2b..44adca431 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.179-SNAPSHOT + 2.1.179 mcMMO https://github.com/mcMMO-Dev/mcMMO From 4402484d47609582427fc02cfd1cbe6457dbb271 Mon Sep 17 00:00:00 2001 From: TheBusyBiscuit Date: Tue, 9 Mar 2021 17:15:11 +0100 Subject: [PATCH 14/33] Fixed NoClassDefFoundError caused by latest Adventure-platform snapshot. (#4446) * Bumped adventure versions * Added Unit Test to ensure Adventure being set up correctly --- pom.xml | 10 +++--- .../gmail/nossr50/util/text/TextUtils.java | 5 ++- .../nossr50/util/text/TextUtilsTest.java | 33 +++++++++++++++++++ 3 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java diff --git a/pom.xml b/pom.xml index 44adca431..bf8fbfddd 100755 --- a/pom.xml +++ b/pom.xml @@ -219,27 +219,27 @@ net.kyori adventure-text-serializer-gson - 4.5.1 + 4.7.0 net.kyori adventure-api - 4.5.1 + 4.7.0 net.kyori adventure-nbt - 4.5.1 + 4.7.0 net.kyori adventure-key - 4.5.1 + 4.7.0 net.kyori adventure-text-serializer-gson-legacy-impl - 4.5.1 + 4.7.0 net.kyori diff --git a/src/main/java/com/gmail/nossr50/util/text/TextUtils.java b/src/main/java/com/gmail/nossr50/util/text/TextUtils.java index b8d71500e..1d3c001d5 100644 --- a/src/main/java/com/gmail/nossr50/util/text/TextUtils.java +++ b/src/main/java/com/gmail/nossr50/util/text/TextUtils.java @@ -16,9 +16,12 @@ import org.jetbrains.annotations.Nullable; import java.util.List; public class TextUtils { - private static @Nullable LegacyComponentSerializer customLegacySerializer; + private TextUtils() { + // We don't want any instances of this class. + } + /** * Makes a single component from an array of components, can optionally add prefixes and suffixes to come before and after each component * @param componentsArray target array diff --git a/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java b/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java new file mode 100644 index 000000000..d46673168 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java @@ -0,0 +1,33 @@ +package com.gmail.nossr50.util.text; + +import org.junit.Assert; +import org.junit.Test; + +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.format.NamedTextColor; + +/** + * This Unit Test checks if Adventure was set up correctly and works as expected. + * Normally we can rely on this to be the case. However sometimes our dependencies + * lack so far behind that things stop working correctly. + * This test ensures that basic functionality is guaranteed to work as we would expect. + * + * See https://github.com/mcMMO-Dev/mcMMO/pull/4446 + * + */ +public class TextUtilsTest { + + @Test + public void testColorizeText() { + String inputText = "&4This text should be red."; + + /* + * If this method raises an exception, we know Adventure is not set up correctly. + * This will also make the test fail and warn us about it. + */ + TextComponent component = TextUtils.colorizeText(inputText); + + Assert.assertEquals("Looks like Adventure is not working correctly.", + NamedTextColor.DARK_RED, component.color()); + } +} From f4976e5ecb288840936adb97ed6de416903a11e2 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 9 Mar 2021 13:56:03 -0800 Subject: [PATCH 15/33] switch SQL from latin1 to utf8mb4 --- Changelog.txt | 3 +++ pom.xml | 2 +- .../gmail/nossr50/database/SQLDatabaseManager.java | 12 +++++++----- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 9f22ab842..a14f8001f 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,6 @@ +Version 2.1.180 + mcMMO now uses UTF-8 compliant encoding for SQL databases (utf8mb4) + Version 2.1.179 Fixed a bug for FlatFile databases where some players with changed nicknames would have their levels not loaded upon login (possibly wiping their data) diff --git a/pom.xml b/pom.xml index bf8fbfddd..01d2a5a7e 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.179 + 2.1.180-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index a8a1fd326..68b20d5dd 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -38,6 +38,8 @@ public final class SQLDatabaseManager implements DatabaseManager { private final ReentrantLock massUpdateLock = new ReentrantLock(); + private final String ENCODING = "utf8mb4"; //This is compliant with UTF-8 while "utf8" is not, confusing but this is how it is. + protected SQLDatabaseManager() { String connectionString = "jdbc:mysql://" + Config.getInstance().getMySQLServerName() + ":" + Config.getInstance().getMySQLServerPort() + "/" + Config.getInstance().getMySQLDatabaseName(); @@ -814,7 +816,7 @@ public final class SQLDatabaseManager implements DatabaseManager { + "`lastlogin` int(32) unsigned NOT NULL," + "PRIMARY KEY (`id`)," + "INDEX(`user`(20) ASC)," - + "UNIQUE KEY `uuid` (`uuid`)) DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;"); + + "UNIQUE KEY `uuid` (`uuid`)) DEFAULT CHARSET=" + ENCODING + " AUTO_INCREMENT=1;"); tryClose(createStatement); } tryClose(resultSet); @@ -828,7 +830,7 @@ public final class SQLDatabaseManager implements DatabaseManager { + "`mobhealthbar` varchar(50) NOT NULL DEFAULT '" + Config.getInstance().getMobHealthbarDefault() + "'," + "`scoreboardtips` int(10) NOT NULL DEFAULT '0'," + "PRIMARY KEY (`user_id`)) " - + "DEFAULT CHARSET=latin1;"); + + "DEFAULT CHARSET=" + ENCODING + ";"); tryClose(createStatement); } tryClose(resultSet); @@ -853,7 +855,7 @@ public final class SQLDatabaseManager implements DatabaseManager { + "`blast_mining` int(32) unsigned NOT NULL DEFAULT '0'," + "`chimaera_wing` int(32) unsigned NOT NULL DEFAULT '0'," + "PRIMARY KEY (`user_id`)) " - + "DEFAULT CHARSET=latin1;"); + + "DEFAULT CHARSET=" + ENCODING + ";"); tryClose(createStatement); } tryClose(resultSet); @@ -881,7 +883,7 @@ public final class SQLDatabaseManager implements DatabaseManager { + "`alchemy` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," + "`total` int(10) unsigned NOT NULL DEFAULT "+totalLevel+"," + "PRIMARY KEY (`user_id`)) " - + "DEFAULT CHARSET=latin1;"); + + "DEFAULT CHARSET=" + ENCODING + ";"); tryClose(createStatement); } tryClose(resultSet); @@ -906,7 +908,7 @@ public final class SQLDatabaseManager implements DatabaseManager { + "`fishing` int(10) unsigned NOT NULL DEFAULT '0'," + "`alchemy` int(10) unsigned NOT NULL DEFAULT '0'," + "PRIMARY KEY (`user_id`)) " - + "DEFAULT CHARSET=latin1;"); + + "DEFAULT CHARSET=" + ENCODING + ";"); tryClose(createStatement); } tryClose(resultSet); From 6c69cd2aea04a503a9e76b9e8e05a89edfa77daf Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 9 Mar 2021 15:10:00 -0800 Subject: [PATCH 16/33] Fixed several SQL bugs + SQL db is now fully UTF-8 compatible --- Changelog.txt | 2 + .../nossr50/database/SQLDatabaseManager.java | 101 ++++++++++++++++-- .../datatypes/database/UpgradeType.java | 3 +- .../nossr50/util/upgrade/UpgradeManager.java | 2 +- .../{upgrades.yml => upgrades_overhaul.yml} | 1 + 5 files changed, 99 insertions(+), 10 deletions(-) rename src/main/resources/{upgrades.yml => upgrades_overhaul.yml} (92%) diff --git a/Changelog.txt b/Changelog.txt index a14f8001f..1189b47c7 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,5 +1,7 @@ Version 2.1.180 mcMMO now uses UTF-8 compliant encoding for SQL databases (utf8mb4) + Fixed a bug where mcMMO could in some circumstances fail to update SQL schema and mark it as successful + Renamed updates.yml to updates_overhaul.yml to avoid some potential issues when upgrading from classic Version 2.1.179 Fixed a bug for FlatFile databases where some players with changed nicknames would have their levels not loaded upon login (possibly wiping their data) diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index 68b20d5dd..a7ee6eb95 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -26,6 +26,9 @@ import java.util.concurrent.locks.ReentrantLock; public final class SQLDatabaseManager implements DatabaseManager { private static final String ALL_QUERY_VERSION = "total"; + public static final String MOBHEALTHBAR_VARCHAR = "VARCHAR(50)"; + public static final String UUID_VARCHAR = "VARCHAR(36)"; + public static final String USER_VARCHAR = "VARCHAR(40)"; private final String tablePrefix = Config.getInstance().getMySQLTablePrefix(); private final Map cachedUserIDs = new HashMap<>(); @@ -38,7 +41,7 @@ public final class SQLDatabaseManager implements DatabaseManager { private final ReentrantLock massUpdateLock = new ReentrantLock(); - private final String ENCODING = "utf8mb4"; //This is compliant with UTF-8 while "utf8" is not, confusing but this is how it is. + private final String CHARSET_SQL = "utf8mb4"; //This is compliant with UTF-8 while "utf8" is not, confusing but this is how it is. protected SQLDatabaseManager() { String connectionString = "jdbc:mysql://" + Config.getInstance().getMySQLServerName() @@ -816,7 +819,7 @@ public final class SQLDatabaseManager implements DatabaseManager { + "`lastlogin` int(32) unsigned NOT NULL," + "PRIMARY KEY (`id`)," + "INDEX(`user`(20) ASC)," - + "UNIQUE KEY `uuid` (`uuid`)) DEFAULT CHARSET=" + ENCODING + " AUTO_INCREMENT=1;"); + + "UNIQUE KEY `uuid` (`uuid`)) DEFAULT CHARSET=" + CHARSET_SQL + " AUTO_INCREMENT=1;"); tryClose(createStatement); } tryClose(resultSet); @@ -830,7 +833,7 @@ public final class SQLDatabaseManager implements DatabaseManager { + "`mobhealthbar` varchar(50) NOT NULL DEFAULT '" + Config.getInstance().getMobHealthbarDefault() + "'," + "`scoreboardtips` int(10) NOT NULL DEFAULT '0'," + "PRIMARY KEY (`user_id`)) " - + "DEFAULT CHARSET=" + ENCODING + ";"); + + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); tryClose(createStatement); } tryClose(resultSet); @@ -855,7 +858,7 @@ public final class SQLDatabaseManager implements DatabaseManager { + "`blast_mining` int(32) unsigned NOT NULL DEFAULT '0'," + "`chimaera_wing` int(32) unsigned NOT NULL DEFAULT '0'," + "PRIMARY KEY (`user_id`)) " - + "DEFAULT CHARSET=" + ENCODING + ";"); + + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); tryClose(createStatement); } tryClose(resultSet); @@ -883,7 +886,7 @@ public final class SQLDatabaseManager implements DatabaseManager { + "`alchemy` int(10) unsigned NOT NULL DEFAULT "+startingLevel+"," + "`total` int(10) unsigned NOT NULL DEFAULT "+totalLevel+"," + "PRIMARY KEY (`user_id`)) " - + "DEFAULT CHARSET=" + ENCODING + ";"); + + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); tryClose(createStatement); } tryClose(resultSet); @@ -908,7 +911,7 @@ public final class SQLDatabaseManager implements DatabaseManager { + "`fishing` int(10) unsigned NOT NULL DEFAULT '0'," + "`alchemy` int(10) unsigned NOT NULL DEFAULT '0'," + "PRIMARY KEY (`user_id`)) " - + "DEFAULT CHARSET=" + ENCODING + ";"); + + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); tryClose(createStatement); } tryClose(resultSet); @@ -1031,12 +1034,14 @@ public final class SQLDatabaseManager implements DatabaseManager { checkUpgradeAddUniqueChimaeraWing(statement); break; + case SQL_CHARSET_UTF8MB4: + updateCharacterSet(statement); + break; + default: break; } - - mcMMO.getUpgradeManager().setUpgradeCompleted(upgrade); } catch (SQLException ex) { printErrors(ex); @@ -1193,6 +1198,7 @@ public final class SQLDatabaseManager implements DatabaseManager { statement.execute("ALTER TABLE `" + tablePrefix + "users` " + "DROP INDEX `user`," + "ADD INDEX `user` (`user`(20) ASC)"); + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.DROP_NAME_UNIQUENESS); } catch (SQLException ex) { ex.printStackTrace(); } finally { @@ -1203,6 +1209,7 @@ public final class SQLDatabaseManager implements DatabaseManager { private void checkUpgradeAddAlchemy(final Statement statement) throws SQLException { try { statement.executeQuery("SELECT `alchemy` FROM `" + tablePrefix + "skills` LIMIT 1"); + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_ALCHEMY); } catch (SQLException ex) { mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Alchemy..."); @@ -1214,6 +1221,7 @@ public final class SQLDatabaseManager implements DatabaseManager { private void checkUpgradeAddBlastMiningCooldown(final Statement statement) throws SQLException { try { statement.executeQuery("SELECT `blast_mining` FROM `" + tablePrefix + "cooldowns` LIMIT 1"); + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_BLAST_MINING_COOLDOWN); } catch (SQLException ex) { mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Blast Mining..."); @@ -1224,6 +1232,7 @@ public final class SQLDatabaseManager implements DatabaseManager { private void checkUpgradeAddUniqueChimaeraWing(final Statement statement) throws SQLException { try { statement.executeQuery("SELECT `chimaera_wing` FROM `" + tablePrefix + "cooldowns` LIMIT 1"); + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_UNIQUE_PLAYER_DATA); } catch (SQLException ex) { mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Chimaera Wing..."); @@ -1234,6 +1243,7 @@ public final class SQLDatabaseManager implements DatabaseManager { private void checkUpgradeAddFishing(final Statement statement) throws SQLException { try { statement.executeQuery("SELECT `fishing` FROM `" + tablePrefix + "skills` LIMIT 1"); + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_FISHING); } catch (SQLException ex) { mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for Fishing..."); @@ -1245,6 +1255,7 @@ public final class SQLDatabaseManager implements DatabaseManager { private void checkUpgradeAddMobHealthbars(final Statement statement) throws SQLException { try { statement.executeQuery("SELECT `mobhealthbar` FROM `" + tablePrefix + "huds` LIMIT 1"); + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_MOB_HEALTHBARS); } catch (SQLException ex) { mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for mob healthbars..."); @@ -1255,6 +1266,7 @@ public final class SQLDatabaseManager implements DatabaseManager { private void checkUpgradeAddScoreboardTips(final Statement statement) throws SQLException { try { statement.executeQuery("SELECT `scoreboardtips` FROM `" + tablePrefix + "huds` LIMIT 1"); + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_SCOREBOARD_TIPS); } catch (SQLException ex) { mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for scoreboard tips..."); @@ -1283,6 +1295,8 @@ public final class SQLDatabaseManager implements DatabaseManager { } } } + + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_SQL_INDEXES); } catch (SQLException ex) { printErrors(ex); @@ -1313,6 +1327,8 @@ public final class SQLDatabaseManager implements DatabaseManager { statement.executeUpdate("ALTER TABLE `" + tablePrefix + "users` ADD `uuid` varchar(36) NULL DEFAULT NULL"); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "users` ADD UNIQUE INDEX `uuid` (`uuid`) USING BTREE"); } + + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_UUIDS); } catch (SQLException ex) { printErrors(ex); @@ -1379,6 +1395,8 @@ public final class SQLDatabaseManager implements DatabaseManager { mcMMO.p.getLogger().info("Removing party name from users table..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "users` DROP COLUMN `party`"); } + + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.DROP_SQL_PARTY_NAMES); } catch (SQLException ex) { printErrors(ex); @@ -1414,6 +1432,8 @@ public final class SQLDatabaseManager implements DatabaseManager { statement.executeUpdate("ALTER TABLE `" + tablePrefix + "skills` ADD INDEX `idx_total` (`total`) USING BTREE"); connection.commit(); } + + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_SKILL_TOTAL); } catch (SQLException ex) { printErrors(ex); @@ -1445,6 +1465,8 @@ public final class SQLDatabaseManager implements DatabaseManager { mcMMO.p.getLogger().info("Removing Spout HUD type from huds table..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "huds` DROP COLUMN `hudtype`"); } + + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.DROP_SPOUT); } catch (SQLException ex) { printErrors(ex); @@ -1557,4 +1579,67 @@ public final class SQLDatabaseManager implements DatabaseManager { tryClose(connection); } } + + private void updateCharacterSet(@NotNull Statement statement) { + //TODO: Could check the tables for being latin1 before executing queries but it seems moot because it is likely the same computational effort + /* + The following columns were set to use latin1 historically (now utf8mb4) + column user in users + column uuid in users + + column mobhealthbar in huds + */ + + //Alter users table + mcMMO.p.getLogger().info("SQL Converting tables from latin1 to utf8mb4"); + + //Update "user" column + try { + mcMMO.p.getLogger().info("Updating user column to new encoding"); + statement.executeUpdate(getUpdateUserInUsersTableSQLQuery()); + + //Update "uuid" column + mcMMO.p.getLogger().info("Updating user column to new encoding"); + statement.executeUpdate(getUpdateUUIDInUsersTableSQLQuery()); + + //Update "mobhealthbar" column + mcMMO.p.getLogger().info("Updating mobhealthbar column to new encoding"); + statement.executeUpdate(getUpdateMobHealthBarInHudsTableSQLQuery()); + + mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.SQL_CHARSET_UTF8MB4); + + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @NotNull + private String getUpdateUserInUsersTableSQLQuery() { + return "ALTER TABLE\n" + + " " + tablePrefix + "users\n" + + " CHANGE user user\n" + + " " + USER_VARCHAR + "\n" + + " CHARACTER SET utf8mb4\n" + + " COLLATE utf8mb4_unicode_ci;"; + } + + @NotNull + private String getUpdateUUIDInUsersTableSQLQuery() { + return "ALTER TABLE\n" + + " " + tablePrefix + "users\n" + + " CHANGE uuid uuid\n" + + " " + UUID_VARCHAR + "\n" + + " CHARACTER SET utf8mb4\n" + + " COLLATE utf8mb4_unicode_ci;"; + } + + @NotNull + private String getUpdateMobHealthBarInHudsTableSQLQuery() { + return "ALTER TABLE\n" + + " " + tablePrefix + "huds\n" + + " CHANGE mobhealthbar mobhealthbar\n" + + " " + MOBHEALTHBAR_VARCHAR + "\n" + + " CHARACTER SET utf8mb4\n" + + " COLLATE utf8mb4_unicode_ci;"; + } } diff --git a/src/main/java/com/gmail/nossr50/datatypes/database/UpgradeType.java b/src/main/java/com/gmail/nossr50/datatypes/database/UpgradeType.java index 412af6fbc..13faa75b7 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/database/UpgradeType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/database/UpgradeType.java @@ -16,5 +16,6 @@ public enum UpgradeType { ADD_UNIQUE_PLAYER_DATA, FIX_SPELLING_NETHERITE_SALVAGE, FIX_SPELLING_NETHERITE_REPAIR, - FIX_NETHERITE_SALVAGE_QUANTITIES + FIX_NETHERITE_SALVAGE_QUANTITIES, + SQL_CHARSET_UTF8MB4 } diff --git a/src/main/java/com/gmail/nossr50/util/upgrade/UpgradeManager.java b/src/main/java/com/gmail/nossr50/util/upgrade/UpgradeManager.java index 082376c0e..55c747ffd 100644 --- a/src/main/java/com/gmail/nossr50/util/upgrade/UpgradeManager.java +++ b/src/main/java/com/gmail/nossr50/util/upgrade/UpgradeManager.java @@ -11,7 +11,7 @@ public class UpgradeManager extends ConfigLoader { private final Set setNeededUpgrades; public UpgradeManager() { - super("upgrades.yml"); + super("upgrades_overhaul.yml"); //overhaul is added so we don't have any issues with classic setNeededUpgrades = EnumSet.allOf(UpgradeType.class); diff --git a/src/main/resources/upgrades.yml b/src/main/resources/upgrades_overhaul.yml similarity index 92% rename from src/main/resources/upgrades.yml rename to src/main/resources/upgrades_overhaul.yml index 3a60fb42c..df0290061 100644 --- a/src/main/resources/upgrades.yml +++ b/src/main/resources/upgrades_overhaul.yml @@ -11,3 +11,4 @@ Upgrades_Finished: FIX_SPELLING_NETHERITE_REPAIR: false FIX_NETHERITE_SALVAGE_QUANTITIES: false ADD_UUIDS: false + SQL_CHARSET_UTF8MB4: false From e8a0e6e4a48acb65ca3647e6a95f5504de4f6abe Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 9 Mar 2021 19:47:35 -0800 Subject: [PATCH 17/33] Don't upgrade old party DB schema from 8 years ago (band-aid fix, real fix coming later) --- .../com/gmail/nossr50/party/PartyManager.java | 140 +++++++++--------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/party/PartyManager.java b/src/main/java/com/gmail/nossr50/party/PartyManager.java index 6a1591a70..c825694b9 100644 --- a/src/main/java/com/gmail/nossr50/party/PartyManager.java +++ b/src/main/java/com/gmail/nossr50/party/PartyManager.java @@ -586,10 +586,10 @@ public final class PartyManager { return; } - if (mcMMO.getUpgradeManager().shouldUpgrade(UpgradeType.ADD_UUIDS_PARTY)) { - loadAndUpgradeParties(); - return; - } +// if (mcMMO.getUpgradeManager().shouldUpgrade(UpgradeType.ADD_UUIDS_PARTY)) { +// loadAndUpgradeParties(); +// return; +// } try { YamlConfiguration partiesFile; @@ -693,72 +693,72 @@ public final class PartyManager { } } - private static void loadAndUpgradeParties() { - YamlConfiguration partiesFile = YamlConfiguration.loadConfiguration(partyFile); - - if (!partyFile.renameTo(new File(mcMMO.getFlatFileDirectory() + "parties.yml.converted"))) { - mcMMO.p.getLogger().severe("Could not rename parties.yml to parties.yml.converted!"); - return; - } - - ArrayList hasAlly = new ArrayList<>(); - - for (String partyName : partiesFile.getConfigurationSection("").getKeys(false)) { - Party party = new Party(partyName); - - String leaderName = partiesFile.getString(partyName + ".Leader"); - PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(leaderName, false); - - if (!profile.isLoaded()) { - mcMMO.p.getLogger().warning("Could not find UUID in database for party leader " + leaderName + " in party " + partyName); - continue; - } - - UUID leaderUniqueId = profile.getUniqueId(); - - party.setLeader(new PartyLeader(leaderUniqueId, leaderName)); - party.setPassword(partiesFile.getString(partyName + ".Password")); - party.setLocked(partiesFile.getBoolean(partyName + ".Locked")); - party.setLevel(partiesFile.getInt(partyName + ".Level")); - party.setXp(partiesFile.getInt(partyName + ".Xp")); - - if (partiesFile.getString(partyName + ".Ally") != null) { - hasAlly.add(party); - } - - party.setXpShareMode(ShareMode.getShareMode(partiesFile.getString(partyName + ".ExpShareMode", "NONE"))); - party.setItemShareMode(ShareMode.getShareMode(partiesFile.getString(partyName + ".ItemShareMode", "NONE"))); - - for (ItemShareType itemShareType : ItemShareType.values()) { - party.setSharingDrops(itemShareType, partiesFile.getBoolean(partyName + ".ItemShareType." + itemShareType.toString(), true)); - } - - LinkedHashMap members = party.getMembers(); - - for (String memberName : partiesFile.getStringList(partyName + ".Members")) { - PlayerProfile memberProfile = mcMMO.getDatabaseManager().loadPlayerProfile(memberName, false); - - if (!memberProfile.isLoaded()) { - mcMMO.p.getLogger().warning("Could not find UUID in database for party member " + memberName + " in party " + partyName); - continue; - } - - UUID memberUniqueId = memberProfile.getUniqueId(); - - members.put(memberUniqueId, memberName); - } - - parties.add(party); - } - - mcMMO.p.debug("Loaded (" + parties.size() + ") Parties..."); - - for (Party party : hasAlly) { - party.setAlly(PartyManager.getParty(partiesFile.getString(party.getName() + ".Ally"))); - } - - mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_UUIDS_PARTY); - } +// private static void loadAndUpgradeParties() { +// YamlConfiguration partiesFile = YamlConfiguration.loadConfiguration(partyFile); +// +// if (!partyFile.renameTo(new File(mcMMO.getFlatFileDirectory() + "parties.yml.converted"))) { +// mcMMO.p.getLogger().severe("Could not rename parties.yml to parties.yml.converted!"); +// return; +// } +// +// ArrayList hasAlly = new ArrayList<>(); +// +// for (String partyName : partiesFile.getConfigurationSection("").getKeys(false)) { +// Party party = new Party(partyName); +// +// String leaderName = partiesFile.getString(partyName + ".Leader"); +// PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(leaderName, false); +// +// if (!profile.isLoaded()) { +// mcMMO.p.getLogger().warning("Could not find UUID in database for party leader " + leaderName + " in party " + partyName); +// continue; +// } +// +// UUID leaderUniqueId = profile.getUniqueId(); +// +// party.setLeader(new PartyLeader(leaderUniqueId, leaderName)); +// party.setPassword(partiesFile.getString(partyName + ".Password")); +// party.setLocked(partiesFile.getBoolean(partyName + ".Locked")); +// party.setLevel(partiesFile.getInt(partyName + ".Level")); +// party.setXp(partiesFile.getInt(partyName + ".Xp")); +// +// if (partiesFile.getString(partyName + ".Ally") != null) { +// hasAlly.add(party); +// } +// +// party.setXpShareMode(ShareMode.getShareMode(partiesFile.getString(partyName + ".ExpShareMode", "NONE"))); +// party.setItemShareMode(ShareMode.getShareMode(partiesFile.getString(partyName + ".ItemShareMode", "NONE"))); +// +// for (ItemShareType itemShareType : ItemShareType.values()) { +// party.setSharingDrops(itemShareType, partiesFile.getBoolean(partyName + ".ItemShareType." + itemShareType.toString(), true)); +// } +// +// LinkedHashMap members = party.getMembers(); +// +// for (String memberName : partiesFile.getStringList(partyName + ".Members")) { +// PlayerProfile memberProfile = mcMMO.getDatabaseManager().loadPlayerProfile(memberName, false); +// +// if (!memberProfile.isLoaded()) { +// mcMMO.p.getLogger().warning("Could not find UUID in database for party member " + memberName + " in party " + partyName); +// continue; +// } +// +// UUID memberUniqueId = memberProfile.getUniqueId(); +// +// members.put(memberUniqueId, memberName); +// } +// +// parties.add(party); +// } +// +// mcMMO.p.debug("Loaded (" + parties.size() + ") Parties..."); +// +// for (Party party : hasAlly) { +// party.setAlly(PartyManager.getParty(partiesFile.getString(party.getName() + ".Ally"))); +// } +// +// mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_UUIDS_PARTY); +// } /** * Handle party change event. From e95b7f72a7bd2749609eb08d3822b6beea6df54a Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 11 Mar 2021 11:58:27 -0800 Subject: [PATCH 18/33] Add some safety measures to loading a user from FlatFile --- .../database/FlatfileDatabaseManager.java | 156 ++++++++++-------- 1 file changed, 83 insertions(+), 73 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java index afd53ecc7..d3a761792 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java @@ -31,6 +31,49 @@ public final class FlatfileDatabaseManager implements DatabaseManager { private final File usersFile; private static final Object fileWritingLock = new Object(); + public static int USERNAME_INDEX = 0; + public static int SKILLS_MINING = 1; + public static int EXP_MINING = 4; + public static int SKILLS_WOODCUTTING = 5; + public static int EXP_WOODCUTTING = 6; + public static int SKILLS_REPAIR = 7; + public static int SKILLS_UNARMED = 8; + public static int SKILLS_HERBALISM = 9; + public static int SKILLS_EXCAVATION = 10; + public static int SKILLS_ARCHERY = 11; + public static int SKILLS_SWORDS = 12; + public static int SKILLS_AXES = 13; + public static int SKILLS_ACROBATICS = 14; + public static int EXP_REPAIR = 15; + public static int EXP_UNARMED = 16; + public static int EXP_HERBALISM = 17; + public static int EXP_EXCAVATION = 18; + public static int EXP_ARCHERY = 19; + public static int EXP_SWORDS = 20; + public static int EXP_AXES = 21; + public static int EXP_ACROBATICS = 22; + public static int SKILLS_TAMING = 24; + public static int EXP_TAMING = 25; + public static int COOLDOWN_BERSERK = 26; + public static int COOLDOWN_GIGA_DRILL_BREAKER = 27; + public static int COOLDOWN_TREE_FELLER = 28; + public static int COOLDOWN_GREEN_TERRA = 29; + public static int COOLDOWN_SERRATED_STRIKES = 30; + public static int COOLDOWN_SKULL_SPLITTER = 31; + public static int COOLDOWN_SUPER_BREAKER = 32; + public static int SKILLS_FISHING = 34; + public static int EXP_FISHING = 35; + public static int COOLDOWN_BLAST_MINING = 36; + public static int LAST_LOGIN = 37; + public static int HEALTHBAR = 38; + public static int SKILLS_ALCHEMY = 39; + public static int EXP_ALCHEMY = 40; + public static int UUID_INDEX = 41; + public static int SCOREBOARD_TIPS = 42; + public static int COOLDOWN_CHIMAERA_WING = 43; + + public static int DATA_ENTRY_COUNT = COOLDOWN_CHIMAERA_WING + 1; //Update this everytime new data is added + protected FlatfileDatabaseManager() { usersFile = new File(mcMMO.getUsersFilePath()); checkStructure(); @@ -127,7 +170,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager { while ((line = in.readLine()) != null) { String[] character = line.split(":"); - String name = character[USERNAME]; + String name = character[USERNAME_INDEX]; long lastPlayed = 0; boolean rewrite = false; try { @@ -204,7 +247,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager { while ((line = in.readLine()) != null) { // Write out the same file but when we get to the player we want to remove, we skip his line. - if (!worked && line.split(":")[USERNAME].equalsIgnoreCase(playerName)) { + if (!worked && line.split(":")[USERNAME_INDEX].equalsIgnoreCase(playerName)) { mcMMO.p.getLogger().info("User found, removing..."); worked = true; continue; // Skip the player @@ -267,13 +310,28 @@ public final class FlatfileDatabaseManager implements DatabaseManager { boolean wroteUser = false; // While not at the end of the file while ((line = in.readLine()) != null) { - // Read the line in and copy it to the output if it's not the player we want to edit - String[] character = line.split(":"); - if (!(uuid != null && character[UUID_INDEX].equalsIgnoreCase(uuid.toString())) && !character[USERNAME].equalsIgnoreCase(playerName)) { - writer.append(line).append("\r\n"); + boolean goodData = true; + + //Check for incomplete or corrupted data + if(!line.contains(":")) + continue; + + String[] splitData = line.split(":"); + + //This would be rare, but check the splitData for having enough entries to contain a username + + if(splitData.length < USERNAME_INDEX) { //UUID have been in mcMMO DB for a very long time so any user without + //Something is wrong if we don't have enough split data to have an entry for a username + mcMMO.p.getLogger().severe("mcMMO found some corrupted data in mcmmo.users and is removing it."); + continue; } - else { - // Otherwise write the new player information + + if (!(uuid != null + && splitData[UUID_INDEX].equalsIgnoreCase(uuid.toString())) + && !splitData[USERNAME_INDEX].equalsIgnoreCase(playerName)) { + writer.append(line).append("\r\n"); //Not the user so write it to file and move on + } else { + //User found writeUserToLine(profile, playerName, uuid, writer); wroteUser = true; } @@ -494,20 +552,20 @@ public final class FlatfileDatabaseManager implements DatabaseManager { // Compare names because we don't have a valid uuid for that player even // if input uuid is not null if (character[UUID_INDEX].equalsIgnoreCase("NULL")) { - if (!character[USERNAME].equalsIgnoreCase(playerName)) { + if (!character[USERNAME_INDEX].equalsIgnoreCase(playerName)) { continue; } } // If input uuid is not null then we should compare uuids - else if ((uuid != null && !character[UUID_INDEX].equalsIgnoreCase(uuid.toString())) || (uuid == null && !character[USERNAME].equalsIgnoreCase(playerName))) { + else if ((uuid != null && !character[UUID_INDEX].equalsIgnoreCase(uuid.toString())) || (uuid == null && !character[USERNAME_INDEX].equalsIgnoreCase(playerName))) { continue; } // Update playerName in database after name change - if (!character[USERNAME].equalsIgnoreCase(playerName)) { + if (!character[USERNAME_INDEX].equalsIgnoreCase(playerName)) { //TODO: A proper fix for changed names - mcMMO.p.debug("Name change detected: " + character[USERNAME] + " => " + playerName); - character[USERNAME] = playerName; + mcMMO.p.debug("Name change detected: " + character[USERNAME_INDEX] + " => " + playerName); + character[USERNAME_INDEX] = playerName; // updateRequired = true; //Flag profile to update } @@ -607,7 +665,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager { while ((line = in.readLine()) != null) { String[] character = line.split(":"); - if (!worked && character[USERNAME].equalsIgnoreCase(userName)) { + if (!worked && character[USERNAME_INDEX].equalsIgnoreCase(userName)) { if (character.length < 42) { mcMMO.p.getLogger().severe("Could not update UUID for " + userName + "!"); mcMMO.p.getLogger().severe("Database entry is invalid."); @@ -666,14 +724,14 @@ public final class FlatfileDatabaseManager implements DatabaseManager { while (((line = in.readLine()) != null)) { String[] character = line.split(":"); - if (!fetchedUUIDs.isEmpty() && fetchedUUIDs.containsKey(character[USERNAME])) { + if (!fetchedUUIDs.isEmpty() && fetchedUUIDs.containsKey(character[USERNAME_INDEX])) { if (character.length < 42) { - mcMMO.p.getLogger().severe("Could not update UUID for " + character[USERNAME] + "!"); + mcMMO.p.getLogger().severe("Could not update UUID for " + character[USERNAME_INDEX] + "!"); mcMMO.p.getLogger().severe("Database entry is invalid."); continue; } - character[UUID_INDEX] = fetchedUUIDs.remove(character[USERNAME]).toString(); + character[UUID_INDEX] = fetchedUUIDs.remove(character[USERNAME_INDEX]).toString(); line = org.apache.commons.lang.StringUtils.join(character, ":") + ":"; } @@ -724,7 +782,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager { while ((line = in.readLine()) != null) { String[] character = line.split(":"); - users.add(character[USERNAME]); + users.add(character[USERNAME_INDEX]); } } catch (Exception e) { @@ -782,7 +840,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager { while ((line = in.readLine()) != null) { String[] data = line.split(":"); - playerName = data[USERNAME]; + playerName = data[USERNAME_INDEX]; int powerLevel = 0; Map skills = getSkillMapFromLine(data); @@ -882,8 +940,8 @@ public final class FlatfileDatabaseManager implements DatabaseManager { String[] character = line.split(":"); // Prevent the same username from being present multiple times - if (!usernames.add(character[USERNAME])) { - character[USERNAME] = "_INVALID_OLD_USERNAME_'"; + if (!usernames.add(character[USERNAME_INDEX])) { + character[USERNAME_INDEX] = "_INVALID_OLD_USERNAME_'"; updated = true; if (character.length < UUID_INDEX + 1 || character[UUID_INDEX].equals("NULL")) { continue; @@ -922,7 +980,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager { } int cap = Config.getInstance().getLevelCap(skill); if (Integer.parseInt(character[index]) > cap) { - mcMMO.p.getLogger().warning("Truncating " + skill.getName() + " to configured max level for player " + character[USERNAME]); + mcMMO.p.getLogger().warning("Truncating " + skill.getName() + " to configured max level for player " + character[USERNAME_INDEX]); character[index] = cap + ""; updated = true; } @@ -1044,11 +1102,11 @@ public final class FlatfileDatabaseManager implements DatabaseManager { } if (corrupted) { - mcMMO.p.debug("Updating corrupted database line for player " + character[USERNAME]); + mcMMO.p.debug("Updating corrupted database line for player " + character[USERNAME_INDEX]); } if (oldVersion != null) { - mcMMO.p.debug("Updating database line from before version " + oldVersion + " for player " + character[USERNAME]); + mcMMO.p.debug("Updating database line from before version " + oldVersion + " for player " + character[USERNAME_INDEX]); } updated |= corrupted; @@ -1215,14 +1273,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager { uniquePlayerDataMap.put(UniqueDataType.CHIMAERA_WING_DATS, 0); } - PlayerProfile playerProfile = new PlayerProfile(character[USERNAME], uuid, skills, skillsXp, skillsDATS, mobHealthbarType, scoreboardTipsShown, uniquePlayerDataMap); - -// if(updateRequired) { -// playerProfile.markProfileDirty(); -// playerProfile.scheduleSyncSave(); //Save profile since fields have changed -// } - - return new PlayerProfile(character[USERNAME], uuid, skills, skillsXp, skillsDATS, mobHealthbarType, scoreboardTipsShown, uniquePlayerDataMap); + return new PlayerProfile(character[USERNAME_INDEX], uuid, skills, skillsXp, skillsDATS, mobHealthbarType, scoreboardTipsShown, uniquePlayerDataMap); } private Map getSkillMapFromLine(String[] character) { @@ -1285,47 +1336,6 @@ public final class FlatfileDatabaseManager implements DatabaseManager { } } - - public static int USERNAME = 0; - public static int SKILLS_MINING = 1; - public static int EXP_MINING = 4; - public static int SKILLS_WOODCUTTING = 5; - public static int EXP_WOODCUTTING = 6; - public static int SKILLS_REPAIR = 7; - public static int SKILLS_UNARMED = 8; - public static int SKILLS_HERBALISM = 9; - public static int SKILLS_EXCAVATION = 10; - public static int SKILLS_ARCHERY = 11; - public static int SKILLS_SWORDS = 12; - public static int SKILLS_AXES = 13; - public static int SKILLS_ACROBATICS = 14; - public static int EXP_REPAIR = 15; - public static int EXP_UNARMED = 16; - public static int EXP_HERBALISM = 17; - public static int EXP_EXCAVATION = 18; - public static int EXP_ARCHERY = 19; - public static int EXP_SWORDS = 20; - public static int EXP_AXES = 21; - public static int EXP_ACROBATICS = 22; - public static int SKILLS_TAMING = 24; - public static int EXP_TAMING = 25; - public static int COOLDOWN_BERSERK = 26; - public static int COOLDOWN_GIGA_DRILL_BREAKER = 27; - public static int COOLDOWN_TREE_FELLER = 28; - public static int COOLDOWN_GREEN_TERRA = 29; - public static int COOLDOWN_SERRATED_STRIKES = 30; - public static int COOLDOWN_SKULL_SPLITTER = 31; - public static int COOLDOWN_SUPER_BREAKER = 32; - public static int SKILLS_FISHING = 34; - public static int EXP_FISHING = 35; - public static int COOLDOWN_BLAST_MINING = 36; - public static int LAST_LOGIN = 37; - public static int HEALTHBAR = 38; - public static int SKILLS_ALCHEMY = 39; - public static int EXP_ALCHEMY = 40; - public static int UUID_INDEX = 41; - public static int SCOREBOARD_TIPS = 42; - public static int COOLDOWN_CHIMAERA_WING = 43; public void resetMobHealthSettings() { BufferedReader in = null; From 72116d809bc8d44c6dabd125fe3d684895e2eebe Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 11 Mar 2021 12:00:11 -0800 Subject: [PATCH 19/33] Add another error message if mcMMO finds something unexpected in the database --- .../gmail/nossr50/database/FlatfileDatabaseManager.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java index d3a761792..ef4f7ff5f 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java @@ -310,16 +310,15 @@ public final class FlatfileDatabaseManager implements DatabaseManager { boolean wroteUser = false; // While not at the end of the file while ((line = in.readLine()) != null) { - boolean goodData = true; - //Check for incomplete or corrupted data - if(!line.contains(":")) + if(!line.contains(":")) { + mcMMO.p.getLogger().severe("mcMMO found some unexpected data in mcmmo.users and is removing it"); continue; + } String[] splitData = line.split(":"); //This would be rare, but check the splitData for having enough entries to contain a username - if(splitData.length < USERNAME_INDEX) { //UUID have been in mcMMO DB for a very long time so any user without //Something is wrong if we don't have enough split data to have an entry for a username mcMMO.p.getLogger().severe("mcMMO found some corrupted data in mcmmo.users and is removing it."); From 7755875dbf3d9c852ab6a28fbfcdb188b1f9219e Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 11 Mar 2021 12:02:21 -0800 Subject: [PATCH 20/33] Some refactoring of FlatFileDatabaseManager --- src/main/java/com/gmail/nossr50/commands/MHDCommand.java | 6 +++--- .../com/gmail/nossr50/database/DatabaseManagerFactory.java | 4 ++-- ...leDatabaseManager.java => FlatFileDatabaseManager.java} | 7 +++---- 3 files changed, 8 insertions(+), 9 deletions(-) rename src/main/java/com/gmail/nossr50/database/{FlatfileDatabaseManager.java => FlatFileDatabaseManager.java} (99%) diff --git a/src/main/java/com/gmail/nossr50/commands/MHDCommand.java b/src/main/java/com/gmail/nossr50/commands/MHDCommand.java index a85fe9426..d3b547acc 100644 --- a/src/main/java/com/gmail/nossr50/commands/MHDCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/MHDCommand.java @@ -1,7 +1,7 @@ package com.gmail.nossr50.commands; import com.gmail.nossr50.config.Config; -import com.gmail.nossr50.database.FlatfileDatabaseManager; +import com.gmail.nossr50.database.FlatFileDatabaseManager; import com.gmail.nossr50.database.SQLDatabaseManager; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.mcMMO; @@ -27,8 +27,8 @@ public class MHDCommand implements TabExecutor { sender.sendMessage("Mob health reset"); return true; } - if (mcMMO.getDatabaseManager() instanceof FlatfileDatabaseManager) { - FlatfileDatabaseManager m = (FlatfileDatabaseManager) mcMMO.getDatabaseManager(); + if (mcMMO.getDatabaseManager() instanceof FlatFileDatabaseManager) { + FlatFileDatabaseManager m = (FlatFileDatabaseManager) mcMMO.getDatabaseManager(); m.resetMobHealthSettings(); for (McMMOPlayer player : UserManager.getPlayers()) { player.getProfile().setMobHealthbarType(Config.getInstance().getMobHealthbarDefault()); diff --git a/src/main/java/com/gmail/nossr50/database/DatabaseManagerFactory.java b/src/main/java/com/gmail/nossr50/database/DatabaseManagerFactory.java index 24013a3a8..b6981403b 100644 --- a/src/main/java/com/gmail/nossr50/database/DatabaseManagerFactory.java +++ b/src/main/java/com/gmail/nossr50/database/DatabaseManagerFactory.java @@ -23,7 +23,7 @@ public class DatabaseManagerFactory { mcMMO.p.debug("Falling back on " + (Config.getInstance().getUseMySQL() ? "SQL" : "Flatfile") + " database"); } - return Config.getInstance().getUseMySQL() ? new SQLDatabaseManager() : new FlatfileDatabaseManager(); + return Config.getInstance().getUseMySQL() ? new SQLDatabaseManager() : new FlatFileDatabaseManager(); } /** @@ -60,7 +60,7 @@ public class DatabaseManagerFactory { switch (type) { case FLATFILE: mcMMO.p.getLogger().info("Using FlatFile Database"); - return new FlatfileDatabaseManager(); + return new FlatFileDatabaseManager(); case SQL: mcMMO.p.getLogger().info("Using SQL Database"); diff --git a/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java similarity index 99% rename from src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java rename to src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index ef4f7ff5f..e5da7aff4 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -22,7 +22,7 @@ import org.jetbrains.annotations.Nullable; import java.io.*; import java.util.*; -public final class FlatfileDatabaseManager implements DatabaseManager { +public final class FlatFileDatabaseManager implements DatabaseManager { private final HashMap> playerStatHash = new HashMap<>(); private final List powerLevels = new ArrayList<>(); private long lastUpdate = 0; @@ -74,7 +74,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager { public static int DATA_ENTRY_COUNT = COOLDOWN_CHIMAERA_WING + 1; //Update this everytime new data is added - protected FlatfileDatabaseManager() { + protected FlatFileDatabaseManager() { usersFile = new File(mcMMO.getUsersFilePath()); checkStructure(); updateLeaderboards(); @@ -339,8 +339,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager { /* * If we couldn't find the user in the DB we need to add him */ - if(!wroteUser) - { + if(!wroteUser) { writeUserToLine(profile, playerName, uuid, writer); } From d77c8c88a31a09203ad9e98dbde8fe85d93d80a7 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 11 Mar 2021 12:16:33 -0800 Subject: [PATCH 21/33] Less spammy corrupt data reporting --- .../nossr50/database/FlatFileDatabaseManager.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index e5da7aff4..988389ccd 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -299,6 +299,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { BufferedReader in = null; FileWriter out = null; String usersFilePath = mcMMO.getUsersFilePath(); + boolean corruptDataFound = false; synchronized (fileWritingLock) { try { @@ -312,7 +313,12 @@ public final class FlatFileDatabaseManager implements DatabaseManager { while ((line = in.readLine()) != null) { //Check for incomplete or corrupted data if(!line.contains(":")) { - mcMMO.p.getLogger().severe("mcMMO found some unexpected data in mcmmo.users and is removing it"); + + if(!corruptDataFound) { + mcMMO.p.getLogger().severe("mcMMO found some unexpected or corrupted data in mcmmo.users and is removing it, it is possible some data has been lost."); + corruptDataFound = true; + } + continue; } @@ -321,7 +327,12 @@ public final class FlatFileDatabaseManager implements DatabaseManager { //This would be rare, but check the splitData for having enough entries to contain a username if(splitData.length < USERNAME_INDEX) { //UUID have been in mcMMO DB for a very long time so any user without //Something is wrong if we don't have enough split data to have an entry for a username - mcMMO.p.getLogger().severe("mcMMO found some corrupted data in mcmmo.users and is removing it."); + + if(!corruptDataFound) { + mcMMO.p.getLogger().severe("mcMMO found some unexpected or corrupted data in mcmmo.users and is removing it, it is possible some data has been lost."); + corruptDataFound = true; + } + continue; } From 2203d61c104b6899d0267d5c9e8ca3d7e10483a2 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 11 Mar 2021 13:11:11 -0800 Subject: [PATCH 22/33] More safety against corrupt data when loading data for FlatFile --- .../database/FlatFileDatabaseManager.java | 125 ++++++++++++------ .../com/gmail/nossr50/party/PartyManager.java | 2 - .../nossr50/util/text/TextUtilsTest.java | 5 +- 3 files changed, 87 insertions(+), 45 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index 988389ccd..8f556520f 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -385,6 +385,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } private void writeUserToLine(PlayerProfile profile, String playerName, UUID uuid, StringBuilder writer) { + // FlyingMonkey_:0:::0:0:0:0:0:0:0:0:0:0:5:0:156:460: writer.append(playerName).append(":"); writer.append(profile.getSkillLevel(PrimarySkillType.MINING)).append(":"); writer.append(":"); @@ -936,6 +937,8 @@ public final class FlatFileDatabaseManager implements DatabaseManager { HashSet players = new HashSet<>(); while ((line = in.readLine()) != null) { + String oldVersion = null; + // Remove empty lines from the file if (line.isEmpty()) { continue; @@ -968,8 +971,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { continue; } - String oldVersion = null; - if (character.length > 33 && !character[33].isEmpty()) { // Removal of Spout Support // Version 1.4.07-dev2 @@ -984,11 +985,21 @@ public final class FlatFileDatabaseManager implements DatabaseManager { if (Config.getInstance().getTruncateSkills()) { for (PrimarySkillType skill : PrimarySkillType.NON_CHILD_SKILLS) { int index = getSkillIndex(skill); + if (index >= character.length) { continue; } + int cap = Config.getInstance().getLevelCap(skill); - if (Integer.parseInt(character[index]) > cap) { + int skillLevel = 0; + + try { + skillLevel = Integer.parseInt(character[index]); + } catch (NumberFormatException e) { + mcMMO.p.getLogger().severe("Repairing some corrupt or unexpected data in mcmmo.users it is possible some data may be lost."); + } + + if (skillLevel > cap) { mcMMO.p.getLogger().warning("Truncating " + skill.getName() + " to configured max level for player " + character[USERNAME_INDEX]); character[index] = cap + ""; updated = true; @@ -1224,34 +1235,34 @@ public final class FlatFileDatabaseManager implements DatabaseManager { MobHealthbarType mobHealthbarType; int scoreboardTipsShown; - // TODO on updates, put new values in a try{} ? + String username = character[USERNAME_INDEX]; - skillsXp.put(PrimarySkillType.TAMING, (float) Integer.parseInt(character[EXP_TAMING])); - skillsXp.put(PrimarySkillType.MINING, (float) Integer.parseInt(character[EXP_MINING])); - skillsXp.put(PrimarySkillType.REPAIR, (float) Integer.parseInt(character[EXP_REPAIR])); - skillsXp.put(PrimarySkillType.WOODCUTTING, (float) Integer.parseInt(character[EXP_WOODCUTTING])); - skillsXp.put(PrimarySkillType.UNARMED, (float) Integer.parseInt(character[EXP_UNARMED])); - skillsXp.put(PrimarySkillType.HERBALISM, (float) Integer.parseInt(character[EXP_HERBALISM])); - skillsXp.put(PrimarySkillType.EXCAVATION, (float) Integer.parseInt(character[EXP_EXCAVATION])); - skillsXp.put(PrimarySkillType.ARCHERY, (float) Integer.parseInt(character[EXP_ARCHERY])); - skillsXp.put(PrimarySkillType.SWORDS, (float) Integer.parseInt(character[EXP_SWORDS])); - skillsXp.put(PrimarySkillType.AXES, (float) Integer.parseInt(character[EXP_AXES])); - skillsXp.put(PrimarySkillType.ACROBATICS, (float) Integer.parseInt(character[EXP_ACROBATICS])); - skillsXp.put(PrimarySkillType.FISHING, (float) Integer.parseInt(character[EXP_FISHING])); - skillsXp.put(PrimarySkillType.ALCHEMY, (float) Integer.parseInt(character[EXP_ALCHEMY])); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.TAMING, EXP_TAMING, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.MINING, EXP_MINING, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.REPAIR, EXP_REPAIR, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.WOODCUTTING, EXP_WOODCUTTING, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.UNARMED, EXP_UNARMED, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.HERBALISM, EXP_HERBALISM, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.EXCAVATION, EXP_EXCAVATION, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.ARCHERY, EXP_ARCHERY, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.SWORDS, EXP_SWORDS, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.AXES, EXP_AXES, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.ACROBATICS, EXP_ACROBATICS, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.FISHING, EXP_FISHING, username); + tryLoadSkillFloatValuesFromRawData(skillsXp, character, PrimarySkillType.ALCHEMY, EXP_ALCHEMY, username); // Taming - Unused - skillsDATS.put(SuperAbilityType.SUPER_BREAKER, Integer.valueOf(character[COOLDOWN_SUPER_BREAKER])); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SUPER_BREAKER, COOLDOWN_SUPER_BREAKER, username); // Repair - Unused - skillsDATS.put(SuperAbilityType.TREE_FELLER, Integer.valueOf(character[COOLDOWN_TREE_FELLER])); - skillsDATS.put(SuperAbilityType.BERSERK, Integer.valueOf(character[COOLDOWN_BERSERK])); - skillsDATS.put(SuperAbilityType.GREEN_TERRA, Integer.valueOf(character[COOLDOWN_GREEN_TERRA])); - skillsDATS.put(SuperAbilityType.GIGA_DRILL_BREAKER, Integer.valueOf(character[COOLDOWN_GIGA_DRILL_BREAKER])); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.TREE_FELLER, COOLDOWN_TREE_FELLER, username); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.BERSERK, COOLDOWN_BERSERK, username); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.GREEN_TERRA, COOLDOWN_GREEN_TERRA, username); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.GIGA_DRILL_BREAKER, COOLDOWN_GIGA_DRILL_BREAKER, username); // Archery - Unused - skillsDATS.put(SuperAbilityType.SERRATED_STRIKES, Integer.valueOf(character[COOLDOWN_SERRATED_STRIKES])); - skillsDATS.put(SuperAbilityType.SKULL_SPLITTER, Integer.valueOf(character[COOLDOWN_SKULL_SPLITTER])); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SERRATED_STRIKES, COOLDOWN_SERRATED_STRIKES, username); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.SKULL_SPLITTER, COOLDOWN_SKULL_SPLITTER, username); // Acrobatics - Unused - skillsDATS.put(SuperAbilityType.BLAST_MINING, Integer.valueOf(character[COOLDOWN_BLAST_MINING])); + tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.BLAST_MINING, COOLDOWN_BLAST_MINING, username); try { mobHealthbarType = MobHealthbarType.valueOf(character[HEALTHBAR]); @@ -1285,26 +1296,60 @@ public final class FlatFileDatabaseManager implements DatabaseManager { return new PlayerProfile(character[USERNAME_INDEX], uuid, skills, skillsXp, skillsDATS, mobHealthbarType, scoreboardTipsShown, uniquePlayerDataMap); } - private Map getSkillMapFromLine(String[] character) { - Map skills = new EnumMap<>(PrimarySkillType.class); // Skill & Level + private void tryLoadSkillCooldownFromRawData(@NotNull Map cooldownMap, @NotNull String[] character, @NotNull SuperAbilityType superAbilityType, int cooldownSuperBreaker, @NotNull String userName) { + try { + cooldownMap.put(superAbilityType, Integer.valueOf(character[cooldownSuperBreaker])); + } catch (NumberFormatException e) { + mcMMO.p.getLogger().severe("Data corruption when trying to load the value for skill "+superAbilityType.toString()+" for player named " + userName+ " setting value to zero"); + e.printStackTrace(); + } + } - skills.put(PrimarySkillType.TAMING, Integer.valueOf(character[SKILLS_TAMING])); - skills.put(PrimarySkillType.MINING, Integer.valueOf(character[SKILLS_MINING])); - skills.put(PrimarySkillType.REPAIR, Integer.valueOf(character[SKILLS_REPAIR])); - skills.put(PrimarySkillType.WOODCUTTING, Integer.valueOf(character[SKILLS_WOODCUTTING])); - skills.put(PrimarySkillType.UNARMED, Integer.valueOf(character[SKILLS_UNARMED])); - skills.put(PrimarySkillType.HERBALISM, Integer.valueOf(character[SKILLS_HERBALISM])); - skills.put(PrimarySkillType.EXCAVATION, Integer.valueOf(character[SKILLS_EXCAVATION])); - skills.put(PrimarySkillType.ARCHERY, Integer.valueOf(character[SKILLS_ARCHERY])); - skills.put(PrimarySkillType.SWORDS, Integer.valueOf(character[SKILLS_SWORDS])); - skills.put(PrimarySkillType.AXES, Integer.valueOf(character[SKILLS_AXES])); - skills.put(PrimarySkillType.ACROBATICS, Integer.valueOf(character[SKILLS_ACROBATICS])); - skills.put(PrimarySkillType.FISHING, Integer.valueOf(character[SKILLS_FISHING])); - skills.put(PrimarySkillType.ALCHEMY, Integer.valueOf(character[SKILLS_ALCHEMY])); + private void tryLoadSkillFloatValuesFromRawData(@NotNull Map skillMap, @NotNull String[] character, @NotNull PrimarySkillType primarySkillType, int expTaming, @NotNull String userName) { + try { + float valueFromString = Integer.parseInt(character[expTaming]); + skillMap.put(primarySkillType, valueFromString); + } catch (NumberFormatException e) { + skillMap.put(primarySkillType, 0F); + mcMMO.p.getLogger().severe("Data corruption when trying to load the value for skill "+primarySkillType.toString()+" for player named " + userName+ " setting value to zero"); + e.printStackTrace(); + } + } + + private void tryLoadSkillIntValuesFromRawData(@NotNull Map skillMap, @NotNull String[] character, @NotNull PrimarySkillType primarySkillType, int expTaming, @NotNull String userName) { + try { + int valueFromString = Integer.parseInt(character[expTaming]); + skillMap.put(primarySkillType, valueFromString); + } catch (NumberFormatException e) { + skillMap.put(primarySkillType, 0); + mcMMO.p.getLogger().severe("Data corruption when trying to load the value for skill "+primarySkillType.toString()+" for player named " + userName+ " setting value to zero"); + e.printStackTrace(); + } + } + + private @NotNull Map getSkillMapFromLine(@NotNull String[] character) { + Map skills = new EnumMap<>(PrimarySkillType.class); // Skill & Level + String username = character[USERNAME_INDEX]; + + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.TAMING, SKILLS_TAMING, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.MINING, SKILLS_MINING, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.REPAIR, SKILLS_REPAIR, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.WOODCUTTING, SKILLS_WOODCUTTING, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.UNARMED, SKILLS_UNARMED, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.HERBALISM, SKILLS_HERBALISM, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.EXCAVATION, SKILLS_EXCAVATION, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.ARCHERY, SKILLS_ARCHERY, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.SWORDS, SKILLS_SWORDS, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.AXES, SKILLS_AXES, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.ACROBATICS, SKILLS_ACROBATICS, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.FISHING, SKILLS_FISHING, username); + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.ALCHEMY, SKILLS_ALCHEMY, username); return skills; } + + public DatabaseType getDatabaseType() { return DatabaseType.FLATFILE; } diff --git a/src/main/java/com/gmail/nossr50/party/PartyManager.java b/src/main/java/com/gmail/nossr50/party/PartyManager.java index c825694b9..1aae85dc0 100644 --- a/src/main/java/com/gmail/nossr50/party/PartyManager.java +++ b/src/main/java/com/gmail/nossr50/party/PartyManager.java @@ -2,14 +2,12 @@ package com.gmail.nossr50.party; import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.chat.ChatChannel; -import com.gmail.nossr50.datatypes.database.UpgradeType; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.party.ItemShareType; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.party.PartyLeader; import com.gmail.nossr50.datatypes.party.ShareMode; import com.gmail.nossr50.datatypes.player.McMMOPlayer; -import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.events.party.McMMOPartyAllianceChangeEvent; import com.gmail.nossr50.events.party.McMMOPartyChangeEvent; import com.gmail.nossr50.events.party.McMMOPartyChangeEvent.EventReason; diff --git a/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java b/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java index d46673168..fee41b9b3 100644 --- a/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java +++ b/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java @@ -1,10 +1,9 @@ package com.gmail.nossr50.util.text; -import org.junit.Assert; -import org.junit.Test; - import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.format.NamedTextColor; +import org.junit.Assert; +import org.junit.Test; /** * This Unit Test checks if Adventure was set up correctly and works as expected. From eb1e657af1b66e4b45e53d89c6a5e3ddfba4fdea Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 11 Mar 2021 14:10:29 -0800 Subject: [PATCH 23/33] Simplify data validation + listen to exceptions again --- .../database/FlatFileDatabaseManager.java | 246 ++++-------------- 1 file changed, 47 insertions(+), 199 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index 8f556520f..4a2d47e21 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -557,29 +557,37 @@ public final class FlatFileDatabaseManager implements DatabaseManager { while ((line = in.readLine()) != null) { // Find if the line contains the player we want. - String[] character = line.split(":"); + String[] rawSplitData = line.split(":"); + + if(rawSplitData.length < (USERNAME_INDEX + 1)) { + //Users without a name aren't worth it + mcMMO.p.getLogger().severe("Corrupted data was found in mcmmo.users, removing it from the database"); + } // Compare names because we don't have a valid uuid for that player even // if input uuid is not null - if (character[UUID_INDEX].equalsIgnoreCase("NULL")) { - if (!character[USERNAME_INDEX].equalsIgnoreCase(playerName)) { + if (rawSplitData[UUID_INDEX].equalsIgnoreCase("NULL") + || rawSplitData[UUID_INDEX].isEmpty() + || rawSplitData[UUID_INDEX].equalsIgnoreCase("")) { + if (!rawSplitData[USERNAME_INDEX].equalsIgnoreCase(playerName)) { continue; } } + // If input uuid is not null then we should compare uuids - else if ((uuid != null && !character[UUID_INDEX].equalsIgnoreCase(uuid.toString())) || (uuid == null && !character[USERNAME_INDEX].equalsIgnoreCase(playerName))) { + else if ((uuid != null && !rawSplitData[UUID_INDEX].equalsIgnoreCase(uuid.toString())) || (uuid == null && !rawSplitData[USERNAME_INDEX].equalsIgnoreCase(playerName))) { continue; } // Update playerName in database after name change - if (!character[USERNAME_INDEX].equalsIgnoreCase(playerName)) { + if (!rawSplitData[USERNAME_INDEX].equalsIgnoreCase(playerName)) { //TODO: A proper fix for changed names - mcMMO.p.debug("Name change detected: " + character[USERNAME_INDEX] + " => " + playerName); - character[USERNAME_INDEX] = playerName; + mcMMO.p.debug("Name change detected: " + rawSplitData[USERNAME_INDEX] + " => " + playerName); + rawSplitData[USERNAME_INDEX] = playerName; // updateRequired = true; //Flag profile to update } - return loadFromLine(character); + return loadFromLine(rawSplitData); } // Didn't find the player, create a new one @@ -930,6 +938,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { synchronized (fileWritingLock) { try { + boolean corruptDataNotice = false; in = new BufferedReader(new FileReader(usersFilePath)); StringBuilder writer = new StringBuilder(); String line; @@ -937,213 +946,52 @@ public final class FlatFileDatabaseManager implements DatabaseManager { HashSet players = new HashSet<>(); while ((line = in.readLine()) != null) { - String oldVersion = null; - // Remove empty lines from the file if (line.isEmpty()) { continue; } - // Length checks depend on last character being ':' + // Length checks depend on last rawSplitData being ':' if (line.charAt(line.length() - 1) != ':') { line = line.concat(":"); } - boolean updated = false; - String[] character = line.split(":"); + + String[] rawSplitData = line.split(":"); + + //Not enough data found to have a name so we remove the data + if(rawSplitData.length < USERNAME_INDEX + 1) { + if(!corruptDataNotice) { + mcMMO.p.getLogger().severe("Removing corrupt data from mcmmo.users"); + corruptDataNotice = true; + } + + continue; + } // Prevent the same username from being present multiple times - if (!usernames.add(character[USERNAME_INDEX])) { - character[USERNAME_INDEX] = "_INVALID_OLD_USERNAME_'"; - updated = true; - if (character.length < UUID_INDEX + 1 || character[UUID_INDEX].equals("NULL")) { + if (!usernames.add(rawSplitData[USERNAME_INDEX])) { + //TODO: Check if the commented out code was even necessary + rawSplitData[USERNAME_INDEX] = "_INVALID_OLD_USERNAME_'"; + if (rawSplitData.length < UUID_INDEX + 1 || rawSplitData[UUID_INDEX].equals("NULL")) { + mcMMO.p.getLogger().severe("Fixing duplicate player names found in mcmmo.users"); continue; } } // Prevent the same player from being present multiple times - if (character.length >= 42 && (!character[UUID_INDEX].isEmpty() && !character[UUID_INDEX].equals("NULL") && !players.add(character[UUID_INDEX]))) { + if (rawSplitData.length >= (UUID_INDEX + 1) //TODO: Test this condition + && (!rawSplitData[UUID_INDEX].isEmpty() + && !rawSplitData[UUID_INDEX].equals("NULL") && !players.add(rawSplitData[UUID_INDEX]))) { + + mcMMO.p.getLogger().severe("Removing duplicate player data from mcmmo.users"); + mcMMO.p.getLogger().info("Duplicate Data: "+line); continue; } - if (character.length < 33) { - // Before Version 1.0 - Drop - mcMMO.p.getLogger().warning("Dropping malformed or before version 1.0 line from database - " + line); - continue; - } - - if (character.length > 33 && !character[33].isEmpty()) { - // Removal of Spout Support - // Version 1.4.07-dev2 - // commit 7bac0e2ca5143bce84dc160617fed97f0b1cb968 - character[33] = ""; - if (oldVersion == null) { - oldVersion = "1.4.07"; - } - updated = true; - } - - if (Config.getInstance().getTruncateSkills()) { - for (PrimarySkillType skill : PrimarySkillType.NON_CHILD_SKILLS) { - int index = getSkillIndex(skill); - - if (index >= character.length) { - continue; - } - - int cap = Config.getInstance().getLevelCap(skill); - int skillLevel = 0; - - try { - skillLevel = Integer.parseInt(character[index]); - } catch (NumberFormatException e) { - mcMMO.p.getLogger().severe("Repairing some corrupt or unexpected data in mcmmo.users it is possible some data may be lost."); - } - - if (skillLevel > cap) { - mcMMO.p.getLogger().warning("Truncating " + skill.getName() + " to configured max level for player " + character[USERNAME_INDEX]); - character[index] = cap + ""; - updated = true; - } - } - } - - // If they're valid, rewrite them to the file. - if (!updated && character.length == 43) { - writer.append(line).append("\r\n"); - continue; - } - - if (character.length <= 33) { - // Introduction of HUDType - // Version 1.1.06 - // commit 78f79213cdd7190cd11ae54526f3b4ea42078e8a - character = Arrays.copyOf(character, character.length + 1); - character[character.length - 1] = ""; - oldVersion = "1.1.06"; - } - - if (character.length <= 35) { - // Introduction of Fishing - // Version 1.2.00 - // commit a814b57311bc7734661109f0e77fc8bab3a0bd29 - character = Arrays.copyOf(character, character.length + 2); - character[character.length - 1] = "0"; - character[character.length - 2] = "0"; - if (oldVersion == null) { - oldVersion = "1.2.00"; - } - } - if (character.length <= 36) { - // Introduction of Blast Mining cooldowns - // Version 1.3.00-dev - // commit fadbaf429d6b4764b8f1ad0efaa524a090e82ef5 - character = Arrays.copyOf(character, character.length + 1); - character[character.length - 1] = "0"; - if (oldVersion == null) { - oldVersion = "1.3.00"; - } - } - if (character.length <= 37) { - // Making old-purge work with flatfile - // Version 1.4.00-dev - // commmit 3f6c07ba6aaf44e388cc3b882cac3d8f51d0ac28 - // XXX Cannot create an OfflinePlayer at startup, use 0 and fix in purge - character = Arrays.copyOf(character, character.length + 1); - character[character.length - 1] = "0"; - if (oldVersion == null) { - oldVersion = "1.4.00"; - } - } - if (character.length <= 38) { - // Addition of mob healthbars - // Version 1.4.06 - // commit da29185b7dc7e0d992754bba555576d48fa08aa6 - character = Arrays.copyOf(character, character.length + 1); - character[character.length - 1] = Config.getInstance().getMobHealthbarDefault().toString(); - if (oldVersion == null) { - oldVersion = "1.4.06"; - } - } - if (character.length <= 39) { - // Addition of Alchemy - // Version 1.4.08 - character = Arrays.copyOf(character, character.length + 2); - character[character.length - 1] = "0"; - character[character.length - 2] = "0"; - if (oldVersion == null) { - oldVersion = "1.4.08"; - } - } - if (character.length <= 41) { - // Addition of UUIDs - // Version 1.5.01 - // Add a value because otherwise it gets removed - character = Arrays.copyOf(character, character.length + 1); - character[character.length - 1] = "NULL"; - if (oldVersion == null) { - oldVersion = "1.5.01"; - } - } - if (character.length <= 42) { - // Addition of scoreboard tips auto disable - // Version 1.5.02 - character = Arrays.copyOf(character, character.length + 1); - character[character.length - 1] = "0"; - if (oldVersion == null) { - oldVersion = "1.5.02"; - } - } - - boolean corrupted = false; - - for (int i = 0; i < character.length; i++) { - if (character[i].isEmpty() && !(i == 2 || i == 3 || i == 23 || i == 33 || i == 41)) { - corrupted = true; - if (i == 37) { - character[i] = String.valueOf(System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR); - } - else if (i == 38) { - character[i] = Config.getInstance().getMobHealthbarDefault().toString(); - } - else { - character[i] = "0"; - } - } - - if (StringUtils.isInt(character[i]) && i == 38) { - corrupted = true; - character[i] = Config.getInstance().getMobHealthbarDefault().toString(); - } - - if (!StringUtils.isInt(character[i]) && !(i == 0 || i == 2 || i == 3 || i == 23 || i == 33 || i == 38 || i == 41)) { - corrupted = true; - character[i] = "0"; - } - } - - if (corrupted) { - mcMMO.p.debug("Updating corrupted database line for player " + character[USERNAME_INDEX]); - } - - if (oldVersion != null) { - mcMMO.p.debug("Updating database line from before version " + oldVersion + " for player " + character[USERNAME_INDEX]); - } - - updated |= corrupted; - updated |= oldVersion != null; - - if (Config.getInstance().getTruncateSkills()) { - Map skills = getSkillMapFromLine(character); - for (PrimarySkillType skill : PrimarySkillType.NON_CHILD_SKILLS) { - int cap = Config.getInstance().getLevelCap(skill); - if (skills.get(skill) > cap) { - updated = true; - } - } - } - - if (updated) { - line = org.apache.commons.lang.StringUtils.join(character, ":") + ":"; + //Correctly size the data (null entries for missing values) + if(line.length() < DATA_ENTRY_COUNT) { //TODO: Test this condition + String[] correctSizeSplitData = Arrays.copyOf(rawSplitData, DATA_ENTRY_COUNT); + line = org.apache.commons.lang.StringUtils.join(rawSplitData, ":") + ":"; } writer.append(line).append("\r\n"); @@ -1162,7 +1010,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { in.close(); } catch (IOException e) { - // Ignore + e.printStackTrace(); } } if (out != null) { @@ -1170,7 +1018,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { out.close(); } catch (IOException e) { - // Ignore + e.printStackTrace(); } } } From 91204262f507cb1f214720d2f394e09904adc0e8 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 11 Mar 2021 14:48:21 -0800 Subject: [PATCH 24/33] More tweaks to handling corrupt data for flat file --- .../database/FlatFileDatabaseManager.java | 49 +++++++++++-------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index 4a2d47e21..c8b09ec5f 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -384,8 +384,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - private void writeUserToLine(PlayerProfile profile, String playerName, UUID uuid, StringBuilder writer) { - // FlyingMonkey_:0:::0:0:0:0:0:0:0:0:0:0:5:0:156:460: + private void writeUserToLine(PlayerProfile profile, String playerName, @Nullable UUID uuid, StringBuilder writer) { writer.append(playerName).append(":"); writer.append(profile.getSkillLevel(PrimarySkillType.MINING)).append(":"); writer.append(":"); @@ -582,7 +581,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { // Update playerName in database after name change if (!rawSplitData[USERNAME_INDEX].equalsIgnoreCase(playerName)) { //TODO: A proper fix for changed names - mcMMO.p.debug("Name change detected: " + rawSplitData[USERNAME_INDEX] + " => " + playerName); + mcMMO.p.getLogger().info("Name change detected: " + rawSplitData[USERNAME_INDEX] + " => " + playerName); rawSplitData[USERNAME_INDEX] = playerName; // updateRequired = true; //Flag profile to update } @@ -931,6 +930,8 @@ public final class FlatFileDatabaseManager implements DatabaseManager { * Checks that the file is present and valid */ private void checkStructure() { + boolean corruptDataFound = false; + if (usersFile.exists()) { BufferedReader in = null; FileWriter out = null; @@ -938,7 +939,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { synchronized (fileWritingLock) { try { - boolean corruptDataNotice = false; + in = new BufferedReader(new FileReader(usersFilePath)); StringBuilder writer = new StringBuilder(); String line; @@ -958,11 +959,17 @@ public final class FlatFileDatabaseManager implements DatabaseManager { String[] rawSplitData = line.split(":"); - //Not enough data found to have a name so we remove the data - if(rawSplitData.length < USERNAME_INDEX + 1) { - if(!corruptDataNotice) { + //Not enough data found to be considered a user reliably (NOTE: not foolproof) + if(rawSplitData.length < (UUID_INDEX + 1)) { + if(!corruptDataFound) { mcMMO.p.getLogger().severe("Removing corrupt data from mcmmo.users"); - corruptDataNotice = true; + corruptDataFound = true; + } + + if(rawSplitData.length >= 10 //The value here is kind of arbitrary, it shouldn't be too low to avoid false positives, but also we aren't really going to correctly identify when player data has been corrupted or not with 100% accuracy ever + && rawSplitData[0] != null && !rawSplitData[0].isEmpty()) { + //This user may have had a name so declare it + mcMMO.p.getLogger().severe("Not enough data found to recover corrupted player data for user: "+rawSplitData[0]); } continue; @@ -991,10 +998,14 @@ public final class FlatFileDatabaseManager implements DatabaseManager { //Correctly size the data (null entries for missing values) if(line.length() < DATA_ENTRY_COUNT) { //TODO: Test this condition String[] correctSizeSplitData = Arrays.copyOf(rawSplitData, DATA_ENTRY_COUNT); - line = org.apache.commons.lang.StringUtils.join(rawSplitData, ":") + ":"; + line = org.apache.commons.lang.StringUtils.join(correctSizeSplitData, ":") + ":"; + rawSplitData = line.split(":"); + PlayerProfile temporaryProfile = loadFromLine(rawSplitData); + writeUserToLine(temporaryProfile, rawSplitData[USERNAME_INDEX], temporaryProfile.getUniqueId(), writer); + } else { + writer.append(line).append("\r\n"); } - writer.append(line).append("\r\n"); } // Write the new file @@ -1024,13 +1035,9 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_FISHING); - mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_BLAST_MINING_COOLDOWN); - mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_SQL_INDEXES); - mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_MOB_HEALTHBARS); - mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.DROP_SQL_PARTY_NAMES); - mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.DROP_SPOUT); - mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_ALCHEMY); + if(corruptDataFound) + mcMMO.p.getLogger().info("Corrupt data was found and removed, everything should be working fine. It is possible some player data was lost."); + return; } @@ -1153,9 +1160,9 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - private void tryLoadSkillFloatValuesFromRawData(@NotNull Map skillMap, @NotNull String[] character, @NotNull PrimarySkillType primarySkillType, int expTaming, @NotNull String userName) { + private void tryLoadSkillFloatValuesFromRawData(@NotNull Map skillMap, @NotNull String[] character, @NotNull PrimarySkillType primarySkillType, int index, @NotNull String userName) { try { - float valueFromString = Integer.parseInt(character[expTaming]); + float valueFromString = Integer.parseInt(character[index]); skillMap.put(primarySkillType, valueFromString); } catch (NumberFormatException e) { skillMap.put(primarySkillType, 0F); @@ -1164,9 +1171,9 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - private void tryLoadSkillIntValuesFromRawData(@NotNull Map skillMap, @NotNull String[] character, @NotNull PrimarySkillType primarySkillType, int expTaming, @NotNull String userName) { + private void tryLoadSkillIntValuesFromRawData(@NotNull Map skillMap, @NotNull String[] character, @NotNull PrimarySkillType primarySkillType, int index, @NotNull String userName) { try { - int valueFromString = Integer.parseInt(character[expTaming]); + int valueFromString = Integer.parseInt(character[index]); skillMap.put(primarySkillType, valueFromString); } catch (NumberFormatException e) { skillMap.put(primarySkillType, 0); From 0979ef555b2d0a7d44a953e7dff1a67f4b2f4047 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 11 Mar 2021 14:59:11 -0800 Subject: [PATCH 25/33] More tweaks to data recovery messages --- .../gmail/nossr50/database/FlatFileDatabaseManager.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index c8b09ec5f..f95a36b57 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -962,15 +962,17 @@ public final class FlatFileDatabaseManager implements DatabaseManager { //Not enough data found to be considered a user reliably (NOTE: not foolproof) if(rawSplitData.length < (UUID_INDEX + 1)) { if(!corruptDataFound) { - mcMMO.p.getLogger().severe("Removing corrupt data from mcmmo.users"); + mcMMO.p.getLogger().severe("Some corrupt data was found in mcmmo.users and has been repaired, it is possible that some player data has been lost in this process."); corruptDataFound = true; } if(rawSplitData.length >= 10 //The value here is kind of arbitrary, it shouldn't be too low to avoid false positives, but also we aren't really going to correctly identify when player data has been corrupted or not with 100% accuracy ever && rawSplitData[0] != null && !rawSplitData[0].isEmpty()) { - //This user may have had a name so declare it - mcMMO.p.getLogger().severe("Not enough data found to recover corrupted player data for user: "+rawSplitData[0]); + if(rawSplitData[0].length() <= 16 && rawSplitData[0].length() >= 3) { + mcMMO.p.getLogger().severe("Not enough data found to recover corrupted player data for user: "+rawSplitData[0]); + } } + //This user may have had a name so declare it continue; } From 7d5bcf3ebf275379de0347b79d933c9c74c894ff Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 11 Mar 2021 15:11:03 -0800 Subject: [PATCH 26/33] 2.1.180 --- Changelog.txt | 7 +++++++ pom.xml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Changelog.txt b/Changelog.txt index 1189b47c7..9c544563c 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,8 +1,15 @@ Version 2.1.180 + mcMMO will now automatically remove corrupted data from mcmmo.users instead of catastrophic failure + When using FlatFile database (the default) mcMMO will try its best to inform you which players had corrupted data when it does repairs + Various minor optimizations and tweaks to the FlatFile database + mcMMO is now much more verbose when things go wrong with the FlatFile database (removed some silent errors, added more error messages/warnings) mcMMO now uses UTF-8 compliant encoding for SQL databases (utf8mb4) Fixed a bug where mcMMO could in some circumstances fail to update SQL schema and mark it as successful Renamed updates.yml to updates_overhaul.yml to avoid some potential issues when upgrading from classic + NOTES: + This update was tested pretty thoroughly so it should be pretty safe, let me know if you have issues in the mcMMO discord or GitHub issues page for mcMMO! + Version 2.1.179 Fixed a bug for FlatFile databases where some players with changed nicknames would have their levels not loaded upon login (possibly wiping their data) diff --git a/pom.xml b/pom.xml index 01d2a5a7e..425a419d4 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.180-SNAPSHOT + 2.1.180 mcMMO https://github.com/mcMMO-Dev/mcMMO From 4a048b47cbffa50ba87f6f99ad475e23d12c9836 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 12 Mar 2021 16:25:14 -0800 Subject: [PATCH 27/33] Refactor DB code a bit and fix console spam when using the Plan plugin Fixes #4450 --- Changelog.txt | 7 + pom.xml | 2 +- .../com/gmail/nossr50/api/DatabaseAPI.java | 2 +- .../com/gmail/nossr50/api/ExperienceAPI.java | 18 ++- .../database/ConvertDatabaseCommand.java | 2 +- .../commands/database/McremoveCommand.java | 2 +- .../experience/ExperienceCommand.java | 18 ++- .../experience/SkillresetCommand.java | 16 +- .../commands/player/InspectCommand.java | 2 +- .../nossr50/database/DatabaseManager.java | 24 +-- .../database/FlatFileDatabaseManager.java | 140 +++++++++++------- .../nossr50/database/SQLDatabaseManager.java | 69 +++++---- .../database/FormulaConversionTask.java | 2 +- .../player/PlayerProfileLoadingTask.java | 8 +- 14 files changed, 187 insertions(+), 125 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 9c544563c..22cfc4169 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,10 @@ +Version 2.1.181 + Removed the "name change detected" message as some plugins (such as Plan) invoke API calls which spams the console with this message + Refactored code related to loading player data from the database + (API) Added DatabaseManager::loadPlayerProfile(String) + (API) Removed DatabaseManager::loadPlayerProfile(String, UUID, boolean) + (API) Removed DatabaseManager::loadPlayerProfile(String, boolean) + Version 2.1.180 mcMMO will now automatically remove corrupted data from mcmmo.users instead of catastrophic failure When using FlatFile database (the default) mcMMO will try its best to inform you which players had corrupted data when it does repairs diff --git a/pom.xml b/pom.xml index 425a419d4..5d8c2bdd5 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.180 + 2.1.181-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/api/DatabaseAPI.java b/src/main/java/com/gmail/nossr50/api/DatabaseAPI.java index 544a23124..8f2879549 100644 --- a/src/main/java/com/gmail/nossr50/api/DatabaseAPI.java +++ b/src/main/java/com/gmail/nossr50/api/DatabaseAPI.java @@ -22,7 +22,7 @@ public class DatabaseAPI { * @return true if the player exists in the DB, false if they do not */ public boolean doesPlayerExistInDB(UUID uuid) { - PlayerProfile playerProfile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid); + PlayerProfile playerProfile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid, null); return playerProfile.isLoaded(); } diff --git a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java index 69a4e1e28..be325c281 100644 --- a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java +++ b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java @@ -13,6 +13,8 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.child.FamilyTree; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.CombatUtils; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; import org.bukkit.block.BlockState; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; @@ -714,7 +716,6 @@ public final class ExperienceAPI { * @throws InvalidSkillException if the given skill is not valid * @throws InvalidPlayerException if the given player does not exist in the database */ - @Deprecated public static int getLevelOffline(String playerName, String skillType) { return getOfflineProfile(playerName).getSkillLevel(getSkillType(skillType)); } @@ -1126,8 +1127,6 @@ public final class ExperienceAPI { } } - - // Utility methods follow. private static void addOfflineXP(UUID playerUniqueId, PrimarySkillType skill, int XP) { PlayerProfile profile = getOfflineProfile(playerUniqueId); @@ -1144,8 +1143,10 @@ public final class ExperienceAPI { profile.scheduleAsyncSave(); } - private static PlayerProfile getOfflineProfile(UUID uuid) { - PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid); + private static PlayerProfile getOfflineProfile(UUID uuid) throws InvalidPlayerException { + OfflinePlayer offlinePlayer = Bukkit.getServer().getOfflinePlayer(uuid); + String playerName = offlinePlayer.getName(); + PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid, playerName); if (!profile.isLoaded()) { throw new InvalidPlayerException(); @@ -1155,9 +1156,10 @@ 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); + private static PlayerProfile getOfflineProfile(String playerName) throws InvalidPlayerException { + OfflinePlayer offlinePlayer = Bukkit.getServer().getOfflinePlayer(playerName); + UUID uuid = offlinePlayer.getUniqueId(); + PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid, playerName); if (!profile.isLoaded()) { throw new InvalidPlayerException(); diff --git a/src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java b/src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java index 327d7da8b..6bbee5f9f 100644 --- a/src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java @@ -54,7 +54,7 @@ public class ConvertDatabaseCommand implements CommandExecutor { UserManager.clearAll(); for (Player player : mcMMO.p.getServer().getOnlinePlayers()) { - PlayerProfile profile = oldDatabase.loadPlayerProfile(player.getUniqueId()); + PlayerProfile profile = oldDatabase.loadPlayerProfile(player.getUniqueId(), null); if (profile.isLoaded()) { mcMMO.getDatabaseManager().saveUser(profile); diff --git a/src/main/java/com/gmail/nossr50/commands/database/McremoveCommand.java b/src/main/java/com/gmail/nossr50/commands/database/McremoveCommand.java index 731a35524..56b817337 100644 --- a/src/main/java/com/gmail/nossr50/commands/database/McremoveCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/database/McremoveCommand.java @@ -22,7 +22,7 @@ public class McremoveCommand implements TabExecutor { if (args.length == 1) { String playerName = CommandUtils.getMatchedPlayerName(args[0]); - if (UserManager.getOfflinePlayer(playerName) == null && CommandUtils.unloadedProfile(sender, mcMMO.getDatabaseManager().loadPlayerProfile(playerName, false))) { + if (UserManager.getOfflinePlayer(playerName) == null && CommandUtils.unloadedProfile(sender, mcMMO.getDatabaseManager().loadPlayerProfile(playerName))) { return true; } diff --git a/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java index 2443e6d62..11684ebf8 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java @@ -97,14 +97,20 @@ public abstract class ExperienceCommand implements TabExecutor { // If the mcMMOPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process. if (mcMMOPlayer == null) { UUID uuid = null; - OfflinePlayer player = mcMMO.p.getServer().getOfflinePlayer(playerName); - if (player != null) { - uuid = player.getUniqueId(); - } - PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName, uuid, false); + OfflinePlayer offlinePlayer = mcMMO.p.getServer().getOfflinePlayer(playerName); + PlayerProfile profile; + uuid = offlinePlayer.getUniqueId(); + profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid, null); + + //Check loading by UUID if (CommandUtils.unloadedProfile(sender, profile)) { - return true; + //Check loading by name + profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName); + + if(CommandUtils.unloadedProfile(sender, profile)) { + return true; + } } editValues(null, profile, skill, value, isSilent(args)); diff --git a/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java index 3df1976d9..9b97fa77a 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java @@ -80,13 +80,19 @@ public class SkillresetCommand implements TabExecutor { if (mcMMOPlayer == null) { UUID uuid = null; OfflinePlayer player = mcMMO.p.getServer().getOfflinePlayer(playerName); - if (player != null) { - uuid = player.getUniqueId(); - } - PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName, uuid, false); + uuid = player.getUniqueId(); + PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid, playerName); + + //Check loading by UUID if (CommandUtils.unloadedProfile(sender, profile)) { - return true; + //Didn't find it by UUID so try to find it by name + profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName); + + //Check if it was present in DB + if(CommandUtils.unloadedProfile(sender, profile)) { + return true; + } } editValues(null, profile, skill); diff --git a/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java b/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java index a65fa1cf2..a65004417 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java @@ -30,7 +30,7 @@ public class InspectCommand implements TabExecutor { // If the mcMMOPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process. if (mcMMOPlayer == null) { - PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName, false); // Temporary Profile + PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName); // Temporary Profile if (!CommandUtils.isLoaded(sender, profile)) { return true; diff --git a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java index c41401296..7b6fc41cd 100644 --- a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java @@ -6,6 +6,7 @@ import com.gmail.nossr50.datatypes.database.DatabaseType; import com.gmail.nossr50.datatypes.database.PlayerStat; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -83,19 +84,16 @@ public interface DatabaseManager { */ void newUser(String playerName, UUID uuid); + @NotNull PlayerProfile newUser(@NotNull Player player); + /** * Load a player from the database. * - * @deprecated replaced by {@link #loadPlayerProfile(String playerName, UUID uuid, boolean createNew)} - * * @param playerName The name of the player to load from the database - * @param createNew Whether to create a new record if the player is not - * found * @return The player's data, or an unloaded PlayerProfile if not found * and createNew is false */ - @Deprecated - PlayerProfile loadPlayerProfile(String playerName, boolean createNew); + @NotNull PlayerProfile loadPlayerProfile(@NotNull String playerName); /** * Load a player from the database. @@ -103,19 +101,7 @@ public interface DatabaseManager { * @param uuid The uuid of the player to load from the database * @return The player's data, or an unloaded PlayerProfile if not found */ - PlayerProfile loadPlayerProfile(UUID uuid); - - /** - * Load a player from the database. Attempt to use uuid, fall back on playername - * - * @param playerName The name of the player to load from the database - * @param uuid The uuid of the player to load from the database - * @param createNew Whether to create a new record if the player is not - * found - * @return The player's data, or an unloaded PlayerProfile if not found - * and createNew is false - */ - PlayerProfile loadPlayerProfile(String playerName, UUID uuid, boolean createNew); + @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid, @Nullable String playerName); /** * Get all users currently stored in the database. diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index f95a36b57..a767a481b 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -14,8 +14,8 @@ import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.database.UUIDUpdateAsyncTask; import com.gmail.nossr50.util.Misc; -import com.gmail.nossr50.util.text.StringUtils; import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -461,6 +461,11 @@ public final class FlatFileDatabaseManager implements DatabaseManager { return skills; } + public @NotNull PlayerProfile newUser(@NotNull Player player) { + newUser(player.getName(), player.getUniqueId()); + return new PlayerProfile(player.getName(), player.getUniqueId(), true); + } + public void newUser(String playerName, UUID uuid) { BufferedWriter out = null; synchronized (fileWritingLock) { @@ -534,17 +539,15 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - @Deprecated - public PlayerProfile loadPlayerProfile(String playerName, boolean create) { - return loadPlayerProfile(playerName, null, false); + public @NotNull PlayerProfile loadPlayerProfile(@NotNull String playerName) { + return loadPlayerByName(playerName); } - public PlayerProfile loadPlayerProfile(UUID uuid) { - return loadPlayerProfile("", uuid, false); + public @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid, @Nullable String playerName) { + return loadPlayerByUUID(uuid, playerName); } - public PlayerProfile loadPlayerProfile(String playerName, UUID uuid, boolean create) { -// boolean updateRequired = false; + private @NotNull PlayerProfile loadPlayerByUUID(@NotNull UUID uuid, @Nullable String playerName) { BufferedReader in = null; String usersFilePath = mcMMO.getUsersFilePath(); @@ -558,68 +561,105 @@ public final class FlatFileDatabaseManager implements DatabaseManager { // Find if the line contains the player we want. String[] rawSplitData = line.split(":"); - if(rawSplitData.length < (USERNAME_INDEX + 1)) { - //Users without a name aren't worth it - mcMMO.p.getLogger().severe("Corrupted data was found in mcmmo.users, removing it from the database"); - } - - // Compare names because we don't have a valid uuid for that player even - // if input uuid is not null - if (rawSplitData[UUID_INDEX].equalsIgnoreCase("NULL") - || rawSplitData[UUID_INDEX].isEmpty() - || rawSplitData[UUID_INDEX].equalsIgnoreCase("")) { - if (!rawSplitData[USERNAME_INDEX].equalsIgnoreCase(playerName)) { - continue; - } - } - - // If input uuid is not null then we should compare uuids - else if ((uuid != null && !rawSplitData[UUID_INDEX].equalsIgnoreCase(uuid.toString())) || (uuid == null && !rawSplitData[USERNAME_INDEX].equalsIgnoreCase(playerName))) { + /* Don't read corrupt data */ + if(rawSplitData.length < (UUID_INDEX + 1)) { continue; } - // Update playerName in database after name change + /* Does this entry have a UUID? */ + if (rawSplitData[UUID_INDEX].equalsIgnoreCase("NULL") + || rawSplitData[UUID_INDEX].isEmpty() + || rawSplitData[UUID_INDEX].equalsIgnoreCase("")) { + continue; //No UUID entry found for this data in the DB, go to next entry + } + + // Compare provided UUID to DB + if (!rawSplitData[UUID_INDEX].equalsIgnoreCase(uuid.toString())) { + continue; //Doesn't match, go to the next entry + } + + /* + * UUID Matched! + * Making it this far means the current data line is considered a match + */ + + + /* Check for nickname changes and update since we are here anyways */ if (!rawSplitData[USERNAME_INDEX].equalsIgnoreCase(playerName)) { - //TODO: A proper fix for changed names - mcMMO.p.getLogger().info("Name change detected: " + rawSplitData[USERNAME_INDEX] + " => " + playerName); + //mcMMO.p.getLogger().info("Name updated for player: " + rawSplitData[USERNAME_INDEX] + " => " + playerName); rawSplitData[USERNAME_INDEX] = playerName; -// updateRequired = true; //Flag profile to update } return loadFromLine(rawSplitData); } - - // Didn't find the player, create a new one - if (create) { - if (uuid == null) { - newUser(playerName, uuid); - return new PlayerProfile(playerName, true); - } - - newUser(playerName, uuid); - return new PlayerProfile(playerName, uuid, true); - } - } - catch (Exception e) { + } catch (Exception e) { e.printStackTrace(); - } - finally { + } finally { // I have no idea why it's necessary to inline tryClose() here, but it removes // a resource leak warning, and I'm trusting the compiler on this one. if (in != null) { try { in.close(); - } - catch (IOException e) { + } catch (IOException e) { // Ignore } } } } - // Return unloaded profile - if (uuid == null) { - return new PlayerProfile(playerName); + /* + * No match was found in the file + */ + + return grabUnloadedProfile(uuid, playerName); //Create an empty new profile and return + } + + private @NotNull PlayerProfile loadPlayerByName(@NotNull String playerName) { + BufferedReader in = null; + String usersFilePath = mcMMO.getUsersFilePath(); + + synchronized (fileWritingLock) { + try { + // Open the user file + in = new BufferedReader(new FileReader(usersFilePath)); + String line; + + while ((line = in.readLine()) != null) { + // Find if the line contains the player we want. + String[] rawSplitData = line.split(":"); + + /* Don't read corrupt data */ + if(rawSplitData.length < (USERNAME_INDEX + 1)) { + continue; + } + + //If we couldn't find anyone + if(playerName.equalsIgnoreCase(rawSplitData[USERNAME_INDEX])) { + return loadFromLine(rawSplitData); + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + // I have no idea why it's necessary to inline tryClose() here, but it removes + // a resource leak warning, and I'm trusting the compiler on this one. + if (in != null) { + try { + in.close(); + } catch (IOException e) { + // Ignore + } + } + } + } + + //Return a new blank profile + return new PlayerProfile(playerName, null); + } + + private @NotNull PlayerProfile grabUnloadedProfile(@NotNull UUID uuid, @Nullable String playerName) { + if(playerName == null) { + playerName = ""; //No name for you boy! } return new PlayerProfile(playerName, uuid); @@ -1205,8 +1245,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { return skills; } - - public DatabaseType getDatabaseType() { return DatabaseType.FLATFILE; } diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index a7ee6eb95..e011b9312 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -16,6 +16,7 @@ import com.gmail.nossr50.runnables.database.UUIDUpdateAsyncTask; import com.gmail.nossr50.util.Misc; import org.apache.tomcat.jdbc.pool.DataSource; import org.apache.tomcat.jdbc.pool.PoolProperties; +import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -506,6 +507,24 @@ public final class SQLDatabaseManager implements DatabaseManager { } } + @Override + public @NotNull PlayerProfile newUser(@NotNull Player player) { + try { + Connection connection = getConnection(PoolIdentifier.SAVE); + int id = newUser(connection, player.getName(), player.getUniqueId()); + + if (id == -1) { + return new PlayerProfile(player.getName(), player.getUniqueId(), false); + } else { + return loadPlayerProfile(player.getUniqueId(), player.getName()); + } + } catch (SQLException e) { + e.printStackTrace(); + } + + return new PlayerProfile(player.getName(), player.getUniqueId(), false); + } + private int newUser(Connection connection, String playerName, UUID uuid) { ResultSet resultSet = null; PreparedStatement statement = null; @@ -544,20 +563,24 @@ public final class SQLDatabaseManager implements DatabaseManager { return -1; } - @Deprecated - public PlayerProfile loadPlayerProfile(String playerName, boolean create) { - return loadPlayerProfile(playerName, null, false, true); + public @NotNull PlayerProfile loadPlayerProfile(@NotNull String playerName) { + try { + return loadPlayerFromDB(null, playerName); + } catch (RuntimeException e) { + e.printStackTrace(); + return new PlayerProfile(playerName, false); + } } - public PlayerProfile loadPlayerProfile(UUID uuid) { - return loadPlayerProfile("", uuid, false, true); + public @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid, @Nullable String playerName) { + return loadPlayerFromDB(uuid, playerName); } - public PlayerProfile loadPlayerProfile(String playerName, UUID uuid, boolean create) { - return loadPlayerProfile(playerName, uuid, create, true); - } + private PlayerProfile loadPlayerFromDB(@Nullable UUID uuid, @Nullable String playerName) throws RuntimeException { + if(uuid == null && playerName == null) { + throw new RuntimeException("Error looking up player, both UUID and playerName are null and one must not be."); + } - private PlayerProfile loadPlayerProfile(String playerName, UUID uuid, boolean create, boolean retry) { PreparedStatement statement = null; Connection connection = null; ResultSet resultSet = null; @@ -567,16 +590,8 @@ public final class SQLDatabaseManager implements DatabaseManager { int id = getUserID(connection, playerName, uuid); if (id == -1) { - // There is no such user - if (create) { - id = newUser(connection, playerName, uuid); - create = false; - if (id == -1) { - return new PlayerProfile(playerName, false); - } - } else { - return new PlayerProfile(playerName, false); - } + // There is no such user + return new PlayerProfile(playerName, false); } // There is such a user writeMissingRows(connection, id); @@ -604,7 +619,10 @@ public final class SQLDatabaseManager implements DatabaseManager { resultSet.close(); statement.close(); - if (!playerName.isEmpty() && !playerName.equalsIgnoreCase(name) && uuid != null) { + if (playerName != null + && !playerName.isEmpty() + && !playerName.equalsIgnoreCase(name) + && uuid != null) { statement = connection.prepareStatement( "UPDATE `" + tablePrefix + "users` " + "SET user = ? " @@ -641,15 +659,8 @@ public final class SQLDatabaseManager implements DatabaseManager { tryClose(connection); } - // Problem, nothing was returned - - // return unloaded profile - if (!retry) { - return new PlayerProfile(playerName, false); - } - - // Retry, and abort on re-failure - return loadPlayerProfile(playerName, uuid, create, false); + //Return empty profile + return new PlayerProfile(playerName, false); } public void convertUsers(DatabaseManager destination) { diff --git a/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java b/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java index f8b231b58..5447feb64 100644 --- a/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java @@ -32,7 +32,7 @@ public class FormulaConversionTask extends BukkitRunnable { // If the mcMMOPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process. if (mcMMOPlayer == null) { - profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName, false); + profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName); if (!profile.isLoaded()) { mcMMO.p.debug("Profile not loaded."); diff --git a/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java b/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java index b97818ebf..8944fb043 100644 --- a/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java @@ -42,7 +42,13 @@ public class PlayerProfileLoadingTask extends BukkitRunnable { return; } - PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(player.getName(), player.getUniqueId(), true); + PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(player.getUniqueId(), player.getName()); + + if(!profile.isLoaded()) { + mcMMO.p.getLogger().info("Creating new data for player: "+player.getName()); + //Profile isn't loaded so add as new user + profile = mcMMO.getDatabaseManager().newUser(player); + } // If successful, schedule the apply if (profile.isLoaded()) { From 75db0af01d8db3ce5168f18f3c4d36e33e008b52 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 12 Mar 2021 16:37:21 -0800 Subject: [PATCH 28/33] More console spam reduction for database operations --- Changelog.txt | 1 + .../com/gmail/nossr50/database/FlatFileDatabaseManager.java | 4 ---- .../java/com/gmail/nossr50/database/SQLDatabaseManager.java | 4 ++-- .../gmail/nossr50/runnables/database/UUIDUpdateAsyncTask.java | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 22cfc4169..d9fe87d35 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,4 +1,5 @@ Version 2.1.181 + mcMMO no longer pointlessly tries to check for missing UUIDs for FlatFile database Removed the "name change detected" message as some plugins (such as Plan) invoke API calls which spams the console with this message Refactored code related to loading player data from the database (API) Added DatabaseManager::loadPlayerProfile(String) diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index a767a481b..46c36d07f 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -78,10 +78,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { usersFile = new File(mcMMO.getUsersFilePath()); checkStructure(); updateLeaderboards(); - - if (mcMMO.getUpgradeManager().shouldUpgrade(UpgradeType.ADD_UUIDS)) { - new UUIDUpdateAsyncTask(mcMMO.p, getStoredUsers()).start(); - } } public void purgePowerlessUsers() { diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index e011b9312..05d621243 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -1337,6 +1337,8 @@ public final class SQLDatabaseManager implements DatabaseManager { mcMMO.p.getLogger().info("Adding UUIDs to mcMMO MySQL user table..."); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "users` ADD `uuid` varchar(36) NULL DEFAULT NULL"); statement.executeUpdate("ALTER TABLE `" + tablePrefix + "users` ADD UNIQUE INDEX `uuid` (`uuid`) USING BTREE"); + + new GetUUIDUpdatesRequired().runTaskLaterAsynchronously(mcMMO.p, 100); // wait until after first purge } mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_UUIDS); @@ -1347,8 +1349,6 @@ public final class SQLDatabaseManager implements DatabaseManager { finally { tryClose(resultSet); } - - new GetUUIDUpdatesRequired().runTaskLaterAsynchronously(mcMMO.p, 100); // wait until after first purge } private class GetUUIDUpdatesRequired extends BukkitRunnable { diff --git a/src/main/java/com/gmail/nossr50/runnables/database/UUIDUpdateAsyncTask.java b/src/main/java/com/gmail/nossr50/runnables/database/UUIDUpdateAsyncTask.java index fe87185aa..fe7a029a7 100644 --- a/src/main/java/com/gmail/nossr50/runnables/database/UUIDUpdateAsyncTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/database/UUIDUpdateAsyncTask.java @@ -99,7 +99,7 @@ public class UUIDUpdateAsyncTask implements Runnable { position += batch.size(); plugin.getLogger().info(String.format("Conversion progress: %d/%d users", position, userNames.size())); - if (position == userNames.size()) { + if (position +1 >= userNames.size()) { mcMMO.getUpgradeManager().setUpgradeCompleted(UpgradeType.ADD_UUIDS); awaiter.countDown(); plugin.getLogger().info("UUID checks completed"); From 6cec253243bba1f661e2374cd0cbe18bb84721aa Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 12 Mar 2021 17:07:14 -0800 Subject: [PATCH 29/33] 2.1.181 --- pom.xml | 2 +- .../nossr50/api/exceptions/McMMOPlayerNotFoundException.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5d8c2bdd5..fb224f530 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.181-SNAPSHOT + 2.1.181 mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/api/exceptions/McMMOPlayerNotFoundException.java b/src/main/java/com/gmail/nossr50/api/exceptions/McMMOPlayerNotFoundException.java index d2df14a70..374c04a9a 100644 --- a/src/main/java/com/gmail/nossr50/api/exceptions/McMMOPlayerNotFoundException.java +++ b/src/main/java/com/gmail/nossr50/api/exceptions/McMMOPlayerNotFoundException.java @@ -7,6 +7,6 @@ public class McMMOPlayerNotFoundException extends RuntimeException { private static final long serialVersionUID = 761917904993202836L; public McMMOPlayerNotFoundException(@NotNull Player player) { - super("McMMOPlayer object was not found for [NOTE: This can mean the profile is not loaded yet!] : " + player.getName() + " " + player.getUniqueId()); + super("McMMOPlayer object was not found for [NOTE: This can mean the profile is not loaded yet! : " + player.getName() + " " + player.getUniqueId()); } } From 06990c858e1e442a3850b8e4ffad8a03fc6a097d Mon Sep 17 00:00:00 2001 From: w1tcherrr <70418164+w1tcherrr@users.noreply.github.com> Date: Tue, 16 Mar 2021 21:03:53 +0100 Subject: [PATCH 30/33] Fixed mistakes in german locale file (#4454) * Fixed mistakes * Update src/main/resources/locale/locale_de.properties Co-authored-by: TheBusyBiscuit * Update src/main/resources/locale/locale_de.properties Co-authored-by: TheBusyBiscuit * More Fixes Co-authored-by: TheBusyBiscuit --- .../resources/locale/locale_de.properties | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/main/resources/locale/locale_de.properties b/src/main/resources/locale/locale_de.properties index 7b6b534b5..87cfc4240 100644 --- a/src/main/resources/locale/locale_de.properties +++ b/src/main/resources/locale/locale_de.properties @@ -17,7 +17,7 @@ Acrobatics.SubSkill.GracefulRoll.Name = Anmutiges Abrollen Acrobatics.SubSkill.Roll.Chance = Chance abzurollen: &e{0} Acrobatics.SubSkill.Roll.Description = Lande gezielt, um deinen Fallschaden zu reduzieren. Acrobatics.SubSkill.Roll.GraceChance = Chance anmutig abzurollen: &e{0} -Acrobatics.SubSkill.Roll.Mechanics = &7Abrollen ist eine aktive F\u00E4higkeit mit einem passiven Teil. Immer, wenn du Fallschaden nimmst, gibt es eine Chance, dass der Schaden reduziert wird, je nachdem wie hoch dein Akrobatik-Level ist. Auf Level 50 hast du eine &e{0}%&7 Chance, den Schaden zu reduzieren bzw. &e{1}%&7 wenn Anmutiges Abrollen aktiviert wird. Die Erfolgschance steigt linear bis Level &e{2}&7, auf welchem es seinen maximalen Wert erreicht. Jedes Akrobatik-Level gibt dir eine &e{3}%&7 Chance zum erfolgreichen Abrollen. H\u00E4ltst du im Fall die Duck-Taste (standardm\u00E4\u00DFig Shift), aktivierst du Anmutiges Abrollen, welches den Fallschaden um noch mehr Schaden reduzieren oder sogar komplett verhindern kann. Normales Abrollen wird maximal &c{4}&7 Schaden verhindern, Anmutiges Abrollen bis zu &a{5}&7. +Acrobatics.SubSkill.Roll.Mechanics = &7Abrollen ist eine aktive F\u00E4higkeit mit einem passiven Teil. Immer, wenn du Fallschaden nimmst, gibt es eine Chance, dass der Schaden reduziert wird, je nachdem wie hoch dein Akrobatik-Level ist. Auf Level 50 hast du eine &e{0}%&7 Chance, den Schaden zu reduzieren bzw. &e{1}%&7 wenn Anmutiges Abrollen aktiviert wird. Die Erfolgschance steigt linear bis Level &e{2}&7, auf welchem es seinen maximalen Wert erreicht. Jedes Akrobatik-Level gibt dir eine &e{3}%&7 Chance zum erfolgreichen Abrollen. H\u00E4ltst du im Fall die Duck-Taste (standardm\u00E4\u00DFig Shift), aktivierst du Anmutiges Abrollen, welches den Fallschaden auf noch weniger Schaden reduzieren oder sogar komplett verhindern kann. Normales Abrollen wird maximal &c{4}&7 Schaden verhindern, Anmutiges Abrollen bis zu &a{5}&7. Acrobatics.SubSkill.Roll.Name = Abrollen Acrobatics.SubSkill.Roll.Stat = Chance abzurollen Acrobatics.SubSkill.Roll.Stat.Extra = Chance anmutig abzurollen @@ -62,7 +62,7 @@ Axes.Ability.Lower = &7&o**Du senkst deine Axt.** Axes.Ability.Ready = &a&o**Du hebst deine Axt...** Axes.Ability.Ready.Extra = &3Du &6hebst&3 deine Axt. &7({0} ist f\u00FCr {1}s pausiert) Axes.Combat.CritStruck = &cDu wurdest &4schwer &cverwundet! -Axes.Combat.CriticalHit = &4&Kritischer Treffer! +Axes.Combat.CriticalHit = &4Kritischer Treffer! Axes.Combat.GI.Proc = &a**Du landest einen &2gewaltigen &aSchlag** Axes.Combat.GI.Struck = &a&o**Von einem Wuchtschlag getroffen** Axes.Combat.SS.Struck = &a&o**Von einem Sch\u00E4delspalter getroffen** @@ -233,7 +233,7 @@ Commands.Party.PartyFull.InviteAccept = Du kannst der Party &a{0}&c nicht beitre Commands.Party.Quit = &a- Verlasse deine aktuelle Party. Commands.Party.Rename = &7Party Name wurde zu &f{0} &7ver\u00E4ndert Commands.Party.SetSharing = &7Party {0} teilen: &3{1} -Commands.Party.ShareMode = &8Teilen Modus: +Commands.Party.ShareMode = &8Teilen-Modus: Commands.Party.Status = &8Name: &f{0} {1} &8Level: &3{2} Commands.Party.Status.Alliance = &8Verb\u00FCndeter: &f{0} Commands.Party.Teleport = &a- Teleportiere dich zu Partymitgliedern. @@ -242,7 +242,7 @@ Commands.Party.ToggleShareCategory = &7Party Item teilen f\u00FCr&6{0} &7wurde & Commands.Party.UnlockedFeatures = &8Freigeschaltete Features: &7&o{0} Commands.Party1 = &a- Erstelle eine neue Party. Commands.Party2 = &a- Tritt der Party eines Spielers bei. -Commands.PowerLevel = &4GESAMT LEVEL: &a{0} +Commands.PowerLevel = &4Gesamtlevel: &a{0} Commands.PowerLevel.Capped = &4Gesamtlevel: &a{0} &4H\u00F6chstlevel: &e{1} Commands.PowerLevel.Leaderboard = --mcMMO&9 Power-Level &eBestenliste-- Commands.Reset = &a- Setze ein Skilllevel auf 0 @@ -262,14 +262,14 @@ Commands.Skill.ChildSkill = Unterskills sind f\u00FCr diesen Befehl nicht benutz Commands.Skill.Invalid = Das ist kein g\u00FCltiger Skillname! Commands.Skill.Leaderboard = --mcMMO &9{0}&e Bestenliste-- Commands.SkillInfo = &a- Detaillierte Informationen zu einem Skill. -Commands.Stats = &a- Zeige deine Skill Statistiken. +Commands.Stats = &a- Zeige deine Skill-Statistiken. Commands.Stats.Self.Overhaul = Statistiken Commands.ToggleAbility = &a- Schalte F\u00E4higkeiten-Aktivierung mit Rechtsklick an oder aus. Commands.Usage.0 = &cDie korrekte Verwendung ist /{0} Commands.Usage.1 = &cDie korrekte Verwendung ist /{0} {1} Commands.Usage.2 = &cDie korrekte Verwendung ist /{0} {1} {2} Commands.Usage.3 = &cDie korrekte Verwendung ist /{0} {1} {2} {3} -Commands.Usage.3.XP = &cDie korrekte Verwendung ist /{0} {1} {2} {3}&7 (Du kannst auch -s an das Ende des Befehls hinzuf\u00FC"gen, damit der Spieler nicht benachrichtigt wird.) +Commands.Usage.3.XP = &cDie korrekte Verwendung ist /{0} {1} {2} {3}&7 (Du kannst auch -s an das Ende des Befehls hinzuf\u00FCgen, damit der Spieler nicht benachrichtigt wird.) Commands.Usage.FullClassName = Klassenname Commands.Usage.Level = Level Commands.Usage.Message = Nachricht @@ -285,7 +285,7 @@ Commands.XPBar.DisableAll = &6Alle mcMMO Erfahrungsleisten wurden deaktiviert, b Commands.XPBar.Reset = &6Die Erfahrungsleisten-Einstellungen f\u00FCr mcMMO wurden zur\u00FCckgesetzt. Commands.XPBar.SettingChanged = &6Die Erfahrungsleisten-Einstellungen f\u00FCr &a{0}&6 wurden gesetzt auf: &a{1} Commands.XPBar.Usage = Die korrekte Verwendung ist /mmoxpbar -Commands.XPGain = &8XP ZUWACHS: &f{0} +Commands.XPGain = &8XP-Zuwachs: &f{0} Commands.XPGain.Acrobatics = Fallen Commands.XPGain.Alchemy = Tr\u00E4nke brauen Commands.XPGain.Archery = Monster angreifen @@ -379,12 +379,12 @@ Excavation.SubSkill.GigaDrillBreaker.Description = Dreifache Droprate, dreifache Excavation.SubSkill.GigaDrillBreaker.Name = Gigabohrer Excavation.SubSkill.GigaDrillBreaker.Stat = Gigabohrer-Dauer -Fishing.Ability.Info = Zauberj\u00E4ger: &7 **Verbessert sich mit Schatzj\u00E4ger-Rang** +Fishing.Ability.Info = Zauberj\u00E4ger: &7**Verbessert sich mit Schatzj\u00E4ger-Rang** Fishing.Ability.Locked.0 = Gesperrt bis Level {0}! Fishing.Ability.Locked.1 = Gesperrt bis Level {0}! Fishing.Ability.Locked.2 = Gesperrt bis Level {0}! Fishing.Ability.TH.Boom = &c&lDeine Angelschnur hat sich in einer &4&lSeemine &c&lverfangen! -Fishing.Ability.TH.MagicFound = &bDu f\u00FChlst etwas Magisches in diesem Fang... +Fishing.Ability.TH.MagicFound = &bDu f\u00FChlst etwas Magisches an diesem Fang... Fishing.Ability.TH.Poison = &7Irgendetwas stinkt hier... Fishing.Chance.Raining = &9Regen-Bonus Fishing.Exhausting = &c&oUnsachgem\u00E4\u00DFe Nutzung der Angelrute f\u00FChrt zu Erm\u00FCdung und Abnutzen der Rute. @@ -557,7 +557,7 @@ Inspect.OfflineStats = mcMMO Stats f\u00FCr Offline-Spieler &e{0} Inspect.Stats = &amcMMO Stats f\u00FCr &e{0} Inspect.TooFar = Du bist zu weit entfernt um den Spieler zu inspizieren! -Item.ChimaeraWing.Fail = &c**CHIMAERA FL\u00DCGEL GESCHEITERT!** +Item.ChimaeraWing.Fail = &c**Chimaera Fl\u00FCgel gescheitert!** Item.ChimaeraWing.Lore = &7Teleportiert dich zu deinem Bett. Item.ChimaeraWing.Name = Chimaera Fl\u00FCgel Item.ChimaeraWing.NotEnough = Du ben\u00F6tigst &e{0}&c weitere &6{1}&c! @@ -595,7 +595,7 @@ JSON.JWrapper.Perks.Lucky = {0}% Bessere Chancen JSON.JWrapper.Target.Block = Block JSON.JWrapper.Target.Player = Spieler JSON.JWrapper.Target.Type = Zieltyp: -JSON.LevelRequirement = Level Voraussetzung +JSON.LevelRequirement = Level-Voraussetzung JSON.Locked = -=[NICHT VERF\u00DCGBAR]=- JSON.Mining = Bergbau JSON.Notification.SuperAbility = {0} @@ -610,7 +610,7 @@ JSON.Type.Passive = Passiv JSON.Type.SuperAbility = Superf\u00E4higkeit JSON.URL.Discord = Der offizielle (englische) mcMMO Discord Server! JSON.URL.Patreon = Unterst\u00FCtze die Entwicklung von mcMMO \u00FCber nossr50's Patreon! -JSON.URL.Spigot = Die offizielle mcmmo Spigot Seite +JSON.URL.Spigot = Die offizielle mcMMO Spigot-Seite. JSON.URL.Translation = \u00DCbersetze mcMMO in andere Sprachen! JSON.URL.Website = Die offizielle mcMMO Website! JSON.URL.Wiki = Das offizielle mcMMO Wiki! @@ -666,7 +666,7 @@ Mining.SubSkill.SuperBreaker.Stat = Superbrecher L\u00E4nge Notifications.Admin.Format.Others = &6(&amcMMO &3Admin&6) &7{0} Notifications.Admin.Format.Self = &6(&amcMMO&6) &7{0} -Notifications.Admin.XPRate.End.Others = {0} &7hat das Bonuserfahrungs-Event beendet +Notifications.Admin.XPRate.End.Others = {0} &7hat das Bonuserfahrungs-Event beendet. Notifications.Admin.XPRate.End.Self = &7Du hast das Bonuserfahrungs-Event beendet. Notifications.Admin.XPRate.Start.Others = {0} &7hat ein Bonuserfahrungs-Event mit einem Faktor von {1}x gestartet. Notifications.Admin.XPRate.Start.Self = &7Du hast den globalen Erfahrungsraten-Multiplikator auf &6{0}x&7 gesetzt. @@ -715,7 +715,7 @@ Party.Help.0 = &cDie korrekte Benutzung ist &3{0} [passwort]. Party.Help.1 = &cUm eine Gruppe zu erstellen, nutze &3{0} [gruppenpasswort]. Party.Help.10 = &cNutze &3{0} &cum Erfahrungsteilung mit Mitgliedern zu aktivieren. Party.Help.2 = &cNutze &3{0} &cf\u00FCr mehr Informationen. -Party.Help.3 = &cNutze &3{0} [passwort] &czum beitreten oder &3{1} &czum verlassen. +Party.Help.3 = &cNutze &3{0} [passwort] &czum Beitreten oder &3{1} &czum Verlassen. Party.Help.4 = &cUm deine Gruppe zu sperren oder entsperren, nutze &3{0}. Party.Help.5 = &cUm deine Gruppe per Passwort zu sch\u00FCtzen, nutze &3{0} . Party.Help.6 = &cUm einen Spieler aus deiner Gruppe zu entfernen, nutze &3{0} . @@ -823,7 +823,7 @@ Repair.SubSkill.StoneRepair.Description = Repariere Stein-Werkzeuge. Repair.SubSkill.StoneRepair.Name = Stein-Reparatur ({0}+ SKILL) Repair.SubSkill.SuperRepair.Description = Doppelte Effektivit\u00E4t. Repair.SubSkill.SuperRepair.Name = Super-Reparatur -Repair.SubSkill.SuperRepair.Stat = Chance auf Superreparatur +Repair.SubSkill.SuperRepair.Stat = Chance auf Super-Reparatur Salvage.Ability.Bonus.0 = Fortgeschrittenes Verwerten Salvage.Ability.Bonus.1 = Max Ertrag {0} Item zerst\u00F6rt @@ -845,7 +845,7 @@ Salvage.Skills.Success = &aItem verwertet! Salvage.Skills.TooDamaged = &4Das Item ist zu besch\u00E4digt um verwertet zu werden. Salvage.SubSkill.ArcaneSalvage.Description = Extrahiere Verzauberungen aus Items. Salvage.SubSkill.ArcaneSalvage.Name = Magische Bergung -Salvage.SubSkill.ArcaneSalvage.Stat = Magische Bergung: &eRank {0}/{1} +Salvage.SubSkill.ArcaneSalvage.Stat = Magische Bergung: &eRang {0}/{1} Salvage.SubSkill.ScrapCollector.Description = Verschrotte einen Gegenstand, um Materialien zur\u00FCckzugewinnen; eine perfekte Verschrottung erfordert Gl\u00FCck und Geschick. Salvage.SubSkill.ScrapCollector.Name = Schrottsammler Salvage.SubSkill.ScrapCollector.Stat = Schrottsammler: &aVerschrotte bis zu &e{0}&a Gegenst\u00E4nde. Hierbei spielt Gl\u00FCck eine gewisse Rolle. @@ -856,13 +856,13 @@ Scoreboard.Header.PlayerCooldowns = mcMMO Abklingzeiten Scoreboard.Header.PlayerInspect = mcMMO Stats: {0} Scoreboard.Header.PlayerRank = mcMMO Bestenlisten Scoreboard.Header.PlayerStats = mcMMO Stats -Scoreboard.Header.PowerLevel = Gesamt Level +Scoreboard.Header.PowerLevel = Gesamt-Level Scoreboard.Misc.Ability = F\u00E4higkeit Scoreboard.Misc.Cooldown = &dAbklingzeit Scoreboard.Misc.CurrentXP = &aAktuelle XP Scoreboard.Misc.Level = &3Level Scoreboard.Misc.Overall = &6Insgesamt -Scoreboard.Misc.PowerLevel = &6Gesamt Level +Scoreboard.Misc.PowerLevel = &6Gesamt-Level Scoreboard.Misc.RemainingXP = Verbliebene XP Server.ConsoleName = &e[Server] @@ -884,9 +884,9 @@ Skills.TooTired = Du bist zu m\u00FCde um diese F\u00E4higkeit zu verwenden. &e( Skills.TooTired.Extra = &6{0} &eSuperf\u00E4higkeit CDs - {1} Skills.TooTired.Named = &7(&6{0}&e {1}s&7) -Smelting.Ability.Locked.0 = Gesperrt bis {0}+ Skill (XP BOOST) -Smelting.Ability.Locked.1 = Gesperrt bis {0}+ Skill (SCHMELZTIEGEL) -Smelting.Effect.4 = Vanilla XP Boost +Smelting.Ability.Locked.0 = Gesperrt bis {0}+ Skill (XP-Boost) +Smelting.Ability.Locked.1 = Gesperrt bis {0}+ Skill (Schmelztiegel) +Smelting.Effect.4 = Vanilla XP-Boost Smelting.Effect.5 = Erh\u00F6ht die erhaltene Erfahrung beim Schmelzen. Smelting.Listener = Schmelzen: Smelting.SkillName = Schmelzen @@ -895,7 +895,7 @@ Smelting.SubSkill.FluxMining.Name = Schmelztiegel Smelting.SubSkill.FluxMining.Stat = Schmelztiegel Chance Smelting.SubSkill.FuelEfficiency.Description = Erh\u00F6he die Brenndauer des Brennstoffes in \u00D6fen. Smelting.SubSkill.FuelEfficiency.Name = Brennstoff Effizienz -Smelting.SubSkill.FuelEfficiency.Stat = Brennstoff Effizienz Multiplikator: &e{0}x +Smelting.SubSkill.FuelEfficiency.Stat = Brennstoff Effizienz-Multiplikator: &e{0}x Smelting.SubSkill.SecondSmelt.Description = Verdoppelt den Ertrag beim Schmelzen. Smelting.SubSkill.SecondSmelt.Name = Extra Schmelzung Smelting.SubSkill.SecondSmelt.Stat = Extra Schmelzung Chance @@ -906,12 +906,12 @@ Smelting.SubSkill.UnderstandingTheArt.Stat = Vanilla Erfahrungsmultiplikator: &e Stats.Header.Combat = &6-=Kampfskills=- Stats.Header.Gathering = &6-=Sammelskills=- Stats.Header.Misc = &6-=Weitere Skills=- -Stats.Own.Stats = &aSkill Statistik +Stats.Own.Stats = &aSkill-Statistik -Swords.Ability.Lower = &7&o**Du senkst dein Sschwert.** +Swords.Ability.Lower = &7&o**Du senkst dein Schwert.** Swords.Ability.Ready = &a&o**Du hebst dein Schwert...** Swords.Combat.Bleeding = &a**Gegner blutet** -Swords.Combat.Bleeding.Started = &4 Du blutest! +Swords.Combat.Bleeding.Started = &4Du blutest! Swords.Combat.Bleeding.Stopped = &7Das Bluten hat &aaufgeh\u00F6rt&7! Swords.Combat.Counter.Hit = &4Treffer durch Gegenangriff! Swords.Combat.Countered = &a**Gegenangriff** @@ -920,7 +920,7 @@ Swords.Combat.SS.Struck = &4Getroffen von S\u00E4gezahnschlag! Swords.Effect.4 = S\u00E4gezahnschlag, Blutung+ Swords.Effect.5 = {0} Ticks Blutung Swords.Listener = Schwert: -Swords.SkillName = Sschwert +Swords.SkillName = Schwert Swords.Skills.SS.Off = &a&o**S\u00E4gezahnschlag abgenutzt** Swords.Skills.SS.On = &a&o**S\u00E4gezahnschlag aktiviert** Swords.Skills.SS.Other.Off = {0}s &cS\u00E4gezahnschlag&a ist &aabgenutzt. @@ -983,7 +983,7 @@ Taming.SubSkill.Pummel.Name = Pummel Taming.SubSkill.Pummel.TargetMessage = Du wurdest von einem Wolf zur\u00FCckgeschlagen! Taming.SubSkill.SharpenedClaws.Description = Schadens-Bonus Taming.SubSkill.SharpenedClaws.Name = Gesch\u00E4rfte Krallen -Taming.SubSkill.ShockProof.Description = Reduktion von Explosions-Schaden. +Taming.SubSkill.ShockProof.Description = Reduktion von Explosionsschaden. Taming.SubSkill.ShockProof.Name = Schock-Sicher Taming.SubSkill.ThickFur.Description = Verminderter Schaden, Feuer-Resistenz Taming.SubSkill.ThickFur.Name = Dicker Pelz @@ -1030,7 +1030,7 @@ Unarmed.SubSkill.SteelArmStyle.Description = Verst\u00E4rkt deinen Arm mit der Z Unarmed.SubSkill.SteelArmStyle.Name = St\u00E4hlerner Arm Unarmed.SubSkill.UnarmedLimitBreak.Description = Durchbreche deine Grenzen! Unarmed.SubSkill.UnarmedLimitBreak.Name = \u00DCberwindung -Unarmed.SubSkill.UnarmedLimitBreak.Stat = Bonus Schaden durch \u00DCberwindung +Unarmed.SubSkill.UnarmedLimitBreak.Stat = Bonus-Schaden durch \u00DCberwindung UpdateChecker.NewAvailable = Eine neue Version von mcMMO ist auf Spigot erh\u00E4ltlich! UpdateChecker.Outdated = Du verwendest eine veraltete mcMMO Version! @@ -1088,9 +1088,9 @@ XPBar.Woodcutting = Holzf\u00E4llen Level: &6{0} XPRate.Event = &6Es findet derzeit ein Skill-Event statt! Du bekommst aktuell &c{0} &6mal so viel Erfahrung f\u00FCr deine Skills wie normal! -mcMMO.Description = &3\u00DCber das &emcMMO&3 Projekt:,&6mcMMO ist ein &copen source&6 RPG mod erstellt in Februar 2011&6von &9nossr50&6. Das Ziel ist es ein qualitatives RPG Erlebnis zu liefern.,&3Tips:,&6 - &aNutze &c/mcmmo help&a um Befehle zu sehen &6,- &aNutze &c/skillname&a f\u00FCr detaillierte Skill Infos,&3Entwickler:,&6 - &anossr50 &9(Erfinder & Projektleitung),&6 - &aGJ &9(Fr\u00FChere Projektleitung),&6 - &aNuclearW &9(Entwickler),&6 - &abm01 &9(Entwickler),&6 - &aTfT_02 &9(Entwickler),&6 - &aGlitchfinder &9(Entwickler),&6 - &at00thpick1 &9(Entwickler),&6 - &alumis31 &9 (Urspr\u00FCngliche Deutsche \u00DCbersetzung),&6 - &aOverCrave &9 (Neue Deutsche \u00DCbersetzung & \u00DCberarbeitung),&3N\u00FCtzliche Links:,&6 - &ahttps://github.com/mcMMO-Dev/mcMMO/issues&6 Bug Reporting,&6 - &ahttps://discord.gg/EJGVanb &6 Offizieller Discord (Englisch) +mcMMO.Description = &3\u00DCber das &emcMMO&3 Projekt: &6mcMMO ist ein &copen source&6 RPG-Mod erstellt im Februar 2011 &6von &9nossr50&6. Das Ziel ist es ein qualitatives RPG Erlebnis zu liefern. &3Tipps:&6 - &aNutze &c/mcmmo help&a um Befehle zu sehen, &6 - &aNutze &c/skillname&a f\u00FCr detaillierte Skill Infos, &3Entwickler:&6 - &anossr50 &9(Erfinder & Projektleitung),&6 - &aGJ &9(Fr\u00FChere Projektleitung),&6 - &aNuclearW &9(Entwickler),&6 - &abm01 &9(Entwickler),&6 - &aTfT_02 &9(Entwickler),&6 - &aGlitchfinder &9(Entwickler),&6 - &at00thpick1 &9(Entwickler),&6 - &alumis31 &9(Urspr\u00FCngliche Deutsche \u00DCbersetzung),&6 - &aOverCrave &9(Neue Deutsche \u00DCbersetzung & \u00DCberarbeitung),&6 - &aAnseba &9(\u00DCberarbeitung Deutsche \u00DCbersetzung), &3N\u00FCtzliche Links:&6 - &ahttps://github.com/mcMMO-Dev/mcMMO/issues&6 Bug Reporting,&6 - &ahttps://discord.gg/EJGVanb &6 Offizieller Discord (Englisch) mcMMO.Description.FormerDevs = &3Ehemalige Entwickler: &aGJ, NuclearW, bm01, TfT_02, Glitchfinder -mcMMO.NoInvites = &cDu hast zurzeit keine Einladungen +mcMMO.NoInvites = &cDu hast zurzeit keine Einladungen. mcMMO.NoPermission = &4Unzureichende Berechtigungen. mcMMO.NoSkillNote = &8Wenn du keinen Zugriff auf einen Skill hast wird er hier nicht angezeigt. mcMMO.Template.Prefix = &6(&amcMMO&6) &7{0} From b181fb4568d5183a695bd9b69816ffe0a07e4e78 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 16 Mar 2021 13:12:45 -0700 Subject: [PATCH 31/33] Update changelog --- Changelog.txt | 4 ++++ pom.xml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Changelog.txt b/Changelog.txt index d9fe87d35..edab3d0bc 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,7 @@ +Version 2.1.182 + Fixed several errors in de locale (Thanks TheBusyBiscuit & w1tcherrr) + + Version 2.1.181 mcMMO no longer pointlessly tries to check for missing UUIDs for FlatFile database Removed the "name change detected" message as some plugins (such as Plan) invoke API calls which spams the console with this message diff --git a/pom.xml b/pom.xml index fb224f530..1a9cd6cfe 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.181 + 2.1.182-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO From 444d5edd66cd463671edc13a61f1a5bf44e65ec5 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 16 Mar 2021 13:16:17 -0700 Subject: [PATCH 32/33] Fixed double smelt not working if furnace was empty --- Changelog.txt | 1 + .../java/com/gmail/nossr50/skills/smelting/SmeltingManager.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Changelog.txt b/Changelog.txt index edab3d0bc..3821b79a4 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,5 +1,6 @@ Version 2.1.182 Fixed several errors in de locale (Thanks TheBusyBiscuit & w1tcherrr) + Fixed a bug where double smelt never succeeded if the furnace was empty Version 2.1.181 diff --git a/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java b/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java index ddda94ba1..0c0e0cb23 100644 --- a/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java @@ -140,7 +140,7 @@ public class SmeltingManager extends SkillManager { ItemStack furnaceResult = furnaceInventory.getResult(); if(furnaceResult == null) - return false; + return true; //This actually means there is nothing yet in the resulting item slot, which means it should always be okay to double smelt int resultAmount = furnaceResult.getAmount(); //Amount before double smelt int itemLimit = furnaceResult.getMaxStackSize(); From 49d4e979301ad8d411a06d7e8a5e7abf0f8b07e5 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 16 Mar 2021 14:05:33 -0700 Subject: [PATCH 33/33] Some safety redundancy --- Changelog.txt | 2 +- src/main/java/com/gmail/nossr50/mcMMO.java | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 3821b79a4..d555798e5 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,7 +1,7 @@ Version 2.1.182 Fixed several errors in de locale (Thanks TheBusyBiscuit & w1tcherrr) Fixed a bug where double smelt never succeeded if the furnace was empty - + Added some safety so that mcMMO automatic save interval is never more frequent than 1 minute Version 2.1.181 mcMMO no longer pointlessly tries to check for missing UUIDs for FlatFile database diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index 858160043..334d26886 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -621,7 +621,11 @@ public class mcMMO extends JavaPlugin { private void scheduleTasks() { // Periodic save timer (Saves every 10 minutes by default) - long saveIntervalTicks = Config.getInstance().getSaveInterval() * 1200; + long second = 20; + long minute = second * 60; + + long saveIntervalTicks = Math.max(minute, Config.getInstance().getSaveInterval() * minute); + new SaveTimerTask().runTaskTimer(this, saveIntervalTicks, saveIntervalTicks); // Cleanup the backups folder