From 5080d86e447b48eb2775f4520fab7fb1888e57ee Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 8 Apr 2021 10:39:07 -0700 Subject: [PATCH 01/57] Refactoring code part 1 to prep for adding a bunch of unit tests --- Changelog.txt | 1 + .../com/gmail/nossr50/api/ExperienceAPI.java | 5 +- .../java/com/gmail/nossr50/api/PartyAPI.java | 3 +- .../gmail/nossr50/commands/MHDCommand.java | 46 --- .../gmail/nossr50/commands/McmmoCommand.java | 3 +- .../nossr50/commands/McscoreboardCommand.java | 4 +- .../gmail/nossr50/commands/XprateCommand.java | 10 +- .../database/ConvertDatabaseCommand.java | 9 +- .../commands/database/McpurgeCommand.java | 3 +- .../commands/database/MmoshowdbCommand.java | 4 +- .../commands/party/PartyInfoCommand.java | 4 +- .../commands/party/PartyInviteCommand.java | 4 +- .../commands/party/PartyItemShareCommand.java | 4 +- .../commands/party/PartyXpShareCommand.java | 4 +- .../party/alliance/PartyAllianceCommand.java | 6 +- .../party/teleport/PtpAcceptCommand.java | 6 +- .../commands/party/teleport/PtpCommand.java | 13 +- .../commands/player/InspectCommand.java | 13 +- .../commands/player/MccooldownCommand.java | 6 +- .../commands/player/McrankCommand.java | 7 +- .../commands/player/McstatsCommand.java | 8 +- .../nossr50/commands/player/MctopCommand.java | 7 +- .../commands/skills/AcrobaticsCommand.java | 2 +- .../nossr50/commands/skills/SkillCommand.java | 15 +- .../commands/skills/SwordsCommand.java | 18 +- .../gmail/nossr50/config/AdvancedConfig.java | 38 +-- .../config/AutoUpdateConfigLoader.java | 12 +- .../gmail/nossr50/config/ConfigLoader.java | 24 +- .../{Config.java => GeneralConfig.java} | 93 +----- .../com/gmail/nossr50/config/RankConfig.java | 3 +- .../nossr50/database/DatabaseManager.java | 7 +- .../database/DatabaseManagerFactory.java | 17 +- .../database/FlatFileDatabaseManager.java | 282 ++++++------------ .../nossr50/database/SQLDatabaseManager.java | 82 ++--- .../datatypes/LevelUpBroadcastPredicate.java | 11 +- .../PowerLevelUpBroadcastPredicate.java | 11 +- .../gmail/nossr50/datatypes/party/Party.java | 11 +- .../nossr50/datatypes/party/PartyFeature.java | 4 +- .../datatypes/party/PartyTeleportRecord.java | 4 +- .../nossr50/datatypes/player/McMMOPlayer.java | 30 +- .../datatypes/player/PlayerProfile.java | 23 +- .../datatypes/skills/PrimarySkillType.java | 59 ++-- .../datatypes/skills/SubSkillType.java | 3 +- .../datatypes/skills/SuperAbilityType.java | 5 +- .../datatypes/skills/interfaces/Skill.java | 96 ++++++ .../skills/subskills/acrobatics/Roll.java | 110 ++++++- .../secondaryabilities/SubSkillEvent.java | 6 +- .../nossr50/listeners/BlockListener.java | 11 +- .../nossr50/listeners/EntityListener.java | 6 +- .../nossr50/listeners/InventoryListener.java | 7 +- .../nossr50/listeners/PlayerListener.java | 29 +- .../gmail/nossr50/listeners/SelfListener.java | 7 +- .../gmail/nossr50/locale/LocaleLoader.java | 5 +- src/main/java/com/gmail/nossr50/mcMMO.java | 76 +++-- .../com/gmail/nossr50/party/PartyManager.java | 13 +- .../com/gmail/nossr50/party/ShareHandler.java | 4 +- .../runnables/backups/CleanBackupsTask.java | 7 +- .../commands/McrankCommandDisplayTask.java | 3 +- .../commands/MctopCommandDisplayTask.java | 3 +- .../runnables/database/UserPurgeTask.java | 3 +- .../runnables/items/ChimaeraWingWarmup.java | 6 +- .../runnables/items/TeleportationWarmup.java | 6 +- .../runnables/party/PartyAutoKickTask.java | 3 +- .../player/PlayerProfileLoadingTask.java | 7 +- .../runnables/skills/AbilityDisableTask.java | 6 +- .../runnables/skills/BleedTimerTask.java | 4 +- .../nossr50/runnables/skills/RuptureTask.java | 4 +- .../runnables/skills/ToolLowerTask.java | 4 +- .../nossr50/skills/acrobatics/Acrobatics.java | 7 +- .../gmail/nossr50/skills/alchemy/Alchemy.java | 9 +- .../gmail/nossr50/skills/archery/Archery.java | 8 +- .../com/gmail/nossr50/skills/axes/Axes.java | 18 +- .../nossr50/skills/axes/AxesManager.java | 4 +- .../skills/excavation/ExcavationManager.java | 4 +- .../skills/fishing/FishingManager.java | 24 +- .../skills/herbalism/HerbalismManager.java | 5 +- .../nossr50/skills/mining/BlastMining.java | 7 +- .../nossr50/skills/mining/MiningManager.java | 18 +- .../nossr50/skills/repair/ArcaneForging.java | 6 +- .../gmail/nossr50/skills/repair/Repair.java | 9 +- .../nossr50/skills/repair/RepairManager.java | 14 +- .../gmail/nossr50/skills/salvage/Salvage.java | 13 +- .../skills/salvage/SalvageManager.java | 14 +- .../skills/smelting/SmeltingManager.java | 4 +- .../gmail/nossr50/skills/swords/Swords.java | 6 +- .../nossr50/skills/swords/SwordsManager.java | 9 +- .../gmail/nossr50/skills/taming/Taming.java | 12 +- .../nossr50/skills/taming/TamingManager.java | 22 +- .../skills/taming/TrackedTamingEntity.java | 3 +- .../gmail/nossr50/skills/unarmed/Unarmed.java | 4 +- .../skills/unarmed/UnarmedManager.java | 7 +- .../woodcutting/WoodcuttingManager.java | 10 +- .../com/gmail/nossr50/util/BlockUtils.java | 11 +- .../com/gmail/nossr50/util/ChimaeraWing.java | 29 +- .../com/gmail/nossr50/util/EventUtils.java | 6 +- .../gmail/nossr50/util/HardcoreManager.java | 10 +- .../com/gmail/nossr50/util/ItemUtils.java | 6 +- .../gmail/nossr50/util/MobHealthbarUtils.java | 7 +- .../com/gmail/nossr50/util/ModManager.java | 39 ++- .../java/com/gmail/nossr50/util/Motd.java | 5 +- .../com/gmail/nossr50/util/Permissions.java | 11 - .../commands/CommandRegistrationManager.java | 13 +- .../nossr50/util/commands/CommandUtils.java | 7 +- .../util/experience/FormulaManager.java | 3 +- .../util/player/NotificationManager.java | 22 +- .../nossr50/util/random/RandomChanceUtil.java | 12 +- .../util/scoreboards/ScoreboardManager.java | 33 +- .../util/scoreboards/ScoreboardWrapper.java | 5 +- .../nossr50/util/skills/CombatUtils.java | 3 +- .../util/skills/ParticleEffectUtils.java | 14 +- .../gmail/nossr50/util/skills/SkillUtils.java | 12 +- .../util/text/TextComponentFactory.java | 3 +- .../shatt/backup/ZipLibrary.java | 3 +- src/main/resources/plugin.yml | 3 - .../database/FlatFileDatabaseManagerTest.java | 119 ++++++++ 115 files changed, 993 insertions(+), 970 deletions(-) delete mode 100644 src/main/java/com/gmail/nossr50/commands/MHDCommand.java rename src/main/java/com/gmail/nossr50/config/{Config.java => GeneralConfig.java} (89%) create mode 100644 src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java diff --git a/Changelog.txt b/Changelog.txt index 14423b85a..8e1b2d0e6 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,4 +1,5 @@ Version 2.1.189 + Removed MHD command (it didn't do anything for a while now) Removed UP warning Updated pl locale (Thanks Mich3l3k) diff --git a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java index be325c281..158aafa27 100644 --- a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java +++ b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.api; import com.gmail.nossr50.api.exceptions.*; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.experience.FormulaType; import com.gmail.nossr50.datatypes.experience.XPGainReason; @@ -802,7 +801,7 @@ public final class ExperienceAPI { * @throws InvalidSkillException if the given skill is not valid */ public static int getLevelCap(String skillType) { - return Config.getInstance().getLevelCap(getSkillType(skillType)); + return mcMMO.p.getGeneralConfig().getLevelCap(getSkillType(skillType)); } /** @@ -813,7 +812,7 @@ public final class ExperienceAPI { * @return the overall power level cap */ public static int getPowerLevelCap() { - return Config.getInstance().getPowerLevelCap(); + return mcMMO.p.getGeneralConfig().getPowerLevelCap(); } /** diff --git a/src/main/java/com/gmail/nossr50/api/PartyAPI.java b/src/main/java/com/gmail/nossr50/api/PartyAPI.java index 97a2bbe40..7592df5e6 100644 --- a/src/main/java/com/gmail/nossr50/api/PartyAPI.java +++ b/src/main/java/com/gmail/nossr50/api/PartyAPI.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.api; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.party.PartyLeader; @@ -108,7 +107,7 @@ public final class PartyAPI { */ public static int getMaxPartySize() { - return Config.getInstance().getPartyMaxSize(); + return mcMMO.p.getGeneralConfig().getPartyMaxSize(); } /** diff --git a/src/main/java/com/gmail/nossr50/commands/MHDCommand.java b/src/main/java/com/gmail/nossr50/commands/MHDCommand.java deleted file mode 100644 index d3b547acc..000000000 --- a/src/main/java/com/gmail/nossr50/commands/MHDCommand.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.gmail.nossr50.commands; - -import com.gmail.nossr50.config.Config; -import com.gmail.nossr50.database.FlatFileDatabaseManager; -import com.gmail.nossr50.database.SQLDatabaseManager; -import com.gmail.nossr50.datatypes.player.McMMOPlayer; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.player.UserManager; -import com.google.common.collect.ImmutableList; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.command.TabExecutor; -import org.jetbrains.annotations.NotNull; - -import java.util.List; - -public class MHDCommand implements TabExecutor { - - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { - if (mcMMO.getDatabaseManager() instanceof SQLDatabaseManager) { - SQLDatabaseManager m = (SQLDatabaseManager) mcMMO.getDatabaseManager(); - m.resetMobHealthSettings(); - for (McMMOPlayer player : UserManager.getPlayers()) { - player.getProfile().setMobHealthbarType(Config.getInstance().getMobHealthbarDefault()); - } - sender.sendMessage("Mob health reset"); - return true; - } - if (mcMMO.getDatabaseManager() instanceof FlatFileDatabaseManager) { - FlatFileDatabaseManager m = (FlatFileDatabaseManager) mcMMO.getDatabaseManager(); - m.resetMobHealthSettings(); - for (McMMOPlayer player : UserManager.getPlayers()) { - player.getProfile().setMobHealthbarType(Config.getInstance().getMobHealthbarDefault()); - } - sender.sendMessage("Mob health reset"); - return true; - } - return false; - } - - @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { - return ImmutableList.of(); - } -} diff --git a/src/main/java/com/gmail/nossr50/commands/McmmoCommand.java b/src/main/java/com/gmail/nossr50/commands/McmmoCommand.java index 9c09763ca..838722131 100644 --- a/src/main/java/com/gmail/nossr50/commands/McmmoCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/McmmoCommand.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.commands; import com.gmail.nossr50.commands.party.PartySubcommandType; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; @@ -26,7 +25,7 @@ public class McmmoCommand implements CommandExecutor { sender.sendMessage(mcSplit); sender.sendMessage(LocaleLoader.getString("mcMMO.Description.FormerDevs")); - if (Config.getInstance().getDonateMessageEnabled()) { + if (mcMMO.p.getGeneralConfig().getDonateMessageEnabled()) { sender.sendMessage(LocaleLoader.getString("MOTD.Donate")); sender.sendMessage(ChatColor.GOLD + " - " + ChatColor.GREEN + "nossr50@gmail.com" + ChatColor.GOLD + " Paypal"); } diff --git a/src/main/java/com/gmail/nossr50/commands/McscoreboardCommand.java b/src/main/java/com/gmail/nossr50/commands/McscoreboardCommand.java index 1afaa110e..4748a5708 100644 --- a/src/main/java/com/gmail/nossr50/commands/McscoreboardCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/McscoreboardCommand.java @@ -1,7 +1,7 @@ package com.gmail.nossr50.commands; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.google.common.collect.ImmutableList; @@ -32,7 +32,7 @@ public class McscoreboardCommand implements TabExecutor { } if (args[0].equalsIgnoreCase("keep")) { - if (!Config.getInstance().getAllowKeepBoard() || !Config.getInstance().getScoreboardsEnabled()) { + if (!mcMMO.p.getGeneralConfig().getAllowKeepBoard() || !mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { sender.sendMessage(LocaleLoader.getString("Commands.Disabled")); return true; } diff --git a/src/main/java/com/gmail/nossr50/commands/XprateCommand.java b/src/main/java/com/gmail/nossr50/commands/XprateCommand.java index 150b97590..f5ad2641c 100644 --- a/src/main/java/com/gmail/nossr50/commands/XprateCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/XprateCommand.java @@ -1,7 +1,5 @@ package com.gmail.nossr50.commands; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.notifications.SensitiveCommandType; import com.gmail.nossr50.locale.LocaleLoader; @@ -39,7 +37,7 @@ public class XprateCommand implements TabExecutor { if (mcMMO.p.isXPEventEnabled()) { - if(AdvancedConfig.getInstance().useTitlesForXPEvent()) + if(mcMMO.p.getAdvancedConfig().useTitlesForXPEvent()) { NotificationManager.broadcastTitle(mcMMO.p.getServer(), LocaleLoader.getString("Commands.Event.Stop"), @@ -47,7 +45,7 @@ public class XprateCommand implements TabExecutor { 10, 10*20, 20); } - if(Config.getInstance().broadcastEventMessages()) + if(mcMMO.p.getGeneralConfig().broadcastEventMessages()) { mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Commands.Event.Stop")); mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Commands.Event.Stop.Subtitle")); @@ -92,7 +90,7 @@ public class XprateCommand implements TabExecutor { ExperienceConfig.getInstance().setExperienceGainsGlobalMultiplier(newXpRate); - if(AdvancedConfig.getInstance().useTitlesForXPEvent()) + if(mcMMO.p.getAdvancedConfig().useTitlesForXPEvent()) { NotificationManager.broadcastTitle(mcMMO.p.getServer(), LocaleLoader.getString("Commands.Event.Start"), @@ -100,7 +98,7 @@ public class XprateCommand implements TabExecutor { 10, 10*20, 20); } - if(Config.getInstance().broadcastEventMessages()) + if(mcMMO.p.getGeneralConfig().broadcastEventMessages()) { mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Commands.Event.Start")); mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Commands.Event.XP", newXpRate)); diff --git a/src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java b/src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java index 6bbee5f9f..bc383cf99 100644 --- a/src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java @@ -27,7 +27,13 @@ public class ConvertDatabaseCommand implements CommandExecutor { return true; } - DatabaseManager oldDatabase = DatabaseManagerFactory.createDatabaseManager(previousType); + DatabaseManager oldDatabase = DatabaseManagerFactory.createDatabaseManager(previousType, mcMMO.getUsersFilePath(), mcMMO.p.getLogger(), mcMMO.p.getPurgeTime(), mcMMO.p.getAdvancedConfig().getStartingLevel()); + if(oldDatabase == null) { + sender.sendMessage("Unable to load the old database! Check your log for errors."); + return true; + } + + oldDatabase.init(); if (previousType == DatabaseType.CUSTOM) { Class clazz; @@ -41,6 +47,7 @@ public class ConvertDatabaseCommand implements CommandExecutor { } oldDatabase = DatabaseManagerFactory.createCustomDatabaseManager((Class) clazz); + oldDatabase.init(); } catch (Throwable e) { e.printStackTrace(); sender.sendMessage(LocaleLoader.getString("Commands.mcconvert.Database.InvalidType", args[1])); diff --git a/src/main/java/com/gmail/nossr50/commands/database/McpurgeCommand.java b/src/main/java/com/gmail/nossr50/commands/database/McpurgeCommand.java index 9bc472875..6f192510f 100644 --- a/src/main/java/com/gmail/nossr50/commands/database/McpurgeCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/database/McpurgeCommand.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.commands.database; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.google.common.collect.ImmutableList; @@ -17,7 +16,7 @@ public class McpurgeCommand implements TabExecutor { if (args.length == 0) { mcMMO.getDatabaseManager().purgePowerlessUsers(); - if (Config.getInstance().getOldUsersCutoff() != -1) { + if (mcMMO.p.getGeneralConfig().getOldUsersCutoff() != -1) { mcMMO.getDatabaseManager().purgeOldUsers(); } diff --git a/src/main/java/com/gmail/nossr50/commands/database/MmoshowdbCommand.java b/src/main/java/com/gmail/nossr50/commands/database/MmoshowdbCommand.java index aafae253e..bcb07312d 100644 --- a/src/main/java/com/gmail/nossr50/commands/database/MmoshowdbCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/database/MmoshowdbCommand.java @@ -1,8 +1,8 @@ package com.gmail.nossr50.commands.database; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.database.DatabaseManagerFactory; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.google.common.collect.ImmutableList; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -22,7 +22,7 @@ public class MmoshowdbCommand implements TabExecutor { return true; } - sender.sendMessage(LocaleLoader.getString("Commands.mmoshowdb", (Config.getInstance().getUseMySQL() ? "sql" : "flatfile"))); + sender.sendMessage(LocaleLoader.getString("Commands.mmoshowdb", (mcMMO.p.getGeneralConfig().getUseMySQL() ? "sql" : "flatfile"))); return true; } return false; diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyInfoCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyInfoCommand.java index ec28ac529..ab46f14de 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyInfoCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyInfoCommand.java @@ -1,11 +1,11 @@ package com.gmail.nossr50.commands.party; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.party.PartyFeature; import com.gmail.nossr50.datatypes.party.ShareMode; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.ChatColor; @@ -85,7 +85,7 @@ public class PartyInfoCommand implements CommandExecutor { } private boolean isUnlockedFeature(Party party, PartyFeature partyFeature) { - return party.getLevel() >= Config.getInstance().getPartyFeatureUnlockLevel(partyFeature); + return party.getLevel() >= mcMMO.p.getGeneralConfig().getPartyFeatureUnlockLevel(partyFeature); } private void displayShareModeInfo(Player player, Party party) { diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyInviteCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyInviteCommand.java index 7d6c6a8ca..7a24a4936 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyInviteCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyInviteCommand.java @@ -1,9 +1,9 @@ package com.gmail.nossr50.commands.party; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; @@ -53,7 +53,7 @@ public class PartyInviteCommand implements CommandExecutor { Party playerParty = mcMMOPlayer.getParty(); if (PartyManager.isPartyFull(target, playerParty)) { - player.sendMessage(LocaleLoader.getString("Commands.Party.PartyFull.Invite", target.getName(), playerParty.toString(), Config.getInstance().getPartyMaxSize())); + player.sendMessage(LocaleLoader.getString("Commands.Party.PartyFull.Invite", target.getName(), playerParty.toString(), mcMMO.p.getGeneralConfig().getPartyMaxSize())); return true; } diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyItemShareCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyItemShareCommand.java index 4b0d8fb23..44822d82f 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyItemShareCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyItemShareCommand.java @@ -1,11 +1,11 @@ package com.gmail.nossr50.commands.party; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.party.ItemShareType; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.party.PartyFeature; import com.gmail.nossr50.datatypes.party.ShareMode; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.text.StringUtils; @@ -28,7 +28,7 @@ public class PartyItemShareCommand implements CommandExecutor { Party party = UserManager.getPlayer((Player) sender).getParty(); - if (party.getLevel() < Config.getInstance().getPartyFeatureUnlockLevel(PartyFeature.ITEM_SHARE)) { + if (party.getLevel() < mcMMO.p.getGeneralConfig().getPartyFeatureUnlockLevel(PartyFeature.ITEM_SHARE)) { sender.sendMessage(LocaleLoader.getString("Party.Feature.Disabled.4")); return true; } diff --git a/src/main/java/com/gmail/nossr50/commands/party/PartyXpShareCommand.java b/src/main/java/com/gmail/nossr50/commands/party/PartyXpShareCommand.java index a8354914e..8322beecf 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/PartyXpShareCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/PartyXpShareCommand.java @@ -1,10 +1,10 @@ package com.gmail.nossr50.commands.party; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.party.PartyFeature; import com.gmail.nossr50.datatypes.party.ShareMode; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.text.StringUtils; @@ -25,7 +25,7 @@ public class PartyXpShareCommand implements CommandExecutor { Party party = UserManager.getPlayer((Player) sender).getParty(); - if (party.getLevel() < Config.getInstance().getPartyFeatureUnlockLevel(PartyFeature.XP_SHARE)) { + if (party.getLevel() < mcMMO.p.getGeneralConfig().getPartyFeatureUnlockLevel(PartyFeature.XP_SHARE)) { sender.sendMessage(LocaleLoader.getString("Party.Feature.Disabled.5")); return true; } diff --git a/src/main/java/com/gmail/nossr50/commands/party/alliance/PartyAllianceCommand.java b/src/main/java/com/gmail/nossr50/commands/party/alliance/PartyAllianceCommand.java index d97edf3d7..27f6e4d21 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/alliance/PartyAllianceCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/alliance/PartyAllianceCommand.java @@ -1,10 +1,10 @@ package com.gmail.nossr50.commands.party.alliance; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.party.PartyFeature; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; @@ -51,7 +51,7 @@ public class PartyAllianceCommand implements TabExecutor { switch (args.length) { case 1: - if (playerParty.getLevel() < Config.getInstance().getPartyFeatureUnlockLevel(PartyFeature.ALLIANCE)) { + if (playerParty.getLevel() < mcMMO.p.getGeneralConfig().getPartyFeatureUnlockLevel(PartyFeature.ALLIANCE)) { sender.sendMessage(LocaleLoader.getString("Party.Feature.Disabled.3")); return true; } @@ -69,7 +69,7 @@ public class PartyAllianceCommand implements TabExecutor { case 2: case 3: - if (playerParty.getLevel() < Config.getInstance().getPartyFeatureUnlockLevel(PartyFeature.ALLIANCE)) { + if (playerParty.getLevel() < mcMMO.p.getGeneralConfig().getPartyFeatureUnlockLevel(PartyFeature.ALLIANCE)) { sender.sendMessage(LocaleLoader.getString("Party.Feature.Disabled.3")); return true; } diff --git a/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpAcceptCommand.java b/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpAcceptCommand.java index 86728e272..19c98ad6a 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpAcceptCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpAcceptCommand.java @@ -1,8 +1,8 @@ package com.gmail.nossr50.commands.party.teleport; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.party.PartyTeleportRecord; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.SkillUtils; @@ -35,7 +35,7 @@ public class PtpAcceptCommand implements CommandExecutor { return true; } - if (SkillUtils.cooldownExpired(ptpRecord.getTimeout(), Config.getInstance().getPTPCommandTimeout())) { + if (SkillUtils.cooldownExpired(ptpRecord.getTimeout(), mcMMO.p.getGeneralConfig().getPTPCommandTimeout())) { ptpRecord.removeRequest(); player.sendMessage(LocaleLoader.getString("Commands.ptp.RequestExpired")); return true; @@ -48,7 +48,7 @@ public class PtpAcceptCommand implements CommandExecutor { return true; } - if (Config.getInstance().getPTPCommandWorldPermissions()) { + if (mcMMO.p.getGeneralConfig().getPTPCommandWorldPermissions()) { World targetWorld = target.getWorld(); World playerWorld = player.getWorld(); diff --git a/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpCommand.java b/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpCommand.java index 893164435..c892fa7e0 100644 --- a/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/party/teleport/PtpCommand.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.commands.party.teleport; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.WorldBlacklist; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.party.PartyFeature; @@ -76,7 +75,7 @@ public class PtpCommand implements TabExecutor { Party party = mcMMOPlayer.getParty(); - if (party.getLevel() < Config.getInstance().getPartyFeatureUnlockLevel(PartyFeature.TELEPORT)) { + if (party.getLevel() < mcMMO.p.getGeneralConfig().getPartyFeatureUnlockLevel(PartyFeature.TELEPORT)) { sender.sendMessage(LocaleLoader.getString("Party.Feature.Disabled.2")); return true; } @@ -91,7 +90,7 @@ public class PtpCommand implements TabExecutor { } long recentlyHurt = mcMMOPlayer.getRecentlyHurt(); - int hurtCooldown = Config.getInstance().getPTPCommandRecentlyHurtCooldown(); + int hurtCooldown = mcMMO.p.getGeneralConfig().getPTPCommandRecentlyHurtCooldown(); if (hurtCooldown > 0) { int timeRemaining = SkillUtils.calculateTimeLeft(recentlyHurt * Misc.TIME_CONVERSION_FACTOR, hurtCooldown, player); @@ -111,7 +110,7 @@ public class PtpCommand implements TabExecutor { return true; } - int ptpCooldown = Config.getInstance().getPTPCommandCooldown(); + int ptpCooldown = mcMMO.p.getGeneralConfig().getPTPCommandCooldown(); long ptpLastUse = mcMMOPlayer.getPartyTeleportRecord().getLastUse(); if (ptpCooldown > 0) { @@ -165,7 +164,7 @@ public class PtpCommand implements TabExecutor { Player target = mcMMOTarget.getPlayer(); - if (Config.getInstance().getPTPCommandWorldPermissions()) { + if (mcMMO.p.getGeneralConfig().getPTPCommandWorldPermissions()) { World targetWorld = target.getWorld(); World playerWorld = player.getWorld(); @@ -194,7 +193,7 @@ public class PtpCommand implements TabExecutor { player.sendMessage(LocaleLoader.getString("Commands.Invite.Success")); target.sendMessage(LocaleLoader.getString("Commands.ptp.Request1", player.getName())); - target.sendMessage(LocaleLoader.getString("Commands.ptp.Request2", Config.getInstance().getPTPCommandTimeout())); + target.sendMessage(LocaleLoader.getString("Commands.ptp.Request2", mcMMO.p.getGeneralConfig().getPTPCommandTimeout())); } protected static boolean canTeleport(CommandSender sender, Player player, String targetName) { @@ -245,7 +244,7 @@ public class PtpCommand implements TabExecutor { McMMOPlayer mcMMOPlayer = UserManager.getPlayer(teleportingPlayer); McMMOPlayer mcMMOTarget = UserManager.getPlayer(targetPlayer); - long warmup = Config.getInstance().getPTPCommandWarmup(); + long warmup = mcMMO.p.getGeneralConfig().getPTPCommandWarmup(); mcMMOPlayer.actualizeTeleportCommenceLocation(teleportingPlayer); diff --git a/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java b/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java index a65004417..267ebca4f 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.commands.player; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; @@ -36,12 +35,12 @@ public class InspectCommand implements TabExecutor { return true; } - if (Config.getInstance().getScoreboardsEnabled() + if (mcMMO.p.getGeneralConfig().getScoreboardsEnabled() && sender instanceof Player - && Config.getInstance().getInspectUseBoard()) { + && mcMMO.p.getGeneralConfig().getInspectUseBoard()) { ScoreboardManager.enablePlayerInspectScoreboard((Player) sender, profile); - if (!Config.getInstance().getInspectUseChat()) { + if (!mcMMO.p.getGeneralConfig().getInspectUseChat()) { return true; } } @@ -76,12 +75,12 @@ public class InspectCommand implements TabExecutor { return true; } - if (Config.getInstance().getScoreboardsEnabled() + if (mcMMO.p.getGeneralConfig().getScoreboardsEnabled() && sender instanceof Player - && Config.getInstance().getInspectUseBoard()) { + && mcMMO.p.getGeneralConfig().getInspectUseBoard()) { ScoreboardManager.enablePlayerInspectScoreboard((Player) sender, mcMMOPlayer); - if (!Config.getInstance().getInspectUseChat()) { + if (!mcMMO.p.getGeneralConfig().getInspectUseChat()) { return true; } } diff --git a/src/main/java/com/gmail/nossr50/commands/player/MccooldownCommand.java b/src/main/java/com/gmail/nossr50/commands/player/MccooldownCommand.java index 74011a39c..4475c984a 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/MccooldownCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/MccooldownCommand.java @@ -1,9 +1,9 @@ package com.gmail.nossr50.commands.player; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; @@ -30,10 +30,10 @@ public class MccooldownCommand implements TabExecutor { if (args.length == 0) { Player player = (Player) sender; - if (Config.getInstance().getScoreboardsEnabled() && Config.getInstance().getCooldownUseBoard()) { + if (mcMMO.p.getGeneralConfig().getScoreboardsEnabled() && mcMMO.p.getGeneralConfig().getCooldownUseBoard()) { ScoreboardManager.enablePlayerCooldownScoreboard(player); - if (!Config.getInstance().getCooldownUseChat()) { + if (!mcMMO.p.getGeneralConfig().getCooldownUseChat()) { return true; } } diff --git a/src/main/java/com/gmail/nossr50/commands/player/McrankCommand.java b/src/main/java/com/gmail/nossr50/commands/player/McrankCommand.java index 5a781cdfb..4958cbc54 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/McrankCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/McrankCommand.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.commands.player; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; @@ -91,7 +90,7 @@ public class McrankCommand implements TabExecutor { return; } - long cooldownMillis = Math.min(Config.getInstance().getDatabasePlayerCooldown(), 1750); + long cooldownMillis = Math.min(mcMMO.p.getGeneralConfig().getDatabasePlayerCooldown(), 1750); if (mcMMOPlayer.getDatabaseATS() + cooldownMillis > System.currentTimeMillis()) { sender.sendMessage(LocaleLoader.getString("Commands.Database.CooldownMS", getCDSeconds(mcMMOPlayer, cooldownMillis))); @@ -108,8 +107,8 @@ public class McrankCommand implements TabExecutor { mcMMOPlayer.actualizeDatabaseATS(); } - boolean useBoard = Config.getInstance().getScoreboardsEnabled() && (sender instanceof Player) && (Config.getInstance().getRankUseBoard()); - boolean useChat = !useBoard || Config.getInstance().getRankUseChat(); + boolean useBoard = mcMMO.p.getGeneralConfig().getScoreboardsEnabled() && (sender instanceof Player) && (mcMMO.p.getGeneralConfig().getRankUseBoard()); + boolean useChat = !useBoard || mcMMO.p.getGeneralConfig().getRankUseChat(); new McrankCommandAsyncTask(playerName, sender, useBoard, useChat).runTaskAsynchronously(mcMMO.p); } diff --git a/src/main/java/com/gmail/nossr50/commands/player/McstatsCommand.java b/src/main/java/com/gmail/nossr50/commands/player/McstatsCommand.java index 87025fac5..a9e8cf6e1 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/McstatsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/McstatsCommand.java @@ -1,7 +1,7 @@ package com.gmail.nossr50.commands.player; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; @@ -33,10 +33,10 @@ public class McstatsCommand implements TabExecutor { Player player = (Player) sender; - if (Config.getInstance().getStatsUseBoard() && Config.getInstance().getScoreboardsEnabled()) { + if (mcMMO.p.getGeneralConfig().getStatsUseBoard() && mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { ScoreboardManager.enablePlayerStatsScoreboard(player); - if (!Config.getInstance().getStatsUseChat()) { + if (!mcMMO.p.getGeneralConfig().getStatsUseChat()) { return true; } } @@ -48,7 +48,7 @@ public class McstatsCommand implements TabExecutor { CommandUtils.printCombatSkills(player); CommandUtils.printMiscSkills(player); - int powerLevelCap = Config.getInstance().getPowerLevelCap(); + int powerLevelCap = mcMMO.p.getGeneralConfig().getPowerLevelCap(); if (powerLevelCap != Integer.MAX_VALUE) { player.sendMessage(LocaleLoader.getString("Commands.PowerLevel.Capped", UserManager.getPlayer(player).getPowerLevel(), powerLevelCap)); diff --git a/src/main/java/com/gmail/nossr50/commands/player/MctopCommand.java b/src/main/java/com/gmail/nossr50/commands/player/MctopCommand.java index 63ed2726e..0ef35cd0f 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/MctopCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/MctopCommand.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.commands.player; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; @@ -86,7 +85,7 @@ public class MctopCommand implements TabExecutor { } McMMOPlayer mcMMOPlayer = UserManager.getPlayer(sender.getName()); - long cooldownMillis = Math.max(Config.getInstance().getDatabasePlayerCooldown(), 1750); + long cooldownMillis = Math.max(mcMMO.p.getGeneralConfig().getDatabasePlayerCooldown(), 1750); if (mcMMOPlayer.getDatabaseATS() + cooldownMillis > System.currentTimeMillis()) { double seconds = ((mcMMOPlayer.getDatabaseATS() + cooldownMillis) - System.currentTimeMillis()) / 1000.0D; @@ -112,8 +111,8 @@ public class MctopCommand implements TabExecutor { } private void display(int page, PrimarySkillType skill, CommandSender sender) { - boolean useBoard = (sender instanceof Player) && (Config.getInstance().getTopUseBoard()); - boolean useChat = !useBoard || Config.getInstance().getTopUseChat(); + boolean useBoard = (sender instanceof Player) && (mcMMO.p.getGeneralConfig().getTopUseBoard()); + boolean useChat = !useBoard || mcMMO.p.getGeneralConfig().getTopUseChat(); new MctopCommandAsyncTask(page, skill, sender, useBoard, useChat).runTaskAsynchronously(mcMMO.p); } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java index 9b6e8ea2f..bb963168f 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/AcrobaticsCommand.java @@ -69,7 +69,7 @@ public class AcrobaticsCommand extends SkillCommand { //Chance Stat Calculations rollChance = RandomChanceUtil.getRandomChanceExecutionChance(roll_rcs); graceChance = RandomChanceUtil.getRandomChanceExecutionChance(grace_rcs); - //damageThreshold = AdvancedConfig.getInstance().getRollDamageThreshold(); + //damageThreshold = mcMMO.p.getAdvancedConfig().getRollDamageThreshold(); String[] rollStrings = getAbilityDisplayValues(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, player, SubSkillType.ACROBATICS_ROLL); diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java index e550913fa..3f35a7e7e 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java @@ -1,11 +1,10 @@ package com.gmail.nossr50.commands.skills; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.child.FamilyTree; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.commands.CommandUtils; @@ -74,7 +73,7 @@ public abstract class SkillCommand implements TabExecutor { float skillValue = mcMMOPlayer.getSkillLevel(skill); //Send the players a few blank lines to make finding the top of the skill command easier - if (AdvancedConfig.getInstance().doesSkillCommandSendBlankLines()) + if (mcMMO.p.getAdvancedConfig().doesSkillCommandSendBlankLines()) for (int i = 0; i < 2; i++) { player.sendMessage(""); } @@ -106,13 +105,13 @@ public abstract class SkillCommand implements TabExecutor { //Link Header - if (Config.getInstance().getUrlLinksEnabled()) { + if (mcMMO.p.getGeneralConfig().getUrlLinksEnabled()) { player.sendMessage(LocaleLoader.getString("Overhaul.mcMMO.Header")); TextComponentFactory.sendPlayerUrlHeader(player); } - if (Config.getInstance().getScoreboardsEnabled() && Config.getInstance().getSkillUseBoard()) { + if (mcMMO.p.getGeneralConfig().getScoreboardsEnabled() && mcMMO.p.getGeneralConfig().getSkillUseBoard()) { ScoreboardManager.enablePlayerSkillScoreboard(player, skill); } @@ -226,8 +225,8 @@ public abstract class SkillCommand implements TabExecutor { protected String[] calculateLengthDisplayValues(Player player, float skillValue) { int maxLength = skill.getAbility().getMaxLength(); - int abilityLengthVar = AdvancedConfig.getInstance().getAbilityLength(); - int abilityLengthCap = AdvancedConfig.getInstance().getAbilityLengthCap(); + int abilityLengthVar = mcMMO.p.getAdvancedConfig().getAbilityLength(); + int abilityLengthCap = mcMMO.p.getAdvancedConfig().getAbilityLengthCap(); int length; @@ -268,7 +267,7 @@ public abstract class SkillCommand implements TabExecutor { } protected String getLimitBreakDescriptionParameter() { - if(AdvancedConfig.getInstance().canApplyLimitBreakPVE()) { + if(mcMMO.p.getAdvancedConfig().canApplyLimitBreakPVE()) { return "(PVP/PVE)"; } else { return "(PVP)"; diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java index 69a5e86ec..83e0264c0 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SwordsCommand.java @@ -1,9 +1,9 @@ package com.gmail.nossr50.commands.skills; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.CombatUtils; @@ -46,17 +46,17 @@ public class SwordsCommand extends SkillCommand { // SWORDS_RUPTURE if (canRupture) { int ruptureRank = RankUtils.getRank(player, SubSkillType.SWORDS_RUPTURE); - ruptureLengthSecondsAgainstPlayers = String.valueOf(AdvancedConfig.getInstance().getRuptureDurationSeconds(true)); - ruptureLengthSecondsAgainstMobs = String.valueOf(AdvancedConfig.getInstance().getRuptureDurationSeconds(false)); + ruptureLengthSecondsAgainstPlayers = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureDurationSeconds(true)); + ruptureLengthSecondsAgainstMobs = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureDurationSeconds(false)); - rupturePureTickDamageAgainstPlayers = String.valueOf(AdvancedConfig.getInstance().getRuptureTickDamage(true, ruptureRank)); - rupturePureTickDamageAgainstMobs = String.valueOf(AdvancedConfig.getInstance().getRuptureTickDamage(false, ruptureRank)); + rupturePureTickDamageAgainstPlayers = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureTickDamage(true, ruptureRank)); + rupturePureTickDamageAgainstMobs = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureTickDamage(false, ruptureRank)); - ruptureExplosionDamageAgainstPlayers = String.valueOf(AdvancedConfig.getInstance().getRuptureExplosionDamage(true, ruptureRank)); - ruptureExplosionDamageAgainstMobs = String.valueOf(AdvancedConfig.getInstance().getRuptureExplosionDamage(false, ruptureRank)); + ruptureExplosionDamageAgainstPlayers = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureExplosionDamage(true, ruptureRank)); + ruptureExplosionDamageAgainstMobs = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureExplosionDamage(false, ruptureRank)); - ruptureChanceToApply = String.valueOf(AdvancedConfig.getInstance().getRuptureChanceToApplyOnHit(ruptureRank) + "%"); - ruptureChanceToApplyLucky = String.valueOf(AdvancedConfig.getInstance().getRuptureChanceToApplyOnHit(ruptureRank) * 1.33); + ruptureChanceToApply = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(ruptureRank) + "%"); + ruptureChanceToApplyLucky = String.valueOf(mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(ruptureRank) * 1.33); } // SERRATED STRIKES diff --git a/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java b/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java index 7e6f8e8a3..fd2736190 100644 --- a/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java +++ b/src/main/java/com/gmail/nossr50/config/AdvancedConfig.java @@ -6,25 +6,17 @@ import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.mcMMO; import net.md_5.bungee.api.ChatColor; +import java.io.File; import java.util.ArrayList; import java.util.List; public class AdvancedConfig extends AutoUpdateConfigLoader { - private static AdvancedConfig instance; - private AdvancedConfig() { - super("advanced.yml"); + public AdvancedConfig(File dataFolder) { + super("advanced.yml", dataFolder); validate(); } - public static AdvancedConfig getInstance() { - if (instance == null) { - instance = new AdvancedConfig(); - } - - return instance; - } - @Override protected boolean validateKeys() { // Validate all the settings! @@ -68,15 +60,6 @@ public class AdvancedConfig extends AutoUpdateConfigLoader { reason.add("Skills.Acrobatics.GracefulRoll.DamageThreshold should be at least 0!"); } - /* ALCHEMY */ - /*if (getCatalysisUnlockLevel() < 0) { - reason.add("Skills.Alchemy.Catalysis.UnlockLevel should be at least 0!"); - } - - if (getCatalysisMaxBonusLevel() <= getCatalysisUnlockLevel()) { - reason.add("Skills.Alchemy.Catalysis.MaxBonusLevel should be greater than Skills.Alchemy.Catalysis.UnlockLevel!"); - }*/ - if (getCatalysisMinSpeed() <= 0) { reason.add("Skills.Alchemy.Catalysis.MinSpeed must be greater than 0!"); } @@ -85,21 +68,6 @@ public class AdvancedConfig extends AutoUpdateConfigLoader { reason.add("Skills.Alchemy.Catalysis.MaxSpeed should be at least Skills.Alchemy.Catalysis.MinSpeed!"); } - /*List alchemyTierList = Arrays.asList(Alchemy.Tier.values()); - for (Alchemy.Tier tier : alchemyTierList) { - if (getConcoctionsTierLevel(tier) < 0) { - reason.add("Skills.Alchemy.Rank_Levels.Rank_" + rank + " should be at least 0!"); - } - - if (tier != Alchemy.Tier.fromNumerical(Alchemy.Tier.values().length)) { - Alchemy.Tier nextTier = alchemyTierList.get(alchemyTierList.indexOf(tier) - 1); - - if (getConcoctionsTierLevel(tier) > getConcoctionsTierLevel(nextTier)) { - reason.add("Skills.Alchemy.Rank_Levels.Rank_" + rank + " should be less than or equal to Skills.Alchemy.Rank_Levels.Rank_" + nextrank + "!"); - } - } - }*/ - /* ARCHERY */ if (getSkillShotRankDamageMultiplier() <= 0) { diff --git a/src/main/java/com/gmail/nossr50/config/AutoUpdateConfigLoader.java b/src/main/java/com/gmail/nossr50/config/AutoUpdateConfigLoader.java index 831dcf144..30fa038cb 100644 --- a/src/main/java/com/gmail/nossr50/config/AutoUpdateConfigLoader.java +++ b/src/main/java/com/gmail/nossr50/config/AutoUpdateConfigLoader.java @@ -11,10 +11,20 @@ import java.util.LinkedHashMap; import java.util.Set; public abstract class AutoUpdateConfigLoader extends ConfigLoader { + public AutoUpdateConfigLoader(String relativePath, String fileName, File dataFolder) { + super(relativePath, fileName, dataFolder); + } + + public AutoUpdateConfigLoader(String fileName, File dataFolder) { + super(fileName, dataFolder); + } + + @Deprecated public AutoUpdateConfigLoader(String relativePath, String fileName) { super(relativePath, fileName); } + @Deprecated public AutoUpdateConfigLoader(String fileName) { super(fileName); } @@ -136,7 +146,7 @@ public abstract class AutoUpdateConfigLoader extends ConfigLoader { saveName += ".new"; } - BufferedWriter writer = new BufferedWriter(new FileWriter(new File(plugin.getDataFolder(), saveName))); + BufferedWriter writer = new BufferedWriter(new FileWriter(new File(dataFolder, saveName))); writer.write(output); writer.flush(); writer.close(); diff --git a/src/main/java/com/gmail/nossr50/config/ConfigLoader.java b/src/main/java/com/gmail/nossr50/config/ConfigLoader.java index 7fb7f19d1..4a168fa50 100644 --- a/src/main/java/com/gmail/nossr50/config/ConfigLoader.java +++ b/src/main/java/com/gmail/nossr50/config/ConfigLoader.java @@ -3,6 +3,7 @@ package com.gmail.nossr50.config; import com.gmail.nossr50.mcMMO; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; +import org.jetbrains.annotations.NotNull; import java.io.File; import java.util.List; @@ -12,16 +13,33 @@ public abstract class ConfigLoader { protected String fileName; protected final File configFile; protected FileConfiguration config; + protected @NotNull File dataFolder; - public ConfigLoader(String relativePath, String fileName) { + public ConfigLoader(String relativePath, String fileName, @NotNull File dataFolder) { this.fileName = fileName; - configFile = new File(plugin.getDataFolder(), relativePath + File.separator + fileName); + this.dataFolder = dataFolder; + configFile = new File(dataFolder, relativePath + File.separator + fileName); loadFile(); } + public ConfigLoader(String fileName, @NotNull File dataFolder) { + this.fileName = fileName; + this.dataFolder = dataFolder; + configFile = new File(dataFolder, fileName); + loadFile(); + } + + @Deprecated + public ConfigLoader(String relativePath, String fileName) { + this.fileName = fileName; + configFile = new File(mcMMO.p.getDataFolder(), relativePath + File.separator + fileName); + loadFile(); + } + + @Deprecated public ConfigLoader(String fileName) { this.fileName = fileName; - configFile = new File(plugin.getDataFolder(), fileName); + configFile = new File(mcMMO.p.getDataFolder(), fileName); loadFile(); } diff --git a/src/main/java/com/gmail/nossr50/config/Config.java b/src/main/java/com/gmail/nossr50/config/GeneralConfig.java similarity index 89% rename from src/main/java/com/gmail/nossr50/config/Config.java rename to src/main/java/com/gmail/nossr50/config/GeneralConfig.java index 18c87f528..e905a3ce1 100644 --- a/src/main/java/com/gmail/nossr50/config/Config.java +++ b/src/main/java/com/gmail/nossr50/config/GeneralConfig.java @@ -12,27 +12,19 @@ import org.bukkit.configuration.ConfigurationSection; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Set; -public class Config extends AutoUpdateConfigLoader { - private static Config instance; +public class GeneralConfig extends AutoUpdateConfigLoader { - private Config() { - super("config.yml"); + public GeneralConfig(@NotNull File dataFolder) { + super("config.yml", dataFolder); validate(); } - public static Config getInstance() { - if (instance == null) { - instance = new Config(); - } - - return instance; - } - @Override protected void loadKeys() { @@ -63,47 +55,6 @@ public class Config extends AutoUpdateConfigLoader { reason.add("Mob_Healthbar.Display_Time cannot be 0! Set to -1 to disable or set a valid value."); } - /* Scoreboards */ - /*if (getRankScoreboardTime() != -1 && getRankScoreboardTime() <= 0) { - reason.add("Scoreboard.Types.Rank.Display_Time should be greater than 0, or -1!"); - } - - if (getStatsScoreboardTime() != -1 && getStatsScoreboardTime() <= 0) { - reason.add("Scoreboard.Types.Stats.Display_Time should be greater than 0, or -1!"); - } - - if (getTopScoreboardTime() != -1 && getTopScoreboardTime() <= 0) { - reason.add("Scoreboard.Types.Top.Display_Time should be greater than 0, or -1!"); - } - - if (getInspectScoreboardTime() != -1 && getInspectScoreboardTime() <= 0) { - reason.add("Scoreboard.Types.Inspect.Display_Time should be greater than 0, or -1!"); - } - - if (getSkillScoreboardTime() != -1 && getSkillScoreboardTime() <= 0) { - reason.add("Scoreboard.Types.Skill.Display_Time should be greater than 0, or -1!"); - } - - if (getSkillLevelUpTime() != -1 && getSkillScoreboardTime() <= 0) { - reason.add("Scoreboard.Types.Skill.Display_Time should be greater than 0, or -1!"); - } - - if (!(getRankUseChat() || getRankUseBoard())) { - reason.add("Either Board or Print in Scoreboard.Types.Rank must be true!"); - } - - if (!(getTopUseChat() || getTopUseBoard())) { - reason.add("Either Board or Print in Scoreboard.Types.Top must be true!"); - } - - if (!(getStatsUseChat() || getStatsUseBoard())) { - reason.add("Either Board or Print in Scoreboard.Types.Stats must be true!"); - } - - if (!(getInspectUseChat() || getInspectUseBoard())) { - reason.add("Either Board or Print in Scoreboard.Types.Inspect must be true!"); - }*/ - /* Database Purging */ if (getPurgeInterval() < -1) { reason.add("Database_Purging.Purge_Interval should be greater than, or equal to -1!"); @@ -200,42 +151,6 @@ public class Config extends AutoUpdateConfigLoader { reason.add("Cannot use the same item for Repair and Salvage anvils!"); } -// if (getTamingCOTWMaterial(EntityType.WOLF) == null) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Item_Material is invalid!!"); -// } -// -// if (getTamingCOTWMaterial(EntityType.OCELOT) == null) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Item_Material is invalid!!"); -// } -// -// if (getTamingCOTWMaterial(EntityType.HORSE) == null) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Item_Material is invalid!!"); -// } -// -// if (getTamingCOTWCost(EntityType.WOLF) <= 0) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Item_Amount should be greater than 0!"); -// } -// -// if (getTamingCOTWCost(EntityType.OCELOT) <= 0) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Item_Amount should be greater than 0!"); -// } -// -// if (getTamingCOTWCost(EntityType.HORSE) <= 0) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Item_Amount should be greater than 0!"); -// } -// -// if (getTamingCOTWAmount(EntityType.WOLF) <= 0) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Wolf.Summon_Amount should be greater than 0!"); -// } -// -// if (getTamingCOTWAmount(EntityType.OCELOT) <= 0) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Ocelot.Summon_Amount should be greater than 0!"); -// } -// -// if (getTamingCOTWAmount(EntityType.HORSE) <= 0) { -// reason.add("Skills.Taming.Call_Of_The_Wild.Horse.Summon_Amount should be greater than 0!"); -// } - return noErrorsInConfig(reason); } diff --git a/src/main/java/com/gmail/nossr50/config/RankConfig.java b/src/main/java/com/gmail/nossr50/config/RankConfig.java index 2fa1a353e..9bdf00947 100644 --- a/src/main/java/com/gmail/nossr50/config/RankConfig.java +++ b/src/main/java/com/gmail/nossr50/config/RankConfig.java @@ -2,6 +2,7 @@ package com.gmail.nossr50.config; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; +import com.gmail.nossr50.mcMMO; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -88,7 +89,7 @@ public class RankConfig extends AutoUpdateConfigLoader { * @return the level requirement for a subskill at this particular rank */ private int findRankByRootAddress(int rank, String key) { - String scalingKey = Config.getInstance().getIsRetroMode() ? ".RetroMode." : ".Standard."; + String scalingKey = mcMMO.p.getGeneralConfig().getIsRetroMode() ? ".RetroMode." : ".Standard."; String targetRank = "Rank_" + rank; diff --git a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java index 7b6fc41cd..47baafe63 100644 --- a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.database; import com.gmail.nossr50.api.exceptions.InvalidSkillException; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.database.DatabaseType; import com.gmail.nossr50.datatypes.database.PlayerStat; import com.gmail.nossr50.datatypes.player.PlayerProfile; @@ -15,15 +14,13 @@ import java.util.Map; import java.util.UUID; public interface DatabaseManager { - // One month in milliseconds - long PURGE_TIME = 2630000000L * Config.getInstance().getOldUsersCutoff(); // During convertUsers, how often to output a status int progressInterval = 200; /** * Purge users with 0 power level from the database. */ - void purgePowerlessUsers(); + int purgePowerlessUsers(); /** * Purge users who haven't logged on in over a certain time frame from the database. @@ -76,6 +73,8 @@ public interface DatabaseManager { */ Map readRank(String playerName); + default void init() {}; + /** * Add a new user to the database. * diff --git a/src/main/java/com/gmail/nossr50/database/DatabaseManagerFactory.java b/src/main/java/com/gmail/nossr50/database/DatabaseManagerFactory.java index b6981403b..1e30c6819 100644 --- a/src/main/java/com/gmail/nossr50/database/DatabaseManagerFactory.java +++ b/src/main/java/com/gmail/nossr50/database/DatabaseManagerFactory.java @@ -1,13 +1,16 @@ package com.gmail.nossr50.database; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.database.DatabaseType; import com.gmail.nossr50.mcMMO; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.logging.Logger; public class DatabaseManagerFactory { private static Class customManager = null; - public static DatabaseManager getDatabaseManager() { + public static DatabaseManager getDatabaseManager(@NotNull String userFilePath, @NotNull Logger logger, long purgeTime, int startingLevel) { if (customManager != null) { try { return createDefaultCustomDatabaseManager(); @@ -20,10 +23,10 @@ public class DatabaseManagerFactory { mcMMO.p.debug("Failed to create custom database manager"); e.printStackTrace(); } - mcMMO.p.debug("Falling back on " + (Config.getInstance().getUseMySQL() ? "SQL" : "Flatfile") + " database"); + mcMMO.p.debug("Falling back on " + (mcMMO.p.getGeneralConfig().getUseMySQL() ? "SQL" : "Flatfile") + " database"); } - return Config.getInstance().getUseMySQL() ? new SQLDatabaseManager() : new FlatFileDatabaseManager(); + return mcMMO.p.getGeneralConfig().getUseMySQL() ? new SQLDatabaseManager() : new FlatFileDatabaseManager(userFilePath, logger, purgeTime, startingLevel); } /** @@ -56,11 +59,11 @@ public class DatabaseManagerFactory { return customManager; } - public static DatabaseManager createDatabaseManager(DatabaseType type) { + public static @Nullable DatabaseManager createDatabaseManager(@NotNull DatabaseType type, @NotNull String userFilePath, @NotNull Logger logger, long purgeTime, int startingLevel) { switch (type) { case FLATFILE: mcMMO.p.getLogger().info("Using FlatFile Database"); - return new FlatFileDatabaseManager(); + return new FlatFileDatabaseManager(userFilePath, logger, purgeTime, startingLevel); case SQL: mcMMO.p.getLogger().info("Using SQL Database"); @@ -80,7 +83,7 @@ public class DatabaseManagerFactory { } } - public static DatabaseManager createDefaultCustomDatabaseManager() throws Throwable { + private static DatabaseManager createDefaultCustomDatabaseManager() throws Throwable { return customManager.getConstructor().newInstance(); } diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index ca2c78681..863d4f8f5 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -1,15 +1,13 @@ package com.gmail.nossr50.database; import com.gmail.nossr50.api.exceptions.InvalidSkillException; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; -import com.gmail.nossr50.datatypes.MobHealthbarType; 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.player.UniqueDataType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; +import com.gmail.nossr50.datatypes.skills.interfaces.Skill; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; import org.bukkit.OfflinePlayer; @@ -19,14 +17,20 @@ import org.jetbrains.annotations.Nullable; import java.io.*; import java.util.*; +import java.util.logging.Logger; public final class FlatFileDatabaseManager implements DatabaseManager { - private final HashMap> playerStatHash = new HashMap<>(); - private final List powerLevels = new ArrayList<>(); + public static final String IGNORED = "IGNORED"; + private final @NotNull HashMap> playerStatHash = new HashMap<>(); + private final @NotNull List powerLevels = new ArrayList<>(); private long lastUpdate = 0; + private final @NotNull String usersFilePath; + private final @NotNull Logger logger; + private final long purgeTime; + private final int startingLevel; private final long UPDATE_WAIT_TIME = 600000L; // 10 minutes - private final File usersFile; + private final @NotNull File usersFile; private static final Object fileWritingLock = new Object(); public static int USERNAME_INDEX = 0; @@ -72,20 +76,26 @@ 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() { - usersFile = new File(mcMMO.getUsersFilePath()); + protected FlatFileDatabaseManager(@NotNull String usersFilePath, @NotNull Logger logger, long purgeTime, int startingLevel) { + usersFile = new File(usersFilePath); + this.usersFilePath = usersFilePath; + this.logger = logger; + this.purgeTime = purgeTime; + this.startingLevel = startingLevel; + } + + public void init() { checkStructure(); updateLeaderboards(); } - public void purgePowerlessUsers() { + public int purgePowerlessUsers() { int purgedUsers = 0; - mcMMO.p.getLogger().info("Purging powerless users..."); + logger.info("Purging powerless users..."); BufferedReader in = null; FileWriter out = null; - String usersFilePath = mcMMO.getUsersFilePath(); // This code is O(n) instead of O(n²) synchronized (fileWritingLock) { @@ -96,7 +106,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { while ((line = in.readLine()) != null) { String[] character = line.split(":"); - Map skills = getSkillMapFromLine(character); + Map skills = getSkillMapFromLine(character); boolean powerless = true; for (int skill : skills.values()) { @@ -120,7 +130,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { out.write(writer.toString()); } catch (IOException e) { - mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString()); + logger.severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e); } finally { if (in != null) { @@ -142,18 +152,18 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - mcMMO.p.getLogger().info("Purged " + purgedUsers + " users from the database."); + logger.info("Purged " + purgedUsers + " users from the database."); + return purgedUsers; } public void purgeOldUsers() { int removedPlayers = 0; long currentTime = System.currentTimeMillis(); - mcMMO.p.getLogger().info("Purging old users..."); + logger.info("Purging old users..."); BufferedReader in = null; FileWriter out = null; - String usersFilePath = mcMMO.getUsersFilePath(); // This code is O(n) instead of O(n²) synchronized (fileWritingLock) { @@ -179,7 +189,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { rewrite = true; } - if (currentTime - lastPlayed > PURGE_TIME) { + if (currentTime - lastPlayed > purgeTime) { removedPlayers++; } else { @@ -200,7 +210,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { out.write(writer.toString()); } catch (IOException e) { - mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString()); + logger.severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e); } finally { if (in != null) { @@ -222,7 +232,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - mcMMO.p.getLogger().info("Purged " + removedPlayers + " users from the database."); + logger.info("Purged " + removedPlayers + " users from the database."); } public boolean removeUser(String playerName, UUID uuid) { @@ -231,7 +241,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { BufferedReader in = null; FileWriter out = null; - String usersFilePath = mcMMO.getUsersFilePath(); synchronized (fileWritingLock) { try { @@ -242,7 +251,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_INDEX].equalsIgnoreCase(playerName)) { - mcMMO.p.getLogger().info("User found, removing..."); + logger.info("User found, removing..."); worked = true; continue; // Skip the player } @@ -254,7 +263,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { out.write(writer.toString()); } catch (Exception e) { - mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString()); + logger.severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e); } finally { if (in != null) { @@ -286,13 +295,12 @@ public final class FlatFileDatabaseManager implements DatabaseManager { //Not used in FlatFile } - public boolean saveUser(PlayerProfile profile) { + public boolean saveUser(@NotNull PlayerProfile profile) { String playerName = profile.getPlayerName(); UUID uuid = profile.getUniqueId(); BufferedReader in = null; FileWriter out = null; - String usersFilePath = mcMMO.getUsersFilePath(); boolean corruptDataFound = false; synchronized (fileWritingLock) { @@ -309,7 +317,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { if(!line.contains(":")) { if(!corruptDataFound) { - mcMMO.p.getLogger().severe("mcMMO found some unexpected or corrupted data in mcmmo.users and is removing it, it is possible some data has been lost."); + logger.severe("mcMMO found some unexpected or corrupted data in mcmmo.users and is removing it, it is possible some data has been lost."); corruptDataFound = true; } @@ -318,12 +326,11 @@ public final class FlatFileDatabaseManager implements DatabaseManager { String[] splitData = line.split(":"); - //This would be rare, but check the splitData for having enough entries to contain a username - if(splitData.length < 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 + //This would be rare, but check the splitData for having enough entries to contain a UUID + if(splitData.length < UUID_INDEX) { //UUID have been in mcMMO DB for a very long time so any user without if(!corruptDataFound) { - mcMMO.p.getLogger().severe("mcMMO found some unexpected or corrupted data in mcmmo.users and is removing it, it is possible some data has been lost."); + logger.severe("mcMMO found some unexpected or corrupted data in mcmmo.users and is removing it, it is possible some data has been lost."); corruptDataFound = true; } @@ -378,7 +385,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - private void writeUserToLine(PlayerProfile profile, String playerName, @Nullable UUID uuid, StringBuilder writer) { + private void writeUserToLine(PlayerProfile profile, @NotNull String playerName, @Nullable UUID uuid, StringBuilder writer) { writer.append(playerName).append(":"); writer.append(profile.getSkillLevel(PrimarySkillType.MINING)).append(":"); writer.append(":"); @@ -417,8 +424,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { writer.append(profile.getSkillXpLevel(PrimarySkillType.FISHING)).append(":"); writer.append((int) profile.getAbilityDATS(SuperAbilityType.BLAST_MINING)).append(":"); writer.append(System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR).append(":"); - MobHealthbarType mobHealthbarType = profile.getMobHealthbarType(); - writer.append(mobHealthbarType == null ? Config.getInstance().getMobHealthbarDefault().toString() : mobHealthbarType.toString()).append(":"); + writer.append(IGNORED).append(":"); //mob health bar writer.append(profile.getSkillLevel(PrimarySkillType.ALCHEMY)).append(":"); writer.append(profile.getSkillXpLevel(PrimarySkillType.ALCHEMY)).append(":"); writer.append(uuid != null ? uuid.toString() : "NULL").append(":"); @@ -430,7 +436,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { public @NotNull List readLeaderboard(@Nullable PrimarySkillType skill, int pageNumber, int statsPerPage) throws InvalidSkillException { //Fix for a plugin that people are using that is throwing SQL errors if(skill != null && skill.isChildSkill()) { - mcMMO.p.getLogger().severe("A plugin hooking into mcMMO is being naughty with our database commands, update all plugins that hook into mcMMO and contact their devs!"); + logger.severe("A plugin hooking into mcMMO is being naughty with our database commands, update all plugins that hook into mcMMO and contact their devs!"); throw new InvalidSkillException("A plugin hooking into mcMMO that you are using is attempting to read leaderboard skills for child skills, child skills do not have leaderboards! This is NOT an mcMMO error!"); } @@ -465,26 +471,26 @@ public final class FlatFileDatabaseManager implements DatabaseManager { synchronized (fileWritingLock) { try { // Open the file to write the player - out = new BufferedWriter(new FileWriter(mcMMO.getUsersFilePath(), true)); + out = new BufferedWriter(new FileWriter(usersFilePath, true)); - String startingLevel = AdvancedConfig.getInstance().getStartingLevel() + ":"; + String startingLevelStr = startingLevel + ":"; // Add the player to the end out.append(playerName).append(":"); - out.append(startingLevel); // Mining + out.append(startingLevelStr); // Mining out.append(":"); out.append(":"); out.append("0:"); // Xp - out.append(startingLevel); // Woodcutting + out.append(startingLevelStr); // Woodcutting out.append("0:"); // WoodCuttingXp - out.append(startingLevel); // Repair - out.append(startingLevel); // Unarmed - out.append(startingLevel); // Herbalism - out.append(startingLevel); // Excavation - out.append(startingLevel); // Archery - out.append(startingLevel); // Swords - out.append(startingLevel); // Axes - out.append(startingLevel); // Acrobatics + out.append(startingLevelStr); // Repair + out.append(startingLevelStr); // Unarmed + out.append(startingLevelStr); // Herbalism + out.append(startingLevelStr); // Excavation + out.append(startingLevelStr); // Archery + out.append(startingLevelStr); // Swords + out.append(startingLevelStr); // Axes + out.append(startingLevelStr); // Acrobatics out.append("0:"); // RepairXp out.append("0:"); // UnarmedXp out.append("0:"); // HerbalismXp @@ -494,7 +500,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { out.append("0:"); // AxesXp out.append("0:"); // AcrobaticsXp out.append(":"); - out.append(startingLevel); // Taming + out.append(startingLevelStr); // Taming out.append("0:"); // TamingXp out.append("0:"); // DATS out.append("0:"); // DATS @@ -504,12 +510,12 @@ public final class FlatFileDatabaseManager implements DatabaseManager { out.append("0:"); // DATS out.append("0:"); // DATS out.append(":"); - out.append(startingLevel); // Fishing + out.append(startingLevelStr); // Fishing out.append("0:"); // FishingXp out.append("0:"); // Blast Mining out.append(String.valueOf(System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR)).append(":"); // LastLogin - out.append(Config.getInstance().getMobHealthbarDefault().toString()).append(":"); // Mob Healthbar HUD - out.append(startingLevel); // Alchemy + out.append(IGNORED).append(":"); // Mob Healthbar HUD + out.append(startingLevelStr); // Alchemy out.append("0:"); // AlchemyXp out.append(uuid != null ? uuid.toString() : "NULL").append(":"); // UUID out.append("0:"); // Scoreboard tips shown @@ -543,7 +549,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { private @NotNull PlayerProfile loadPlayerByUUID(@NotNull UUID uuid, @Nullable String playerName) { BufferedReader in = null; - String usersFilePath = mcMMO.getUsersFilePath(); synchronized (fileWritingLock) { try { @@ -580,7 +585,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { /* Check for nickname changes and update since we are here anyways */ if (!rawSplitData[USERNAME_INDEX].equalsIgnoreCase(playerName)) { - //mcMMO.p.getLogger().info("Name updated for player: " + rawSplitData[USERNAME_INDEX] + " => " + playerName); + //logger.info("Name updated for player: " + rawSplitData[USERNAME_INDEX] + " => " + playerName); rawSplitData[USERNAME_INDEX] = playerName; } @@ -610,7 +615,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { private @NotNull PlayerProfile loadPlayerByName(@NotNull String playerName) { BufferedReader in = null; - String usersFilePath = mcMMO.getUsersFilePath(); synchronized (fileWritingLock) { try { @@ -661,7 +665,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { public void convertUsers(DatabaseManager destination) { BufferedReader in = null; - String usersFilePath = mcMMO.getUsersFilePath(); int convertedUsers = 0; long startMillis = System.currentTimeMillis(); @@ -706,7 +709,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { int i = 0; BufferedReader in = null; FileWriter out = null; - String usersFilePath = mcMMO.getUsersFilePath(); synchronized (fileWritingLock) { try { @@ -718,8 +720,8 @@ public final class FlatFileDatabaseManager implements DatabaseManager { String[] character = line.split(":"); if (!worked && character[USERNAME_INDEX].equalsIgnoreCase(userName)) { if (character.length < 42) { - mcMMO.p.getLogger().severe("Could not update UUID for " + userName + "!"); - mcMMO.p.getLogger().severe("Database entry is invalid."); + logger.severe("Could not update UUID for " + userName + "!"); + logger.severe("Database entry is invalid."); continue; } @@ -735,10 +737,10 @@ public final class FlatFileDatabaseManager implements DatabaseManager { out.write(writer.toString()); } catch (Exception e) { - mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString()); + logger.severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e); } finally { - mcMMO.p.getLogger().info(i + " entries written while saving UUID for " + userName); + logger.info(i + " entries written while saving UUID for " + userName); if (in != null) { try { in.close(); @@ -764,7 +766,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { public boolean saveUserUUIDs(Map fetchedUUIDs) { BufferedReader in = null; FileWriter out = null; - String usersFilePath = mcMMO.getUsersFilePath(); int i = 0; synchronized (fileWritingLock) { @@ -777,8 +778,8 @@ public final class FlatFileDatabaseManager implements DatabaseManager { String[] character = line.split(":"); if (!fetchedUUIDs.isEmpty() && fetchedUUIDs.containsKey(character[USERNAME_INDEX])) { if (character.length < 42) { - mcMMO.p.getLogger().severe("Could not update UUID for " + character[USERNAME_INDEX] + "!"); - mcMMO.p.getLogger().severe("Database entry is invalid."); + logger.severe("Could not update UUID for " + character[USERNAME_INDEX] + "!"); + logger.severe("Database entry is invalid."); continue; } @@ -794,10 +795,10 @@ public final class FlatFileDatabaseManager implements DatabaseManager { out.write(writer.toString()); } catch (Exception e) { - mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString()); + logger.severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e); } finally { - mcMMO.p.getLogger().info(i + " entries written while saving UUID batch"); + logger.info(i + " entries written while saving UUID batch"); if (in != null) { try { in.close(); @@ -823,7 +824,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { public List getStoredUsers() { ArrayList users = new ArrayList<>(); BufferedReader in = null; - String usersFilePath = mcMMO.getUsersFilePath(); synchronized (fileWritingLock) { try { @@ -862,7 +862,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { return; } - String usersFilePath = mcMMO.getUsersFilePath(); lastUpdate = System.currentTimeMillis(); // Log when the last update was run powerLevels.clear(); // Clear old values from the power levels @@ -894,7 +893,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { playerName = data[USERNAME_INDEX]; int powerLevel = 0; - Map skills = getSkillMapFromLine(data); + Map skills = getSkillMapFromLine(data); powerLevel += putStat(acrobatics, playerName, skills.get(PrimarySkillType.ACROBATICS)); powerLevel += putStat(alchemy, playerName, skills.get(PrimarySkillType.ALCHEMY)); @@ -914,7 +913,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } catch (Exception e) { - mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " during user " + playerName + " (Are you sure you formatted it correctly?) " + e.toString()); + logger.severe("Exception while reading " + usersFilePath + " during user " + playerName + " (Are you sure you formatted it correctly?) " + e); } finally { if (in != null) { @@ -969,7 +968,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { if (usersFile.exists()) { BufferedReader in = null; FileWriter out = null; - String usersFilePath = mcMMO.getUsersFilePath(); synchronized (fileWritingLock) { try { @@ -996,14 +994,14 @@ 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("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."); + logger.severe("Some corrupt data was found in mcmmo.users and has been repaired, it is possible that some player data has been lost in this process."); corruptDataFound = true; } if(rawSplitData.length >= 10 //The value here is kind of arbitrary, it shouldn't be too low to avoid false positives, but also we aren't really going to correctly identify when player data has been corrupted or not with 100% accuracy ever && rawSplitData[0] != null && !rawSplitData[0].isEmpty()) { if(rawSplitData[0].length() <= 16 && rawSplitData[0].length() >= 3) { - mcMMO.p.getLogger().severe("Not enough data found to recover corrupted player data for user: "+rawSplitData[0]); + logger.severe("Not enough data found to recover corrupted player data for user: "+rawSplitData[0]); } } //This user may have had a name so declare it @@ -1016,7 +1014,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { //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"); + logger.severe("Fixing duplicate player names found in mcmmo.users"); continue; } } @@ -1026,8 +1024,8 @@ public final class FlatFileDatabaseManager implements DatabaseManager { && (!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); + logger.severe("Removing duplicate player data from mcmmo.users"); + logger.info("Duplicate Data: "+line); continue; } @@ -1049,7 +1047,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { out.write(writer.toString()); } catch (IOException e) { - mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString()); + logger.severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e); } finally { if (in != null) { @@ -1072,7 +1070,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } 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."); + logger.info("Corrupt data was found and removed, everything should be working fine. It is possible some player data was lost."); return; } @@ -1080,8 +1078,8 @@ public final class FlatFileDatabaseManager implements DatabaseManager { usersFile.getParentFile().mkdir(); try { - mcMMO.p.debug("Creating mcmmo.users file..."); - new File(mcMMO.getUsersFilePath()).createNewFile(); + logger.info("Creating mcmmo.users file..."); + new File(usersFilePath).createNewFile(); } catch (IOException e) { e.printStackTrace(); @@ -1119,11 +1117,10 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } private PlayerProfile loadFromLine(@NotNull String[] character) { - Map skills = getSkillMapFromLine(character); // Skill levels - Map skillsXp = new EnumMap<>(PrimarySkillType.class); // Skill & XP + Map skills = getSkillMapFromLine(character); // Skill levels + Map skillsXp = new HashMap<>(); // Skill & XP Map skillsDATS = new EnumMap<>(SuperAbilityType.class); // Ability & Cooldown Map uniquePlayerDataMap = new EnumMap<>(UniqueDataType.class); - MobHealthbarType mobHealthbarType; int scoreboardTipsShown; String username = character[USERNAME_INDEX]; @@ -1155,12 +1152,12 @@ public final class FlatFileDatabaseManager implements DatabaseManager { // Acrobatics - Unused tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.BLAST_MINING, COOLDOWN_BLAST_MINING, username); - try { - mobHealthbarType = MobHealthbarType.valueOf(character[HEALTHBAR]); - } - catch (Exception e) { - mobHealthbarType = Config.getInstance().getMobHealthbarDefault(); - } +// try { +// mobHealthbarType = MobHealthbarType.valueOf(character[HEALTHBAR]); +// } +// catch (Exception e) { +// mobHealthbarType = Config.getInstance().getMobHealthbarDefault(); +// } UUID uuid; try { @@ -1184,44 +1181,45 @@ public final class FlatFileDatabaseManager implements DatabaseManager { uniquePlayerDataMap.put(UniqueDataType.CHIMAERA_WING_DATS, 0); } - return new PlayerProfile(character[USERNAME_INDEX], uuid, skills, skillsXp, skillsDATS, mobHealthbarType, scoreboardTipsShown, uniquePlayerDataMap); + return new PlayerProfile(character[USERNAME_INDEX], uuid, skills, skillsXp, skillsDATS, null, scoreboardTipsShown, uniquePlayerDataMap); } private void tryLoadSkillCooldownFromRawData(@NotNull Map cooldownMap, @NotNull String[] character, @NotNull SuperAbilityType superAbilityType, int cooldownSuperBreaker, @NotNull String userName) { try { cooldownMap.put(superAbilityType, Integer.valueOf(character[cooldownSuperBreaker])); } catch (NumberFormatException e) { - mcMMO.p.getLogger().severe("Data corruption when trying to load the value for skill "+superAbilityType.toString()+" for player named " + userName+ " setting value to zero"); + logger.severe("Data corruption when trying to load the value for skill "+superAbilityType+" for player named " + userName+ " setting value to zero"); e.printStackTrace(); } } - private void tryLoadSkillFloatValuesFromRawData(@NotNull Map skillMap, @NotNull String[] character, @NotNull PrimarySkillType primarySkillType, int index, @NotNull String userName) { + private void tryLoadSkillFloatValuesFromRawData(@NotNull Map skillMap, @NotNull String[] character, @NotNull Skill primarySkillType, int index, @NotNull String userName) { try { float valueFromString = Integer.parseInt(character[index]); skillMap.put(primarySkillType, valueFromString); } catch (NumberFormatException e) { skillMap.put(primarySkillType, 0F); - mcMMO.p.getLogger().severe("Data corruption when trying to load the value for skill "+primarySkillType.toString()+" for player named " + userName+ " setting value to zero"); + logger.severe("Data corruption when trying to load the value for skill "+primarySkillType+" for player named " + userName+ " setting value to zero"); e.printStackTrace(); } } - private void tryLoadSkillIntValuesFromRawData(@NotNull Map skillMap, @NotNull String[] character, @NotNull PrimarySkillType primarySkillType, int index, @NotNull String userName) { + private void tryLoadSkillIntValuesFromRawData(@NotNull Map skillMap, @NotNull String[] character, @NotNull Skill skill, int index, @NotNull String userName) { try { int valueFromString = Integer.parseInt(character[index]); - skillMap.put(primarySkillType, valueFromString); + skillMap.put(skill, 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"); + skillMap.put(skill, 0); + logger.severe("Data corruption when trying to load the value for skill "+skill+" 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 + private @NotNull Map getSkillMapFromLine(@NotNull String[] character) { + HashMap skills = new HashMap<>(); // Skill & Level String username = character[USERNAME_INDEX]; + tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.ACROBATICS, SKILLS_ACROBATICS, username); tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.TAMING, SKILLS_TAMING, username); tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.MINING, SKILLS_MINING, username); tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.REPAIR, SKILLS_REPAIR, username); @@ -1232,7 +1230,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { 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); @@ -1243,93 +1240,10 @@ public final class FlatFileDatabaseManager implements DatabaseManager { return DatabaseType.FLATFILE; } + public File getUsersFile() { + return usersFile; + } + @Override public void onDisable() { } - - private int getSkillIndex(PrimarySkillType skill) { - switch (skill) { - case ACROBATICS: - return SKILLS_ACROBATICS; - case ALCHEMY: - return SKILLS_ALCHEMY; - case ARCHERY: - return SKILLS_ARCHERY; - case AXES: - return SKILLS_AXES; - case EXCAVATION: - return SKILLS_EXCAVATION; - case FISHING: - return SKILLS_FISHING; - case HERBALISM: - return SKILLS_HERBALISM; - case MINING: - return SKILLS_MINING; - case REPAIR: - return SKILLS_REPAIR; - case SWORDS: - return SKILLS_SWORDS; - case TAMING: - return SKILLS_TAMING; - case UNARMED: - return SKILLS_UNARMED; - case WOODCUTTING: - return SKILLS_WOODCUTTING; - default: - throw new RuntimeException("Primary Skills only"); - - } - } - - public void resetMobHealthSettings() { - BufferedReader in = null; - FileWriter out = null; - String usersFilePath = mcMMO.getUsersFilePath(); - - synchronized (fileWritingLock) { - try { - in = new BufferedReader(new FileReader(usersFilePath)); - StringBuilder writer = new StringBuilder(); - String line; - - while ((line = in.readLine()) != null) { - // Remove empty lines from the file - if (line.isEmpty()) { - continue; - } - String[] character = line.split(":"); - - character[HEALTHBAR] = Config.getInstance().getMobHealthbarDefault().toString(); - - line = org.apache.commons.lang.StringUtils.join(character, ":") + ":"; - - writer.append(line).append("\r\n"); - } - - // Write the new file - out = new FileWriter(usersFilePath); - out.write(writer.toString()); - } - catch (IOException e) { - mcMMO.p.getLogger().severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e.toString()); - } - finally { - if (in != null) { - try { - in.close(); - } - catch (IOException e) { - // Ignore - } - } - if (out != null) { - try { - out.close(); - } - catch (IOException e) { - // Ignore - } - } - } - } - } } diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index 05d621243..debd4d2ba 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -1,8 +1,6 @@ package com.gmail.nossr50.database; import com.gmail.nossr50.api.exceptions.InvalidSkillException; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.MobHealthbarType; import com.gmail.nossr50.datatypes.database.DatabaseType; import com.gmail.nossr50.datatypes.database.PlayerStat; @@ -11,6 +9,7 @@ import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.player.UniqueDataType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; +import com.gmail.nossr50.datatypes.skills.interfaces.Skill; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.database.UUIDUpdateAsyncTask; import com.gmail.nossr50.util.Misc; @@ -30,7 +29,7 @@ public final class SQLDatabaseManager implements DatabaseManager { public static final String MOBHEALTHBAR_VARCHAR = "VARCHAR(50)"; public static final String UUID_VARCHAR = "VARCHAR(36)"; public static final String USER_VARCHAR = "VARCHAR(40)"; - private final String tablePrefix = Config.getInstance().getMySQLTablePrefix(); + private final String tablePrefix = mcMMO.p.getGeneralConfig().getMySQLTablePrefix(); private final Map cachedUserIDs = new HashMap<>(); @@ -45,10 +44,10 @@ public final class SQLDatabaseManager implements DatabaseManager { 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() - + ":" + Config.getInstance().getMySQLServerPort() + "/" + Config.getInstance().getMySQLDatabaseName(); + String connectionString = "jdbc:mysql://" + mcMMO.p.getGeneralConfig().getMySQLServerName() + + ":" + mcMMO.p.getGeneralConfig().getMySQLServerPort() + "/" + mcMMO.p.getGeneralConfig().getMySQLDatabaseName(); - if(Config.getInstance().getMySQLSSL()) + if(mcMMO.p.getGeneralConfig().getMySQLSSL()) connectionString += "?verifyServerCertificate=false"+ "&useSSL=true"+ @@ -67,16 +66,15 @@ public final class SQLDatabaseManager implements DatabaseManager { //throw e; // aborts onEnable() Riking if you want to do this, fully implement it. } - debug = Config.getInstance().getMySQLDebug(); - + debug = mcMMO.p.getGeneralConfig().getMySQLDebug(); PoolProperties poolProperties = new PoolProperties(); poolProperties.setDriverClassName("com.mysql.jdbc.Driver"); poolProperties.setUrl(connectionString); - poolProperties.setUsername(Config.getInstance().getMySQLUserName()); - poolProperties.setPassword(Config.getInstance().getMySQLUserPassword()); - poolProperties.setMaxIdle(Config.getInstance().getMySQLMaxPoolSize(PoolIdentifier.MISC)); - poolProperties.setMaxActive(Config.getInstance().getMySQLMaxConnections(PoolIdentifier.MISC)); + poolProperties.setUsername(mcMMO.p.getGeneralConfig().getMySQLUserName()); + poolProperties.setPassword(mcMMO.p.getGeneralConfig().getMySQLUserPassword()); + poolProperties.setMaxIdle(mcMMO.p.getGeneralConfig().getMySQLMaxPoolSize(PoolIdentifier.MISC)); + poolProperties.setMaxActive(mcMMO.p.getGeneralConfig().getMySQLMaxConnections(PoolIdentifier.MISC)); poolProperties.setInitialSize(0); poolProperties.setMaxWait(-1); poolProperties.setRemoveAbandoned(true); @@ -88,11 +86,11 @@ public final class SQLDatabaseManager implements DatabaseManager { poolProperties = new PoolProperties(); poolProperties.setDriverClassName("com.mysql.jdbc.Driver"); poolProperties.setUrl(connectionString); - poolProperties.setUsername(Config.getInstance().getMySQLUserName()); - poolProperties.setPassword(Config.getInstance().getMySQLUserPassword()); + poolProperties.setUsername(mcMMO.p.getGeneralConfig().getMySQLUserName()); + poolProperties.setPassword(mcMMO.p.getGeneralConfig().getMySQLUserPassword()); poolProperties.setInitialSize(0); - poolProperties.setMaxIdle(Config.getInstance().getMySQLMaxPoolSize(PoolIdentifier.SAVE)); - poolProperties.setMaxActive(Config.getInstance().getMySQLMaxConnections(PoolIdentifier.SAVE)); + poolProperties.setMaxIdle(mcMMO.p.getGeneralConfig().getMySQLMaxPoolSize(PoolIdentifier.SAVE)); + poolProperties.setMaxActive(mcMMO.p.getGeneralConfig().getMySQLMaxConnections(PoolIdentifier.SAVE)); poolProperties.setMaxWait(-1); poolProperties.setRemoveAbandoned(true); poolProperties.setRemoveAbandonedTimeout(60); @@ -103,11 +101,11 @@ public final class SQLDatabaseManager implements DatabaseManager { poolProperties = new PoolProperties(); poolProperties.setDriverClassName("com.mysql.jdbc.Driver"); poolProperties.setUrl(connectionString); - poolProperties.setUsername(Config.getInstance().getMySQLUserName()); - poolProperties.setPassword(Config.getInstance().getMySQLUserPassword()); + poolProperties.setUsername(mcMMO.p.getGeneralConfig().getMySQLUserName()); + poolProperties.setPassword(mcMMO.p.getGeneralConfig().getMySQLUserPassword()); poolProperties.setInitialSize(0); - poolProperties.setMaxIdle(Config.getInstance().getMySQLMaxPoolSize(PoolIdentifier.LOAD)); - poolProperties.setMaxActive(Config.getInstance().getMySQLMaxConnections(PoolIdentifier.LOAD)); + poolProperties.setMaxIdle(mcMMO.p.getGeneralConfig().getMySQLMaxPoolSize(PoolIdentifier.LOAD)); + poolProperties.setMaxActive(mcMMO.p.getGeneralConfig().getMySQLMaxConnections(PoolIdentifier.LOAD)); poolProperties.setMaxWait(-1); poolProperties.setRemoveAbandoned(true); poolProperties.setRemoveAbandonedTimeout(60); @@ -115,11 +113,14 @@ public final class SQLDatabaseManager implements DatabaseManager { poolProperties.setValidationQuery("SELECT 1"); poolProperties.setValidationInterval(30000); loadPool = new DataSource(poolProperties); + } + @Override + public void init() { checkStructure(); } - public void purgePowerlessUsers() { + public int purgePowerlessUsers() { massUpdateLock.lock(); mcMMO.p.getLogger().info("Purging powerless users..."); @@ -152,11 +153,12 @@ public final class SQLDatabaseManager implements DatabaseManager { } mcMMO.p.getLogger().info("Purged " + purged + " users from the database."); + return purged; } public void purgeOldUsers() { massUpdateLock.lock(); - mcMMO.p.getLogger().info("Purging inactive users older than " + (PURGE_TIME / 2630000000L) + " months..."); + mcMMO.p.getLogger().info("Purging inactive users older than " + (mcMMO.p.getPurgeTime() / 2630000000L) + " months..."); Connection connection = null; Statement statement = null; @@ -171,7 +173,7 @@ public final class SQLDatabaseManager implements DatabaseManager { "JOIN " + tablePrefix + "huds h ON (u.id = h.user_id) " + "JOIN " + tablePrefix + "skills s ON (u.id = s.user_id) " + "JOIN " + tablePrefix + "cooldowns c ON (u.id = c.user_id) " + - "WHERE ((UNIX_TIMESTAMP() - lastlogin) > " + PURGE_TIME + ")"); + "WHERE ((UNIX_TIMESTAMP() - lastlogin) > " + mcMMO.p.getPurgeTime() + ")"); } catch (SQLException ex) { printErrors(ex); @@ -331,7 +333,7 @@ public final class SQLDatabaseManager implements DatabaseManager { } statement = connection.prepareStatement("UPDATE " + tablePrefix + "huds SET mobhealthbar = ?, scoreboardtips = ? WHERE user_id = ?"); - statement.setString(1, profile.getMobHealthbarType() == null ? Config.getInstance().getMobHealthbarDefault().name() : profile.getMobHealthbarType().name()); + statement.setString(1, profile.getMobHealthbarType() == null ? mcMMO.p.getGeneralConfig().getMobHealthbarDefault().name() : profile.getMobHealthbarType().name()); statement.setInt(2, profile.getScoreboardTipsShown()); statement.setInt(3, id); success = (statement.executeUpdate() != 0); @@ -818,7 +820,7 @@ public final class SQLDatabaseManager implements DatabaseManager { statement = connection.prepareStatement("SELECT table_name FROM INFORMATION_SCHEMA.TABLES" + " WHERE table_schema = ?" + " AND table_name = ?"); - statement.setString(1, Config.getInstance().getMySQLDatabaseName()); + statement.setString(1, mcMMO.p.getGeneralConfig().getMySQLDatabaseName()); statement.setString(2, tablePrefix + "users"); resultSet = statement.executeQuery(); if (!resultSet.next()) { @@ -834,21 +836,21 @@ public final class SQLDatabaseManager implements DatabaseManager { tryClose(createStatement); } tryClose(resultSet); - statement.setString(1, Config.getInstance().getMySQLDatabaseName()); + statement.setString(1, mcMMO.p.getGeneralConfig().getMySQLDatabaseName()); statement.setString(2, tablePrefix + "huds"); resultSet = statement.executeQuery(); if (!resultSet.next()) { createStatement = connection.createStatement(); createStatement.executeUpdate("CREATE TABLE IF NOT EXISTS `" + tablePrefix + "huds` (" + "`user_id` int(10) unsigned NOT NULL," - + "`mobhealthbar` varchar(50) NOT NULL DEFAULT '" + Config.getInstance().getMobHealthbarDefault() + "'," + + "`mobhealthbar` varchar(50) NOT NULL DEFAULT '" + mcMMO.p.getGeneralConfig().getMobHealthbarDefault() + "'," + "`scoreboardtips` int(10) NOT NULL DEFAULT '0'," + "PRIMARY KEY (`user_id`)) " + "DEFAULT CHARSET=" + CHARSET_SQL + ";"); tryClose(createStatement); } tryClose(resultSet); - statement.setString(1, Config.getInstance().getMySQLDatabaseName()); + statement.setString(1, mcMMO.p.getGeneralConfig().getMySQLDatabaseName()); statement.setString(2, tablePrefix + "cooldowns"); resultSet = statement.executeQuery(); if (!resultSet.next()) { @@ -873,12 +875,12 @@ public final class SQLDatabaseManager implements DatabaseManager { tryClose(createStatement); } tryClose(resultSet); - statement.setString(1, Config.getInstance().getMySQLDatabaseName()); + statement.setString(1, mcMMO.p.getGeneralConfig().getMySQLDatabaseName()); statement.setString(2, tablePrefix + "skills"); resultSet = statement.executeQuery(); if (!resultSet.next()) { - String startingLevel = "'" + AdvancedConfig.getInstance().getStartingLevel() + "'"; - String totalLevel = "'" + (AdvancedConfig.getInstance().getStartingLevel() * (PrimarySkillType.values().length - PrimarySkillType.CHILD_SKILLS.size())) + "'"; + String startingLevel = "'" + mcMMO.p.getAdvancedConfig().getStartingLevel() + "'"; + String totalLevel = "'" + (mcMMO.p.getAdvancedConfig().getStartingLevel() * (PrimarySkillType.values().length - PrimarySkillType.CHILD_SKILLS.size())) + "'"; createStatement = connection.createStatement(); createStatement.executeUpdate("CREATE TABLE IF NOT EXISTS `" + tablePrefix + "skills` (" + "`user_id` int(10) unsigned NOT NULL," @@ -901,7 +903,7 @@ public final class SQLDatabaseManager implements DatabaseManager { tryClose(createStatement); } tryClose(resultSet); - statement.setString(1, Config.getInstance().getMySQLDatabaseName()); + statement.setString(1, mcMMO.p.getGeneralConfig().getMySQLDatabaseName()); statement.setString(2, tablePrefix + "experience"); resultSet = statement.executeQuery(); if (!resultSet.next()) { @@ -932,9 +934,9 @@ public final class SQLDatabaseManager implements DatabaseManager { checkDatabaseStructure(connection, updateType); } - if (Config.getInstance().getTruncateSkills()) { + if (mcMMO.p.getGeneralConfig().getTruncateSkills()) { for (PrimarySkillType skill : PrimarySkillType.NON_CHILD_SKILLS) { - int cap = Config.getInstance().getLevelCap(skill); + int cap = mcMMO.p.getGeneralConfig().getLevelCap(skill); if (cap != Integer.MAX_VALUE) { statement = connection.prepareStatement("UPDATE `" + tablePrefix + "skills` SET `" + skill.name().toLowerCase(Locale.ENGLISH) + "` = " + cap + " WHERE `" + skill.name().toLowerCase(Locale.ENGLISH) + "` > " + cap); statement.executeUpdate(); @@ -1083,7 +1085,7 @@ public final class SQLDatabaseManager implements DatabaseManager { statement = connection.prepareStatement("INSERT IGNORE INTO " + tablePrefix + "huds (user_id, mobhealthbar, scoreboardtips) VALUES (?, ?, ?)"); statement.setInt(1, id); - statement.setString(2, Config.getInstance().getMobHealthbarDefault().name()); + statement.setString(2, mcMMO.p.getGeneralConfig().getMobHealthbarDefault().name()); statement.setInt(3, 0); statement.execute(); statement.close(); @@ -1097,8 +1099,8 @@ public final class SQLDatabaseManager implements DatabaseManager { } private PlayerProfile loadFromResult(String playerName, ResultSet result) throws SQLException { - Map skills = new EnumMap<>(PrimarySkillType.class); // Skill & Level - Map skillsXp = new EnumMap<>(PrimarySkillType.class); // Skill & XP + Map skills = new HashMap<>(); // Skill & Level + Map skillsXp = new HashMap<>(); // Skill & XP Map skillsDATS = new EnumMap<>(SuperAbilityType.class); // Ability & Cooldown Map uniqueData = new EnumMap<>(UniqueDataType.class); //Chimaera wing cooldown and other misc info MobHealthbarType mobHealthbarType; @@ -1158,7 +1160,7 @@ public final class SQLDatabaseManager implements DatabaseManager { mobHealthbarType = MobHealthbarType.valueOf(result.getString(OFFSET_OTHER + 1)); } catch (Exception e) { - mobHealthbarType = Config.getInstance().getMobHealthbarDefault(); + mobHealthbarType = mcMMO.p.getGeneralConfig().getMobHealthbarDefault(); } try { @@ -1270,7 +1272,7 @@ public final class SQLDatabaseManager implements DatabaseManager { } catch (SQLException ex) { mcMMO.p.getLogger().info("Updating mcMMO MySQL tables for mob healthbars..."); - statement.executeUpdate("ALTER TABLE `" + tablePrefix + "huds` ADD `mobhealthbar` varchar(50) NOT NULL DEFAULT '" + Config.getInstance().getMobHealthbarDefault() + "'"); + statement.executeUpdate("ALTER TABLE `" + tablePrefix + "huds` ADD `mobhealthbar` varchar(50) NOT NULL DEFAULT '" + mcMMO.p.getGeneralConfig().getMobHealthbarDefault() + "'"); } } @@ -1579,7 +1581,7 @@ public final class SQLDatabaseManager implements DatabaseManager { try { connection = getConnection(PoolIdentifier.MISC); statement = connection.prepareStatement("UPDATE " + tablePrefix + "huds SET mobhealthbar = ?"); - statement.setString(1, Config.getInstance().getMobHealthbarDefault().toString()); + statement.setString(1, mcMMO.p.getGeneralConfig().getMobHealthbarDefault().toString()); statement.executeUpdate(); } catch (SQLException ex) { diff --git a/src/main/java/com/gmail/nossr50/datatypes/LevelUpBroadcastPredicate.java b/src/main/java/com/gmail/nossr50/datatypes/LevelUpBroadcastPredicate.java index 8820f7742..51ab29a14 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/LevelUpBroadcastPredicate.java +++ b/src/main/java/com/gmail/nossr50/datatypes/LevelUpBroadcastPredicate.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.datatypes; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.mcMMO; @@ -42,7 +41,7 @@ public class LevelUpBroadcastPredicate implements Predi Player listeningPlayer = (Player) t; //Party Member Check - if(Config.getInstance().isLevelUpBroadcastsPartyMembersOnly()) { + if(mcMMO.p.getGeneralConfig().isLevelUpBroadcastsPartyMembersOnly()) { McMMOPlayer mmoListeningPlayer = UserManager.getPlayer(listeningPlayer); if(mmoListeningPlayer == null) { @@ -68,8 +67,8 @@ public class LevelUpBroadcastPredicate implements Predi } //Distance checks - if(Config.getInstance().shouldLevelUpBroadcastsRestrictDistance()) { - if(!Misc.isNear(mmoBroadcastingPlayer.getPlayer().getLocation(), listeningPlayer.getLocation(), Config.getInstance().getLevelUpBroadcastRadius())) { + if(mcMMO.p.getGeneralConfig().shouldLevelUpBroadcastsRestrictDistance()) { + if(!Misc.isNear(mmoBroadcastingPlayer.getPlayer().getLocation(), listeningPlayer.getLocation(), mcMMO.p.getGeneralConfig().getLevelUpBroadcastRadius())) { return false; } } @@ -83,12 +82,12 @@ public class LevelUpBroadcastPredicate implements Predi return true; } else { //Send out to console - return Config.getInstance().shouldLevelUpBroadcastToConsole(); + return mcMMO.p.getGeneralConfig().shouldLevelUpBroadcastToConsole(); } } private static boolean isLevelUpBroadcastsSameWorldOnly() { - return Config.getInstance().isLevelUpBroadcastsSameWorldOnly(); + return mcMMO.p.getGeneralConfig().isLevelUpBroadcastsSameWorldOnly(); } @Override diff --git a/src/main/java/com/gmail/nossr50/datatypes/PowerLevelUpBroadcastPredicate.java b/src/main/java/com/gmail/nossr50/datatypes/PowerLevelUpBroadcastPredicate.java index 549255006..b50d731eb 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/PowerLevelUpBroadcastPredicate.java +++ b/src/main/java/com/gmail/nossr50/datatypes/PowerLevelUpBroadcastPredicate.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.datatypes; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.mcMMO; @@ -42,7 +41,7 @@ public class PowerLevelUpBroadcastPredicate implements Player listeningPlayer = (Player) t; //Party Member Check - if(Config.getInstance().isPowerLevelUpBroadcastsPartyMembersOnly()) { + if(mcMMO.p.getGeneralConfig().isPowerLevelUpBroadcastsPartyMembersOnly()) { McMMOPlayer mmoListeningPlayer = UserManager.getPlayer(listeningPlayer); if(mmoListeningPlayer == null) { @@ -68,8 +67,8 @@ public class PowerLevelUpBroadcastPredicate implements } //Distance checks - if(Config.getInstance().shouldPowerLevelUpBroadcastsRestrictDistance()) { - if(!Misc.isNear(mmoBroadcastingPlayer.getPlayer().getLocation(), listeningPlayer.getLocation(), Config.getInstance().getPowerLevelUpBroadcastRadius())) { + if(mcMMO.p.getGeneralConfig().shouldPowerLevelUpBroadcastsRestrictDistance()) { + if(!Misc.isNear(mmoBroadcastingPlayer.getPlayer().getLocation(), listeningPlayer.getLocation(), mcMMO.p.getGeneralConfig().getPowerLevelUpBroadcastRadius())) { return false; } } @@ -83,12 +82,12 @@ public class PowerLevelUpBroadcastPredicate implements return true; } else { //Send out to console - return Config.getInstance().shouldPowerLevelUpBroadcastToConsole(); + return mcMMO.p.getGeneralConfig().shouldPowerLevelUpBroadcastToConsole(); } } private static boolean isPowerLevelUpBroadcastsSameWorldOnly() { - return Config.getInstance().isPowerLevelUpBroadcastsSameWorldOnly(); + return mcMMO.p.getGeneralConfig().isPowerLevelUpBroadcastsSameWorldOnly(); } @Override diff --git a/src/main/java/com/gmail/nossr50/datatypes/party/Party.java b/src/main/java/com/gmail/nossr50/datatypes/party/Party.java index f185f24e5..fe7b9cb91 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/party/Party.java +++ b/src/main/java/com/gmail/nossr50/datatypes/party/Party.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.datatypes.party; import com.gmail.nossr50.chat.SamePartyPredicate; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.experience.FormulaType; import com.gmail.nossr50.datatypes.player.McMMOPlayer; @@ -204,7 +203,7 @@ public class Party { public int getXpToLevel() { FormulaType formulaType = ExperienceConfig.getInstance().getFormulaType(); - return (mcMMO.getFormulaManager().getXPtoNextLevel(level, formulaType)) * (getOnlineMembers().size() + Config.getInstance().getPartyXpCurveMultiplier()); + return (mcMMO.getFormulaManager().getXPtoNextLevel(level, formulaType)) * (getOnlineMembers().size() + mcMMO.p.getGeneralConfig().getPartyXpCurveMultiplier()); } public String getXpToLevelPercentage() { @@ -243,13 +242,13 @@ public class Party { return; } - if (!Config.getInstance().getPartyInformAllMembers()) { + if (!mcMMO.p.getGeneralConfig().getPartyInformAllMembers()) { Player leader = mcMMO.p.getServer().getPlayer(this.leader.getUniqueId()); if (leader != null) { leader.sendMessage(LocaleLoader.getString("Party.LevelUp", levelsGained, getLevel())); - if (Config.getInstance().getLevelUpSoundsEnabled()) { + if (mcMMO.p.getGeneralConfig().getLevelUpSoundsEnabled()) { SoundManager.sendSound(leader, leader.getLocation(), SoundType.LEVEL_UP); } } @@ -260,7 +259,7 @@ public class Party { } public boolean hasReachedLevelCap() { - return Config.getInstance().getPartyLevelCap() < getLevel() + 1; + return mcMMO.p.getGeneralConfig().getPartyLevelCap() < getLevel() + 1; } public void setXpShareMode(ShareMode xpShareMode) { @@ -386,7 +385,7 @@ public class Party { if (party != null) { Player player = mcMMOPlayer.getPlayer(); - double range = Config.getInstance().getPartyShareRange(); + double range = mcMMO.p.getGeneralConfig().getPartyShareRange(); for (Player member : party.getOnlineMembers()) { if (!player.equals(member) && member.isValid() && Misc.isNear(player.getLocation(), member.getLocation(), range)) { diff --git a/src/main/java/com/gmail/nossr50/datatypes/party/PartyFeature.java b/src/main/java/com/gmail/nossr50/datatypes/party/PartyFeature.java index dd215fb5a..b50bfe852 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/party/PartyFeature.java +++ b/src/main/java/com/gmail/nossr50/datatypes/party/PartyFeature.java @@ -1,8 +1,8 @@ package com.gmail.nossr50.datatypes.party; import com.gmail.nossr50.commands.party.PartySubcommandType; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.text.StringUtils; import org.bukkit.entity.Player; @@ -19,7 +19,7 @@ public enum PartyFeature { } public String getFeatureLockedLocaleString() { - return LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Party.Feature.Locked." + StringUtils.getPrettyPartyFeatureString(this).replace(" ", ""), Config.getInstance().getPartyFeatureUnlockLevel(this))); + return LocaleLoader.getString("Ability.Generic.Template.Lock", LocaleLoader.getString("Party.Feature.Locked." + StringUtils.getPrettyPartyFeatureString(this).replace(" ", ""), mcMMO.p.getGeneralConfig().getPartyFeatureUnlockLevel(this))); } public boolean hasPermission(Player player) { diff --git a/src/main/java/com/gmail/nossr50/datatypes/party/PartyTeleportRecord.java b/src/main/java/com/gmail/nossr50/datatypes/party/PartyTeleportRecord.java index 50c2f8fee..17d815a6b 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/party/PartyTeleportRecord.java +++ b/src/main/java/com/gmail/nossr50/datatypes/party/PartyTeleportRecord.java @@ -1,6 +1,6 @@ package com.gmail.nossr50.datatypes.party; -import com.gmail.nossr50.config.Config; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; import org.bukkit.entity.Player; @@ -12,7 +12,7 @@ public class PartyTeleportRecord { public PartyTeleportRecord() { requestor = null; enabled = true; - confirmRequired = Config.getInstance().getPTPCommandConfirmRequired(); + confirmRequired = mcMMO.p.getGeneralConfig().getPTPCommandConfirmRequired(); timeout = 0; lastUse = 0; } diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index ec2ff905d..834d1c491 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -1,9 +1,7 @@ package com.gmail.nossr50.datatypes.player; import com.gmail.nossr50.chat.author.PlayerAuthor; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.config.ChatConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.WorldBlacklist; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.chat.ChatChannel; @@ -200,9 +198,9 @@ public class McMMOPlayer implements Identified { { //Check if they've reached the power level cap just now if(hasReachedPowerLevelCap()) { - NotificationManager.sendPlayerInformationChatOnly(player, "LevelCap.PowerLevel", String.valueOf(Config.getInstance().getPowerLevelCap())); + NotificationManager.sendPlayerInformationChatOnly(player, "LevelCap.PowerLevel", String.valueOf(mcMMO.p.getGeneralConfig().getPowerLevelCap())); } else if(hasReachedLevelCap(primarySkillType)) { - NotificationManager.sendPlayerInformationChatOnly(player, "LevelCap.Skill", String.valueOf(Config.getInstance().getLevelCap(primarySkillType)), primarySkillType.getName()); + NotificationManager.sendPlayerInformationChatOnly(player, "LevelCap.Skill", String.valueOf(mcMMO.p.getGeneralConfig().getLevelCap(primarySkillType)), primarySkillType.getName()); } //Updates from Party sources @@ -537,7 +535,7 @@ public class McMMOPlayer implements Identified { if(hasReachedPowerLevelCap()) return true; - return getSkillLevel(primarySkillType) >= Config.getInstance().getLevelCap(primarySkillType); + return getSkillLevel(primarySkillType) >= mcMMO.p.getGeneralConfig().getLevelCap(primarySkillType); } /** @@ -546,7 +544,7 @@ public class McMMOPlayer implements Identified { * @return true if they have reached the power level cap */ public boolean hasReachedPowerLevelCap() { - return this.getPowerLevel() >= Config.getInstance().getPowerLevelCap(); + return this.getPowerLevel() >= mcMMO.p.getGeneralConfig().getPowerLevelCap(); } /** @@ -597,7 +595,7 @@ public class McMMOPlayer implements Identified { return; } - if (!Config.getInstance().getPartyXpNearMembersNeeded() || !PartyManager.getNearMembers(this).isEmpty()) { + if (!mcMMO.p.getGeneralConfig().getPartyXpNearMembersNeeded() || !PartyManager.getNearMembers(this).isEmpty()) { party.applyXpGain(modifyXpGain(skill, xp)); } } @@ -666,7 +664,7 @@ public class McMMOPlayer implements Identified { return; } - if (Config.getInstance().getLevelUpSoundsEnabled()) { + if (mcMMO.p.getGeneralConfig().getLevelUpSoundsEnabled()) { SoundManager.sendSound(player, player.getLocation(), SoundType.LEVEL_UP); } @@ -787,13 +785,13 @@ public class McMMOPlayer implements Identified { private float modifyXpGain(PrimarySkillType primarySkillType, float xp) { //TODO: A rare situation can occur where the default Power Level cap can prevent a player with one skill edited to something silly like Integer.MAX_VALUE from gaining XP in any skill, we may need to represent power level with another data type if ((primarySkillType.getMaxLevel() <= getSkillLevel(primarySkillType)) - || (Config.getInstance().getPowerLevelCap() <= getPowerLevel())) { + || (mcMMO.p.getGeneralConfig().getPowerLevelCap() <= getPowerLevel())) { return 0; } xp = (float) (xp / primarySkillType.getXpModifier() * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()); - if (Config.getInstance().getToolModsEnabled()) { + if (mcMMO.p.getGeneralConfig().getToolModsEnabled()) { CustomTool tool = mcMMO.getModManager().getTool(player.getInventory().getItemInMainHand()); if (tool != null) { @@ -863,8 +861,8 @@ public class McMMOPlayer implements Identified { } //These values change depending on whether or not the server is in retro mode - int abilityLengthVar = AdvancedConfig.getInstance().getAbilityLength(); - int abilityLengthCap = AdvancedConfig.getInstance().getAbilityLengthCap(); + int abilityLengthVar = mcMMO.p.getAdvancedConfig().getAbilityLength(); + int abilityLengthCap = mcMMO.p.getAdvancedConfig().getAbilityLengthCap(); int ticks; @@ -881,7 +879,7 @@ public class McMMOPlayer implements Identified { //player.sendMessage(ability.getAbilityOn()); } - if (AdvancedConfig.getInstance().sendAbilityNotificationToOtherPlayers()) { + if (mcMMO.p.getAdvancedConfig().sendAbilityNotificationToOtherPlayers()) { SkillUtils.sendSkillMessage(player, NotificationType.SUPER_ABILITY_ALERT_OTHERS, ability.getAbilityPlayer()); } @@ -905,7 +903,7 @@ public class McMMOPlayer implements Identified { return; } - if (Config.getInstance().getAbilitiesOnlyActivateWhenSneaking() && !player.isSneaking()) { + if (mcMMO.p.getGeneralConfig().getAbilitiesOnlyActivateWhenSneaking() && !player.isSneaking()) { return; } @@ -942,7 +940,7 @@ public class McMMOPlayer implements Identified { } } - if (Config.getInstance().getAbilityMessagesEnabled()) { + if (mcMMO.p.getGeneralConfig().getAbilityMessagesEnabled()) { /* * * IF THE TOOL IS AN AXE @@ -1099,7 +1097,7 @@ public class McMMOPlayer implements Identified { UserManager.remove(thisPlayer); - if(Config.getInstance().getScoreboardsEnabled()) + if(mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) ScoreboardManager.teardownPlayer(thisPlayer); if (inParty()) { diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java index 1d1cb53c2..eaad9f299 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java @@ -1,18 +1,19 @@ package com.gmail.nossr50.datatypes.player; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.MobHealthbarType; import com.gmail.nossr50.datatypes.experience.FormulaType; import com.gmail.nossr50.datatypes.experience.SkillXpGain; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; +import com.gmail.nossr50.datatypes.skills.interfaces.Skill; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.player.PlayerProfileSaveTask; import com.gmail.nossr50.skills.child.FamilyTree; import com.gmail.nossr50.util.player.UserManager; import com.google.common.collect.ImmutableMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.HashMap; import java.util.Map; @@ -32,14 +33,14 @@ public class PlayerProfile { private int saveAttempts = 0; /* Skill Data */ - private final Map skills = new HashMap<>(); // Skill & Level - private final Map skillsXp = new HashMap<>(); // Skill & XP + private final Map skills = new HashMap<>(); // Skill & Level + private final Map skillsXp = new HashMap<>(); // Skill & XP private final Map abilityDATS = new HashMap<>(); // Ability & Cooldown private final Map uniquePlayerData = new HashMap<>(); //Misc data that doesn't fit into other categories (chimaera wing, etc..) // Store previous XP gains for diminished returns private final DelayQueue gainedSkillsXp = new DelayQueue<>(); - private final HashMap rollingSkillsXp = new HashMap<>(); + private final HashMap rollingSkillsXp = new HashMap<>(); @Deprecated public PlayerProfile(String playerName) { @@ -50,7 +51,7 @@ public class PlayerProfile { this.uuid = uuid; this.playerName = playerName; - mobHealthbarType = Config.getInstance().getMobHealthbarDefault(); + mobHealthbarType = mcMMO.p.getGeneralConfig().getMobHealthbarDefault(); scoreboardTipsShown = 0; for (SuperAbilityType superAbilityType : SuperAbilityType.values()) { @@ -58,7 +59,7 @@ public class PlayerProfile { } for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { - skills.put(primarySkillType, AdvancedConfig.getInstance().getStartingLevel()); + skills.put(primarySkillType, mcMMO.p.getAdvancedConfig().getStartingLevel()); skillsXp.put(primarySkillType, 0F); } @@ -67,20 +68,20 @@ public class PlayerProfile { } @Deprecated - public PlayerProfile(String playerName, boolean isLoaded) { + public PlayerProfile(@NotNull String playerName, boolean isLoaded) { this(playerName); this.loaded = isLoaded; } - public PlayerProfile(String playerName, UUID uuid, boolean isLoaded) { + public PlayerProfile(@NotNull String playerName, UUID uuid, boolean isLoaded) { this(playerName, uuid); this.loaded = isLoaded; } - public PlayerProfile(String playerName, UUID uuid, Map levelData, Map xpData, Map cooldownData, MobHealthbarType mobHealthbarType, int scoreboardTipsShown, Map uniqueProfileData) { + public PlayerProfile(@NotNull String playerName, UUID uuid, Map levelData, Map xpData, Map cooldownData, @Nullable MobHealthbarType mobHealthbarType, int scoreboardTipsShown, Map uniqueProfileData) { this.playerName = playerName; this.uuid = uuid; - this.mobHealthbarType = mobHealthbarType; + mobHealthbarType = mcMMO.p.getGeneralConfig().getMobHealthbarDefault(); this.scoreboardTipsShown = scoreboardTipsShown; skills.putAll(levelData); diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java index 0673db147..fa8fd41c6 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java @@ -1,7 +1,7 @@ package com.gmail.nossr50.datatypes.skills; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; +import com.gmail.nossr50.datatypes.skills.interfaces.Skill; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.SkillManager; @@ -33,7 +33,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -public enum PrimarySkillType { +public enum PrimarySkillType implements Skill { ACROBATICS(AcrobaticsManager.class, Color.WHITE, ImmutableList.of(SubSkillType.ACROBATICS_DODGE, SubSkillType.ACROBATICS_ROLL)), ALCHEMY(AlchemyManager.class, Color.FUCHSIA, @@ -122,6 +122,14 @@ public enum PrimarySkillType { this.subSkillTypes = subSkillTypes; } + public PrimarySkillType getPrimarySkill() { + return this; + } + + public String getPrimaryKeyName() { + return StringUtils.getCapitalized(this.toString()); + } + public Class getManagerClass() { return managerClass; } @@ -136,37 +144,37 @@ public enum PrimarySkillType { * @return the max level of this skill */ public int getMaxLevel() { - return Config.getInstance().getLevelCap(this); + return mcMMO.p.getGeneralConfig().getLevelCap(this); } public boolean isSuperAbilityUnlocked(Player player) { return RankUtils.getRank(player, getAbility().getSubSkillTypeDefinition()) >= 1; } public boolean getPVPEnabled() { - return Config.getInstance().getPVPEnabled(this); + return mcMMO.p.getGeneralConfig().getPVPEnabled(this); } public boolean getPVEEnabled() { - return Config.getInstance().getPVEEnabled(this); + return mcMMO.p.getGeneralConfig().getPVEEnabled(this); } public boolean getDoubleDropsDisabled() { - return Config.getInstance().getDoubleDropsDisabled(this); + return mcMMO.p.getGeneralConfig().getDoubleDropsDisabled(this); } public boolean getHardcoreStatLossEnabled() { - return Config.getInstance().getHardcoreStatLossEnabled(this); + return mcMMO.p.getGeneralConfig().getHardcoreStatLossEnabled(this); } public void setHardcoreStatLossEnabled(boolean enable) { - Config.getInstance().setHardcoreStatLossEnabled(this, enable); + mcMMO.p.getGeneralConfig().setHardcoreStatLossEnabled(this, enable); } public boolean getHardcoreVampirismEnabled() { - return Config.getInstance().getHardcoreVampirismEnabled(this); + return mcMMO.p.getGeneralConfig().getHardcoreVampirismEnabled(this); } public void setHardcoreVampirismEnabled(boolean enable) { - Config.getInstance().setHardcoreVampirismEnabled(this, enable); + mcMMO.p.getGeneralConfig().setHardcoreVampirismEnabled(this, enable); } public ToolType getTool() { @@ -182,7 +190,7 @@ public enum PrimarySkillType { } public static PrimarySkillType getSkill(String skillName) { - if (!Config.getInstance().getLocale().equalsIgnoreCase("en_US")) { + if (!mcMMO.p.getGeneralConfig().getLocale().equalsIgnoreCase("en_US")) { for (PrimarySkillType type : values()) { if (skillName.equalsIgnoreCase(LocaleLoader.getString(StringUtils.getCapitalized(type.name()) + ".SkillName"))) { return type; @@ -215,42 +223,17 @@ public enum PrimarySkillType { } } - public static PrimarySkillType bySecondaryAbility(SubSkillType subSkillType) { - for (PrimarySkillType type : values()) { - if (type.getSkillAbilities().contains(subSkillType)) { - return type; - } - } - return null; - } - - public static PrimarySkillType byAbility(SuperAbilityType ability) { - for (PrimarySkillType type : values()) { - if (type.getAbility() == ability) { - return type; - } - } - - return null; - } - public String getName() { return StringUtils.getCapitalized(LocaleLoader.getString(StringUtils.getCapitalized(this.toString()) + ".SkillName")); } -// public String getName() { -// return StringUtils.getCapitalized(StringUtils.getCapitalized(this.toString())); -// } - public boolean getPermissions(Player player) { return Permissions.skillEnabled(player, this); } -/* public void celebrateLevelUp(Player player) { - ParticleEffectUtils.fireworkParticleShower(player, skillColor); - }*/ - public boolean shouldProcess(Entity target) { return (target instanceof Player || (target instanceof Tameable && ((Tameable) target).isTamed())) ? getPVPEnabled() : getPVEEnabled(); } + + } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java index 059df8db9..67b256a47 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java @@ -1,5 +1,6 @@ package com.gmail.nossr50.datatypes.skills; +import com.gmail.nossr50.datatypes.skills.interfaces.Skill; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.util.text.StringUtils; @@ -135,7 +136,7 @@ public enum SubSkillType { * If we add skills, those immutable lists need to be updated * @return */ - public PrimarySkillType getParentSkill() { return PrimarySkillType.bySecondaryAbility(this); } + public PrimarySkillType getParentSkill() { return Skill.bySecondaryAbility(this); } /** * Returns the root address for this skill in the advanced.yml file diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java index 6d038332c..72c9fee69 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.datatypes.skills; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.BlockUtils; @@ -112,11 +111,11 @@ public enum SuperAbilityType { } public int getCooldown() { - return Config.getInstance().getCooldown(this); + return mcMMO.p.getGeneralConfig().getCooldown(this); } public int getMaxLength() { - return Config.getInstance().getMaxLength(this); + return mcMMO.p.getGeneralConfig().getMaxLength(this); } public String getAbilityOn() { diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Skill.java b/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Skill.java index 68cf7180e..a0487e0df 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Skill.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Skill.java @@ -1,6 +1,18 @@ package com.gmail.nossr50.datatypes.skills.interfaces; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.datatypes.skills.SuperAbilityType; +import com.gmail.nossr50.datatypes.skills.ToolType; +import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.skills.SkillManager; +import com.gmail.nossr50.util.text.StringUtils; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.List; public interface Skill { /** @@ -14,4 +26,88 @@ public interface Skill { * @return config file key name */ String getPrimaryKeyName(); + + Class getManagerClass(); + + SuperAbilityType getAbility(); + + /** + * Get the max level of this skill. + * + * @return the max level of this skill + */ + int getMaxLevel(); + + boolean isSuperAbilityUnlocked(Player player); + + boolean getPVPEnabled(); + + boolean getPVEEnabled(); + + boolean getDoubleDropsDisabled(); + + boolean getHardcoreStatLossEnabled(); + + void setHardcoreStatLossEnabled(boolean enable); + + boolean getHardcoreVampirismEnabled(); + + void setHardcoreVampirismEnabled(boolean enable); + + ToolType getTool(); + + List getSkillAbilities(); + + double getXpModifier(); + + // TODO: This is a little "hacky", we probably need to add something to distinguish child skills in the enum, or to use another enum for them + boolean isChildSkill(); + + static PrimarySkillType bySecondaryAbility(SubSkillType subSkillType) { + for (PrimarySkillType type : PrimarySkillType.values()) { + if (type.getSkillAbilities().contains(subSkillType)) { + return type; + } + } + + return null; + } + + static PrimarySkillType byAbility(SuperAbilityType ability) { + for (PrimarySkillType type : PrimarySkillType.values()) { + if (type.getAbility() == ability) { + return type; + } + } + + return null; + } + + static PrimarySkillType getSkill(@NotNull String skillName) { + if (!mcMMO.p.getGeneralConfig().getLocale().equalsIgnoreCase("en_US")) { + for (PrimarySkillType type : PrimarySkillType.values()) { + if (skillName.equalsIgnoreCase(LocaleLoader.getString(StringUtils.getCapitalized(type.name()) + ".SkillName"))) { + return type; + } + } + } + + for (PrimarySkillType type : PrimarySkillType.values()) { + if (type.name().equalsIgnoreCase(skillName)) { + return type; + } + } + + if (!skillName.equalsIgnoreCase("all")) { + mcMMO.p.getLogger().warning("Invalid mcMMO skill (" + skillName + ")"); //TODO: Localize + } + + return null; + } + + String getName(); + + boolean getPermissions(Player player); + + boolean shouldProcess(Entity target); } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java index f13f5b922..d81320761 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.datatypes.skills.subskills.acrobatics; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.interactions.NotificationType; @@ -8,8 +7,11 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.datatypes.skills.SuperAbilityType; +import com.gmail.nossr50.datatypes.skills.ToolType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.EventUtils; import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.Permissions; @@ -29,12 +31,14 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.SoundCategory; import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.inventory.ItemStack; +import java.util.List; import java.util.Locale; public class Roll extends AcrobaticsSubSkill { @@ -200,7 +204,7 @@ public class Roll extends AcrobaticsSubSkill { return gracefulRollCheck(player, mcMMOPlayer, damage, skillLevel); } - double modifiedDamage = calculateModifiedRollDamage(damage, AdvancedConfig.getInstance().getRollDamageThreshold()); + double modifiedDamage = calculateModifiedRollDamage(damage, mcMMO.p.getAdvancedConfig().getRollDamageThreshold()); if (!isFatal(player, modifiedDamage) && RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.ACROBATICS_ROLL, player)) { @@ -238,7 +242,7 @@ public class Roll extends AcrobaticsSubSkill { * @return the modified event damage if the ability was successful, the original event damage otherwise */ private double gracefulRollCheck(Player player, McMMOPlayer mcMMOPlayer, double damage, int skillLevel) { - double modifiedDamage = calculateModifiedRollDamage(damage, AdvancedConfig.getInstance().getRollDamageThreshold() * 2); + double modifiedDamage = calculateModifiedRollDamage(damage, mcMMO.p.getAdvancedConfig().getRollDamageThreshold() * 2); RandomChanceSkill rcs = new RandomChanceSkill(player, subSkillType); rcs.setSkillLevel(rcs.getSkillLevel() * 2); //Double the effective odds @@ -381,7 +385,7 @@ public class Roll extends AcrobaticsSubSkill { // // //Chance to roll at half max skill // RandomChanceSkill rollHalfMaxSkill = new RandomChanceSkill(null, subSkillType); -// int halfMaxSkillValue = AdvancedConfig.getInstance().getMaxBonusLevel(SubSkillType.ACROBATICS_ROLL)/2; +// int halfMaxSkillValue = mcMMO.p.getAdvancedConfig().getMaxBonusLevel(SubSkillType.ACROBATICS_ROLL)/2; // rollHalfMaxSkill.setSkillLevel(halfMaxSkillValue); // // //Chance to graceful roll at full skill @@ -395,11 +399,11 @@ public class Roll extends AcrobaticsSubSkill { // //Chance Stat Calculations // rollChanceHalfMax = RandomChanceUtil.getRandomChanceExecutionChance(rollHalfMaxSkill); // graceChanceHalfMax = RandomChanceUtil.getRandomChanceExecutionChance(rollGraceHalfMaxSkill); -// damageThreshold = AdvancedConfig.getInstance().getRollDamageThreshold(); +// damageThreshold = mcMMO.p.getAdvancedConfig().getRollDamageThreshold(); // // chancePerLevel = RandomChanceUtil.getRandomChanceExecutionChance(rollOneSkillLevel); // -// double maxLevel = AdvancedConfig.getInstance().getMaxBonusLevel(SubSkillType.ACROBATICS_ROLL); +// double maxLevel = mcMMO.p.getAdvancedConfig().getMaxBonusLevel(SubSkillType.ACROBATICS_ROLL); // // return LocaleLoader.getString("Acrobatics.SubSkill.Roll.Mechanics", rollChanceHalfMax, graceChanceHalfMax, maxLevel, chancePerLevel, damageThreshold, damageThreshold * 2,halfMaxSkillValue); } @@ -436,4 +440,98 @@ public class Roll extends AcrobaticsSubSkill { { return player.getLocation().getBlock().getLocation(); } + + public String getPrimaryKeyName() { + return getPrimarySkill().getPrimaryKeyName(); + } + + @Override + public Class getManagerClass() { + return getPrimarySkill().getManagerClass(); + } + + @Override + public SuperAbilityType getAbility() { + return getPrimarySkill().getAbility(); + } + + @Override + public int getMaxLevel() { + return getPrimarySkill().getMaxLevel(); + } + + @Override + public boolean isSuperAbilityUnlocked(Player player) { + return getPrimarySkill().isSuperAbilityUnlocked(player); + } + + @Override + public boolean getPVPEnabled() { + return getPrimarySkill().getPVPEnabled(); + } + + @Override + public boolean getPVEEnabled() { + return getPrimarySkill().getPVEEnabled(); + } + + @Override + public boolean getDoubleDropsDisabled() { + return getPrimarySkill().getDoubleDropsDisabled(); + } + + @Override + public boolean getHardcoreStatLossEnabled() { + return getPrimarySkill().getHardcoreStatLossEnabled(); + } + + @Override + public void setHardcoreStatLossEnabled(boolean enable) { + getPrimarySkill().setHardcoreStatLossEnabled(enable); + } + + @Override + public boolean getHardcoreVampirismEnabled() { + return getPrimarySkill().getHardcoreVampirismEnabled(); + } + + @Override + public void setHardcoreVampirismEnabled(boolean enable) { + getPrimarySkill().setHardcoreVampirismEnabled(enable); + } + + @Override + public ToolType getTool() { + return getPrimarySkill().getTool(); + } + + @Override + public List getSkillAbilities() { + return getPrimarySkill().getSkillAbilities(); + } + + @Override + public double getXpModifier() { + return getPrimarySkill().getXpModifier(); + } + + @Override + public boolean isChildSkill() { + return getPrimarySkill().isChildSkill(); + } + + @Override + public String getName() { + return getPrimarySkill().getName(); + } + + @Override + public boolean getPermissions(Player player) { + return getPrimarySkill().getPermissions(player); + } + + @Override + public boolean shouldProcess(Entity target) { + return getPrimarySkill().shouldProcess(target); + } } diff --git a/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java b/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java index ee4fbb873..215a7f224 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java @@ -1,7 +1,7 @@ package com.gmail.nossr50.events.skills.secondaryabilities; -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.datatypes.skills.interfaces.Skill; import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.events.skills.McMMOPlayerSkillEvent; import org.bukkit.entity.Player; @@ -20,7 +20,7 @@ public class SubSkillEvent extends McMMOPlayerSkillEvent implements Cancellable */ @Deprecated public SubSkillEvent(Player player, SubSkillType subSkillType) { - super(player, PrimarySkillType.bySecondaryAbility(subSkillType)); + super(player, Skill.bySecondaryAbility(subSkillType)); this.subSkillType = subSkillType; } @@ -33,7 +33,7 @@ public class SubSkillEvent extends McMMOPlayerSkillEvent implements Cancellable */ @Deprecated public SubSkillEvent(Player player, SubSkillType subSkillType, double resultModifier) { - super(player, PrimarySkillType.bySecondaryAbility(subSkillType)); + super(player, Skill.bySecondaryAbility(subSkillType)); this.subSkillType = subSkillType; this.resultModifier = resultModifier; } diff --git a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java index 863a09ac3..33b68076c 100644 --- a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.listeners; import com.gmail.nossr50.api.ItemSpawnReason; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.HiddenConfig; import com.gmail.nossr50.config.WorldBlacklist; import com.gmail.nossr50.config.experience.ExperienceConfig; @@ -79,9 +78,9 @@ public class BlockListener implements Listener { continue; //TODO: Ignore this abomination its rewritten in 2.2 - if(!Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.MINING, is.getType()) - && !Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.HERBALISM, is.getType()) - && !Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, is.getType())) + if(!mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.MINING, is.getType()) + && !mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.HERBALISM, is.getType()) + && !mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, is.getType())) continue; //If we suspect TEs might be duped only reward block @@ -524,7 +523,7 @@ public class BlockListener implements Listener { * * We don't need to check permissions here because they've already been checked for the ability to even activate. */ - if (mcMMOPlayer.getAbilityMode(SuperAbilityType.TREE_FELLER) && BlockUtils.hasWoodcuttingXP(blockState) && Config.getInstance().getTreeFellerSoundsEnabled()) { + if (mcMMOPlayer.getAbilityMode(SuperAbilityType.TREE_FELLER) && BlockUtils.hasWoodcuttingXP(blockState) && mcMMO.p.getGeneralConfig().getTreeFellerSoundsEnabled()) { SoundManager.sendSound(player, blockState.getLocation(), SoundType.FIZZ); } } @@ -579,7 +578,7 @@ public class BlockListener implements Listener { blockState.update(true); } } - else if (mcMMOPlayer.getAbilityMode(SuperAbilityType.BERSERK) && (heldItem.getType() == Material.AIR || Config.getInstance().getUnarmedItemsAsUnarmed())) { + else if (mcMMOPlayer.getAbilityMode(SuperAbilityType.BERSERK) && (heldItem.getType() == Material.AIR || mcMMO.p.getGeneralConfig().getUnarmedItemsAsUnarmed())) { if (mcMMOPlayer.getUnarmedManager().canUseBlockCracker() && BlockUtils.affectedByBlockCracker(blockState)) { if (EventUtils.simulateBlockBreak(block, player, true) && mcMMOPlayer.getUnarmedManager().blockCrackerCheck(blockState)) { blockState.update(); diff --git a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java index f01a13d71..9042e1286 100644 --- a/src/main/java/com/gmail/nossr50/listeners/EntityListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/EntityListener.java @@ -1,7 +1,5 @@ package com.gmail.nossr50.listeners; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.WorldBlacklist; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.player.McMMOPlayer; @@ -163,7 +161,7 @@ public class EntityListener implements Listener { projectile.setMetadata(mcMMO.infiniteArrowKey, mcMMO.metadataValue); } - projectile.setMetadata(mcMMO.bowForceKey, new FixedMetadataValue(pluginRef, Math.min(event.getForce() * AdvancedConfig.getInstance().getForceMultiplier(), 1.0))); + projectile.setMetadata(mcMMO.bowForceKey, new FixedMetadataValue(pluginRef, Math.min(event.getForce() * mcMMO.p.getAdvancedConfig().getForceMultiplier(), 1.0))); projectile.setMetadata(mcMMO.arrowDistanceKey, new FixedMetadataValue(pluginRef, projectile.getLocation())); //Cleanup metadata in 1 minute in case normal collection falls through CombatUtils.delayArrowMetaCleanup((Projectile) projectile); @@ -466,7 +464,7 @@ public class EntityListener implements Listener { } //Party Friendly Fire - if(!Config.getInstance().getPartyFriendlyFire()) + if(!mcMMO.p.getGeneralConfig().getPartyFriendlyFire()) if ((PartyManager.inSameParty(defendingPlayer, attackingPlayer) || PartyManager.areAllies(defendingPlayer, attackingPlayer)) && !(Permissions.friendlyFire(attackingPlayer) diff --git a/src/main/java/com/gmail/nossr50/listeners/InventoryListener.java b/src/main/java/com/gmail/nossr50/listeners/InventoryListener.java index c110de94c..df4dd6e78 100644 --- a/src/main/java/com/gmail/nossr50/listeners/InventoryListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/InventoryListener.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.listeners; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.WorldBlacklist; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; @@ -382,17 +381,17 @@ public class InventoryListener implements Listener { ItemStack item = event.getItem(); - if (Config.getInstance().getPreventHopperTransferIngredients() && item.getType() != Material.POTION && item.getType() != Material.SPLASH_POTION && item.getType() != Material.LINGERING_POTION) { + if (mcMMO.p.getGeneralConfig().getPreventHopperTransferIngredients() && item.getType() != Material.POTION && item.getType() != Material.SPLASH_POTION && item.getType() != Material.LINGERING_POTION) { event.setCancelled(true); return; } - if (Config.getInstance().getPreventHopperTransferBottles() && (item.getType() == Material.POTION || item.getType() == Material.SPLASH_POTION || item.getType() == Material.LINGERING_POTION)) { + if (mcMMO.p.getGeneralConfig().getPreventHopperTransferBottles() && (item.getType() == Material.POTION || item.getType() == Material.SPLASH_POTION || item.getType() == Material.LINGERING_POTION)) { event.setCancelled(true); return; } - if (Config.getInstance().getEnabledForHoppers() && AlchemyPotionBrewer.isValidIngredient(null, item)) { + if (mcMMO.p.getGeneralConfig().getEnabledForHoppers() && AlchemyPotionBrewer.isValidIngredient(null, item)) { AlchemyPotionBrewer.scheduleCheck(null, (BrewingStand) holder); } } diff --git a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java index bf4b3faa0..53e40ca14 100644 --- a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.listeners; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.WorldBlacklist; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.chat.ChatChannel; @@ -73,11 +72,11 @@ public class PlayerListener implements Listener { /* WORLD BLACKLIST CHECK */ if(WorldBlacklist.isWorldBlacklisted(event.getPlayer().getWorld())) { //Remove scoreboards - if(Config.getInstance().getScoreboardsEnabled()) { + if(mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { ScoreboardManager.teardownPlayer(event.getPlayer()); } return; - } else if(WorldBlacklist.isWorldBlacklisted(event.getFrom().getWorld()) && Config.getInstance().getScoreboardsEnabled()) { + } else if(WorldBlacklist.isWorldBlacklisted(event.getFrom().getWorld()) && mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { //This only fires if they are travelling to a non-blacklisted world from a blacklisted world //Setup scoreboards @@ -93,7 +92,7 @@ public class PlayerListener implements Listener { return; } - if (!UserManager.hasPlayerDataKey(player) || Config.getInstance().getXPAfterTeleportCooldown() <= 0 || event.getFrom().equals(event.getTo())) { + if (!UserManager.hasPlayerDataKey(player) || mcMMO.p.getGeneralConfig().getXPAfterTeleportCooldown() <= 0 || event.getFrom().equals(event.getTo())) { return; } @@ -292,7 +291,7 @@ public class PlayerListener implements Listener { if(event.getCaught() != null) { Item fishingCatch = (Item) event.getCaught(); - if (Config.getInstance().getFishingOverrideTreasures() && + if (mcMMO.p.getGeneralConfig().getFishingOverrideTreasures() && fishingCatch.getItemStack().getType() != Material.SALMON && fishingCatch.getItemStack().getType() != Material.COD && fishingCatch.getItemStack().getType() != Material.TROPICAL_FISH && @@ -565,11 +564,11 @@ public class PlayerListener implements Listener { //Delay loading for 3 seconds in case the player has a save task running, its hacky but it should do the trick new PlayerProfileLoadingTask(player).runTaskLaterAsynchronously(mcMMO.p, 60); - if (Config.getInstance().getMOTDEnabled() && Permissions.motd(player)) { + if (mcMMO.p.getGeneralConfig().getMOTDEnabled() && Permissions.motd(player)) { Motd.displayAll(player); } - if (plugin.isXPEventEnabled() && Config.getInstance().playerJoinEventInfo()) { + if (plugin.isXPEventEnabled() && mcMMO.p.getGeneralConfig().playerJoinEventInfo()) { player.sendMessage(LocaleLoader.getString("XPRate.Event", ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier())); } } @@ -652,7 +651,7 @@ public class PlayerListener implements Listener { case RIGHT_CLICK_BLOCK: Material type = clickedBlock.getType(); - if (!Config.getInstance().getAbilitiesOnlyActivateWhenSneaking() || player.isSneaking()) { + if (!mcMMO.p.getGeneralConfig().getAbilitiesOnlyActivateWhenSneaking() || player.isSneaking()) { /* REPAIR CHECKS */ if (type == Repair.anvilMaterial && PrimarySkillType.REPAIR.getPermissions(player) @@ -700,7 +699,7 @@ public class PlayerListener implements Listener { case LEFT_CLICK_BLOCK: type = clickedBlock.getType(); - if (!Config.getInstance().getAbilitiesOnlyActivateWhenSneaking() || player.isSneaking()) { + if (!mcMMO.p.getGeneralConfig().getAbilitiesOnlyActivateWhenSneaking() || player.isSneaking()) { /* REPAIR CHECKS */ if (type == Repair.anvilMaterial && PrimarySkillType.REPAIR.getPermissions(player) && mcMMO.getRepairableManager().isRepairable(heldItem)) { RepairManager repairManager = mcMMOPlayer.getRepairManager(); @@ -794,7 +793,7 @@ public class PlayerListener implements Listener { /* ACTIVATION & ITEM CHECKS */ if (BlockUtils.canActivateTools(blockState)) { - if (Config.getInstance().getAbilitiesEnabled()) { + if (mcMMO.p.getGeneralConfig().getAbilitiesEnabled()) { if (BlockUtils.canActivateHerbalism(blockState)) { mcMMOPlayer.processAbilityActivation(PrimarySkillType.HERBALISM); } @@ -860,7 +859,7 @@ public class PlayerListener implements Listener { } /* ACTIVATION CHECKS */ - if (Config.getInstance().getAbilitiesEnabled()) { + if (mcMMO.p.getGeneralConfig().getAbilitiesEnabled()) { mcMMOPlayer.processAbilityActivation(PrimarySkillType.AXES); mcMMOPlayer.processAbilityActivation(PrimarySkillType.EXCAVATION); mcMMOPlayer.processAbilityActivation(PrimarySkillType.HERBALISM); @@ -892,13 +891,13 @@ public class PlayerListener implements Listener { Material type = heldItem.getType(); TamingManager tamingManager = mcMMOPlayer.getTamingManager(); - if (type == Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.WOLF.getConfigEntityTypeEntry())) { + if (type == mcMMO.p.getGeneralConfig().getTamingCOTWMaterial(CallOfTheWildType.WOLF.getConfigEntityTypeEntry())) { tamingManager.summonWolf(); } - else if (type == Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.CAT.getConfigEntityTypeEntry())) { + else if (type == mcMMO.p.getGeneralConfig().getTamingCOTWMaterial(CallOfTheWildType.CAT.getConfigEntityTypeEntry())) { tamingManager.summonOcelot(); } - else if (type == Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.HORSE.getConfigEntityTypeEntry())) { + else if (type == mcMMO.p.getGeneralConfig().getTamingCOTWMaterial(CallOfTheWildType.HORSE.getConfigEntityTypeEntry())) { tamingManager.summonHorse(); } @@ -951,7 +950,7 @@ public class PlayerListener implements Listener { */ @EventHandler(priority = EventPriority.LOWEST) public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { - if (!Config.getInstance().getLocale().equalsIgnoreCase("en_US")) { + if (!mcMMO.p.getGeneralConfig().getLocale().equalsIgnoreCase("en_US")) { String message = event.getMessage(); String command = message.substring(1).split(" ")[0]; String lowerCaseCommand = command.toLowerCase(Locale.ENGLISH); diff --git a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java index 2ea4ac582..5bd3f5ec0 100644 --- a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.listeners; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.player.McMMOPlayer; @@ -45,7 +44,7 @@ public class SelfListener implements Listener { //Reset the delay timer RankUtils.resetUnlockDelayTimer(); - if(Config.getInstance().getScoreboardsEnabled()) + if(mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) ScoreboardManager.handleLevelUp(player, skill); } } @@ -55,7 +54,7 @@ public class SelfListener implements Listener { Player player = event.getPlayer(); if(player.isOnline()) { - if(Config.getInstance().getScoreboardsEnabled()) + if(mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) ScoreboardManager.handleXp(player, event.getSkill()); } } @@ -64,7 +63,7 @@ public class SelfListener implements Listener { public void onAbility(McMMOPlayerAbilityActivateEvent event) { Player player = event.getPlayer(); if(player.isOnline()) { - if(Config.getInstance().getScoreboardsEnabled()) + if(mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) ScoreboardManager.cooldownUpdate(event.getPlayer(), event.getSkill()); } } diff --git a/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java b/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java index f4f57ceaf..a3b285689 100644 --- a/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java +++ b/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.locale; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.text.TextUtils; import net.kyori.adventure.text.TextComponent; @@ -130,7 +129,7 @@ public final class LocaleLoader { if (bundle == null) { Locale.setDefault(new Locale("en", "US")); Locale locale = null; - String[] myLocale = Config.getInstance().getLocale().split("[-_ ]"); + String[] myLocale = mcMMO.p.getGeneralConfig().getLocale().split("[-_ ]"); if (myLocale.length == 1) { locale = new Locale(myLocale[0]); @@ -140,7 +139,7 @@ public final class LocaleLoader { } if (locale == null) { - throw new IllegalStateException("Failed to parse locale string '" + Config.getInstance().getLocale() + "'"); + throw new IllegalStateException("Failed to parse locale string '" + mcMMO.p.getGeneralConfig().getLocale() + "'"); } Path localePath = Paths.get(mcMMO.getLocalesDirectory() + "locale_" + locale.toString() + ".properties"); diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index 99d7a461f..ef3ead515 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -9,7 +9,9 @@ import com.gmail.nossr50.config.mods.BlockConfigManager; import com.gmail.nossr50.config.mods.EntityConfigManager; import com.gmail.nossr50.config.mods.ToolConfigManager; import com.gmail.nossr50.config.skills.alchemy.PotionConfig; +import com.gmail.nossr50.config.skills.repair.RepairConfig; import com.gmail.nossr50.config.skills.repair.RepairConfigManager; +import com.gmail.nossr50.config.skills.salvage.SalvageConfig; import com.gmail.nossr50.config.skills.salvage.SalvageConfigManager; import com.gmail.nossr50.config.treasure.FishingTreasureConfig; import com.gmail.nossr50.config.treasure.TreasureConfig; @@ -146,8 +148,19 @@ public class mcMMO extends JavaPlugin { public static final String databaseCommandKey = "mcMMO: Processing Database Command"; public static FixedMetadataValue metadataValue; + private long purgeTime = 2630000000L; - public static final String ULTRA_PERMISSONS = "UltraPermissons"; + private GeneralConfig generalConfig; + private AdvancedConfig advancedConfig; + private RepairConfig repairConfig; + private SalvageConfig salvageConfig; + private PersistentDataConfig persistentDataConfig; + private ChatConfig chatConfig; + private CoreSkillsConfig coreSkillsConfig; + private RankConfig rankConfig; + private TreasureConfig treasureConfig; + private FishingTreasureConfig fishingTreasureConfig; + private SoundConfig soundConfig; public mcMMO() { p = this; @@ -159,8 +172,12 @@ public class mcMMO extends JavaPlugin { @Override public void onEnable() { try { + //Init configs + generalConfig = new GeneralConfig(getDataFolder()); + advancedConfig = new AdvancedConfig(getDataFolder()); + //Store this value so other plugins can check it - isRetroModeEnabled = Config.getInstance().getIsRetroMode(); + isRetroModeEnabled = generalConfig.getIsRetroMode(); //Platform Manager platformManager = new PlatformManager(); @@ -206,7 +223,11 @@ public class mcMMO extends JavaPlugin { getLogger().warning("mcMMO will not work properly alongside NoCheatPlus without CompatNoCheatPlus"); } - databaseManager = DatabaseManagerFactory.getDatabaseManager(); + // One month in milliseconds + this.purgeTime = 2630000000L * generalConfig.getOldUsersCutoff(); + + databaseManager = DatabaseManagerFactory.getDatabaseManager(mcMMO.getUsersFilePath(), getLogger(), purgeTime, mcMMO.p.getAdvancedConfig().getStartingLevel()); + databaseManager.init(); //Check for the newer API and tell them what to do if its missing checkForOutdatedAPI(); @@ -246,7 +267,7 @@ public class mcMMO extends JavaPlugin { placeStore = ChunkManagerFactory.getChunkManager(); // Get our ChunkletManager - if (Config.getInstance().getPTPCommandWorldPermissions()) { + if (generalConfig.getPTPCommandWorldPermissions()) { Permissions.generateWorldTeleportPermissions(); } @@ -257,11 +278,11 @@ public class mcMMO extends JavaPlugin { //If anonymous statistics are enabled then use them Metrics metrics; - if(Config.getInstance().getIsMetricsEnabled()) { + if(generalConfig.getIsMetricsEnabled()) { metrics = new Metrics(this, 3894); metrics.addCustomChart(new SimplePie("version", () -> getDescription().getVersion())); - if(Config.getInstance().getIsRetroMode()) + if(generalConfig.getIsRetroMode()) metrics.addCustomChart(new SimplePie("leveling_system", () -> "Retro")); else metrics.addCustomChart(new SimplePie("leveling_system", () -> "Standard")); @@ -350,7 +371,7 @@ public class mcMMO extends JavaPlugin { PartyManager.saveParties(); // Save our parties //TODO: Needed? - if(Config.getInstance().getScoreboardsEnabled()) + if(generalConfig.getScoreboardsEnabled()) ScoreboardManager.teardownAll(); formulaManager.saveFormula(); @@ -360,7 +381,7 @@ public class mcMMO extends JavaPlugin { e.printStackTrace(); } - if (Config.getInstance().getBackupsEnabled()) { + if (generalConfig.getBackupsEnabled()) { // Remove other tasks BEFORE starting the Backup, or we just cancel it straight away. try { ZipLibrary.mcMMOBackup(); @@ -532,7 +553,7 @@ public class mcMMO extends JavaPlugin { TreasureConfig.getInstance(); FishingTreasureConfig.getInstance(); HiddenConfig.getInstance(); - AdvancedConfig.getInstance(); + mcMMO.p.getAdvancedConfig(); PotionConfig.getInstance(); CoreSkillsConfig.getInstance(); SoundConfig.getInstance(); @@ -542,19 +563,19 @@ public class mcMMO extends JavaPlugin { List repairables = new ArrayList<>(); - if (Config.getInstance().getToolModsEnabled()) { + if (generalConfig.getToolModsEnabled()) { new ToolConfigManager(this); } - if (Config.getInstance().getArmorModsEnabled()) { + if (generalConfig.getArmorModsEnabled()) { new ArmorConfigManager(this); } - if (Config.getInstance().getBlockModsEnabled()) { + if (generalConfig.getBlockModsEnabled()) { new BlockConfigManager(this); } - if (Config.getInstance().getEntityModsEnabled()) { + if (generalConfig.getEntityModsEnabled()) { new EntityConfigManager(this); } @@ -609,7 +630,7 @@ public class mcMMO extends JavaPlugin { private void registerCustomRecipes() { getServer().getScheduler().scheduleSyncDelayedTask(this, () -> { - if (Config.getInstance().getChimaeraEnabled()) { + if (generalConfig.getChimaeraEnabled()) { getServer().addRecipe(ChimaeraWing.getChimaeraWingRecipe()); } }, 40); @@ -620,7 +641,7 @@ public class mcMMO extends JavaPlugin { long second = 20; long minute = second * 60; - long saveIntervalTicks = Math.max(minute, Config.getInstance().getSaveInterval() * minute); + long saveIntervalTicks = Math.max(minute, generalConfig.getSaveInterval() * minute); new SaveTimerTask().runTaskTimer(this, saveIntervalTicks, saveIntervalTicks); @@ -628,7 +649,7 @@ public class mcMMO extends JavaPlugin { new CleanBackupsTask().runTaskAsynchronously(mcMMO.p); // Old & Powerless User remover - long purgeIntervalTicks = Config.getInstance().getPurgeInterval() * 60L * 60L * Misc.TICK_CONVERSION_FACTOR; + long purgeIntervalTicks = generalConfig.getPurgeInterval() * 60L * 60L * Misc.TICK_CONVERSION_FACTOR; if (purgeIntervalTicks == 0) { new UserPurgeTask().runTaskLaterAsynchronously(this, 2 * Misc.TICK_CONVERSION_FACTOR); // Start 2 seconds after startup. @@ -638,7 +659,7 @@ public class mcMMO extends JavaPlugin { } // Automatically remove old members from parties - long kickIntervalTicks = Config.getInstance().getAutoPartyKickInterval() * 60L * 60L * Misc.TICK_CONVERSION_FACTOR; + long kickIntervalTicks = generalConfig.getAutoPartyKickInterval() * 60L * 60L * Misc.TICK_CONVERSION_FACTOR; if (kickIntervalTicks == 0) { new PartyAutoKickTask().runTaskLater(this, 2 * Misc.TICK_CONVERSION_FACTOR); // Start 2 seconds after startup. @@ -655,29 +676,29 @@ public class mcMMO extends JavaPlugin { new ClearRegisteredXPGainTask().runTaskTimer(this, 60, 60); } - if(AdvancedConfig.getInstance().allowPlayerTips()) + if(mcMMO.p.getAdvancedConfig().allowPlayerTips()) { new NotifySquelchReminderTask().runTaskTimer(this, 60, ((20 * 60) * 60)); } } private void checkModConfigs() { - if (!Config.getInstance().getToolModsEnabled()) { + if (!generalConfig.getToolModsEnabled()) { getLogger().warning("Cauldron implementation found, but the custom tool config for mcMMO is disabled!"); getLogger().info("To enable, set Mods.Tool_Mods_Enabled to TRUE in config.yml."); } - if (!Config.getInstance().getArmorModsEnabled()) { + if (!generalConfig.getArmorModsEnabled()) { getLogger().warning("Cauldron implementation found, but the custom armor config for mcMMO is disabled!"); getLogger().info("To enable, set Mods.Armor_Mods_Enabled to TRUE in config.yml."); } - if (!Config.getInstance().getBlockModsEnabled()) { + if (!generalConfig.getBlockModsEnabled()) { getLogger().warning("Cauldron implementation found, but the custom block config for mcMMO is disabled!"); getLogger().info("To enable, set Mods.Block_Mods_Enabled to TRUE in config.yml."); } - if (!Config.getInstance().getEntityModsEnabled()) { + if (!generalConfig.getEntityModsEnabled()) { getLogger().warning("Cauldron implementation found, but the custom entity config for mcMMO is disabled!"); getLogger().info("To enable, set Mods.Entity_Mods_Enabled to TRUE in config.yml."); } @@ -742,4 +763,15 @@ public class mcMMO extends JavaPlugin { serverShutdownExecuted = bool; } + public long getPurgeTime() { + return purgeTime; + } + + public @NotNull GeneralConfig getGeneralConfig() { + return generalConfig; + } + + public @NotNull AdvancedConfig getAdvancedConfig() { + return advancedConfig; + } } diff --git a/src/main/java/com/gmail/nossr50/party/PartyManager.java b/src/main/java/com/gmail/nossr50/party/PartyManager.java index 52d3836a5..4cd483329 100644 --- a/src/main/java/com/gmail/nossr50/party/PartyManager.java +++ b/src/main/java/com/gmail/nossr50/party/PartyManager.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.party; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.chat.ChatChannel; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.party.ItemShareType; @@ -61,7 +60,7 @@ public final class PartyManager { */ public static boolean isPartyFull(Player player, Party targetParty) { - return !Permissions.partySizeBypass(player) && Config.getInstance().getPartyMaxSize() >= 1 && targetParty.getOnlineMembers().size() >= Config.getInstance().getPartyMaxSize(); + return !Permissions.partySizeBypass(player) && mcMMO.p.getGeneralConfig().getPartyMaxSize() >= 1 && targetParty.getOnlineMembers().size() >= mcMMO.p.getGeneralConfig().getPartyMaxSize(); } /** @@ -153,7 +152,7 @@ public final class PartyManager { if (party != null) { Player player = mcMMOPlayer.getPlayer(); - double range = Config.getInstance().getPartyShareRange(); + double range = mcMMO.p.getGeneralConfig().getPartyShareRange(); for (Player member : party.getOnlineMembers()) { if (!player.equals(member) && member.isValid() && Misc.isNear(player.getLocation(), member.getLocation(), range)) { @@ -171,7 +170,7 @@ public final class PartyManager { if (party != null) { Player player = mcMMOPlayer.getPlayer(); - double range = Config.getInstance().getPartyShareRange(); + double range = mcMMO.p.getGeneralConfig().getPartyShareRange(); for (Player member : party.getVisibleMembers(player)) { if (!player.equals(member) @@ -439,9 +438,9 @@ public final class PartyManager { /* * Don't let players join a full party */ - if(Config.getInstance().getPartyMaxSize() > 0 && invite.getMembers().size() >= Config.getInstance().getPartyMaxSize()) + if(mcMMO.p.getGeneralConfig().getPartyMaxSize() > 0 && invite.getMembers().size() >= mcMMO.p.getGeneralConfig().getPartyMaxSize()) { - NotificationManager.sendPlayerInformation(mcMMOPlayer.getPlayer(), NotificationType.PARTY_MESSAGE, "Commands.Party.PartyFull.InviteAccept", invite.getName(), String.valueOf(Config.getInstance().getPartyMaxSize())); + NotificationManager.sendPlayerInformation(mcMMOPlayer.getPlayer(), NotificationType.PARTY_MESSAGE, "Commands.Party.PartyFull.InviteAccept", invite.getName(), String.valueOf(mcMMO.p.getGeneralConfig().getPartyMaxSize())); return; } @@ -810,7 +809,7 @@ public final class PartyManager { * @param level The current party level */ public static void informPartyMembersLevelUp(Party party, int levelsGained, int level) { - boolean levelUpSoundsEnabled = Config.getInstance().getLevelUpSoundsEnabled(); + boolean levelUpSoundsEnabled = mcMMO.p.getGeneralConfig().getLevelUpSoundsEnabled(); for (Player member : party.getOnlineMembers()) { member.sendMessage(LocaleLoader.getString("Party.LevelUp", levelsGained, level)); diff --git a/src/main/java/com/gmail/nossr50/party/ShareHandler.java b/src/main/java/com/gmail/nossr50/party/ShareHandler.java index c0a78e253..cc991104d 100644 --- a/src/main/java/com/gmail/nossr50/party/ShareHandler.java +++ b/src/main/java/com/gmail/nossr50/party/ShareHandler.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.party; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.party.ItemWeightConfig; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.experience.XPGainSource; @@ -9,6 +8,7 @@ import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.datatypes.party.ShareMode; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.entity.Item; @@ -44,7 +44,7 @@ public final class ShareHandler { nearMembers.add(mcMMOPlayer.getPlayer()); int partySize = nearMembers.size(); - double shareBonus = Math.min(Config.getInstance().getPartyShareBonusBase() + (partySize * Config.getInstance().getPartyShareBonusIncrease()), Config.getInstance().getPartyShareBonusCap()); + double shareBonus = Math.min(mcMMO.p.getGeneralConfig().getPartyShareBonusBase() + (partySize * mcMMO.p.getGeneralConfig().getPartyShareBonusIncrease()), mcMMO.p.getGeneralConfig().getPartyShareBonusCap()); float splitXp = (float) (xp / partySize * shareBonus); for (Player member : nearMembers) { diff --git a/src/main/java/com/gmail/nossr50/runnables/backups/CleanBackupsTask.java b/src/main/java/com/gmail/nossr50/runnables/backups/CleanBackupsTask.java index 114211c80..1a8162843 100644 --- a/src/main/java/com/gmail/nossr50/runnables/backups/CleanBackupsTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/backups/CleanBackupsTask.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.runnables.backups; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.mcMMO; import org.bukkit.scheduler.BukkitRunnable; @@ -48,11 +47,11 @@ public class CleanBackupsTask extends BukkitRunnable { int weekOfYear = cal.get(Calendar.WEEK_OF_YEAR); int year = cal.get(Calendar.YEAR); - if (isPast24Hours(date) && Config.getInstance().getKeepLast24Hours()) { + if (isPast24Hours(date) && mcMMO.p.getGeneralConfig().getKeepLast24Hours()) { // Keep all files from the last 24 hours continue; } - else if (isLastWeek(date) && !savedDays.contains(dayOfWeek) && Config.getInstance().getKeepDailyLastWeek()) { + else if (isLastWeek(date) && !savedDays.contains(dayOfWeek) && mcMMO.p.getGeneralConfig().getKeepDailyLastWeek()) { // Keep daily backups of the past week savedDays.add(dayOfWeek); continue; @@ -60,7 +59,7 @@ public class CleanBackupsTask extends BukkitRunnable { else { List savedWeeks = savedYearsWeeks.computeIfAbsent(year, k -> new ArrayList<>()); - if (!savedWeeks.contains(weekOfYear) && Config.getInstance().getKeepWeeklyPastMonth()) { + if (!savedWeeks.contains(weekOfYear) && mcMMO.p.getGeneralConfig().getKeepWeeklyPastMonth()) { // Keep one backup of each week savedWeeks.add(weekOfYear); continue; diff --git a/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java b/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java index 353e0ea04..1640d9301 100644 --- a/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.runnables.commands; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; @@ -30,7 +29,7 @@ public class McrankCommandDisplayTask extends BukkitRunnable { @Override public void run() { - if (useBoard && Config.getInstance().getScoreboardsEnabled()) { + if (useBoard && mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { displayBoard(); } diff --git a/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java b/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java index 664a1da10..82ab947dd 100644 --- a/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.runnables.commands; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.database.PlayerStat; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; @@ -34,7 +33,7 @@ public class MctopCommandDisplayTask extends BukkitRunnable { @Override public void run() { - if (useBoard && Config.getInstance().getScoreboardsEnabled()) { + if (useBoard && mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { displayBoard(); } diff --git a/src/main/java/com/gmail/nossr50/runnables/database/UserPurgeTask.java b/src/main/java/com/gmail/nossr50/runnables/database/UserPurgeTask.java index 8ce66bfa8..cf570e3f2 100644 --- a/src/main/java/com/gmail/nossr50/runnables/database/UserPurgeTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/database/UserPurgeTask.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.runnables.database; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.mcMMO; import org.bukkit.scheduler.BukkitRunnable; @@ -13,7 +12,7 @@ public class UserPurgeTask extends BukkitRunnable { lock.lock(); mcMMO.getDatabaseManager().purgePowerlessUsers(); - if (Config.getInstance().getOldUsersCutoff() != -1) { + if (mcMMO.p.getGeneralConfig().getOldUsersCutoff() != -1) { mcMMO.getDatabaseManager().purgeOldUsers(); } lock.unlock(); diff --git a/src/main/java/com/gmail/nossr50/runnables/items/ChimaeraWingWarmup.java b/src/main/java/com/gmail/nossr50/runnables/items/ChimaeraWingWarmup.java index b4ae92426..c7409b3ce 100644 --- a/src/main/java/com/gmail/nossr50/runnables/items/ChimaeraWingWarmup.java +++ b/src/main/java/com/gmail/nossr50/runnables/items/ChimaeraWingWarmup.java @@ -1,8 +1,8 @@ package com.gmail.nossr50.runnables.items; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.ChimaeraWing; import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.Misc; @@ -36,13 +36,13 @@ public class ChimaeraWingWarmup extends BukkitRunnable { ItemStack inHand = player.getInventory().getItemInMainHand(); - if (!ItemUtils.isChimaeraWing(inHand) || inHand.getAmount() < Config.getInstance().getChimaeraUseCost()) { + if (!ItemUtils.isChimaeraWing(inHand) || inHand.getAmount() < mcMMO.p.getGeneralConfig().getChimaeraUseCost()) { player.sendMessage(LocaleLoader.getString("Skills.NeedMore", LocaleLoader.getString("Item.ChimaeraWing.Name"))); return; } long recentlyHurt = mcMMOPlayer.getRecentlyHurt(); - int hurtCooldown = Config.getInstance().getChimaeraRecentlyHurtCooldown(); + int hurtCooldown = mcMMO.p.getGeneralConfig().getChimaeraRecentlyHurtCooldown(); if (hurtCooldown > 0) { int timeRemaining = SkillUtils.calculateTimeLeft(recentlyHurt * Misc.TIME_CONVERSION_FACTOR, hurtCooldown, player); diff --git a/src/main/java/com/gmail/nossr50/runnables/items/TeleportationWarmup.java b/src/main/java/com/gmail/nossr50/runnables/items/TeleportationWarmup.java index d3315d4ab..49ce24aad 100644 --- a/src/main/java/com/gmail/nossr50/runnables/items/TeleportationWarmup.java +++ b/src/main/java/com/gmail/nossr50/runnables/items/TeleportationWarmup.java @@ -1,8 +1,8 @@ package com.gmail.nossr50.runnables.items; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.util.EventUtils; import com.gmail.nossr50.util.Misc; @@ -42,7 +42,7 @@ public class TeleportationWarmup extends BukkitRunnable { return; } - int hurtCooldown = Config.getInstance().getPTPCommandRecentlyHurtCooldown(); + int hurtCooldown = mcMMO.p.getGeneralConfig().getPTPCommandRecentlyHurtCooldown(); if (hurtCooldown > 0) { int timeRemaining = SkillUtils.calculateTimeLeft(recentlyHurt * Misc.TIME_CONVERSION_FACTOR, hurtCooldown, teleportingPlayer); @@ -53,7 +53,7 @@ public class TeleportationWarmup extends BukkitRunnable { } } - if (Config.getInstance().getPTPCommandWorldPermissions()) { + if (mcMMO.p.getGeneralConfig().getPTPCommandWorldPermissions()) { World targetWorld = targetPlayer.getWorld(); World playerWorld = teleportingPlayer.getWorld(); diff --git a/src/main/java/com/gmail/nossr50/runnables/party/PartyAutoKickTask.java b/src/main/java/com/gmail/nossr50/runnables/party/PartyAutoKickTask.java index 31d961bf6..f66b003b6 100644 --- a/src/main/java/com/gmail/nossr50/runnables/party/PartyAutoKickTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/party/PartyAutoKickTask.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.runnables.party; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.party.Party; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.party.PartyManager; @@ -14,7 +13,7 @@ import java.util.Map.Entry; import java.util.UUID; public class PartyAutoKickTask extends BukkitRunnable { - private final static long KICK_TIME = 24L * 60L * 60L * 1000L * Config.getInstance().getAutoPartyKickTime(); + private final static long KICK_TIME = 24L * 60L * 60L * 1000L * mcMMO.p.getGeneralConfig().getAutoPartyKickTime(); @Override public void run() { diff --git a/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java b/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java index 8944fb043..5dccb2cf1 100644 --- a/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.runnables.player; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.locale.LocaleLoader; @@ -97,16 +96,16 @@ public class PlayerProfileLoadingTask extends BukkitRunnable { UserManager.track(mcMMOPlayer); mcMMOPlayer.actualizeRespawnATS(); - if (Config.getInstance().getScoreboardsEnabled()) { + if (mcMMO.p.getGeneralConfig().getScoreboardsEnabled()) { ScoreboardManager.setupPlayer(player); - if (Config.getInstance().getShowStatsAfterLogin()) { + if (mcMMO.p.getGeneralConfig().getShowStatsAfterLogin()) { ScoreboardManager.enablePlayerStatsScoreboard(player); new McScoreboardKeepTask(player).runTaskLater(mcMMO.p, Misc.TICK_CONVERSION_FACTOR); } } - if (Config.getInstance().getShowProfileLoadedMessage()) { + if (mcMMO.p.getGeneralConfig().getShowProfileLoadedMessage()) { player.sendMessage(LocaleLoader.getString("Profile.Loading.Success")); } diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/AbilityDisableTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/AbilityDisableTask.java index 11cd015a6..cce276fc2 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/AbilityDisableTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/AbilityDisableTask.java @@ -1,7 +1,5 @@ package com.gmail.nossr50.runnables.skills; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; @@ -41,7 +39,7 @@ public class AbilityDisableTask extends BukkitRunnable { // Fallthrough case BERSERK: - if (Config.getInstance().getRefreshChunksEnabled()) { + if (mcMMO.p.getGeneralConfig().getRefreshChunksEnabled()) { resendChunkRadiusAt(player); } // Fallthrough @@ -62,7 +60,7 @@ public class AbilityDisableTask extends BukkitRunnable { NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_OFF, ability.getAbilityOff()); } - if (AdvancedConfig.getInstance().sendAbilityNotificationToOtherPlayers()) { + if (mcMMO.p.getAdvancedConfig().sendAbilityNotificationToOtherPlayers()) { SkillUtils.sendSkillMessage(player, NotificationType.SUPER_ABILITY_ALERT_OTHERS, ability.getAbilityPlayerOff()); } new AbilityCooldownTask(mcMMOPlayer, ability).runTaskLater(mcMMO.p, PerksUtils.handleCooldownPerks(player, ability.getCooldown()) * Misc.TICK_CONVERSION_FACTOR); diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/BleedTimerTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/BleedTimerTask.java index 49298c2bb..839358afd 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/BleedTimerTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/BleedTimerTask.java @@ -57,7 +57,7 @@ // double damage; // // if (target instanceof Player) { -// damage = AdvancedConfig.getInstance().getRuptureDamagePlayer(); +// damage = mcMMO.p.getAdvancedConfig().getRuptureDamagePlayer(); // // //Above Bleed Rank 3 deals 50% more damage // if (containerEntry.getValue().toolTier >= 4 && containerEntry.getValue().bleedRank >= 3) @@ -78,7 +78,7 @@ // } // // } else { -// damage = AdvancedConfig.getInstance().getRuptureDamageMobs(); +// damage = mcMMO.p.getAdvancedConfig().getRuptureDamageMobs(); // //// debugMessage+="BaseDMG=["+damage+"], "; // diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/RuptureTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/RuptureTask.java index 9e4f3ee2b..e740a3fcd 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/RuptureTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/RuptureTask.java @@ -1,9 +1,7 @@ package com.gmail.nossr50.runnables.skills; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.MobHealthbarUtils; import com.gmail.nossr50.util.skills.ParticleEffectUtils; import com.google.common.base.Objects; import org.bukkit.entity.LivingEntity; @@ -28,7 +26,7 @@ public class RuptureTask extends BukkitRunnable { public RuptureTask(@NotNull McMMOPlayer ruptureSource, @NotNull LivingEntity targetEntity, double pureTickDamage, double explosionDamage) { this.ruptureSource = ruptureSource; this.targetEntity = targetEntity; - this.expireTick = AdvancedConfig.getInstance().getRuptureDurationSeconds(targetEntity instanceof Player) * 20; + this.expireTick = mcMMO.p.getAdvancedConfig().getRuptureDurationSeconds(targetEntity instanceof Player) * 20; this.ruptureTick = 0; this.damageTickTracker = 0; diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/ToolLowerTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/ToolLowerTask.java index 5f8881ff0..ef3cd0561 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/ToolLowerTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/ToolLowerTask.java @@ -1,9 +1,9 @@ package com.gmail.nossr50.runnables.skills; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.ToolType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.player.NotificationManager; import org.bukkit.scheduler.BukkitRunnable; @@ -24,7 +24,7 @@ public class ToolLowerTask extends BukkitRunnable { mcMMOPlayer.setToolPreparationMode(tool, false); - if (Config.getInstance().getAbilityMessagesEnabled()) { + if (mcMMO.p.getGeneralConfig().getAbilityMessagesEnabled()) { NotificationManager.sendPlayerInformation(mcMMOPlayer.getPlayer(), NotificationType.TOOL, tool.getLowerTool()); } } diff --git a/src/main/java/com/gmail/nossr50/skills/acrobatics/Acrobatics.java b/src/main/java/com/gmail/nossr50/skills/acrobatics/Acrobatics.java index 1c72521f8..60f948d90 100644 --- a/src/main/java/com/gmail/nossr50/skills/acrobatics/Acrobatics.java +++ b/src/main/java/com/gmail/nossr50/skills/acrobatics/Acrobatics.java @@ -1,13 +1,12 @@ package com.gmail.nossr50.skills.acrobatics; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; +import com.gmail.nossr50.mcMMO; public final class Acrobatics { - public static double dodgeDamageModifier = AdvancedConfig.getInstance().getDodgeDamageModifier(); + public static double dodgeDamageModifier = mcMMO.p.getAdvancedConfig().getDodgeDamageModifier(); public static int dodgeXpModifier = ExperienceConfig.getInstance().getDodgeXPModifier(); - public static boolean dodgeLightningDisabled = Config.getInstance().getDodgeLightningDisabled(); + public static boolean dodgeLightningDisabled = mcMMO.p.getGeneralConfig().getDodgeLightningDisabled(); private Acrobatics() {} diff --git a/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java b/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java index 58ac14bee..7aaa1844d 100644 --- a/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java +++ b/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.skills.alchemy; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.skills.AlchemyBrewTask; @@ -43,16 +42,16 @@ public final class Alchemy { } protected int getLevel() { - return AdvancedConfig.getInstance().getConcoctionsTierLevel(this); + return mcMMO.p.getAdvancedConfig().getConcoctionsTierLevel(this); } }*/ public static final int INGREDIENT_SLOT = 3; public static int catalysisUnlockLevel = RankUtils.getUnlockLevel(SubSkillType.ALCHEMY_CATALYSIS); - public static int catalysisMaxBonusLevel = AdvancedConfig.getInstance().getCatalysisMaxBonusLevel(); - public static double catalysisMinSpeed = AdvancedConfig.getInstance().getCatalysisMinSpeed(); - public static double catalysisMaxSpeed = AdvancedConfig.getInstance().getCatalysisMaxSpeed(); + public static int catalysisMaxBonusLevel = mcMMO.p.getAdvancedConfig().getCatalysisMaxBonusLevel(); + public static double catalysisMinSpeed = mcMMO.p.getAdvancedConfig().getCatalysisMinSpeed(); + public static double catalysisMaxSpeed = mcMMO.p.getAdvancedConfig().getCatalysisMaxSpeed(); public static Map brewingStandMap = new HashMap<>(); diff --git a/src/main/java/com/gmail/nossr50/skills/archery/Archery.java b/src/main/java/com/gmail/nossr50/skills/archery/Archery.java index a892b0a89..b980a6f34 100644 --- a/src/main/java/com/gmail/nossr50/skills/archery/Archery.java +++ b/src/main/java/com/gmail/nossr50/skills/archery/Archery.java @@ -1,9 +1,9 @@ package com.gmail.nossr50.skills.archery; import com.gmail.nossr50.api.ItemSpawnReason; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.skills.RankUtils; import org.bukkit.Material; @@ -19,9 +19,9 @@ import java.util.List; public class Archery { private static final List trackedEntities = new ArrayList<>(); - public static double skillShotMaxBonusDamage = AdvancedConfig.getInstance().getSkillShotDamageMax(); + public static double skillShotMaxBonusDamage = mcMMO.p.getAdvancedConfig().getSkillShotDamageMax(); - public static double dazeBonusDamage = AdvancedConfig.getInstance().getDazeBonusDamage(); + public static double dazeBonusDamage = mcMMO.p.getAdvancedConfig().getDazeBonusDamage(); public static final double DISTANCE_XP_MULTIPLIER = ExperienceConfig.getInstance().getArcheryDistanceMultiplier(); @@ -72,6 +72,6 @@ public class Archery { } public static double getDamageBonusPercent(Player player) { - return ((RankUtils.getRank(player, SubSkillType.ARCHERY_SKILL_SHOT)) * (AdvancedConfig.getInstance().getSkillShotRankDamageMultiplier()) / 100.0D); + return ((RankUtils.getRank(player, SubSkillType.ARCHERY_SKILL_SHOT)) * (mcMMO.p.getAdvancedConfig().getSkillShotRankDamageMultiplier()) / 100.0D); } } diff --git a/src/main/java/com/gmail/nossr50/skills/axes/Axes.java b/src/main/java/com/gmail/nossr50/skills/axes/Axes.java index 7f1ba62df..47d95be3f 100644 --- a/src/main/java/com/gmail/nossr50/skills/axes/Axes.java +++ b/src/main/java/com/gmail/nossr50/skills/axes/Axes.java @@ -1,7 +1,7 @@ package com.gmail.nossr50.skills.axes; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.skills.RankUtils; import org.bukkit.entity.LivingEntity; @@ -9,18 +9,18 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; public class Axes { - public static double axeMasteryRankDamageMultiplier = AdvancedConfig.getInstance().getAxeMasteryRankDamageMultiplier(); + public static double axeMasteryRankDamageMultiplier = mcMMO.p.getAdvancedConfig().getAxeMasteryRankDamageMultiplier(); - public static double criticalHitPVPModifier = AdvancedConfig.getInstance().getCriticalStrikesPVPModifier(); - public static double criticalHitPVEModifier = AdvancedConfig.getInstance().getCriticalStrikesPVEModifier(); + public static double criticalHitPVPModifier = mcMMO.p.getAdvancedConfig().getCriticalStrikesPVPModifier(); + public static double criticalHitPVEModifier = mcMMO.p.getAdvancedConfig().getCriticalStrikesPVEModifier(); - public static double impactChance = AdvancedConfig.getInstance().getImpactChance(); + public static double impactChance = mcMMO.p.getAdvancedConfig().getImpactChance(); - public static double greaterImpactBonusDamage = AdvancedConfig.getInstance().getGreaterImpactBonusDamage(); - public static double greaterImpactChance = AdvancedConfig.getInstance().getGreaterImpactChance(); - public static double greaterImpactKnockbackMultiplier = AdvancedConfig.getInstance().getGreaterImpactModifier(); + public static double greaterImpactBonusDamage = mcMMO.p.getAdvancedConfig().getGreaterImpactBonusDamage(); + public static double greaterImpactChance = mcMMO.p.getAdvancedConfig().getGreaterImpactChance(); + public static double greaterImpactKnockbackMultiplier = mcMMO.p.getAdvancedConfig().getGreaterImpactModifier(); - public static double skullSplitterModifier = AdvancedConfig.getInstance().getSkullSplitterModifier(); + public static double skullSplitterModifier = mcMMO.p.getAdvancedConfig().getSkullSplitterModifier(); protected static boolean hasArmor(LivingEntity target) { if(target == null || !target.isValid() || target.getEquipment() == null) diff --git a/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java b/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java index ead48f6d8..6f2bbe08c 100644 --- a/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java +++ b/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java @@ -1,12 +1,12 @@ package com.gmail.nossr50.skills.axes; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.datatypes.skills.ToolType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.Permissions; @@ -127,7 +127,7 @@ public class AxesManager extends SkillManager { } public double getImpactDurabilityDamage() { - return AdvancedConfig.getInstance().getImpactDurabilityDamageMultiplier() * RankUtils.getRank(getPlayer(), SubSkillType.AXES_ARMOR_IMPACT); + return mcMMO.p.getAdvancedConfig().getImpactDurabilityDamageMultiplier() * RankUtils.getRank(getPlayer(), SubSkillType.AXES_ARMOR_IMPACT); } /** diff --git a/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java b/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java index 14eda7e32..5412c9ef8 100644 --- a/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java +++ b/src/main/java/com/gmail/nossr50/skills/excavation/ExcavationManager.java @@ -1,12 +1,12 @@ package com.gmail.nossr50.skills.excavation; import com.gmail.nossr50.api.ItemSpawnReason; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.treasure.ExcavationTreasure; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.Permissions; @@ -98,6 +98,6 @@ public class ExcavationManager extends SkillManager { excavationBlockCheck(blockState); excavationBlockCheck(blockState); - SkillUtils.handleDurabilityChange(getPlayer().getInventory().getItemInMainHand(), Config.getInstance().getAbilityToolDamage()); + SkillUtils.handleDurabilityChange(getPlayer().getInventory().getItemInMainHand(), mcMMO.p.getGeneralConfig().getAbilityToolDamage()); } } diff --git a/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java b/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java index 22f8eecc7..d4a4d266c 100644 --- a/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/fishing/FishingManager.java @@ -1,8 +1,6 @@ package com.gmail.nossr50.skills.fishing; import com.gmail.nossr50.api.ItemSpawnReason; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.config.treasure.FishingTreasureConfig; import com.gmail.nossr50.datatypes.experience.XPGainReason; @@ -198,11 +196,11 @@ public class FishingManager extends SkillManager { } public double getShakeChance() { - return AdvancedConfig.getInstance().getShakeChance(RankUtils.getRank(mmoPlayer.getPlayer(), SubSkillType.FISHING_SHAKE)); + return mcMMO.p.getAdvancedConfig().getShakeChance(RankUtils.getRank(mmoPlayer.getPlayer(), SubSkillType.FISHING_SHAKE)); } protected int getVanillaXPBoostModifier() { - return AdvancedConfig.getInstance().getFishingVanillaXPModifier(getLootTier()); + return mcMMO.p.getAdvancedConfig().getFishingVanillaXPModifier(getLootTier()); } /** @@ -273,8 +271,8 @@ public class FishingManager extends SkillManager { int maxWaitReduction = getMasterAnglerTickMaxWaitReduction(masterAnglerRank, boatBonus, convertedLureBonus); //Ticks for minWait and maxWait never go below this value - int bonusCapMin = AdvancedConfig.getInstance().getFishingReductionMinWaitCap(); - int bonusCapMax = AdvancedConfig.getInstance().getFishingReductionMaxWaitCap(); + int bonusCapMin = mcMMO.p.getAdvancedConfig().getFishingReductionMinWaitCap(); + int bonusCapMax = mcMMO.p.getAdvancedConfig().getFishingReductionMaxWaitCap(); int reducedMinWaitTime = getReducedTicks(minWaitTicks, minWaitReduction, bonusCapMin); int reducedMaxWaitTime = getReducedTicks(maxWaitTicks, maxWaitReduction, bonusCapMax); @@ -337,7 +335,7 @@ public class FishingManager extends SkillManager { } public int getMasterAnglerTickMaxWaitReduction(int masterAnglerRank, boolean boatBonus, int emulatedLureBonus) { - int totalBonus = AdvancedConfig.getInstance().getFishingReductionMaxWaitTicks() * masterAnglerRank; + int totalBonus = mcMMO.p.getAdvancedConfig().getFishingReductionMaxWaitTicks() * masterAnglerRank; if(boatBonus) { totalBonus += getFishingBoatMaxWaitReduction(); @@ -349,7 +347,7 @@ public class FishingManager extends SkillManager { } public int getMasterAnglerTickMinWaitReduction(int masterAnglerRank, boolean boatBonus) { - int totalBonus = AdvancedConfig.getInstance().getFishingReductionMinWaitTicks() * masterAnglerRank; + int totalBonus = mcMMO.p.getAdvancedConfig().getFishingReductionMinWaitTicks() * masterAnglerRank; if(boatBonus) { totalBonus += getFishingBoatMinWaitReduction(); @@ -359,11 +357,11 @@ public class FishingManager extends SkillManager { } public int getFishingBoatMinWaitReduction() { - return AdvancedConfig.getInstance().getFishingBoatReductionMinWaitTicks(); + return mcMMO.p.getAdvancedConfig().getFishingBoatReductionMinWaitTicks(); } public int getFishingBoatMaxWaitReduction() { - return AdvancedConfig.getInstance().getFishingBoatReductionMaxWaitTicks(); + return mcMMO.p.getAdvancedConfig().getFishingBoatReductionMaxWaitTicks(); } public boolean isMagicHunterEnabled() { @@ -386,7 +384,7 @@ public class FishingManager extends SkillManager { FishingTreasure treasure = null; boolean fishingSucceeds = false; - if (Config.getInstance().getFishingDropsEnabled() && Permissions.isSubSkillEnabled(player, SubSkillType.FISHING_TREASURE_HUNTER)) { + if (mcMMO.p.getGeneralConfig().getFishingDropsEnabled() && Permissions.isSubSkillEnabled(player, SubSkillType.FISHING_TREASURE_HUNTER)) { treasure = getFishingTreasure(); this.fishingCatch = null; } @@ -447,7 +445,7 @@ public class FishingManager extends SkillManager { } if(fishingSucceeds) { - if (Config.getInstance().getFishingExtraFish()) { + if (mcMMO.p.getGeneralConfig().getFishingExtraFish()) { Misc.spawnItem(player.getEyeLocation(), fishingCatch.getItemStack(), ItemSpawnReason.FISHING_EXTRA_FISH); } @@ -579,7 +577,7 @@ public class FishingManager extends SkillManager { } // Rather than subtracting luck (and causing a minimum 3% chance for every drop), scale by luck. - diceRoll *= (1.0 - luck * Config.getInstance().getFishingLureModifier() / 100); + diceRoll *= (1.0 - luck * mcMMO.p.getGeneralConfig().getFishingLureModifier() / 100); FishingTreasure treasure = null; diff --git a/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java b/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java index 85f87ed51..7cf4ce1c4 100644 --- a/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java +++ b/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.skills.herbalism; import com.gmail.nossr50.api.ItemSpawnReason; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.config.treasure.TreasureConfig; import com.gmail.nossr50.datatypes.BlockSnapshot; @@ -210,7 +209,7 @@ public class HerbalismManager extends SkillManager { public void processHerbalismBlockBreakEvent(BlockBreakEvent blockBreakEvent) { Player player = getPlayer(); - if (Config.getInstance().getHerbalismPreventAFK() && player.isInsideVehicle()) { + if (mcMMO.p.getGeneralConfig().getHerbalismPreventAFK() && player.isInsideVehicle()) { return; } @@ -257,7 +256,7 @@ public class HerbalismManager extends SkillManager { //TODO: The design of Green Terra needs to change, this is a mess if(Permissions.greenThumbPlant(getPlayer(), originalBreak.getType())) { - if(Config.getInstance().isGreenThumbReplantableCrop(originalBreak.getType())) { + if(mcMMO.p.getGeneralConfig().isGreenThumbReplantableCrop(originalBreak.getType())) { if(!getPlayer().isSneaking()) { greenThumbActivated = processGreenThumbPlants(originalBreak, blockBreakEvent, isGreenTerraActive()); } diff --git a/src/main/java/com/gmail/nossr50/skills/mining/BlastMining.java b/src/main/java/com/gmail/nossr50/skills/mining/BlastMining.java index 4ca7756d2..f2df8399d 100644 --- a/src/main/java/com/gmail/nossr50/skills/mining/BlastMining.java +++ b/src/main/java/com/gmail/nossr50/skills/mining/BlastMining.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.skills.mining; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.player.UserManager; @@ -33,7 +32,7 @@ public class BlastMining { } protected int getLevel() { - return AdvancedConfig.getInstance().getBlastMiningRankLevel(this); + return mcMMO.p.getAdvancedConfig().getBlastMiningRankLevel(this); } @@ -42,13 +41,13 @@ public class BlastMining { public final static int MAXIMUM_REMOTE_DETONATION_DISTANCE = 100; public static double getBlastRadiusModifier(int rank) { - return AdvancedConfig.getInstance().getBlastRadiusModifier(rank); + return mcMMO.p.getAdvancedConfig().getBlastRadiusModifier(rank); } public static double getBlastDamageDecrease(int rank) { - return AdvancedConfig.getInstance().getBlastDamageDecrease(rank); + return mcMMO.p.getAdvancedConfig().getBlastDamageDecrease(rank); } diff --git a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java index 868cdaad1..b1ffd853a 100644 --- a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java +++ b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java @@ -1,8 +1,6 @@ package com.gmail.nossr50.skills.mining; import com.gmail.nossr50.api.ItemSpawnReason; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.interactions.NotificationType; @@ -48,7 +46,7 @@ public class MiningManager extends SkillManager { Player player = getPlayer(); return canUseBlastMining() && player.isSneaking() - && (ItemUtils.isPickaxe(getPlayer().getInventory().getItemInMainHand()) || player.getInventory().getItemInMainHand().getType() == Config.getInstance().getDetonatorItem()) + && (ItemUtils.isPickaxe(getPlayer().getInventory().getItemInMainHand()) || player.getInventory().getItemInMainHand().getType() == mcMMO.p.getGeneralConfig().getDetonatorItem()) && Permissions.remoteDetonation(player); } @@ -83,20 +81,20 @@ public class MiningManager extends SkillManager { } if (mmoPlayer.getAbilityMode(skill.getAbility())) { - SkillUtils.handleDurabilityChange(getPlayer().getInventory().getItemInMainHand(), Config.getInstance().getAbilityToolDamage()); + SkillUtils.handleDurabilityChange(getPlayer().getInventory().getItemInMainHand(), mcMMO.p.getGeneralConfig().getAbilityToolDamage()); } - if(!Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.MINING, blockState.getType()) || !canDoubleDrop()) + if(!mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.MINING, blockState.getType()) || !canDoubleDrop()) return; boolean silkTouch = player.getInventory().getItemInMainHand().containsEnchantment(Enchantment.SILK_TOUCH); - if(silkTouch && !AdvancedConfig.getInstance().getDoubleDropSilkTouchEnabled()) + if(silkTouch && !mcMMO.p.getAdvancedConfig().getDoubleDropSilkTouchEnabled()) return; //TODO: Make this readable if (RandomChanceUtil.checkRandomChanceExecutionSuccess(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS, true)) { - boolean useTriple = mmoPlayer.getAbilityMode(skill.getAbility()) && AdvancedConfig.getInstance().getAllowMiningTripleDrops(); + boolean useTriple = mmoPlayer.getAbilityMode(skill.getAbility()) && mcMMO.p.getAdvancedConfig().getAllowMiningTripleDrops(); BlockUtils.markDropsAsBonus(blockState, useTriple); } } @@ -249,11 +247,11 @@ public class MiningManager extends SkillManager { } public static double getOreBonus(int rank) { - return AdvancedConfig.getInstance().getOreBonus(rank); + return mcMMO.p.getAdvancedConfig().getOreBonus(rank); } public static double getDebrisReduction(int rank) { - return AdvancedConfig.getInstance().getDebrisReduction(rank); + return mcMMO.p.getAdvancedConfig().getDebrisReduction(rank); } /** @@ -266,7 +264,7 @@ public class MiningManager extends SkillManager { } public static int getDropMultiplier(int rank) { - return AdvancedConfig.getInstance().getDropMultiplier(rank); + return mcMMO.p.getAdvancedConfig().getDropMultiplier(rank); } /** diff --git a/src/main/java/com/gmail/nossr50/skills/repair/ArcaneForging.java b/src/main/java/com/gmail/nossr50/skills/repair/ArcaneForging.java index f7ea4fd70..05bcfb160 100644 --- a/src/main/java/com/gmail/nossr50/skills/repair/ArcaneForging.java +++ b/src/main/java/com/gmail/nossr50/skills/repair/ArcaneForging.java @@ -1,9 +1,9 @@ package com.gmail.nossr50.skills.repair; -import com.gmail.nossr50.config.AdvancedConfig; +import com.gmail.nossr50.mcMMO; public class ArcaneForging { - public static boolean arcaneForgingDowngrades = AdvancedConfig.getInstance().getArcaneForgingDowngradeEnabled(); - public static boolean arcaneForgingEnchantLoss = AdvancedConfig.getInstance().getArcaneForgingEnchantLossEnabled(); + public static boolean arcaneForgingDowngrades = mcMMO.p.getAdvancedConfig().getArcaneForgingDowngradeEnabled(); + public static boolean arcaneForgingEnchantLoss = mcMMO.p.getAdvancedConfig().getArcaneForgingEnchantLossEnabled(); } diff --git a/src/main/java/com/gmail/nossr50/skills/repair/Repair.java b/src/main/java/com/gmail/nossr50/skills/repair/Repair.java index 4ee346ea1..36ba8cdc5 100644 --- a/src/main/java/com/gmail/nossr50/skills/repair/Repair.java +++ b/src/main/java/com/gmail/nossr50/skills/repair/Repair.java @@ -1,13 +1,12 @@ package com.gmail.nossr50.skills.repair; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.mcMMO; import org.bukkit.Material; public class Repair { - public static int repairMasteryMaxBonusLevel = AdvancedConfig.getInstance().getMaxBonusLevel(SubSkillType.REPAIR_REPAIR_MASTERY); - public static double repairMasteryMaxBonus = AdvancedConfig.getInstance().getRepairMasteryMaxBonus(); + public static int repairMasteryMaxBonusLevel = mcMMO.p.getAdvancedConfig().getMaxBonusLevel(SubSkillType.REPAIR_REPAIR_MASTERY); + public static double repairMasteryMaxBonus = mcMMO.p.getAdvancedConfig().getRepairMasteryMaxBonus(); - public static Material anvilMaterial = Config.getInstance().getRepairAnvilMaterial(); + public static Material anvilMaterial = mcMMO.p.getGeneralConfig().getRepairAnvilMaterial(); } diff --git a/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java b/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java index 8e8e56a3c..aec9f007c 100644 --- a/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java +++ b/src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java @@ -1,7 +1,5 @@ package com.gmail.nossr50.skills.repair; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.interactions.NotificationType; @@ -51,11 +49,11 @@ public class RepairManager extends SkillManager { return; } - if (Config.getInstance().getRepairAnvilMessagesEnabled()) { + if (mcMMO.p.getGeneralConfig().getRepairAnvilMessagesEnabled()) { NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Repair.Listener.Anvil"); } - if (Config.getInstance().getRepairAnvilPlaceSoundsEnabled()) { + if (mcMMO.p.getGeneralConfig().getRepairAnvilPlaceSoundsEnabled()) { SoundManager.sendSound(player, player.getLocation(), SoundType.ANVIL); } @@ -153,7 +151,7 @@ public class RepairManager extends SkillManager { * ExperienceConfig.getInstance().getRepairXP(repairable.getRepairMaterialType())), XPGainReason.PVE); // BWONG BWONG BWONG - if (Config.getInstance().getRepairAnvilUseSoundsEnabled()) { + if (mcMMO.p.getGeneralConfig().getRepairAnvilUseSoundsEnabled()) { SoundManager.sendSound(player, player.getLocation(), SoundType.ANVIL); SoundManager.sendSound(player, player.getLocation(), SoundType.ITEM_BREAK); } @@ -175,7 +173,7 @@ public class RepairManager extends SkillManager { Player player = getPlayer(); long lastUse = getLastAnvilUse(); - if (!SkillUtils.cooldownExpired(lastUse, 3) || !Config.getInstance().getRepairConfirmRequired()) { + if (!SkillUtils.cooldownExpired(lastUse, 3) || !mcMMO.p.getGeneralConfig().getRepairConfirmRequired()) { return true; } @@ -204,7 +202,7 @@ public class RepairManager extends SkillManager { * @return The chance of keeping the enchantment */ public double getKeepEnchantChance() { - return AdvancedConfig.getInstance().getArcaneForgingKeepEnchantsChance(getArcaneForgingRank()); + return mcMMO.p.getAdvancedConfig().getArcaneForgingKeepEnchantsChance(getArcaneForgingRank()); } /** @@ -213,7 +211,7 @@ public class RepairManager extends SkillManager { * @return The chance of the enchantment being downgraded */ public double getDowngradeEnchantChance() { - return AdvancedConfig.getInstance().getArcaneForgingDowngradeChance(getArcaneForgingRank()); + return mcMMO.p.getAdvancedConfig().getArcaneForgingDowngradeChance(getArcaneForgingRank()); } /* diff --git a/src/main/java/com/gmail/nossr50/skills/salvage/Salvage.java b/src/main/java/com/gmail/nossr50/skills/salvage/Salvage.java index 0e94b0589..4f510f909 100644 --- a/src/main/java/com/gmail/nossr50/skills/salvage/Salvage.java +++ b/src/main/java/com/gmail/nossr50/skills/salvage/Salvage.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.skills.salvage; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; +import com.gmail.nossr50.mcMMO; import org.bukkit.Material; public final class Salvage { @@ -12,15 +11,15 @@ public final class Salvage { */ private Salvage() {} - public static Material anvilMaterial = Config.getInstance().getSalvageAnvilMaterial(); + public static Material anvilMaterial = mcMMO.p.getGeneralConfig().getSalvageAnvilMaterial(); - /*public static int salvageMaxPercentageLevel = AdvancedConfig.getInstance().getSalvageMaxPercentageLevel(); - public static double salvageMaxPercentage = AdvancedConfig.getInstance().getSalvageMaxPercentage(); + /*public static int salvageMaxPercentageLevel = mcMMO.p.getAdvancedConfig().getSalvageMaxPercentageLevel(); + public static double salvageMaxPercentage = mcMMO.p.getAdvancedConfig().getSalvageMaxPercentage(); public static int advancedSalvageUnlockLevel = RankUtils.getRankUnlockLevel(SubSkillType.SALVAGE_SCRAP_COLLECTOR, 1);*/ - public static boolean arcaneSalvageDowngrades = AdvancedConfig.getInstance().getArcaneSalvageEnchantDowngradeEnabled(); - public static boolean arcaneSalvageEnchantLoss = AdvancedConfig.getInstance().getArcaneSalvageEnchantLossEnabled(); + public static boolean arcaneSalvageDowngrades = mcMMO.p.getAdvancedConfig().getArcaneSalvageEnchantDowngradeEnabled(); + public static boolean arcaneSalvageEnchantLoss = mcMMO.p.getAdvancedConfig().getArcaneSalvageEnchantLossEnabled(); static int calculateSalvageableAmount(int currentDurability, short maxDurability, int baseAmount) { double percentDamaged = (maxDurability <= 0) ? 1D : (double) (maxDurability - currentDurability) / maxDurability; diff --git a/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java b/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java index 2545a15d2..28afb1192 100644 --- a/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java +++ b/src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java @@ -1,8 +1,6 @@ package com.gmail.nossr50.skills.salvage; import com.gmail.nossr50.api.ItemSpawnReason; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.player.McMMOPlayer; @@ -53,11 +51,11 @@ public class SalvageManager extends SkillManager { return; } - if (Config.getInstance().getSalvageAnvilMessagesEnabled()) { + if (mcMMO.p.getGeneralConfig().getSalvageAnvilMessagesEnabled()) { NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE, "Salvage.Listener.Anvil"); } - if (Config.getInstance().getSalvageAnvilPlaceSoundsEnabled()) { + if (mcMMO.p.getGeneralConfig().getSalvageAnvilPlaceSoundsEnabled()) { SoundManager.sendSound(player, player.getLocation(), SoundType.ANVIL); } @@ -168,7 +166,7 @@ public class SalvageManager extends SkillManager { Misc.spawnItemTowardsLocation(anvilLoc.clone(), playerLoc.clone(), salvageResults, vectorSpeed, ItemSpawnReason.SALVAGE_MATERIALS); // BWONG BWONG BWONG - CLUNK! - if (Config.getInstance().getSalvageAnvilUseSoundsEnabled()) { + if (mcMMO.p.getGeneralConfig().getSalvageAnvilUseSoundsEnabled()) { SoundManager.sendSound(player, player.getLocation(), SoundType.ITEM_BREAK); } @@ -220,11 +218,11 @@ public class SalvageManager extends SkillManager { if(Permissions.hasSalvageEnchantBypassPerk(getPlayer())) return 100.0D; - return AdvancedConfig.getInstance().getArcaneSalvageExtractFullEnchantsChance(getArcaneSalvageRank()); + return mcMMO.p.getAdvancedConfig().getArcaneSalvageExtractFullEnchantsChance(getArcaneSalvageRank()); } public double getExtractPartialEnchantChance() { - return AdvancedConfig.getInstance().getArcaneSalvageExtractPartialEnchantsChance(getArcaneSalvageRank()); + return mcMMO.p.getAdvancedConfig().getArcaneSalvageExtractPartialEnchantsChance(getArcaneSalvageRank()); } private ItemStack arcaneSalvageCheck(Map enchants) { @@ -293,7 +291,7 @@ public class SalvageManager extends SkillManager { Player player = getPlayer(); long lastUse = getLastAnvilUse(); - if (!SkillUtils.cooldownExpired(lastUse, 3) || !Config.getInstance().getSalvageConfirmRequired()) { + if (!SkillUtils.cooldownExpired(lastUse, 3) || !mcMMO.p.getGeneralConfig().getSalvageConfirmRequired()) { return true; } diff --git a/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java b/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java index 0c0e0cb23..e30100723 100644 --- a/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java @@ -1,11 +1,11 @@ package com.gmail.nossr50.skills.smelting; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.experience.XPGainSource; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.random.RandomChanceUtil; @@ -125,7 +125,7 @@ public class SmeltingManager extends SkillManager { */ //Process double smelt - if (Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.SMELTING, resultItemStack.getType()) + if (mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.SMELTING, resultItemStack.getType()) && canDoubleSmeltItemStack(furnace) //Effectively two less than max stack size && isSecondSmeltSuccessful()) { diff --git a/src/main/java/com/gmail/nossr50/skills/swords/Swords.java b/src/main/java/com/gmail/nossr50/skills/swords/Swords.java index 0c2bd8fad..7dda504ea 100644 --- a/src/main/java/com/gmail/nossr50/skills/swords/Swords.java +++ b/src/main/java/com/gmail/nossr50/skills/swords/Swords.java @@ -1,9 +1,9 @@ package com.gmail.nossr50.skills.swords; -import com.gmail.nossr50.config.AdvancedConfig; +import com.gmail.nossr50.mcMMO; public class Swords { - public static double counterAttackModifier = AdvancedConfig.getInstance().getCounterModifier(); + public static double counterAttackModifier = mcMMO.p.getAdvancedConfig().getCounterModifier(); - public static double serratedStrikesModifier = AdvancedConfig.getInstance().getSerratedStrikesModifier(); + public static double serratedStrikesModifier = mcMMO.p.getAdvancedConfig().getSerratedStrikesModifier(); } diff --git a/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java b/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java index d6d07b62e..b3a194d00 100644 --- a/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.skills.swords; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.meta.RuptureTaskMeta; import com.gmail.nossr50.datatypes.player.McMMOPlayer; @@ -76,7 +75,7 @@ public class SwordsManager extends SkillManager { return; //Don't apply bleed } - if (RandomChanceUtil.rollDice(AdvancedConfig.getInstance().getRuptureChanceToApplyOnHit(getRuptureRank()), 100)) { + if (RandomChanceUtil.rollDice(mcMMO.p.getAdvancedConfig().getRuptureChanceToApplyOnHit(getRuptureRank()), 100)) { if (target instanceof Player) { Player defender = (Player) target; @@ -91,8 +90,8 @@ public class SwordsManager extends SkillManager { } RuptureTask ruptureTask = new RuptureTask(mmoPlayer, target, - AdvancedConfig.getInstance().getRuptureTickDamage(target instanceof Player, getRuptureRank()), - AdvancedConfig.getInstance().getRuptureExplosionDamage(target instanceof Player, getRuptureRank())); + mcMMO.p.getAdvancedConfig().getRuptureTickDamage(target instanceof Player, getRuptureRank()), + mcMMO.p.getAdvancedConfig().getRuptureExplosionDamage(target instanceof Player, getRuptureRank())); RuptureTaskMeta ruptureTaskMeta = new RuptureTaskMeta(mcMMO.p, ruptureTask); @@ -136,7 +135,7 @@ public class SwordsManager extends SkillManager { } public int getRuptureBleedTicks(boolean isTargetPlayer) { - return AdvancedConfig.getInstance().getRuptureDurationSeconds(isTargetPlayer) / RuptureTask.DAMAGE_TICK_INTERVAL; + return mcMMO.p.getAdvancedConfig().getRuptureDurationSeconds(isTargetPlayer) / RuptureTask.DAMAGE_TICK_INTERVAL; } /** diff --git a/src/main/java/com/gmail/nossr50/skills/taming/Taming.java b/src/main/java/com/gmail/nossr50/skills/taming/Taming.java index 1313c4c46..26ee15a67 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/Taming.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/Taming.java @@ -1,20 +1,20 @@ package com.gmail.nossr50.skills.taming; -import com.gmail.nossr50.config.AdvancedConfig; +import com.gmail.nossr50.mcMMO; import org.bukkit.EntityEffect; import org.bukkit.entity.*; public class Taming { - public static double fastFoodServiceActivationChance = AdvancedConfig.getInstance().getFastFoodChance(); + public static double fastFoodServiceActivationChance = mcMMO.p.getAdvancedConfig().getFastFoodChance(); public static int goreBleedTicks = 2; //Equivalent to rank 1 in Rupture - public static double goreModifier = AdvancedConfig.getInstance().getGoreModifier(); + public static double goreModifier = mcMMO.p.getAdvancedConfig().getGoreModifier(); - public static double sharpenedClawsBonusDamage = AdvancedConfig.getInstance().getSharpenedClawsBonus(); + public static double sharpenedClawsBonusDamage = mcMMO.p.getAdvancedConfig().getSharpenedClawsBonus(); - public static double shockProofModifier = AdvancedConfig.getInstance().getShockProofModifier(); + public static double shockProofModifier = mcMMO.p.getAdvancedConfig().getShockProofModifier(); - public static double thickFurModifier = AdvancedConfig.getInstance().getThickFurModifier(); + public static double thickFurModifier = mcMMO.p.getAdvancedConfig().getThickFurModifier(); public static boolean canPreventDamage(Tameable pet, AnimalTamer owner) { return pet.isTamed() && owner instanceof Player && pet instanceof Wolf; diff --git a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java index 23a12081b..cd5f14545 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/TamingManager.java @@ -1,7 +1,5 @@ package com.gmail.nossr50.skills.taming; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.interactions.NotificationType; @@ -64,9 +62,9 @@ public class TamingManager extends SkillManager { if(summoningItems == null) { summoningItems = new HashMap<>(); - summoningItems.put(Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.CAT.getConfigEntityTypeEntry()), CallOfTheWildType.CAT); - summoningItems.put(Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.WOLF.getConfigEntityTypeEntry()), CallOfTheWildType.WOLF); - summoningItems.put(Config.getInstance().getTamingCOTWMaterial(CallOfTheWildType.HORSE.getConfigEntityTypeEntry()), CallOfTheWildType.HORSE); + summoningItems.put(mcMMO.p.getGeneralConfig().getTamingCOTWMaterial(CallOfTheWildType.CAT.getConfigEntityTypeEntry()), CallOfTheWildType.CAT); + summoningItems.put(mcMMO.p.getGeneralConfig().getTamingCOTWMaterial(CallOfTheWildType.WOLF.getConfigEntityTypeEntry()), CallOfTheWildType.WOLF); + summoningItems.put(mcMMO.p.getGeneralConfig().getTamingCOTWMaterial(CallOfTheWildType.HORSE.getConfigEntityTypeEntry()), CallOfTheWildType.HORSE); } //TODO: Temporary static cache, will be changed in 2.2 @@ -75,11 +73,11 @@ public class TamingManager extends SkillManager { cotwSummonDataProperties = new HashMap<>(); for(CallOfTheWildType callOfTheWildType : CallOfTheWildType.values()) { - Material itemSummonMaterial = Config.getInstance().getTamingCOTWMaterial(callOfTheWildType.getConfigEntityTypeEntry()); - int itemAmountRequired = Config.getInstance().getTamingCOTWCost(callOfTheWildType.getConfigEntityTypeEntry()); - int entitiesSummonedPerCOTW = Config.getInstance().getTamingCOTWAmount(callOfTheWildType.getConfigEntityTypeEntry()); - int summonLifespanSeconds = Config.getInstance().getTamingCOTWLength(callOfTheWildType.getConfigEntityTypeEntry()); - int perPlayerMaxAmount = Config.getInstance().getTamingCOTWMaxAmount(callOfTheWildType.getConfigEntityTypeEntry()); + Material itemSummonMaterial = mcMMO.p.getGeneralConfig().getTamingCOTWMaterial(callOfTheWildType.getConfigEntityTypeEntry()); + int itemAmountRequired = mcMMO.p.getGeneralConfig().getTamingCOTWCost(callOfTheWildType.getConfigEntityTypeEntry()); + int entitiesSummonedPerCOTW = mcMMO.p.getGeneralConfig().getTamingCOTWAmount(callOfTheWildType.getConfigEntityTypeEntry()); + int summonLifespanSeconds = mcMMO.p.getGeneralConfig().getTamingCOTWLength(callOfTheWildType.getConfigEntityTypeEntry()); + int perPlayerMaxAmount = mcMMO.p.getGeneralConfig().getTamingCOTWMaxAmount(callOfTheWildType.getConfigEntityTypeEntry()); TamingSummon tamingSummon = new TamingSummon(callOfTheWildType, itemSummonMaterial, itemAmountRequired, entitiesSummonedPerCOTW, summonLifespanSeconds, perPlayerMaxAmount); cotwSummonDataProperties.put(callOfTheWildType, tamingSummon); @@ -273,7 +271,7 @@ public class TamingManager extends SkillManager { if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.TAMING_PUMMEL)) return; - if(!RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(AdvancedConfig.getInstance().getPummelChance(), getPlayer(), SubSkillType.TAMING_PUMMEL))) + if(!RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(mcMMO.p.getAdvancedConfig().getPummelChance(), getPlayer(), SubSkillType.TAMING_PUMMEL))) return; ParticleEffectUtils.playGreaterImpactEffect(target); @@ -459,7 +457,7 @@ public class TamingManager extends SkillManager { callOfWildEntity.setHealth(callOfWildEntity.getMaxHealth()); horse.setColor(Horse.Color.values()[Misc.getRandom().nextInt(Horse.Color.values().length)]); horse.setStyle(Horse.Style.values()[Misc.getRandom().nextInt(Horse.Style.values().length)]); - horse.setJumpStrength(Math.max(AdvancedConfig.getInstance().getMinHorseJumpStrength(), Math.min(Math.min(Misc.getRandom().nextDouble(), Misc.getRandom().nextDouble()) * 2, AdvancedConfig.getInstance().getMaxHorseJumpStrength()))); + horse.setJumpStrength(Math.max(mcMMO.p.getAdvancedConfig().getMinHorseJumpStrength(), Math.min(Math.min(Misc.getRandom().nextDouble(), Misc.getRandom().nextDouble()) * 2, mcMMO.p.getAdvancedConfig().getMaxHorseJumpStrength()))); horse.setAdult(); //TODO: setSpeed, once available diff --git a/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java b/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java index 9116c4fdf..79cd4802b 100644 --- a/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java +++ b/src/main/java/com/gmail/nossr50/skills/taming/TrackedTamingEntity.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.skills.taming; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.skills.subskills.taming.CallOfTheWildType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; @@ -19,7 +18,7 @@ public class TrackedTamingEntity extends BukkitRunnable { this.callOfTheWildType = callOfTheWildType; this.livingEntity = livingEntity; - int tamingCOTWLength = Config.getInstance().getTamingCOTWLength(callOfTheWildType.getConfigEntityTypeEntry()); + int tamingCOTWLength = mcMMO.p.getGeneralConfig().getTamingCOTWLength(callOfTheWildType.getConfigEntityTypeEntry()); if (tamingCOTWLength > 0) { int length = tamingCOTWLength * Misc.TICK_CONVERSION_FACTOR; diff --git a/src/main/java/com/gmail/nossr50/skills/unarmed/Unarmed.java b/src/main/java/com/gmail/nossr50/skills/unarmed/Unarmed.java index a39cbccc5..cb1124dd4 100644 --- a/src/main/java/com/gmail/nossr50/skills/unarmed/Unarmed.java +++ b/src/main/java/com/gmail/nossr50/skills/unarmed/Unarmed.java @@ -1,6 +1,6 @@ package com.gmail.nossr50.skills.unarmed; -import com.gmail.nossr50.config.Config; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundType; import org.bukkit.entity.Player; @@ -8,7 +8,7 @@ import org.bukkit.event.entity.EntityPickupItemEvent; import org.bukkit.inventory.ItemStack; public class Unarmed { - public static boolean blockCrackerSmoothBrick = Config.getInstance().getUnarmedBlockCrackerSmoothbrickToCracked(); + public static boolean blockCrackerSmoothBrick = mcMMO.p.getGeneralConfig().getUnarmedBlockCrackerSmoothbrickToCracked(); public static double berserkDamageModifier = 1.5; public static void handleItemPickup(Player player, EntityPickupItemEvent event) { diff --git a/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java b/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java index 73bf3dce9..668eae038 100644 --- a/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java +++ b/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.skills.unarmed; import com.gmail.nossr50.api.ItemSpawnReason; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; @@ -113,7 +112,7 @@ public class UnarmedManager extends SkillManager { Item item = Misc.spawnItem(defender.getLocation(), defender.getInventory().getItemInMainHand(), ItemSpawnReason.UNARMED_DISARMED_ITEM); - if (item != null && AdvancedConfig.getInstance().getDisarmProtected()) { + if (item != null && mcMMO.p.getAdvancedConfig().getDisarmProtected()) { item.setMetadata(mcMMO.disarmedItemKey, UserManager.getPlayer(defender).getPlayerMetadata()); } @@ -167,8 +166,8 @@ public class UnarmedManager extends SkillManager { double finalBonus = bonus + 0.5 + (rank / 2); - if(AdvancedConfig.getInstance().isSteelArmDamageCustom()) { - return AdvancedConfig.getInstance().getSteelArmOverride(RankUtils.getRank(getPlayer(), SubSkillType.UNARMED_STEEL_ARM_STYLE), finalBonus); + if(mcMMO.p.getAdvancedConfig().isSteelArmDamageCustom()) { + return mcMMO.p.getAdvancedConfig().getSteelArmOverride(RankUtils.getRank(getPlayer(), SubSkillType.UNARMED_STEEL_ARM_STYLE), finalBonus); } else { return finalBonus; } diff --git a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java index a2bb23790..49fa5bd20 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java @@ -1,8 +1,6 @@ package com.gmail.nossr50.skills.woodcutting; import com.gmail.nossr50.api.ItemSpawnReason; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.interactions.NotificationType; @@ -54,7 +52,7 @@ public class WoodcuttingManager extends SkillManager { public WoodcuttingManager(McMMOPlayer mcMMOPlayer) { super(mcMMOPlayer, PrimarySkillType.WOODCUTTING); - treeFellerThreshold = Config.getInstance().getTreeFellerThreshold(); + treeFellerThreshold = mcMMO.p.getGeneralConfig().getTreeFellerThreshold(); } public boolean canUseLeafBlower(ItemStack heldItem) { @@ -72,7 +70,7 @@ public class WoodcuttingManager extends SkillManager { return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER) && RankUtils.hasReachedRank(1, getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER) && RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.WOODCUTTING_HARVEST_LUMBER, getPlayer()) - && Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, material); + && mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, material); } /** @@ -217,7 +215,7 @@ public class WoodcuttingManager extends SkillManager { for (BlockState blockState : treeFellerBlocks) { if (BlockUtils.hasWoodcuttingXP(blockState)) { - durabilityLoss += Config.getInstance().getAbilityToolDamage(); + durabilityLoss += mcMMO.p.getGeneralConfig().getAbilityToolDamage(); } } @@ -307,7 +305,7 @@ public class WoodcuttingManager extends SkillManager { Misc.spawnItemsFromCollection(Misc.getBlockCenter(blockState), block.getDrops(), ItemSpawnReason.TREE_FELLER_DISPLACED_BLOCK); if(RankUtils.hasReachedRank(2, player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)) { - if(AdvancedConfig.getInstance().isKnockOnWoodXPOrbEnabled()) { + if(mcMMO.p.getAdvancedConfig().isKnockOnWoodXPOrbEnabled()) { if(RandomChanceUtil.rollDice(10, 100)) { int randOrbCount = Math.max(1, Misc.getRandom().nextInt(100)); Misc.spawnExperienceOrb(blockState.getLocation(), randOrbCount); diff --git a/src/main/java/com/gmail/nossr50/util/BlockUtils.java b/src/main/java/com/gmail/nossr50/util/BlockUtils.java index 8a443c119..e1944f738 100644 --- a/src/main/java/com/gmail/nossr50/util/BlockUtils.java +++ b/src/main/java/com/gmail/nossr50/util/BlockUtils.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.util; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.meta.BonusDropMeta; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; @@ -53,7 +52,7 @@ public final class BlockUtils { * @return true if the player succeeded in the check */ public static boolean checkDoubleDrops(Player player, BlockState blockState, PrimarySkillType skillType, SubSkillType subSkillType) { - if (Config.getInstance().getDoubleDropsEnabled(skillType, blockState.getType()) && Permissions.isSubSkillEnabled(player, subSkillType)) { + if (mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(skillType, blockState.getType()) && Permissions.isSubSkillEnabled(player, subSkillType)) { return RandomChanceUtil.checkRandomChanceExecutionSuccess(new RandomChanceSkill(player, subSkillType, true)); } @@ -68,10 +67,10 @@ public final class BlockUtils { */ public static boolean shouldBeWatched(BlockState blockState) { return affectedByGigaDrillBreaker(blockState) || affectedByGreenTerra(blockState) || affectedBySuperBreaker(blockState) || hasWoodcuttingXP(blockState) - || Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.MINING, blockState.getType()) - || Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.EXCAVATION, blockState.getType()) - || Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, blockState.getType()) - || Config.getInstance().getDoubleDropsEnabled(PrimarySkillType.SMELTING, blockState.getType()); + || mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.MINING, blockState.getType()) + || mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.EXCAVATION, blockState.getType()) + || mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, blockState.getType()) + || mcMMO.p.getGeneralConfig().getDoubleDropsEnabled(PrimarySkillType.SMELTING, blockState.getType()); } /** diff --git a/src/main/java/com/gmail/nossr50/util/ChimaeraWing.java b/src/main/java/com/gmail/nossr50/util/ChimaeraWing.java index c1bccbca2..07bace1a5 100644 --- a/src/main/java/com/gmail/nossr50/util/ChimaeraWing.java +++ b/src/main/java/com/gmail/nossr50/util/ChimaeraWing.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.util; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.locale.LocaleLoader; @@ -37,7 +36,7 @@ public final class ChimaeraWing { * @param player Player whose item usage to check */ public static void activationCheck(Player player) { - if (!Config.getInstance().getChimaeraEnabled()) { + if (!mcMMO.p.getGeneralConfig().getChimaeraEnabled()) { return; } @@ -64,13 +63,13 @@ public final class ChimaeraWing { int amount = inHand.getAmount(); - if (amount < Config.getInstance().getChimaeraUseCost()) { - NotificationManager.sendPlayerInformation(player, NotificationType.REQUIREMENTS_NOT_MET, "Item.ChimaeraWing.NotEnough",String.valueOf(Config.getInstance().getChimaeraUseCost() - amount), "Item.ChimaeraWing.Name"); + if (amount < mcMMO.p.getGeneralConfig().getChimaeraUseCost()) { + NotificationManager.sendPlayerInformation(player, NotificationType.REQUIREMENTS_NOT_MET, "Item.ChimaeraWing.NotEnough",String.valueOf(mcMMO.p.getGeneralConfig().getChimaeraUseCost() - amount), "Item.ChimaeraWing.Name"); return; } long lastTeleport = mcMMOPlayer.getChimeraWingLastUse(); - int cooldown = Config.getInstance().getChimaeraCooldown(); + int cooldown = mcMMO.p.getGeneralConfig().getChimaeraCooldown(); if (cooldown > 0) { int timeRemaining = SkillUtils.calculateTimeLeft(lastTeleport * Misc.TIME_CONVERSION_FACTOR, cooldown, player); @@ -82,7 +81,7 @@ public final class ChimaeraWing { } long recentlyHurt = mcMMOPlayer.getRecentlyHurt(); - int hurtCooldown = Config.getInstance().getChimaeraRecentlyHurtCooldown(); + int hurtCooldown = mcMMO.p.getGeneralConfig().getChimaeraRecentlyHurtCooldown(); if (hurtCooldown > 0) { int timeRemaining = SkillUtils.calculateTimeLeft(recentlyHurt * Misc.TIME_CONVERSION_FACTOR, hurtCooldown, player); @@ -95,9 +94,9 @@ public final class ChimaeraWing { location = player.getLocation(); - if (Config.getInstance().getChimaeraPreventUseUnderground()) { + if (mcMMO.p.getGeneralConfig().getChimaeraPreventUseUnderground()) { if (location.getY() < player.getWorld().getHighestBlockYAt(location)) { - player.getInventory().setItemInMainHand(new ItemStack(getChimaeraWing(amount - Config.getInstance().getChimaeraUseCost()))); + player.getInventory().setItemInMainHand(new ItemStack(getChimaeraWing(amount - mcMMO.p.getGeneralConfig().getChimaeraUseCost()))); NotificationManager.sendPlayerInformation(player, NotificationType.REQUIREMENTS_NOT_MET, "Item.ChimaeraWing.Fail"); player.updateInventory(); player.setVelocity(new Vector(0, 0.5D, 0)); @@ -109,7 +108,7 @@ public final class ChimaeraWing { mcMMOPlayer.actualizeTeleportCommenceLocation(player); - long warmup = Config.getInstance().getChimaeraWarmup(); + long warmup = mcMMO.p.getGeneralConfig().getChimaeraWarmup(); if (warmup > 0) { NotificationManager.sendPlayerInformation(player, NotificationType.ITEM_MESSAGE, "Teleport.Commencing", String.valueOf(warmup)); @@ -123,7 +122,7 @@ public final class ChimaeraWing { public static void chimaeraExecuteTeleport() { Player player = mcMMOPlayer.getPlayer(); - if (Config.getInstance().getChimaeraUseBedSpawn() && player.getBedSpawnLocation() != null) { + if (mcMMO.p.getGeneralConfig().getChimaeraUseBedSpawn() && player.getBedSpawnLocation() != null) { player.teleport(player.getBedSpawnLocation()); } else { @@ -136,12 +135,12 @@ public final class ChimaeraWing { } } - player.getInventory().setItemInMainHand(new ItemStack(getChimaeraWing(player.getInventory().getItemInMainHand().getAmount() - Config.getInstance().getChimaeraUseCost()))); + player.getInventory().setItemInMainHand(new ItemStack(getChimaeraWing(player.getInventory().getItemInMainHand().getAmount() - mcMMO.p.getGeneralConfig().getChimaeraUseCost()))); player.updateInventory(); mcMMOPlayer.actualizeChimeraWingLastUse(); mcMMOPlayer.setTeleportCommenceLocation(null); - if (Config.getInstance().getChimaeraSoundEnabled()) { + if (mcMMO.p.getGeneralConfig().getChimaeraSoundEnabled()) { SoundManager.sendSound(player, location, SoundType.CHIMAERA_WING); } @@ -149,7 +148,7 @@ public final class ChimaeraWing { } public static ItemStack getChimaeraWing(int amount) { - ItemStack itemStack = new ItemStack(Config.getInstance().getChimaeraItem(), amount); + ItemStack itemStack = new ItemStack(mcMMO.p.getGeneralConfig().getChimaeraItem(), amount); ItemMeta itemMeta = itemStack.getItemMeta(); //noinspection ConstantConditions @@ -165,8 +164,8 @@ public final class ChimaeraWing { } public static ShapelessRecipe getChimaeraWingRecipe() { - Material ingredient = Config.getInstance().getChimaeraItem(); - int amount = Config.getInstance().getChimaeraRecipeCost(); + Material ingredient = mcMMO.p.getGeneralConfig().getChimaeraItem(); + int amount = mcMMO.p.getGeneralConfig().getChimaeraRecipeCost(); ShapelessRecipe chimeraWing = new ShapelessRecipe(new NamespacedKey(mcMMO.p, "Chimera"), getChimaeraWing(1)); chimeraWing.addIngredient(amount, ingredient); diff --git a/src/main/java/com/gmail/nossr50/util/EventUtils.java b/src/main/java/com/gmail/nossr50/util/EventUtils.java index e1f2d1b97..c2d181063 100644 --- a/src/main/java/com/gmail/nossr50/util/EventUtils.java +++ b/src/main/java/com/gmail/nossr50/util/EventUtils.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.util; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.experience.XPGainSource; import com.gmail.nossr50.datatypes.party.Party; @@ -9,6 +8,7 @@ import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; +import com.gmail.nossr50.datatypes.skills.interfaces.Skill; import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.events.experience.McMMOPlayerLevelChangeEvent; import com.gmail.nossr50.events.experience.McMMOPlayerLevelDownEvent; @@ -409,7 +409,7 @@ public final class EventUtils { for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { String skillName = primarySkillType.toString(); int playerSkillLevel = playerProfile.getSkillLevel(primarySkillType); - int threshold = Config.getInstance().getHardcoreDeathStatPenaltyLevelThreshold(); + int threshold = mcMMO.p.getGeneralConfig().getHardcoreDeathStatPenaltyLevelThreshold(); if(playerSkillLevel > threshold) { playerProfile.modifySkill(primarySkillType, Math.max(threshold, playerSkillLevel - levelChanged.get(skillName))); playerProfile.removeXp(primarySkillType, experienceChanged.get(skillName)); @@ -479,7 +479,7 @@ public final class EventUtils { } public static McMMOPlayerAbilityDeactivateEvent callAbilityDeactivateEvent(Player player, SuperAbilityType ability) { - McMMOPlayerAbilityDeactivateEvent event = new McMMOPlayerAbilityDeactivateEvent(player, PrimarySkillType.byAbility(ability)); + McMMOPlayerAbilityDeactivateEvent event = new McMMOPlayerAbilityDeactivateEvent(player, Skill.byAbility(ability)); mcMMO.p.getServer().getPluginManager().callEvent(event); return event; diff --git a/src/main/java/com/gmail/nossr50/util/HardcoreManager.java b/src/main/java/com/gmail/nossr50/util/HardcoreManager.java index 11b7e01c4..4e6152b1c 100644 --- a/src/main/java/com/gmail/nossr50/util/HardcoreManager.java +++ b/src/main/java/com/gmail/nossr50/util/HardcoreManager.java @@ -1,9 +1,9 @@ package com.gmail.nossr50.util; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.worldguard.WorldGuardManager; @@ -22,8 +22,8 @@ public final class HardcoreManager { return; } - double statLossPercentage = Config.getInstance().getHardcoreDeathStatPenaltyPercentage(); - int levelThreshold = Config.getInstance().getHardcoreDeathStatPenaltyLevelThreshold(); + double statLossPercentage = mcMMO.p.getGeneralConfig().getHardcoreDeathStatPenaltyPercentage(); + int levelThreshold = mcMMO.p.getGeneralConfig().getHardcoreDeathStatPenaltyLevelThreshold(); if(UserManager.getPlayer(player) == null) return; @@ -73,8 +73,8 @@ public final class HardcoreManager { return; } - double vampirismStatLeechPercentage = Config.getInstance().getHardcoreVampirismStatLeechPercentage(); - int levelThreshold = Config.getInstance().getHardcoreVampirismLevelThreshold(); + double vampirismStatLeechPercentage = mcMMO.p.getGeneralConfig().getHardcoreVampirismStatLeechPercentage(); + int levelThreshold = mcMMO.p.getGeneralConfig().getHardcoreVampirismLevelThreshold(); if(UserManager.getPlayer(killer) == null || UserManager.getPlayer(victim) == null) return; diff --git a/src/main/java/com/gmail/nossr50/util/ItemUtils.java b/src/main/java/com/gmail/nossr50/util/ItemUtils.java index 46c68183b..2c66ff84f 100644 --- a/src/main/java/com/gmail/nossr50/util/ItemUtils.java +++ b/src/main/java/com/gmail/nossr50/util/ItemUtils.java @@ -1,7 +1,5 @@ package com.gmail.nossr50.util; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.config.party.ItemWeightConfig; import com.gmail.nossr50.datatypes.treasure.EnchantmentWrapper; @@ -186,7 +184,7 @@ public final class ItemUtils { * @return true if the item counts as unarmed, false otherwise */ public static boolean isUnarmed(ItemStack item) { - if (Config.getInstance().getUnarmedItemsAsUnarmed()) { + if (mcMMO.p.getGeneralConfig().getUnarmedItemsAsUnarmed()) { return !isMinecraftTool(item); } @@ -622,7 +620,7 @@ public final class ItemUtils { if(itemMeta == null) return; - itemMeta.addEnchant(Enchantment.DIG_SPEED, existingEnchantLevel + AdvancedConfig.getInstance().getEnchantBuff(), true); + itemMeta.addEnchant(Enchantment.DIG_SPEED, existingEnchantLevel + mcMMO.p.getAdvancedConfig().getEnchantBuff(), true); itemStack.setItemMeta(itemMeta); } diff --git a/src/main/java/com/gmail/nossr50/util/MobHealthbarUtils.java b/src/main/java/com/gmail/nossr50/util/MobHealthbarUtils.java index 9c1f6b76e..ff77f38e8 100644 --- a/src/main/java/com/gmail/nossr50/util/MobHealthbarUtils.java +++ b/src/main/java/com/gmail/nossr50/util/MobHealthbarUtils.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.util; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.MobHealthbarType; import com.gmail.nossr50.datatypes.meta.OldName; import com.gmail.nossr50.mcMMO; @@ -36,7 +35,7 @@ public final class MobHealthbarUtils { * @param damage damage done by the attack triggering this */ public static void handleMobHealthbars(LivingEntity target, double damage, mcMMO plugin) { - if (mcMMO.isHealthBarPluginEnabled() || !Config.getInstance().getMobHealthbarEnabled()) { + if (mcMMO.isHealthBarPluginEnabled() || !mcMMO.p.getGeneralConfig().getMobHealthbarEnabled()) { return; } @@ -63,12 +62,12 @@ public final class MobHealthbarUtils { } boolean oldNameVisible = target.isCustomNameVisible(); - String newName = createHealthDisplay(Config.getInstance().getMobHealthbarDefault(), target, damage); + String newName = createHealthDisplay(mcMMO.p.getGeneralConfig().getMobHealthbarDefault(), target, damage); target.setCustomName(newName); target.setCustomNameVisible(true); - int displayTime = Config.getInstance().getMobHealthbarTime(); + int displayTime = mcMMO.p.getGeneralConfig().getMobHealthbarTime(); if (displayTime != -1) { boolean updateName = !ChatColor.stripColor(oldName).equalsIgnoreCase(ChatColor.stripColor(newName)); diff --git a/src/main/java/com/gmail/nossr50/util/ModManager.java b/src/main/java/com/gmail/nossr50/util/ModManager.java index 184b571b1..62646466a 100644 --- a/src/main/java/com/gmail/nossr50/util/ModManager.java +++ b/src/main/java/com/gmail/nossr50/util/ModManager.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.util; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.mods.CustomArmorConfig; import com.gmail.nossr50.config.mods.CustomBlockConfig; import com.gmail.nossr50.config.mods.CustomEntityConfig; @@ -89,67 +88,67 @@ public class ModManager { } public boolean isCustomBoots(Material material) { - return Config.getInstance().getArmorModsEnabled() && customBoots.contains(material); + return mcMMO.p.getGeneralConfig().getArmorModsEnabled() && customBoots.contains(material); } public boolean isCustomChestplate(Material material) { - return Config.getInstance().getArmorModsEnabled() && customChestplates.contains(material); + return mcMMO.p.getGeneralConfig().getArmorModsEnabled() && customChestplates.contains(material); } public boolean isCustomHelmet(Material material) { - return Config.getInstance().getArmorModsEnabled() && customHelmets.contains(material); + return mcMMO.p.getGeneralConfig().getArmorModsEnabled() && customHelmets.contains(material); } public boolean isCustomLeggings(Material material) { - return Config.getInstance().getArmorModsEnabled() && customLeggings.contains(material); + return mcMMO.p.getGeneralConfig().getArmorModsEnabled() && customLeggings.contains(material); } public boolean isCustomAxe(Material material) { - return Config.getInstance().getToolModsEnabled() && customAxes.contains(material); + return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customAxes.contains(material); } public boolean isCustomBow(Material material) { - return Config.getInstance().getToolModsEnabled() && customBows.contains(material); + return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customBows.contains(material); } public boolean isCustomHoe(Material material) { - return Config.getInstance().getToolModsEnabled() && customHoes.contains(material); + return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customHoes.contains(material); } public boolean isCustomPickaxe(Material material) { - return Config.getInstance().getToolModsEnabled() && customPickaxes.contains(material); + return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customPickaxes.contains(material); } public boolean isCustomShovel(Material material) { - return Config.getInstance().getToolModsEnabled() && customShovels.contains(material); + return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customShovels.contains(material); } public boolean isCustomSword(Material material) { - return Config.getInstance().getToolModsEnabled() && customSwords.contains(material); + return mcMMO.p.getGeneralConfig().getToolModsEnabled() && customSwords.contains(material); } public boolean isCustomOre(Material data) { - return Config.getInstance().getBlockModsEnabled() && customOres.contains(data); + return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customOres.contains(data); } public boolean isCustomLog(BlockState state) { - return Config.getInstance().getBlockModsEnabled() && customLogs.contains(state.getType()); + return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customLogs.contains(state.getType()); } public boolean isCustomAbilityBlock(BlockState state) { - return Config.getInstance().getBlockModsEnabled() && customAbilityBlocks.contains(state.getType()); + return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customAbilityBlocks.contains(state.getType()); } public boolean isCustomExcavationBlock(BlockState state) { - return Config.getInstance().getBlockModsEnabled() && customExcavationBlocks.contains(state.getType()); + return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customExcavationBlocks.contains(state.getType()); } public boolean isCustomHerbalismBlock(BlockState state) { - return Config.getInstance().getBlockModsEnabled() && customHerbalismBlocks.contains(state.getType()); + return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customHerbalismBlocks.contains(state.getType()); } public boolean isCustomMiningBlock(BlockState state) { - return Config.getInstance().getBlockModsEnabled() && customMiningBlocks.contains(state.getType()); + return mcMMO.p.getGeneralConfig().getBlockModsEnabled() && customMiningBlocks.contains(state.getType()); } public CustomBlock getBlock(BlockState state) { @@ -167,7 +166,7 @@ public class ModManager { * @return true if the item is a custom tool, false otherwise */ public boolean isCustomTool(ItemStack item) { - return Config.getInstance().getToolModsEnabled() && item != null && customToolMap.containsKey(item.getType()); + return mcMMO.p.getGeneralConfig().getToolModsEnabled() && item != null && customToolMap.containsKey(item.getType()); } /** @@ -185,7 +184,7 @@ public class ModManager { } public boolean isCustomEntity(Entity entity) { - if (!Config.getInstance().getEntityModsEnabled()) { + if (!mcMMO.p.getGeneralConfig().getEntityModsEnabled()) { return false; } @@ -227,7 +226,7 @@ public class ModManager { } public void addCustomEntity(Entity entity) { - if (!Config.getInstance().getEntityModsEnabled()) { + if (!mcMMO.p.getGeneralConfig().getEntityModsEnabled()) { return; } diff --git a/src/main/java/com/gmail/nossr50/util/Motd.java b/src/main/java/com/gmail/nossr50/util/Motd.java index ac3fd4e70..ddad205c0 100644 --- a/src/main/java/com/gmail/nossr50/util/Motd.java +++ b/src/main/java/com/gmail/nossr50/util/Motd.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.util; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; @@ -70,11 +69,11 @@ public final class Motd { player.sendMessage(LocaleLoader.getString("MOTD.Hardcore.Enabled", statLossInfo + seperator + vampirismInfo)); if (deathStatLossEnabled) { - player.sendMessage(LocaleLoader.getString("MOTD.Hardcore.DeathStatLoss.Stats", Config.getInstance().getHardcoreDeathStatPenaltyPercentage())); + player.sendMessage(LocaleLoader.getString("MOTD.Hardcore.DeathStatLoss.Stats", mcMMO.p.getGeneralConfig().getHardcoreDeathStatPenaltyPercentage())); } if (vampirismEnabled) { - player.sendMessage(LocaleLoader.getString("MOTD.Hardcore.Vampirism.Stats", Config.getInstance().getHardcoreVampirismStatLeechPercentage())); + player.sendMessage(LocaleLoader.getString("MOTD.Hardcore.Vampirism.Stats", mcMMO.p.getGeneralConfig().getHardcoreVampirismStatLeechPercentage())); } } diff --git a/src/main/java/com/gmail/nossr50/util/Permissions.java b/src/main/java/com/gmail/nossr50/util/Permissions.java index a64c476f3..2dabff51e 100644 --- a/src/main/java/com/gmail/nossr50/util/Permissions.java +++ b/src/main/java/com/gmail/nossr50/util/Permissions.java @@ -26,7 +26,6 @@ public final class Permissions { */ public static boolean motd(Permissible permissible) { return permissible.hasPermission("mcmmo.motd"); } public static boolean levelUpBroadcast(Permissible permissible) { return permissible.hasPermission("mcmmo.broadcast.levelup"); } - public static boolean mobHealthDisplay(Permissible permissible) { return permissible.hasPermission("mcmmo.mobhealthdisplay"); } public static boolean updateNotifications(Permissible permissible) {return permissible.hasPermission("mcmmo.tools.updatecheck"); } public static boolean chimaeraWing(Permissible permissible) { return permissible.hasPermission("mcmmo.item.chimaerawing"); } public static boolean showversion(Permissible permissible) { return permissible.hasPermission("mcmmo.showversion"); } @@ -34,8 +33,6 @@ public final class Permissions { /* BYPASS */ public static boolean hardcoreBypass(Permissible permissible) { return permissible.hasPermission("mcmmo.bypass.hardcoremode"); } public static boolean arcaneBypass(Permissible permissible) { return permissible.hasPermission("mcmmo.bypass.arcanebypass"); } - public static boolean krakenBypass(Permissible permissible) { return permissible.hasPermission("mcmmo.bypass.kraken"); } - public static boolean trapsBypass(Permissible permissible) { return permissible.hasPermission("mcmmo.bypass.fishingtraps"); } /* CHAT */ public static boolean partyChat(Permissible permissible) { return permissible.hasPermission("mcmmo.chat.partychat"); } @@ -60,9 +57,6 @@ public final class Permissions { public static boolean inspectFar(Permissible permissible) { return (permissible.hasPermission("mcmmo.commands.inspect.far")); } public static boolean inspectHidden(Permissible permissible) { return (permissible.hasPermission("mcmmo.commands.inspect.hidden")); } - public static boolean kraken(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.kraken"); } - public static boolean krakenOthers(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.kraken.others"); } - public static boolean mcability(Permissible permissible) { return (permissible.hasPermission("mcmmo.commands.mcability")); } public static boolean mcabilityOthers(Permissible permissible) { return (permissible.hasPermission("mcmmo.commands.mcability.others")); } @@ -98,9 +92,6 @@ public final class Permissions { public static boolean xprateSet(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.xprate.set"); } public static boolean xprateReset(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.xprate.reset"); } - public static boolean vampirismModify(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.vampirism.modify"); } - public static boolean vampirismToggle(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.vampirism.toggle"); } - public static boolean mcpurge(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.mcpurge"); } public static boolean mcremove(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.mcremove"); } public static boolean mmoupdate(Permissible permissible) { return permissible.hasPermission("mcmmo.commands.mmoupdate"); } @@ -172,7 +163,6 @@ public final class Permissions { public static boolean vanillaXpBoost(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.ability." + skill.toString().toLowerCase(Locale.ENGLISH) + ".vanillaxpboost"); } public static boolean isSubSkillEnabled(Permissible permissible, SubSkillType subSkillType) { return permissible.hasPermission(subSkillType.getPermissionNodeAddress()); } public static boolean isSubSkillEnabled(Permissible permissible, AbstractSubSkill abstractSubSkill) { return permissible.hasPermission(abstractSubSkill.getPermissionNode()); } - public static boolean bonusDamage(Permissible permissible, PrimarySkillType skill) { return permissible.hasPermission("mcmmo.ability." + skill.toString().toLowerCase(Locale.ENGLISH) + ".bonusdamage"); } /* ACROBATICS */ public static boolean dodge(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.acrobatics.dodge"); } @@ -209,7 +199,6 @@ public final class Permissions { public static boolean repairMaterialType(Permissible permissible, MaterialType repairMaterialType) { return permissible.hasPermission("mcmmo.ability.repair." + repairMaterialType.toString().toLowerCase(Locale.ENGLISH) + "repair"); } /* SALVAGE */ - public static boolean advancedSalvage(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.salvage.advancedsalvage"); } public static boolean arcaneSalvage(Permissible permissible) { return permissible.hasPermission("mcmmo.ability.salvage.arcanesalvage"); } public static boolean salvageItemType(Permissible permissible, ItemType salvageItemType) { return permissible.hasPermission("mcmmo.ability.salvage." + salvageItemType.toString().toLowerCase(Locale.ENGLISH) + "salvage"); } diff --git a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java b/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java index 3f93437a7..ed98345a1 100644 --- a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java +++ b/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java @@ -16,7 +16,6 @@ import com.gmail.nossr50.commands.party.PartyCommand; import com.gmail.nossr50.commands.party.teleport.PtpCommand; import com.gmail.nossr50.commands.player.*; import com.gmail.nossr50.commands.skills.*; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; @@ -283,7 +282,7 @@ public final class CommandRegistrationManager { private static void registerMcpurgeCommand() { PluginCommand command = mcMMO.p.getCommand("mcpurge"); - command.setDescription(LocaleLoader.getString("Commands.Description.mcpurge", Config.getInstance().getOldUsersCutoff())); + command.setDescription(LocaleLoader.getString("Commands.Description.mcpurge", mcMMO.p.getGeneralConfig().getOldUsersCutoff())); command.setPermission("mcmmo.commands.mcpurge"); command.setPermissionMessage(permissionsMessage); command.setUsage(LocaleLoader.getString("Commands.Usage.0", "mcpurge")); @@ -389,15 +388,6 @@ public final class CommandRegistrationManager { command.setUsage(LocaleLoader.getString("Commands.Usage.0", "mcnotify")); command.setExecutor(new McnotifyCommand()); } - - private static void registerMHDCommand() { - PluginCommand command = mcMMO.p.getCommand("mhd"); - command.setDescription("Resets all mob health bar settings for all players to the default"); //TODO: Localize - command.setPermission("mcmmo.commands.mhd"); - command.setPermissionMessage(permissionsMessage); - command.setUsage(LocaleLoader.getString("Commands.Usage.0", "mhd")); - command.setExecutor(new MHDCommand()); - } private static void registerMcscoreboardCommand() { PluginCommand command = mcMMO.p.getCommand("mcscoreboard"); @@ -455,7 +445,6 @@ public final class CommandRegistrationManager { registerMcnotifyCommand(); registerMcrefreshCommand(); registerMcscoreboardCommand(); - registerMHDCommand(); registerXprateCommand(); // Database Commands diff --git a/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java b/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java index de6f689fb..e7cee3107 100644 --- a/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java +++ b/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.util.commands; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; @@ -38,7 +37,7 @@ public final class CommandUtils { if(!target.isOnline() && !hasPermission) { sender.sendMessage(LocaleLoader.getString("Inspect.Offline")); return true; - } else if (sender instanceof Player && !Misc.isNear(((Player) sender).getLocation(), target.getLocation(), Config.getInstance().getInspectDistance()) && !hasPermission) { + } else if (sender instanceof Player && !Misc.isNear(((Player) sender).getLocation(), target.getLocation(), mcMMO.p.getGeneralConfig().getInspectDistance()) && !hasPermission) { sender.sendMessage(LocaleLoader.getString("Inspect.TooFar")); return true; } @@ -209,7 +208,7 @@ public final class CommandUtils { if (skill.isChildSkill()) { return LocaleLoader.getString("Skills.ChildStats", LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".Listener") + " ", profile.getSkillLevel(skill)); } - if (profile.getSkillLevel(skill) == Config.getInstance().getLevelCap(skill)){ + if (profile.getSkillLevel(skill) == mcMMO.p.getGeneralConfig().getLevelCap(skill)){ return LocaleLoader.getString("Skills.Stats", LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".Listener") + " ", profile.getSkillLevel(skill), profile.getSkillXpLevel(skill), LocaleLoader.getString("Skills.MaxXP")); } return LocaleLoader.getString("Skills.Stats", LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".Listener") + " ", profile.getSkillLevel(skill), profile.getSkillXpLevel(skill), profile.getXpToLevel(skill)); @@ -258,7 +257,7 @@ public final class CommandUtils { * @return Matched name or {@code partialName} if no match was found */ public static String getMatchedPlayerName(String partialName) { - if (Config.getInstance().getMatchOfflinePlayers()) { + if (mcMMO.p.getGeneralConfig().getMatchOfflinePlayers()) { List matches = matchPlayer(partialName); if (matches.size() == 1) { diff --git a/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java b/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java index 3c7ff308f..c82a6e00e 100644 --- a/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java +++ b/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.util.experience; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.experience.FormulaType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; @@ -89,7 +88,7 @@ public class FormulaManager { public int[] calculateNewLevel(PrimarySkillType primarySkillType, int experience, FormulaType formulaType) { int newLevel = 0; int remainder = 0; - int maxLevel = Config.getInstance().getLevelCap(primarySkillType); + int maxLevel = mcMMO.p.getGeneralConfig().getLevelCap(primarySkillType); while (experience > 0 && newLevel < maxLevel) { int experienceToNextLevel = getXPtoNextLevel(newLevel, formulaType); diff --git a/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java b/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java index e616760a8..fc7de2b28 100644 --- a/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java +++ b/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java @@ -1,7 +1,5 @@ package com.gmail.nossr50.util.player; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.LevelUpBroadcastPredicate; import com.gmail.nossr50.datatypes.PowerLevelUpBroadcastPredicate; import com.gmail.nossr50.datatypes.interactions.NotificationType; @@ -50,7 +48,7 @@ public class NotificationManager { if(UserManager.getPlayer(player) == null || !UserManager.getPlayer(player).useChatNotifications()) return; - McMMOMessageType destination = AdvancedConfig.getInstance().doesNotificationUseActionBar(notificationType) ? McMMOMessageType.ACTION_BAR : McMMOMessageType.SYSTEM; + McMMOMessageType destination = mcMMO.p.getAdvancedConfig().doesNotificationUseActionBar(notificationType) ? McMMOMessageType.ACTION_BAR : McMMOMessageType.SYSTEM; Component message = TextComponentFactory.getNotificationTextComponentFromLocale(key); McMMOPlayerNotificationEvent customEvent = checkNotificationEvent(player, notificationType, destination, message); @@ -105,7 +103,7 @@ public class NotificationManager { if(UserManager.getPlayer(player) == null || !UserManager.getPlayer(player).useChatNotifications()) return; - McMMOMessageType destination = AdvancedConfig.getInstance().doesNotificationUseActionBar(notificationType) ? McMMOMessageType.ACTION_BAR : McMMOMessageType.SYSTEM; + McMMOMessageType destination = mcMMO.p.getAdvancedConfig().doesNotificationUseActionBar(notificationType) ? McMMOMessageType.ACTION_BAR : McMMOMessageType.SYSTEM; Component message = TextComponentFactory.getNotificationMultipleValues(key, values); McMMOPlayerNotificationEvent customEvent = checkNotificationEvent(player, notificationType, destination, message); @@ -137,7 +135,7 @@ public class NotificationManager { private static McMMOPlayerNotificationEvent checkNotificationEvent(Player player, NotificationType notificationType, McMMOMessageType destination, Component message) { //Init event McMMOPlayerNotificationEvent customEvent = new McMMOPlayerNotificationEvent(player, - notificationType, message, destination, AdvancedConfig.getInstance().doesNotificationSendCopyToChat(notificationType)); + notificationType, message, destination, mcMMO.p.getAdvancedConfig().doesNotificationSendCopyToChat(notificationType)); //Call event Bukkit.getServer().getPluginManager().callEvent(customEvent); @@ -155,7 +153,7 @@ public class NotificationManager { if(!mcMMOPlayer.useChatNotifications()) return; - McMMOMessageType destination = AdvancedConfig.getInstance().doesNotificationUseActionBar(NotificationType.LEVEL_UP_MESSAGE) ? McMMOMessageType.ACTION_BAR : McMMOMessageType.SYSTEM; + McMMOMessageType destination = mcMMO.p.getAdvancedConfig().doesNotificationUseActionBar(NotificationType.LEVEL_UP_MESSAGE) ? McMMOMessageType.ACTION_BAR : McMMOMessageType.SYSTEM; Component levelUpTextComponent = TextComponentFactory.getNotificationLevelUpTextComponent(skillName, levelsGained, newLevel); McMMOPlayerNotificationEvent customEvent = checkNotificationEvent(mcMMOPlayer.getPlayer(), NotificationType.LEVEL_UP_MESSAGE, destination, levelUpTextComponent); @@ -183,7 +181,7 @@ public class NotificationManager { SoundManager.sendCategorizedSound(mcMMOPlayer.getPlayer(), mcMMOPlayer.getPlayer().getLocation(), SoundType.SKILL_UNLOCKED, SoundCategory.MASTER); //ACTION BAR MESSAGE - /*if(AdvancedConfig.getInstance().doesNotificationUseActionBar(NotificationType.SUBSKILL_UNLOCKED)) + /*if(mcMMO.p.getAdvancedConfig().doesNotificationUseActionBar(NotificationType.SUBSKILL_UNLOCKED)) mcMMOPlayer.getPlayer().spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(LocaleLoader.getString("JSON.SkillUnlockMessage", subSkillType.getLocaleName(), String.valueOf(RankUtils.getRank(mcMMOPlayer.getPlayer(), @@ -197,7 +195,7 @@ public class NotificationManager { */ private static void sendAdminNotification(String msg) { //If its not enabled exit - if(!Config.getInstance().adminNotifications()) + if(!mcMMO.p.getGeneralConfig().adminNotifications()) return; for(Player player : Bukkit.getServer().getOnlinePlayers()) @@ -274,13 +272,13 @@ public class NotificationManager { return; //Check if broadcasting is enabled - if(Config.getInstance().shouldLevelUpBroadcasts()) { + if(mcMMO.p.getGeneralConfig().shouldLevelUpBroadcasts()) { //Permission check if(!Permissions.levelUpBroadcast(mmoPlayer.getPlayer())) { return; } - int levelInterval = Config.getInstance().getLevelUpBroadcastInterval(); + int levelInterval = mcMMO.p.getGeneralConfig().getLevelUpBroadcastInterval(); int remainder = level % levelInterval; if(remainder == 0) { @@ -309,13 +307,13 @@ public class NotificationManager { return; //Check if broadcasting is enabled - if(Config.getInstance().shouldPowerLevelUpBroadcasts()) { + if(mcMMO.p.getGeneralConfig().shouldPowerLevelUpBroadcasts()) { //Permission check if(!Permissions.levelUpBroadcast(mmoPlayer.getPlayer())) { return; } - int levelInterval = Config.getInstance().getPowerLevelUpBroadcastInterval(); + int levelInterval = mcMMO.p.getGeneralConfig().getPowerLevelUpBroadcastInterval(); int remainder = powerLevel % levelInterval; if(remainder == 0) { diff --git a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java b/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java index a59cd2861..67982ce59 100644 --- a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java +++ b/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java @@ -1,10 +1,10 @@ package com.gmail.nossr50.util.random; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.events.skills.secondaryabilities.SubSkillEvent; import com.gmail.nossr50.events.skills.secondaryabilities.SubSkillRandomCheckEvent; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.EventUtils; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.skills.SkillActivationType; @@ -252,11 +252,11 @@ public class RandomChanceUtil { public static double getStaticRandomChance(@NotNull SubSkillType subSkillType) throws InvalidStaticChance { switch (subSkillType) { case AXES_ARMOR_IMPACT: - return AdvancedConfig.getInstance().getImpactChance(); + return mcMMO.p.getAdvancedConfig().getImpactChance(); case AXES_GREATER_IMPACT: - return AdvancedConfig.getInstance().getGreaterImpactChance(); + return mcMMO.p.getAdvancedConfig().getGreaterImpactChance(); case TAMING_FAST_FOOD_SERVICE: - return AdvancedConfig.getInstance().getFastFoodChance(); + return mcMMO.p.getAdvancedConfig().getFastFoodChance(); default: throw new InvalidStaticChance(); } @@ -328,10 +328,10 @@ public class RandomChanceUtil { } public static double getMaximumProbability(@NotNull SubSkillType subSkillType) { - return AdvancedConfig.getInstance().getMaximumProbability(subSkillType); + return mcMMO.p.getAdvancedConfig().getMaximumProbability(subSkillType); } public static double getMaxBonusLevelCap(@NotNull SubSkillType subSkillType) { - return AdvancedConfig.getInstance().getMaxBonusLevel(subSkillType); + return mcMMO.p.getAdvancedConfig().getMaxBonusLevel(subSkillType); } } diff --git a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java index b6bb064b5..5ec4381b6 100644 --- a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java +++ b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.util.scoreboards; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.database.PlayerStat; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; @@ -72,7 +71,7 @@ public class ScoreboardManager { * Stylizes the targetBoard in a Rainbow Pattern * This is off by default */ - if (Config.getInstance().getScoreboardRainbows()) { + if (mcMMO.p.getGeneralConfig().getScoreboardRainbows()) { // Everything but black, gray, gold List colors = Lists.newArrayList( ChatColor.WHITE, @@ -153,7 +152,7 @@ public class ScoreboardManager { } private static String formatAbility(ChatColor color, String abilityName) { - if (Config.getInstance().getShowAbilityNames()) { + if (mcMMO.p.getGeneralConfig().getShowAbilityNames()) { return getShortenedName(color + abilityName); } else { @@ -244,11 +243,11 @@ public class ScoreboardManager { } } - if (Config.getInstance().getPowerLevelTagsEnabled() && !dirtyPowerLevels.contains(playerName)) { + if (mcMMO.p.getGeneralConfig().getPowerLevelTagsEnabled() && !dirtyPowerLevels.contains(playerName)) { dirtyPowerLevels.add(playerName); } - if (Config.getInstance().getSkillLevelUpBoard()) { + if (mcMMO.p.getGeneralConfig().getSkillLevelUpBoard()) { enablePlayerSkillLevelUpScoreboard(player, skill); } @@ -299,7 +298,7 @@ public class ScoreboardManager { wrapper.setOldScoreboard(); wrapper.setTypeSkill(skill); - changeScoreboard(wrapper, Config.getInstance().getSkillScoreboardTime()); + changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getSkillScoreboardTime()); } } @@ -318,7 +317,7 @@ public class ScoreboardManager { wrapper.setOldScoreboard(); wrapper.setTypeSkill(primarySkillType); - changeScoreboard(wrapper, Config.getInstance().getSkillScoreboardTime()); + changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getSkillScoreboardTime()); } } @@ -333,7 +332,7 @@ public class ScoreboardManager { wrapper.setOldScoreboard(); wrapper.setTypeSkill(skill); - changeScoreboard(wrapper, Config.getInstance().getSkillLevelUpTime()); + changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getSkillLevelUpTime()); } } @@ -347,7 +346,7 @@ public class ScoreboardManager { wrapper.setOldScoreboard(); wrapper.setTypeSelfStats(); - changeScoreboard(wrapper, Config.getInstance().getStatsScoreboardTime()); + changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getStatsScoreboardTime()); } public static void enablePlayerInspectScoreboard(@NotNull Player player, @NotNull PlayerProfile targetProfile) { @@ -362,7 +361,7 @@ public class ScoreboardManager { wrapper.setOldScoreboard(); wrapper.setTypeInspectStats(targetProfile); - changeScoreboard(wrapper, Config.getInstance().getInspectScoreboardTime()); + changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getInspectScoreboardTime()); } } @@ -378,7 +377,7 @@ public class ScoreboardManager { wrapper.setOldScoreboard(); wrapper.setTypeInspectStats(targetMcMMOPlayer); - changeScoreboard(wrapper, Config.getInstance().getInspectScoreboardTime()); + changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getInspectScoreboardTime()); } } @@ -394,7 +393,7 @@ public class ScoreboardManager { wrapper.setOldScoreboard(); wrapper.setTypeCooldowns(); - changeScoreboard(wrapper, Config.getInstance().getCooldownScoreboardTime()); + changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getCooldownScoreboardTime()); } } @@ -411,7 +410,7 @@ public class ScoreboardManager { wrapper.setTypeSelfRank(); wrapper.acceptRankData(rank); - changeScoreboard(wrapper, Config.getInstance().getRankScoreboardTime()); + changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getRankScoreboardTime()); } } @@ -428,7 +427,7 @@ public class ScoreboardManager { wrapper.setTypeInspectRank(targetName); wrapper.acceptRankData(rank); - changeScoreboard(wrapper, Config.getInstance().getRankScoreboardTime()); + changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getRankScoreboardTime()); } } @@ -446,7 +445,7 @@ public class ScoreboardManager { wrapper.setTypeTop(skill, pageNumber); wrapper.acceptLeaderboardData(stats); - changeScoreboard(wrapper, Config.getInstance().getTopScoreboardTime()); + changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getTopScoreboardTime()); } } @@ -463,7 +462,7 @@ public class ScoreboardManager { wrapper.setTypeTopPower(pageNumber); wrapper.acceptLeaderboardData(stats); - changeScoreboard(wrapper, Config.getInstance().getTopScoreboardTime()); + changeScoreboard(wrapper, mcMMO.p.getGeneralConfig().getTopScoreboardTime()); } } @@ -517,7 +516,7 @@ public class ScoreboardManager { * @return the main targetBoard objective, or null if disabled */ public static @Nullable Objective getPowerLevelObjective() { - if (!Config.getInstance().getPowerLevelTagsEnabled()) { + if (!mcMMO.p.getGeneralConfig().getPowerLevelTagsEnabled()) { if(getScoreboardManager() == null) return null; diff --git a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java index e2669d4c0..20f3d4d97 100644 --- a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java +++ b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.util.scoreboards; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.datatypes.database.PlayerStat; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; @@ -75,7 +74,7 @@ public class ScoreboardWrapper { registered = true; } - if (Config.getInstance().getPowerLevelTagsEnabled()) { + if (mcMMO.p.getGeneralConfig().getPowerLevelTagsEnabled()) { powerObjective.setDisplayName(ScoreboardManager.TAG_POWER_LEVEL); powerObjective.setDisplaySlot(DisplaySlot.BELOW_NAME); @@ -225,7 +224,7 @@ public class ScoreboardWrapper { PlayerProfile profile = UserManager.getPlayer(player).getProfile(); - if (profile.getScoreboardTipsShown() >= Config.getInstance().getTipsAmount()) { + if (profile.getScoreboardTipsShown() >= mcMMO.p.getGeneralConfig().getTipsAmount()) { return; } diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index 615ad89eb..e3dcf0e6f 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.util.skills; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.interactions.NotificationType; @@ -536,7 +535,7 @@ public final class CombatUtils { * @return true if the player has access to the limit break */ public static boolean canUseLimitBreak(@NotNull Player player, LivingEntity target, @NotNull SubSkillType subSkillType) { - if(target instanceof Player || AdvancedConfig.getInstance().canApplyLimitBreakPVE()) { + if(target instanceof Player || mcMMO.p.getAdvancedConfig().canApplyLimitBreakPVE()) { return RankUtils.hasUnlockedSubskill(player, subSkillType) && Permissions.isSubSkillEnabled(player, subSkillType); } else { diff --git a/src/main/java/com/gmail/nossr50/util/skills/ParticleEffectUtils.java b/src/main/java/com/gmail/nossr50/util/skills/ParticleEffectUtils.java index f63b5dd83..a70f09471 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/ParticleEffectUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/ParticleEffectUtils.java @@ -1,6 +1,6 @@ package com.gmail.nossr50.util.skills; -import com.gmail.nossr50.config.Config; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundType; import org.apache.commons.lang.math.RandomUtils; @@ -24,7 +24,7 @@ public final class ParticleEffectUtils { } public static void playBleedEffect(LivingEntity livingEntity) { - if (!Config.getInstance().getBleedEffectEnabled()) { + if (!mcMMO.p.getGeneralConfig().getBleedEffectEnabled()) { return; } @@ -63,7 +63,7 @@ public final class ParticleEffectUtils { public static void playDodgeEffect(Player player) { - if (!Config.getInstance().getDodgeEffectEnabled()) { + if (!mcMMO.p.getGeneralConfig().getDodgeEffectEnabled()) { return; } @@ -71,7 +71,7 @@ public final class ParticleEffectUtils { } public static void playFluxEffect(Location location) { - if (!Config.getInstance().getFluxEffectEnabled()) { + if (!mcMMO.p.getGeneralConfig().getFluxEffectEnabled()) { return; } @@ -100,7 +100,7 @@ public final class ParticleEffectUtils { } public static void playGreaterImpactEffect(LivingEntity livingEntity) { - if (!Config.getInstance().getGreaterImpactEffectEnabled()) { + if (!mcMMO.p.getGeneralConfig().getGreaterImpactEffectEnabled()) { return; } @@ -110,7 +110,7 @@ public final class ParticleEffectUtils { } public static void playCallOfTheWildEffect(LivingEntity livingEntity) { - if (!Config.getInstance().getCallOfTheWildEffectEnabled()) { + if (!mcMMO.p.getGeneralConfig().getCallOfTheWildEffectEnabled()) { return; } @@ -118,7 +118,7 @@ public final class ParticleEffectUtils { } public static void playAbilityDisabledEffect(Player player) { - if (!Config.getInstance().getAbilityDeactivationEffectEnabled()) { + if (!mcMMO.p.getGeneralConfig().getAbilityDeactivationEffectEnabled()) { } /*if (hasHeadRoom(player)) { diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java index 08b931764..434828dca 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java @@ -1,7 +1,5 @@ package com.gmail.nossr50.util.skills; -import com.gmail.nossr50.config.AdvancedConfig; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.HiddenConfig; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.experience.XPGainSource; @@ -56,8 +54,8 @@ public final class SkillUtils { public static String[] calculateLengthDisplayValues(Player player, float skillValue, PrimarySkillType skill) { int maxLength = skill.getAbility().getMaxLength(); - int abilityLengthVar = AdvancedConfig.getInstance().getAbilityLength(); - int abilityLengthCap = AdvancedConfig.getInstance().getAbilityLengthCap(); + int abilityLengthVar = mcMMO.p.getAdvancedConfig().getAbilityLength(); + int abilityLengthCap = mcMMO.p.getAdvancedConfig().getAbilityLengthCap(); int length; @@ -125,7 +123,7 @@ public final class SkillUtils { * @return true if this is a valid skill, false otherwise */ public static boolean isSkill(String skillName) { - return Config.getInstance().getLocale().equalsIgnoreCase("en_US") ? PrimarySkillType.getSkill(skillName) != null : isLocalizedSkill(skillName); + return mcMMO.p.getGeneralConfig().getLocale().equalsIgnoreCase("en_US") ? PrimarySkillType.getSkill(skillName) != null : isLocalizedSkill(skillName); } public static void sendSkillMessage(Player player, NotificationType notificationType, String key) { @@ -183,8 +181,8 @@ public final class SkillUtils { PrimarySkillType skill = mcMMOPlayer.getAbilityMode(SuperAbilityType.SUPER_BREAKER) ? PrimarySkillType.MINING : PrimarySkillType.EXCAVATION; - int abilityLengthVar = AdvancedConfig.getInstance().getAbilityLength(); - int abilityLengthCap = AdvancedConfig.getInstance().getAbilityLengthCap(); + int abilityLengthVar = mcMMO.p.getAdvancedConfig().getAbilityLength(); + int abilityLengthCap = mcMMO.p.getAdvancedConfig().getAbilityLengthCap(); int ticks; diff --git a/src/main/java/com/gmail/nossr50/util/text/TextComponentFactory.java b/src/main/java/com/gmail/nossr50/util/text/TextComponentFactory.java index 2259c509f..5506b6685 100644 --- a/src/main/java/com/gmail/nossr50/util/text/TextComponentFactory.java +++ b/src/main/java/com/gmail/nossr50/util/text/TextComponentFactory.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.util.text; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.config.RankConfig; import com.gmail.nossr50.datatypes.json.McMMOUrl; import com.gmail.nossr50.datatypes.json.McMMOWebLinks; @@ -64,7 +63,7 @@ public class TextComponentFactory { public static void sendPlayerSubSkillWikiLink(Player player, String subskillformatted) { - if(!Config.getInstance().getUrlLinksEnabled()) + if(!mcMMO.p.getGeneralConfig().getUrlLinksEnabled()) return; TextComponent.Builder wikiLinkComponent = Component.text().content(LocaleLoader.getString("Overhaul.mcMMO.MmoInfo.Wiki")); diff --git a/src/main/java/net/shatteredlands/shatt/backup/ZipLibrary.java b/src/main/java/net/shatteredlands/shatt/backup/ZipLibrary.java index e60c8554b..f6f0d829c 100644 --- a/src/main/java/net/shatteredlands/shatt/backup/ZipLibrary.java +++ b/src/main/java/net/shatteredlands/shatt/backup/ZipLibrary.java @@ -1,6 +1,5 @@ package net.shatteredlands.shatt.backup; -import com.gmail.nossr50.config.Config; import com.gmail.nossr50.mcMMO; import java.io.File; @@ -27,7 +26,7 @@ public class ZipLibrary { private static final File REPAIR_FILE = new File(mcMMO.getMainDirectory() + "repair.vanilla.yml"); public static void mcMMOBackup() throws IOException { - if (Config.getInstance().getUseMySQL()) { + if (mcMMO.p.getGeneralConfig().getUseMySQL()) { mcMMO.p.debug("This server is running in SQL Mode."); mcMMO.p.debug("Only config files will be backed up."); } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 508e96ee8..0a7c82b62 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -168,9 +168,6 @@ commands: aliases: [notify] description: Toggle mcMMO abilities chat display notifications on/off permission: mcmmo.commands.mcnotify - mhd: - description: Sets all players mob health settings to default - permission: mcmmo.commands.mhd mcscoreboard: aliases: [mcsb] description: Manage your mcMMO Scoreboard diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java new file mode 100644 index 000000000..99a019c0d --- /dev/null +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -0,0 +1,119 @@ +package com.gmail.nossr50.database; + +import com.gmail.nossr50.TestUtil; +import com.gmail.nossr50.config.GeneralConfig; +import com.google.common.io.Files; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import java.io.*; +import java.util.logging.Logger; + + +@PrepareForTest({GeneralConfig.class}) +@RunWith(PowerMockRunner.class) +public class FlatFileDatabaseManagerTest { + + public static final @NotNull String TEST_FILE_NAME = "test.mcmmo.users"; + private static File tempDir; + private final static @NotNull Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); + private final long PURGE_TIME = 2630000000L; + private static @Nullable FlatFileDatabaseManager flatFileDatabaseManager; + + @Before + public void init() { + logger.info("Preparing new test..."); + tempDir = Files.createTempDir(); + flatFileDatabaseManager = new FlatFileDatabaseManager(tempDir.getPath() + File.separator + TEST_FILE_NAME, logger, PURGE_TIME, 0); + } + + @After + public void tearDown() { + logger.info("Tearing down after test..."); + TestUtil.recursiveDelete(tempDir); + flatFileDatabaseManager = null; + } + + private static String[] normalDatabaseData = { + "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", + "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:", + "powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:" + }; + + private static String[] splitDataBadDatabase = { + //First entry here is missing some values + "nossr50:1000:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", + //Second entry here has an integer value replaced by a string + "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:badvalue:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:" + }; + + @Test + public void testPurgePowerlessUsers() { +// logger.info("testPurgePowerlessUsers"); +// Assert.assertNotNull(flatFileDatabaseManager); +// addDataToFile(flatFileDatabaseManager, normalDatabaseData); +// int purgeCount = flatFileDatabaseManager.purgePowerlessUsers(); +// Assert.assertEquals(purgeCount, 1); //1 User should have been purged + } + + private void addDataToFile(@NotNull FlatFileDatabaseManager flatFileDatabaseManager, @NotNull String[] dataEntries) { + String filePath = flatFileDatabaseManager.getUsersFile().getAbsolutePath(); + BufferedReader in = null; + FileWriter out = null; + + try { + + StringBuilder writer = new StringBuilder(); + + for(String data : dataEntries) { + writer.append(data).append("\r\n"); + } + + out = new FileWriter(filePath); + out.write(writer.toString()); + } catch (FileNotFoundException e) { + e.printStackTrace(); + logger.severe("File not found"); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (out != null) { + try { + out.close(); + } + catch (IOException e) { + // Ignore + } + } + } + + try { + logger.info("Added the following lines to the FlatFileDatabase for the purposes of the test..."); + // Open the file + in = new BufferedReader(new FileReader(filePath)); + String line; + while ((line = in.readLine()) != null) { + logger.info(line); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (in != null) { + try { + in.close(); + } + catch (IOException e) { + // Ignore + } + } + } + + } +} \ No newline at end of file From eec5feb2bf1bb467392638c5504c819069e3d80b Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 8 Apr 2021 13:21:34 -0700 Subject: [PATCH 02/57] PrimarySkillType refactor and other refactors --- Changelog.txt | 3 + .../com/gmail/nossr50/api/ExperienceAPI.java | 25 +- .../java/com/gmail/nossr50/api/SkillAPI.java | 11 +- .../commands/experience/AddlevelsCommand.java | 3 +- .../commands/experience/AddxpCommand.java | 3 +- .../experience/ExperienceCommand.java | 14 +- .../commands/experience/MmoeditCommand.java | 3 +- .../experience/SkillresetCommand.java | 12 +- .../commands/hardcore/HardcoreCommand.java | 4 +- .../hardcore/HardcoreModeCommand.java | 258 ++++----- .../commands/hardcore/VampirismCommand.java | 2 +- .../commands/player/InspectCommand.java | 6 +- .../nossr50/commands/player/MctopCommand.java | 4 +- .../nossr50/commands/player/XPBarCommand.java | 5 +- .../commands/skills/HerbalismCommand.java | 3 +- .../commands/skills/MmoInfoCommand.java | 5 +- .../nossr50/commands/skills/SkillCommand.java | 12 +- .../commands/skills/SkillGuideCommand.java | 3 +- .../commands/skills/WoodcuttingCommand.java | 5 +- .../gmail/nossr50/config/GeneralConfig.java | 2 +- .../database/FlatFileDatabaseManager.java | 35 +- .../nossr50/database/SQLDatabaseManager.java | 20 +- .../nossr50/datatypes/player/McMMOPlayer.java | 164 ++++-- .../datatypes/player/PlayerProfile.java | 35 +- .../datatypes/skills/PrimarySkillType.java | 492 +++++++++--------- .../datatypes/skills/SubSkillType.java | 3 +- .../datatypes/skills/interfaces/Skill.java | 84 --- .../skills/subskills/acrobatics/Roll.java | 93 ---- .../abilities/McMMOPlayerAbilityEvent.java | 3 +- .../secondaryabilities/SubSkillEvent.java | 5 +- .../nossr50/listeners/BlockListener.java | 12 +- .../nossr50/listeners/PlayerListener.java | 14 +- .../gmail/nossr50/listeners/SelfListener.java | 4 +- .../gmail/nossr50/locale/LocaleLoader.java | 1 + src/main/java/com/gmail/nossr50/mcMMO.java | 12 +- .../commands/McrankCommandDisplayTask.java | 6 +- .../commands/MctopCommandDisplayTask.java | 4 +- .../database/FormulaConversionTask.java | 2 +- .../runnables/skills/AbilityDisableTask.java | 4 +- .../skills/acrobatics/AcrobaticsManager.java | 2 +- .../gmail/nossr50/skills/alchemy/Alchemy.java | 1 - .../skills/alchemy/AlchemyManager.java | 4 +- .../nossr50/skills/child/ChildConfig.java | 3 +- .../nossr50/skills/child/FamilyTree.java | 5 +- .../nossr50/skills/mining/MiningManager.java | 4 +- .../com/gmail/nossr50/util/EventUtils.java | 6 +- .../gmail/nossr50/util/HardcoreManager.java | 16 +- .../commands/CommandRegistrationManager.java | 2 +- .../nossr50/util/commands/CommandUtils.java | 23 +- .../util/experience/ExperienceBarManager.java | 4 +- .../util/player/NotificationManager.java | 4 +- .../util/scoreboards/ScoreboardManager.java | 20 +- .../util/scoreboards/ScoreboardWrapper.java | 15 +- .../nossr50/util/skills/CombatUtils.java | 24 +- .../gmail/nossr50/util/skills/RankUtils.java | 3 +- .../gmail/nossr50/util/skills/SkillTools.java | 450 ++++++++++++++++ .../gmail/nossr50/util/skills/SkillUtils.java | 8 +- .../gmail/nossr50/util/text/StringUtils.java | 29 ++ .../database/FlatFileDatabaseManagerTest.java | 1 - 59 files changed, 1204 insertions(+), 796 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/util/skills/SkillTools.java diff --git a/Changelog.txt b/Changelog.txt index 8e1b2d0e6..7e251df2a 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -2,6 +2,9 @@ Version 2.1.189 Removed MHD command (it didn't do anything for a while now) Removed UP warning Updated pl locale (Thanks Mich3l3k) + Fixed an IllegalPluginAccessException error that could happen during server shutdown + Minor performance optimizations to FlatFile database + Refactored a lot of code NOTES: Ultra Permissions is SAFE to use with mcMMO diff --git a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java index 158aafa27..81873a699 100644 --- a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java +++ b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java @@ -35,7 +35,7 @@ public final class ExperienceAPI { * @return true if this is a valid mcMMO skill */ public static boolean isValidSkillType(String skillType) { - return PrimarySkillType.getSkill(skillType) != null; + return mcMMO.p.getSkillTools().matchSkill(skillType) != null; } /** @@ -78,9 +78,9 @@ public final class ExperienceAPI { * @return true if this is a valid, non-child mcMMO skill */ public static boolean isNonChildSkill(String skillType) { - PrimarySkillType skill = PrimarySkillType.getSkill(skillType); + PrimarySkillType skill = mcMMO.p.getSkillTools().matchSkill(skillType); - return skill != null && !skill.isChildSkill(); + return skill != null && !mcMMO.p.getSkillTools().isChildSkill(skill); } @Deprecated @@ -294,11 +294,12 @@ public final class ExperienceAPI { PrimarySkillType skill = getSkillType(skillType); if (isUnshared) { - getPlayer(player).beginUnsharedXpGain(skill, (int) (XP / skill.getXpModifier() * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()), getXPGainReason(xpGainReason), XPGainSource.CUSTOM); + getPlayer(player).beginUnsharedXpGain(skill, + (int) (XP / ExperienceConfig.getInstance().getFormulaSkillModifier(skill) * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()), getXPGainReason(xpGainReason), XPGainSource.CUSTOM); return; } - getPlayer(player).applyXpGain(skill, (int) (XP / skill.getXpModifier() * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()), getXPGainReason(xpGainReason), XPGainSource.CUSTOM); + getPlayer(player).applyXpGain(skill, (int) (XP / ExperienceConfig.getInstance().getFormulaSkillModifier(skill) * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()), getXPGainReason(xpGainReason), XPGainSource.CUSTOM); } /** @@ -317,7 +318,7 @@ public final class ExperienceAPI { public static void addModifiedXPOffline(String playerName, String skillType, int XP) { PrimarySkillType skill = getSkillType(skillType); - addOfflineXP(playerName, skill, (int) (XP / skill.getXpModifier() * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier())); + addOfflineXP(playerName, skill, (int) (XP / ExperienceConfig.getInstance().getFormulaSkillModifier(skill) * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier())); } /** @@ -625,7 +626,7 @@ public final class ExperienceAPI { PlayerProfile profile = getOfflineProfile(playerName); PrimarySkillType skill = getSkillType(skillType); - if (skill.isChildSkill()) { + if (mcMMO.p.getSkillTools().isChildSkill(skill)) { Set parentSkills = FamilyTree.getParents(skill); for (PrimarySkillType parentSkill : parentSkills) { @@ -656,7 +657,7 @@ public final class ExperienceAPI { PlayerProfile profile = getOfflineProfile(uuid); PrimarySkillType skill = getSkillType(skillType); - if (skill.isChildSkill()) { + if (mcMMO.p.getSkillTools().isChildSkill(skill)) { Set parentSkills = FamilyTree.getParents(skill); for (PrimarySkillType parentSkill : parentSkills) { @@ -762,7 +763,7 @@ public final class ExperienceAPI { int powerLevel = 0; PlayerProfile profile = getOfflineProfile(playerName); - for (PrimarySkillType type : PrimarySkillType.NON_CHILD_SKILLS) { + for (PrimarySkillType type : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { powerLevel += profile.getSkillLevel(type); } @@ -783,7 +784,7 @@ public final class ExperienceAPI { int powerLevel = 0; PlayerProfile profile = getOfflineProfile(uuid); - for (PrimarySkillType type : PrimarySkillType.NON_CHILD_SKILLS) { + for (PrimarySkillType type : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { powerLevel += profile.getSkillLevel(type); } @@ -1168,7 +1169,7 @@ public final class ExperienceAPI { } private static PrimarySkillType getSkillType(String skillType) throws InvalidSkillException { - PrimarySkillType skill = PrimarySkillType.getSkill(skillType); + PrimarySkillType skill = mcMMO.p.getSkillTools().matchSkill(skillType); if (skill == null) { throw new InvalidSkillException(); @@ -1180,7 +1181,7 @@ public final class ExperienceAPI { private static PrimarySkillType getNonChildSkillType(String skillType) throws InvalidSkillException, UnsupportedOperationException { PrimarySkillType skill = getSkillType(skillType); - if (skill.isChildSkill()) { + if (mcMMO.p.getSkillTools().isChildSkill(skill)) { throw new UnsupportedOperationException("Child skills do not have XP"); } diff --git a/src/main/java/com/gmail/nossr50/api/SkillAPI.java b/src/main/java/com/gmail/nossr50/api/SkillAPI.java index cdb686af8..db98ed08a 100644 --- a/src/main/java/com/gmail/nossr50/api/SkillAPI.java +++ b/src/main/java/com/gmail/nossr50/api/SkillAPI.java @@ -1,6 +1,7 @@ package com.gmail.nossr50.api; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.mcMMO; import java.util.ArrayList; import java.util.Arrays; @@ -30,7 +31,7 @@ public final class SkillAPI { * @return a list of strings with valid skill names */ public static List getNonChildSkills() { - return getListFromEnum(PrimarySkillType.NON_CHILD_SKILLS); + return getListFromEnum(mcMMO.p.getSkillTools().NON_CHILD_SKILLS); } /** @@ -42,7 +43,7 @@ public final class SkillAPI { * @return a list of strings with valid skill names */ public static List getChildSkills() { - return getListFromEnum(PrimarySkillType.CHILD_SKILLS); + return getListFromEnum(mcMMO.p.getSkillTools().CHILD_SKILLS); } /** @@ -54,7 +55,7 @@ public final class SkillAPI { * @return a list of strings with valid skill names */ public static List getCombatSkills() { - return getListFromEnum(PrimarySkillType.COMBAT_SKILLS); + return getListFromEnum(mcMMO.p.getSkillTools().COMBAT_SKILLS); } /** @@ -66,7 +67,7 @@ public final class SkillAPI { * @return a list of strings with valid skill names */ public static List getGatheringSkills() { - return getListFromEnum(PrimarySkillType.GATHERING_SKILLS); + return getListFromEnum(mcMMO.p.getSkillTools().GATHERING_SKILLS); } /** @@ -78,7 +79,7 @@ public final class SkillAPI { * @return a list of strings with valid skill names */ public static List getMiscSkills() { - return getListFromEnum(PrimarySkillType.MISC_SKILLS); + return getListFromEnum(mcMMO.p.getSkillTools().MISC_SKILLS); } private static List getListFromEnum(List skillsTypes) { diff --git a/src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java index af3b3366c..ca54d293a 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java @@ -5,6 +5,7 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.EventUtils; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; @@ -55,6 +56,6 @@ public class AddlevelsCommand extends ExperienceCommand { if(isSilent) return; - player.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.1", value, skill.getName())); + player.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.1", value, mcMMO.p.getSkillTools().getLocalizedSkillName(skill))); } } diff --git a/src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java index 03ad449bb..25d77e5c0 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java @@ -5,6 +5,7 @@ import com.gmail.nossr50.datatypes.experience.XPGainSource; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.command.CommandSender; @@ -49,6 +50,6 @@ public class AddxpCommand extends ExperienceCommand { if(isSilent) return; - player.sendMessage(LocaleLoader.getString("Commands.addxp.AwardSkill", value, skill.getName())); + player.sendMessage(LocaleLoader.getString("Commands.addxp.AwardSkill", value, mcMMO.p.getSkillTools().getLocalizedSkillName(skill))); } } diff --git a/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java index 11684ebf8..f43c3e35f 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java @@ -44,13 +44,13 @@ public abstract class ExperienceCommand implements TabExecutor { return true; } - skill = PrimarySkillType.getSkill(args[0]); + skill = mcMMO.p.getSkillTools().matchSkill(args[0]); if (args[1].equalsIgnoreCase("all")) { skill = null; } - if (skill != null && skill.isChildSkill()) + if (skill != null && mcMMO.p.getSkillTools().isChildSkill(skill)) { sender.sendMessage(LocaleLoader.getString("Commands.Skill.ChildSkill")); return true; @@ -77,13 +77,13 @@ public abstract class ExperienceCommand implements TabExecutor { return true; } - skill = PrimarySkillType.getSkill(args[1]); + skill = mcMMO.p.getSkillTools().matchSkill(args[1]); if (args[1].equalsIgnoreCase("all")) { skill = null; } - if (skill != null && skill.isChildSkill()) + if (skill != null && mcMMO.p.getSkillTools().isChildSkill(skill)) { sender.sendMessage(LocaleLoader.getString("Commands.Skill.ChildSkill")); return true; @@ -144,7 +144,7 @@ public abstract class ExperienceCommand implements TabExecutor { List playerNames = CommandUtils.getOnlinePlayerNames(sender); return StringUtil.copyPartialMatches(args[0], playerNames, new ArrayList<>(playerNames.size())); case 2: - return StringUtil.copyPartialMatches(args[1], PrimarySkillType.SKILL_NAMES, new ArrayList<>(PrimarySkillType.SKILL_NAMES.size())); + return StringUtil.copyPartialMatches(args[1], mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES, new ArrayList<>(mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES.size())); default: return ImmutableList.of(); } @@ -165,13 +165,13 @@ public abstract class ExperienceCommand implements TabExecutor { sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardAll.2", playerName)); } else { - sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", skill.getName(), playerName)); + sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", mcMMO.p.getSkillTools().getLocalizedSkillName(skill), playerName)); } } protected void editValues(Player player, PlayerProfile profile, PrimarySkillType skill, int value, boolean isSilent) { if (skill == null) { - for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { handleCommand(player, profile, primarySkillType, value); } diff --git a/src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java index ac8405525..93089ac69 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java @@ -5,6 +5,7 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.EventUtils; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; @@ -61,6 +62,6 @@ public class MmoeditCommand extends ExperienceCommand { if(isSilent) return; - player.sendMessage(LocaleLoader.getString("Commands.mmoedit.Modified.1", skill.getName(), value)); + player.sendMessage(LocaleLoader.getString("Commands.mmoedit.Modified.1", mcMMO.p.getSkillTools().getLocalizedSkillName(skill), value)); } } diff --git a/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java index 9b97fa77a..72c1718cd 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java @@ -50,7 +50,7 @@ public class SkillresetCommand implements TabExecutor { skill = null; } else { - skill = PrimarySkillType.getSkill(args[0]); + skill = mcMMO.p.getSkillTools().matchSkill(args[0]); } editValues((Player) sender, UserManager.getPlayer(sender.getName()).getProfile(), skill); @@ -70,7 +70,7 @@ public class SkillresetCommand implements TabExecutor { skill = null; } else { - skill = PrimarySkillType.getSkill(args[1]); + skill = mcMMO.p.getSkillTools().matchSkill(args[1]); } String playerName = CommandUtils.getMatchedPlayerName(args[0]); @@ -116,7 +116,7 @@ public class SkillresetCommand implements TabExecutor { List playerNames = CommandUtils.getOnlinePlayerNames(sender); return StringUtil.copyPartialMatches(args[0], playerNames, new ArrayList<>(playerNames.size())); case 2: - return StringUtil.copyPartialMatches(args[1], PrimarySkillType.SKILL_NAMES, new ArrayList<>(PrimarySkillType.SKILL_NAMES.size())); + return StringUtil.copyPartialMatches(args[1], mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES, new ArrayList<>(mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES.size())); default: return ImmutableList.of(); } @@ -149,7 +149,7 @@ public class SkillresetCommand implements TabExecutor { } protected void handlePlayerMessageSkill(Player player, PrimarySkillType skill) { - player.sendMessage(LocaleLoader.getString("Commands.Reset.Single", skill.getName())); + player.sendMessage(LocaleLoader.getString("Commands.Reset.Single", mcMMO.p.getSkillTools().getLocalizedSkillName(skill))); } private boolean validateArguments(CommandSender sender, String skillName) { @@ -161,13 +161,13 @@ public class SkillresetCommand implements TabExecutor { sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardAll.2", playerName)); } else { - sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", skill.getName(), playerName)); + sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", mcMMO.p.getSkillTools().getLocalizedSkillName(skill), playerName)); } } protected void editValues(Player player, PlayerProfile profile, PrimarySkillType skill) { if (skill == null) { - for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { handleCommand(player, profile, primarySkillType); } diff --git a/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreCommand.java b/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreCommand.java index e3697be36..d6b8de57b 100644 --- a/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreCommand.java @@ -51,7 +51,7 @@ // // private void toggle(boolean enable, PrimarySkillType skill) { // if (skill == null) { -// for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { +// for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { // primarySkillType.setHardcoreStatLossEnabled(enable); // } // } @@ -59,6 +59,6 @@ // skill.setHardcoreStatLossEnabled(enable); // } // -// mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Hardcore.Mode." + (enable ? "Enabled" : "Disabled"), LocaleLoader.getString("Hardcore.DeathStatLoss.Name"), (skill == null ? "all skills" : skill.getName()))); +// mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Hardcore.Mode." + (enable ? "Enabled" : "Disabled"), LocaleLoader.getString("Hardcore.DeathStatLoss.Name"), (skill == null ? "all skills" : mcMMO.p.getSkillTools().getLocalizedSkillName(skill)))); // } //} \ No newline at end of file diff --git a/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreModeCommand.java b/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreModeCommand.java index 62206566a..1bffa7a65 100644 --- a/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreModeCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreModeCommand.java @@ -1,129 +1,129 @@ -package com.gmail.nossr50.commands.hardcore; - -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -import com.gmail.nossr50.util.Permissions; -import com.gmail.nossr50.util.commands.CommandUtils; -import com.gmail.nossr50.util.text.StringUtils; -import com.google.common.collect.ImmutableList; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.command.TabExecutor; -import org.bukkit.util.StringUtil; -import org.jetbrains.annotations.NotNull; - -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.List; - -public abstract class HardcoreModeCommand implements TabExecutor { - protected final DecimalFormat percent = new DecimalFormat("##0.00%"); - - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { - switch (args.length) { - case 0: - if (!checkTogglePermissions(sender)) { - sender.sendMessage(command.getPermissionMessage()); - return true; - } - - if (checkEnabled(null)) { - disable(null); - } - else { - enable(null); - } - - return true; - - case 1: - if (CommandUtils.shouldEnableToggle(args[0])) { - if (!Permissions.hardcoreToggle(sender)) { - sender.sendMessage(command.getPermissionMessage()); - return true; - } - - enable(null); - return true; - } - - if (CommandUtils.shouldDisableToggle(args[0])) { - if (!Permissions.hardcoreToggle(sender)) { - sender.sendMessage(command.getPermissionMessage()); - return true; - } - - disable(null); - return true; - } - - if (CommandUtils.isInvalidDouble(sender, args[0])) { - return true; - } - - if (!Permissions.hardcoreModify(sender)) { - sender.sendMessage(command.getPermissionMessage()); - return true; - } - - modify(sender, Double.parseDouble(args[0])); - return true; - - - case 2: - if (CommandUtils.isInvalidSkill(sender, args[0])) { - return true; - } - - PrimarySkillType skill = PrimarySkillType.getSkill(args[0]); - - if (!CommandUtils.isChildSkill(sender, skill)) { - return true; - } - - if (CommandUtils.shouldEnableToggle(args[1])) { - if (!Permissions.hardcoreToggle(sender)) { - sender.sendMessage(command.getPermissionMessage()); - return true; - } - - enable(skill); - return true; - } - - if (CommandUtils.shouldDisableToggle(args[1])) { - if (!Permissions.hardcoreToggle(sender)) { - sender.sendMessage(command.getPermissionMessage()); - return true; - } - - enable(skill); - return true; - } - - return true; - - default: - return false; - } - } - - @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { - if (args.length == 1) { - if (StringUtils.isDouble(args[0])) { - return ImmutableList.of(); - } - - return StringUtil.copyPartialMatches(args[0], CommandUtils.TRUE_FALSE_OPTIONS, new ArrayList<>(CommandUtils.TRUE_FALSE_OPTIONS.size())); - } - return ImmutableList.of(); - } - - protected abstract boolean checkTogglePermissions(CommandSender sender); - protected abstract boolean checkModifyPermissions(CommandSender sender); - protected abstract boolean checkEnabled(PrimarySkillType skill); - protected abstract void enable(PrimarySkillType skill); - protected abstract void disable(PrimarySkillType skill); - protected abstract void modify(CommandSender sender, double newPercentage); -} +//package com.gmail.nossr50.commands.hardcore; +// +//import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +//import com.gmail.nossr50.util.Permissions; +//import com.gmail.nossr50.util.commands.CommandUtils; +//import com.gmail.nossr50.util.text.StringUtils; +//import com.google.common.collect.ImmutableList; +//import org.bukkit.command.Command; +//import org.bukkit.command.CommandSender; +//import org.bukkit.command.TabExecutor; +//import org.bukkit.util.StringUtil; +//import org.jetbrains.annotations.NotNull; +// +//import java.text.DecimalFormat; +//import java.util.ArrayList; +//import java.util.List; +// +//public abstract class HardcoreModeCommand implements TabExecutor { +// protected final DecimalFormat percent = new DecimalFormat("##0.00%"); +// +// @Override +// public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { +// switch (args.length) { +// case 0: +// if (!checkTogglePermissions(sender)) { +// sender.sendMessage(command.getPermissionMessage()); +// return true; +// } +// +// if (checkEnabled(null)) { +// disable(null); +// } +// else { +// enable(null); +// } +// +// return true; +// +// case 1: +// if (CommandUtils.shouldEnableToggle(args[0])) { +// if (!Permissions.hardcoreToggle(sender)) { +// sender.sendMessage(command.getPermissionMessage()); +// return true; +// } +// +// enable(null); +// return true; +// } +// +// if (CommandUtils.shouldDisableToggle(args[0])) { +// if (!Permissions.hardcoreToggle(sender)) { +// sender.sendMessage(command.getPermissionMessage()); +// return true; +// } +// +// disable(null); +// return true; +// } +// +// if (CommandUtils.isInvalidDouble(sender, args[0])) { +// return true; +// } +// +// if (!Permissions.hardcoreModify(sender)) { +// sender.sendMessage(command.getPermissionMessage()); +// return true; +// } +// +// modify(sender, Double.parseDouble(args[0])); +// return true; +// +// +// case 2: +// if (CommandUtils.isInvalidSkill(sender, args[0])) { +// return true; +// } +// +// PrimarySkillType skill = PrimarySkillType.getSkill(args[0]); +// +// if (!CommandUtils.isChildSkill(sender, skill)) { +// return true; +// } +// +// if (CommandUtils.shouldEnableToggle(args[1])) { +// if (!Permissions.hardcoreToggle(sender)) { +// sender.sendMessage(command.getPermissionMessage()); +// return true; +// } +// +// enable(skill); +// return true; +// } +// +// if (CommandUtils.shouldDisableToggle(args[1])) { +// if (!Permissions.hardcoreToggle(sender)) { +// sender.sendMessage(command.getPermissionMessage()); +// return true; +// } +// +// enable(skill); +// return true; +// } +// +// return true; +// +// default: +// return false; +// } +// } +// +// @Override +// public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { +// if (args.length == 1) { +// if (StringUtils.isDouble(args[0])) { +// return ImmutableList.of(); +// } +// +// return StringUtil.copyPartialMatches(args[0], CommandUtils.TRUE_FALSE_OPTIONS, new ArrayList<>(CommandUtils.TRUE_FALSE_OPTIONS.size())); +// } +// return ImmutableList.of(); +// } +// +// protected abstract boolean checkTogglePermissions(CommandSender sender); +// protected abstract boolean checkModifyPermissions(CommandSender sender); +// protected abstract boolean checkEnabled(PrimarySkillType skill); +// protected abstract void enable(PrimarySkillType skill); +// protected abstract void disable(PrimarySkillType skill); +// protected abstract void modify(CommandSender sender, double newPercentage); +//} diff --git a/src/main/java/com/gmail/nossr50/commands/hardcore/VampirismCommand.java b/src/main/java/com/gmail/nossr50/commands/hardcore/VampirismCommand.java index 8bdfa83f9..fbeaee56b 100644 --- a/src/main/java/com/gmail/nossr50/commands/hardcore/VampirismCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/hardcore/VampirismCommand.java @@ -51,7 +51,7 @@ // // private void toggle(boolean enable, PrimarySkillType skill) { // if (skill == null) { -// for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { +// for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { // primarySkillType.setHardcoreVampirismEnabled(enable); // } // } 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 267ebca4f..5779147ea 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java @@ -48,17 +48,17 @@ public class InspectCommand implements TabExecutor { sender.sendMessage(LocaleLoader.getString("Inspect.OfflineStats", playerName)); sender.sendMessage(LocaleLoader.getString("Stats.Header.Gathering")); - for (PrimarySkillType skill : PrimarySkillType.GATHERING_SKILLS) { + for (PrimarySkillType skill : mcMMO.p.getSkillTools().GATHERING_SKILLS) { sender.sendMessage(CommandUtils.displaySkill(profile, skill)); } sender.sendMessage(LocaleLoader.getString("Stats.Header.Combat")); - for (PrimarySkillType skill : PrimarySkillType.COMBAT_SKILLS) { + for (PrimarySkillType skill : mcMMO.p.getSkillTools().COMBAT_SKILLS) { sender.sendMessage(CommandUtils.displaySkill(profile, skill)); } sender.sendMessage(LocaleLoader.getString("Stats.Header.Misc")); - for (PrimarySkillType skill : PrimarySkillType.MISC_SKILLS) { + for (PrimarySkillType skill : mcMMO.p.getSkillTools().MISC_SKILLS) { sender.sendMessage(CommandUtils.displaySkill(profile, skill)); } diff --git a/src/main/java/com/gmail/nossr50/commands/player/MctopCommand.java b/src/main/java/com/gmail/nossr50/commands/player/MctopCommand.java index 0ef35cd0f..04f0f82e1 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/MctopCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/MctopCommand.java @@ -68,7 +68,7 @@ public class MctopCommand implements TabExecutor { @Override public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { if (args.length == 1) { - return StringUtil.copyPartialMatches(args[0], PrimarySkillType.SKILL_NAMES, new ArrayList<>(PrimarySkillType.SKILL_NAMES.size())); + return StringUtil.copyPartialMatches(args[0], mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES, new ArrayList<>(mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES.size())); } return ImmutableList.of(); } @@ -122,7 +122,7 @@ public class MctopCommand implements TabExecutor { return null; } - PrimarySkillType skill = PrimarySkillType.getSkill(skillName); + PrimarySkillType skill = mcMMO.p.getSkillTools().matchSkill(skillName); if (CommandUtils.isChildSkill(sender, skill)) { return null; diff --git a/src/main/java/com/gmail/nossr50/commands/player/XPBarCommand.java b/src/main/java/com/gmail/nossr50/commands/player/XPBarCommand.java index ad24c60da..e780fa19d 100644 --- a/src/main/java/com/gmail/nossr50/commands/player/XPBarCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/player/XPBarCommand.java @@ -2,6 +2,7 @@ package com.gmail.nossr50.commands.player; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.experience.ExperienceBarManager; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; @@ -51,7 +52,7 @@ public class XPBarCommand implements TabExecutor { if(SkillUtils.isSkill(skillName)) { - PrimarySkillType targetSkill = PrimarySkillType.getSkill(skillName); + PrimarySkillType targetSkill = mcMMO.p.getSkillTools().matchSkill(skillName); //Target setting String option = args[0].toLowerCase(); @@ -103,7 +104,7 @@ public class XPBarCommand implements TabExecutor { return StringUtil.copyPartialMatches(args[0], options, new ArrayList<>(ExperienceBarManager.XPBarSettingTarget.values().length)); case 2: if(!args[0].equalsIgnoreCase(ExperienceBarManager.XPBarSettingTarget.RESET.toString())) - return StringUtil.copyPartialMatches(args[1], PrimarySkillType.SKILL_NAMES, new ArrayList<>(PrimarySkillType.SKILL_NAMES.size())); + return StringUtil.copyPartialMatches(args[1], mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES, new ArrayList<>(mcMMO.p.getSkillTools().LOCALIZED_SKILL_NAMES.size())); default: return ImmutableList.of(); } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java index 3d4693b77..871d0066f 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/HerbalismCommand.java @@ -3,6 +3,7 @@ package com.gmail.nossr50.commands.skills; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillActivationType; @@ -93,7 +94,7 @@ public class HerbalismCommand extends SkillCommand { canGreenThumbPlants = RankUtils.hasUnlockedSubskill(player, SubSkillType.HERBALISM_GREEN_THUMB) && (Permissions.greenThumbPlant(player, Material.WHEAT) || Permissions.greenThumbPlant(player, Material.CARROT) || Permissions.greenThumbPlant(player, Material.POTATO) || Permissions.greenThumbPlant(player, Material.BEETROOT) || Permissions.greenThumbPlant(player, Material.NETHER_WART) || Permissions.greenThumbPlant(player, Material.COCOA)); canGreenThumbBlocks = RankUtils.hasUnlockedSubskill(player, SubSkillType.HERBALISM_GREEN_THUMB) && (Permissions.greenThumbBlock(player, Material.DIRT) || Permissions.greenThumbBlock(player, Material.COBBLESTONE) || Permissions.greenThumbBlock(player, Material.COBBLESTONE_WALL) || Permissions.greenThumbBlock(player, Material.STONE_BRICKS)); canFarmersDiet = canUseSubskill(player, SubSkillType.HERBALISM_FARMERS_DIET); - canDoubleDrop = canUseSubskill(player, SubSkillType.HERBALISM_DOUBLE_DROPS) && !skill.getDoubleDropsDisabled(); + canDoubleDrop = canUseSubskill(player, SubSkillType.HERBALISM_DOUBLE_DROPS) && !mcMMO.p.getGeneralConfig().getDoubleDropsDisabled(skill); canShroomThumb = canUseSubskill(player, SubSkillType.HERBALISM_SHROOM_THUMB); } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java index e724ee8cd..0c6436bf1 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java @@ -4,6 +4,7 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.listeners.InteractionManager; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.text.TextComponentFactory; import com.google.common.collect.ImmutableList; @@ -45,7 +46,7 @@ public class MmoInfoCommand implements TabExecutor { player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.DetailsHeader")); player.sendMessage(LocaleLoader.getString("Commands.MmoInfo.Mystery")); return true; - } else if(InteractionManager.getAbstractByName(args[0]) != null || PrimarySkillType.SUBSKILL_NAMES.contains(args[0])) + } else if(InteractionManager.getAbstractByName(args[0]) != null || mcMMO.p.getSkillTools().EXACT_SUBSKILL_NAMES.contains(args[0])) { displayInfo(player, args[0]); return true; @@ -63,7 +64,7 @@ public class MmoInfoCommand implements TabExecutor { @Override public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { if (args.length == 1) { - return StringUtil.copyPartialMatches(args[0], PrimarySkillType.SUBSKILL_NAMES, new ArrayList<>(PrimarySkillType.SUBSKILL_NAMES.size())); + return StringUtil.copyPartialMatches(args[0], mcMMO.p.getSkillTools().EXACT_SUBSKILL_NAMES, new ArrayList<>(mcMMO.p.getSkillTools().EXACT_SUBSKILL_NAMES.size())); } return ImmutableList.of(); } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java index 3f35a7e7e..ab5c027ba 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java @@ -44,7 +44,7 @@ public abstract class SkillCommand implements TabExecutor { public SkillCommand(PrimarySkillType skill) { this.skill = skill; - skillName = skill.getName(); + skillName = mcMMO.p.getSkillTools().getLocalizedSkillName(skill); skillGuideCommand = new SkillGuideCommand(skill); } @@ -142,7 +142,7 @@ public abstract class SkillCommand implements TabExecutor { player.sendMessage(LocaleLoader.getString("Skills.Overhaul.Header", skillName)); - if(!skill.isChildSkill()) + if(!mcMMO.p.getSkillTools().isChildSkill(skill)) { /* * NON-CHILD SKILLS @@ -172,10 +172,10 @@ public abstract class SkillCommand implements TabExecutor { { if(i+1 < parentList.size()) { - parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", parentList.get(i).getName(), mcMMOPlayer.getSkillLevel(parentList.get(i)))); + parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", mcMMO.p.getSkillTools().getLocalizedSkillName(parentList.get(i)), mcMMOPlayer.getSkillLevel(parentList.get(i)))); parentMessage.append(ChatColor.GRAY).append(", "); } else { - parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", parentList.get(i).getName(), mcMMOPlayer.getSkillLevel(parentList.get(i)))); + parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", mcMMO.p.getSkillTools().getLocalizedSkillName(parentList.get(i)), mcMMOPlayer.getSkillLevel(parentList.get(i)))); } } @@ -188,7 +188,7 @@ public abstract class SkillCommand implements TabExecutor { } /* - if (!skill.isChildSkill()) { + if (!mcMMO.p.getSkillTools().isChildSkill(skill)) { player.sendMessage(LocaleLoader.getString("Skills.Header", skillName)); player.sendMessage(LocaleLoader.getString("Commands.XPGain", LocaleLoader.getString("Commands.XPGain." + StringUtils.getCapitalized(skill.toString())))); player.sendMessage(LocaleLoader.getString("Effects.Level", skillValue, mcMMOPlayer.getSkillXpLevel(skill), mcMMOPlayer.getXpToLevel(skill))); @@ -224,7 +224,7 @@ public abstract class SkillCommand implements TabExecutor { } protected String[] calculateLengthDisplayValues(Player player, float skillValue) { - int maxLength = skill.getAbility().getMaxLength(); + int maxLength = mcMMO.p.getSkillTools().getSuperAbilityMaxLength(mcMMO.p.getSkillTools().getSuperAbility(skill)); int abilityLengthVar = mcMMO.p.getAdvancedConfig().getAbilityLength(); int abilityLengthCap = mcMMO.p.getAdvancedConfig().getAbilityLengthCap(); diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SkillGuideCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SkillGuideCommand.java index a7879bb8d..ed471f188 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillGuideCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SkillGuideCommand.java @@ -2,6 +2,7 @@ package com.gmail.nossr50.commands.skills; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.text.StringUtils; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -18,7 +19,7 @@ public class SkillGuideCommand implements CommandExecutor { private final String invalidPage = LocaleLoader.getString("Guides.Page.Invalid"); public SkillGuideCommand(PrimarySkillType skill) { - header = LocaleLoader.getString("Guides.Header", skill.getName()); + header = LocaleLoader.getString("Guides.Header", mcMMO.p.getSkillTools().getLocalizedSkillName(skill)); guide = getGuide(skill); } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java index a817a312d..08639c27b 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/WoodcuttingCommand.java @@ -3,6 +3,7 @@ package com.gmail.nossr50.commands.skills; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillActivationType; @@ -55,7 +56,9 @@ public class WoodcuttingCommand extends SkillCommand { @Override protected void permissionsCheck(Player player) { canTreeFell = RankUtils.hasUnlockedSubskill(player, SubSkillType.WOODCUTTING_TREE_FELLER) && Permissions.treeFeller(player); - canDoubleDrop = canUseSubskill(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) && !skill.getDoubleDropsDisabled() && RankUtils.getRank(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) >= 1; + canDoubleDrop = canUseSubskill(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) + && !mcMMO.p.getGeneralConfig().getDoubleDropsDisabled(skill) + && RankUtils.getRank(player, SubSkillType.WOODCUTTING_HARVEST_LUMBER) >= 1; canLeafBlow = canUseSubskill(player, SubSkillType.WOODCUTTING_LEAF_BLOWER); canKnockOnWood = canTreeFell && canUseSubskill(player, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD); /*canSplinter = canUseSubskill(player, SubSkillType.WOODCUTTING_SPLINTER); diff --git a/src/main/java/com/gmail/nossr50/config/GeneralConfig.java b/src/main/java/com/gmail/nossr50/config/GeneralConfig.java index e905a3ce1..f40956695 100644 --- a/src/main/java/com/gmail/nossr50/config/GeneralConfig.java +++ b/src/main/java/com/gmail/nossr50/config/GeneralConfig.java @@ -164,7 +164,7 @@ public class GeneralConfig extends AutoUpdateConfigLoader { //Retro mode will default the value to true if the config file doesn't contain the entry (server is from a previous mcMMO install) public boolean getIsRetroMode() { return config.getBoolean("General.RetroMode.Enabled", true); } - public String getLocale() { return config.getString("General.Locale", "en_us"); } + public String getLocale() { return config.getString("General.Locale", "en_US"); } public boolean getMOTDEnabled() { return config.getBoolean("General.MOTD_Enabled", true); } public boolean getShowProfileLoadedMessage() { return config.getBoolean("General.Show_Profile_Loaded", true); } public boolean getDonateMessageEnabled() { return config.getBoolean("Commands.mcmmo.Donate_Message", true); } diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index 863d4f8f5..80d3f8ca7 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -7,7 +7,6 @@ import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.player.UniqueDataType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; -import com.gmail.nossr50.datatypes.skills.interfaces.Skill; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; import org.bukkit.OfflinePlayer; @@ -21,7 +20,7 @@ import java.util.logging.Logger; public final class FlatFileDatabaseManager implements DatabaseManager { public static final String IGNORED = "IGNORED"; - private final @NotNull HashMap> playerStatHash = new HashMap<>(); + private final @NotNull EnumMap> playerStatHash = new EnumMap>(PrimarySkillType.class); private final @NotNull List powerLevels = new ArrayList<>(); private long lastUpdate = 0; private final @NotNull String usersFilePath; @@ -106,7 +105,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { while ((line = in.readLine()) != null) { String[] character = line.split(":"); - Map skills = getSkillMapFromLine(character); + Map skills = getSkillMapFromLine(character); boolean powerless = true; for (int skill : skills.values()) { @@ -433,15 +432,15 @@ public final class FlatFileDatabaseManager implements DatabaseManager { writer.append("\r\n"); } - public @NotNull List readLeaderboard(@Nullable PrimarySkillType skill, int pageNumber, int statsPerPage) throws InvalidSkillException { + public @NotNull List readLeaderboard(@Nullable PrimarySkillType primarySkillType, int pageNumber, int statsPerPage) throws InvalidSkillException { //Fix for a plugin that people are using that is throwing SQL errors - if(skill != null && skill.isChildSkill()) { + if(primarySkillType != null && mcMMO.p.getSkillTools().isChildSkill(primarySkillType)) { logger.severe("A plugin hooking into mcMMO is being naughty with our database commands, update all plugins that hook into mcMMO and contact their devs!"); throw new InvalidSkillException("A plugin hooking into mcMMO that you are using is attempting to read leaderboard skills for child skills, child skills do not have leaderboards! This is NOT an mcMMO error!"); } updateLeaderboards(); - List statsList = skill == null ? powerLevels : playerStatHash.get(skill); + List statsList = primarySkillType == null ? powerLevels : playerStatHash.get(primarySkillType); int fromIndex = (Math.max(pageNumber, 1) - 1) * statsPerPage; return statsList.subList(Math.min(fromIndex, statsList.size()), Math.min(fromIndex + statsPerPage, statsList.size())); @@ -450,9 +449,9 @@ public final class FlatFileDatabaseManager implements DatabaseManager { public Map readRank(String playerName) { updateLeaderboards(); - Map skills = new HashMap<>(); + Map skills = new EnumMap(PrimarySkillType.class); - for (PrimarySkillType skill : PrimarySkillType.NON_CHILD_SKILLS) { + for (PrimarySkillType skill : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { skills.put(skill, getPlayerRank(playerName, playerStatHash.get(skill))); } @@ -893,7 +892,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { playerName = data[USERNAME_INDEX]; int powerLevel = 0; - Map skills = getSkillMapFromLine(data); + Map skills = getSkillMapFromLine(data); powerLevel += putStat(acrobatics, playerName, skills.get(PrimarySkillType.ACROBATICS)); powerLevel += putStat(alchemy, playerName, skills.get(PrimarySkillType.ALCHEMY)); @@ -1117,8 +1116,8 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } private PlayerProfile loadFromLine(@NotNull String[] character) { - Map skills = getSkillMapFromLine(character); // Skill levels - Map skillsXp = new HashMap<>(); // Skill & XP + Map skills = getSkillMapFromLine(character); // Skill levels + Map skillsXp = new EnumMap<>(PrimarySkillType.class); // Skill & XP Map skillsDATS = new EnumMap<>(SuperAbilityType.class); // Ability & Cooldown Map uniquePlayerDataMap = new EnumMap<>(UniqueDataType.class); int scoreboardTipsShown; @@ -1193,7 +1192,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - private void tryLoadSkillFloatValuesFromRawData(@NotNull Map skillMap, @NotNull String[] character, @NotNull Skill primarySkillType, int index, @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[index]); skillMap.put(primarySkillType, valueFromString); @@ -1204,19 +1203,19 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - private void tryLoadSkillIntValuesFromRawData(@NotNull Map skillMap, @NotNull String[] character, @NotNull Skill skill, int index, @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[index]); - skillMap.put(skill, valueFromString); + skillMap.put(primarySkillType, valueFromString); } catch (NumberFormatException e) { - skillMap.put(skill, 0); - logger.severe("Data corruption when trying to load the value for skill "+skill+" for player named " + userName+ " setting value to zero"); + skillMap.put(primarySkillType, 0); + logger.severe("Data corruption when trying to load the value for skill "+primarySkillType+" for player named " + userName+ " setting value to zero"); e.printStackTrace(); } } - private @NotNull Map getSkillMapFromLine(@NotNull String[] character) { - HashMap skills = new HashMap<>(); // Skill & Level + private @NotNull Map getSkillMapFromLine(@NotNull String[] character) { + EnumMap skills = new EnumMap<>(PrimarySkillType.class); // Skill & Level String username = character[USERNAME_INDEX]; tryLoadSkillIntValuesFromRawData(skills, character, PrimarySkillType.ACROBATICS, SKILLS_ACROBATICS, username); diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index debd4d2ba..c218401a2 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -9,7 +9,6 @@ import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.player.UniqueDataType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; -import com.gmail.nossr50.datatypes.skills.interfaces.Skill; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.database.UUIDUpdateAsyncTask; import com.gmail.nossr50.util.Misc; @@ -29,6 +28,7 @@ public final class SQLDatabaseManager implements DatabaseManager { public static final String MOBHEALTHBAR_VARCHAR = "VARCHAR(50)"; public static final String UUID_VARCHAR = "VARCHAR(36)"; public static final String USER_VARCHAR = "VARCHAR(40)"; + public static final int CHILD_SKILLS_SIZE = 2; private final String tablePrefix = mcMMO.p.getGeneralConfig().getMySQLTablePrefix(); private final Map cachedUserIDs = new HashMap<>(); @@ -274,7 +274,7 @@ public final class SQLDatabaseManager implements DatabaseManager { statement.setInt(12, profile.getSkillLevel(PrimarySkillType.FISHING)); statement.setInt(13, profile.getSkillLevel(PrimarySkillType.ALCHEMY)); int total = 0; - for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) + for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) total += profile.getSkillLevel(primarySkillType); statement.setInt(14, total); statement.setInt(15, id); @@ -358,7 +358,7 @@ public final class SQLDatabaseManager implements DatabaseManager { List stats = new ArrayList<>(); //Fix for a plugin that people are using that is throwing SQL errors - if(skill != null && skill.isChildSkill()) { + if(skill != null && mcMMO.p.getSkillTools().isChildSkill(skill)) { mcMMO.p.getLogger().severe("A plugin hooking into mcMMO is being naughty with our database commands, update all plugins that hook into mcMMO and contact their devs!"); throw new InvalidSkillException("A plugin hooking into mcMMO that you are using is attempting to read leaderboard skills for child skills, child skills do not have leaderboards! This is NOT an mcMMO error!"); } @@ -407,7 +407,7 @@ public final class SQLDatabaseManager implements DatabaseManager { try { connection = getConnection(PoolIdentifier.MISC); - for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { String skillName = primarySkillType.name().toLowerCase(Locale.ENGLISH); // Get count of all users with higher skill level than player String sql = "SELECT COUNT(*) AS 'rank' FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE " + skillName + " > 0 " + @@ -880,7 +880,7 @@ public final class SQLDatabaseManager implements DatabaseManager { resultSet = statement.executeQuery(); if (!resultSet.next()) { String startingLevel = "'" + mcMMO.p.getAdvancedConfig().getStartingLevel() + "'"; - String totalLevel = "'" + (mcMMO.p.getAdvancedConfig().getStartingLevel() * (PrimarySkillType.values().length - PrimarySkillType.CHILD_SKILLS.size())) + "'"; + String totalLevel = "'" + (mcMMO.p.getAdvancedConfig().getStartingLevel() * (PrimarySkillType.values().length - CHILD_SKILLS_SIZE)) + "'"; createStatement = connection.createStatement(); createStatement.executeUpdate("CREATE TABLE IF NOT EXISTS `" + tablePrefix + "skills` (" + "`user_id` int(10) unsigned NOT NULL," @@ -935,7 +935,7 @@ public final class SQLDatabaseManager implements DatabaseManager { } if (mcMMO.p.getGeneralConfig().getTruncateSkills()) { - for (PrimarySkillType skill : PrimarySkillType.NON_CHILD_SKILLS) { + for (PrimarySkillType skill : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { int cap = mcMMO.p.getGeneralConfig().getLevelCap(skill); if (cap != Integer.MAX_VALUE) { statement = connection.prepareStatement("UPDATE `" + tablePrefix + "skills` SET `" + skill.name().toLowerCase(Locale.ENGLISH) + "` = " + cap + " WHERE `" + skill.name().toLowerCase(Locale.ENGLISH) + "` > " + cap); @@ -1099,8 +1099,8 @@ public final class SQLDatabaseManager implements DatabaseManager { } private PlayerProfile loadFromResult(String playerName, ResultSet result) throws SQLException { - Map skills = new HashMap<>(); // Skill & Level - Map skillsXp = new HashMap<>(); // Skill & XP + Map skills = new EnumMap(PrimarySkillType.class); // Skill & Level + Map skillsXp = new EnumMap(PrimarySkillType.class); // Skill & XP Map skillsDATS = new EnumMap<>(SuperAbilityType.class); // Ability & Cooldown Map uniqueData = new EnumMap<>(UniqueDataType.class); //Chimaera wing cooldown and other misc info MobHealthbarType mobHealthbarType; @@ -1294,10 +1294,10 @@ public final class SQLDatabaseManager implements DatabaseManager { resultSet = statement.executeQuery("SHOW INDEX FROM `" + tablePrefix + "skills` WHERE `Key_name` LIKE 'idx\\_%'"); resultSet.last(); - if (resultSet.getRow() != PrimarySkillType.NON_CHILD_SKILLS.size()) { + if (resultSet.getRow() != mcMMO.p.getSkillTools().NON_CHILD_SKILLS.size()) { mcMMO.p.getLogger().info("Indexing tables, this may take a while on larger databases"); - for (PrimarySkillType skill : PrimarySkillType.NON_CHILD_SKILLS) { + for (PrimarySkillType skill : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { String skill_name = skill.name().toLowerCase(Locale.ENGLISH); try { diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index 834d1c491..64f482fea 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -1,5 +1,6 @@ package com.gmail.nossr50.datatypes.player; +import com.gmail.nossr50.api.exceptions.InvalidSkillException; import com.gmail.nossr50.chat.author.PlayerAuthor; import com.gmail.nossr50.config.ChatConfig; import com.gmail.nossr50.config.WorldBlacklist; @@ -66,7 +67,7 @@ import org.bukkit.plugin.Plugin; import org.checkerframework.checker.nullness.qual.NonNull; import org.jetbrains.annotations.NotNull; -import java.util.HashMap; +import java.util.EnumMap; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -80,7 +81,7 @@ public class McMMOPlayer implements Identified { private final Player player; private final PlayerProfile profile; - private final Map skillManagers = new HashMap<>(); + private final Map skillManagers = new EnumMap(PrimarySkillType.class); private final ExperienceBarManager experienceBarManager; private Party party; @@ -99,10 +100,10 @@ public class McMMOPlayer implements Identified { private ChatChannel chatChannel; - private final Map abilityMode = new HashMap<>(); - private final Map abilityInformed = new HashMap<>(); + private final Map abilityMode = new EnumMap(SuperAbilityType.class); + private final Map abilityInformed = new EnumMap(SuperAbilityType.class); - private final Map toolMode = new HashMap<>(); + private final Map toolMode = new EnumMap(ToolType.class); private int recentlyHurt; private int respawnATS; @@ -131,20 +132,7 @@ public class McMMOPlayer implements Identified { profile.setUniqueId(uuid); } - /* - * I'm using this method because it makes code shorter and safer (we don't have to add all SkillTypes manually), - * but I actually have no idea about the performance impact, if there is any. - * If in the future someone wants to remove this, don't forget to also remove what is in the PrimarySkillType enum. - bm01 - */ - try { - for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { - skillManagers.put(primarySkillType, primarySkillType.getManagerClass().getConstructor(McMMOPlayer.class).newInstance(this)); - } - } - catch (Exception e) { - e.printStackTrace(); - mcMMO.p.getPluginLoader().disablePlugin(mcMMO.p); - } + initSkillManagers(); for (SuperAbilityType superAbilityType : SuperAbilityType.values()) { abilityMode.put(superAbilityType, false); @@ -169,6 +157,69 @@ public class McMMOPlayer implements Identified { } } + private void initSkillManagers() { + for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { + try { + initManager(primarySkillType); + } catch (InvalidSkillException e) { + e.printStackTrace(); + } + } + } + + //TODO: Add test + private void initManager(PrimarySkillType primarySkillType) throws InvalidSkillException { + switch(primarySkillType) { + case ACROBATICS: + skillManagers.put(primarySkillType, new AcrobaticsManager(this)); + break; + case ALCHEMY: + skillManagers.put(primarySkillType, new AlchemyManager(this)); + break; + case ARCHERY: + skillManagers.put(primarySkillType, new ArcheryManager(this)); + break; + case AXES: + skillManagers.put(primarySkillType, new AxesManager(this)); + break; + case EXCAVATION: + skillManagers.put(primarySkillType, new ExcavationManager(this)); + break; + case FISHING: + skillManagers.put(primarySkillType, new FishingManager(this)); + break; + case HERBALISM: + skillManagers.put(primarySkillType, new HerbalismManager(this)); + break; + case MINING: + skillManagers.put(primarySkillType, new MiningManager(this)); + break; + case REPAIR: + skillManagers.put(primarySkillType, new RepairManager(this)); + break; + case SALVAGE: + skillManagers.put(primarySkillType, new SalvageManager(this)); + break; + case SMELTING: + skillManagers.put(primarySkillType, new SmeltingManager(this)); + break; + case SWORDS: + skillManagers.put(primarySkillType, new SwordsManager(this)); + break; + case TAMING: + skillManagers.put(primarySkillType, new TamingManager(this)); + break; + case UNARMED: + skillManagers.put(primarySkillType, new UnarmedManager(this)); + break; + case WOODCUTTING: + skillManagers.put(primarySkillType, new WoodcuttingManager(this)); + break; + default: + throw new InvalidSkillException("The skill named has no manager! Contact the devs!"); + } + } + public String getPlayerName() { return playerName; } @@ -200,7 +251,9 @@ public class McMMOPlayer implements Identified { if(hasReachedPowerLevelCap()) { NotificationManager.sendPlayerInformationChatOnly(player, "LevelCap.PowerLevel", String.valueOf(mcMMO.p.getGeneralConfig().getPowerLevelCap())); } else if(hasReachedLevelCap(primarySkillType)) { - NotificationManager.sendPlayerInformationChatOnly(player, "LevelCap.Skill", String.valueOf(mcMMO.p.getGeneralConfig().getLevelCap(primarySkillType)), primarySkillType.getName()); + NotificationManager.sendPlayerInformationChatOnly(player, "LevelCap.Skill", + String.valueOf(mcMMO.p.getGeneralConfig().getLevelCap(primarySkillType)), + mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType)); } //Updates from Party sources @@ -227,7 +280,7 @@ public class McMMOPlayer implements Identified { public double getProgressInCurrentSkillLevel(PrimarySkillType primarySkillType) { - if(primarySkillType.isChildSkill()) { + if(mcMMO.p.getSkillTools().isChildSkill(primarySkillType)) { return 1.0D; } @@ -516,9 +569,9 @@ public class McMMOPlayer implements Identified { public int getPowerLevel() { int powerLevel = 0; - for (PrimarySkillType type : PrimarySkillType.NON_CHILD_SKILLS) { - if (type.getPermissions(player)) { - powerLevel += getSkillLevel(type); + for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + if (Permissions.skillEnabled(player, primarySkillType)) { + powerLevel += getSkillLevel(primarySkillType); } } @@ -558,12 +611,12 @@ public class McMMOPlayer implements Identified { return; } - if (skill.isChildSkill()) { + if (mcMMO.p.getSkillTools().isChildSkill(skill)) { Set parentSkills = FamilyTree.getParents(skill); float splitXp = xp / parentSkills.size(); for (PrimarySkillType parentSkill : parentSkills) { - if (parentSkill.getPermissions(player)) { + if (Permissions.skillEnabled(player, parentSkill)) { beginXpGain(parentSkill, splitXp, xpGainReason, xpGainSource); } } @@ -607,7 +660,7 @@ public class McMMOPlayer implements Identified { * @param xp Experience amount to add */ public void applyXpGain(PrimarySkillType primarySkillType, float xp, XPGainReason xpGainReason, XPGainSource xpGainSource) { - if (!primarySkillType.getPermissions(player)) { + if (!Permissions.skillEnabled(player, primarySkillType)) { return; } @@ -615,7 +668,7 @@ public class McMMOPlayer implements Identified { Bukkit.getPluginManager().callEvent(mcMMOPlayerPreXpGainEvent); xp = mcMMOPlayerPreXpGainEvent.getXpGained(); - if (primarySkillType.isChildSkill()) { + if (mcMMO.p.getSkillTools().isChildSkill(primarySkillType)) { Set parentSkills = FamilyTree.getParents(primarySkillType); for (PrimarySkillType parentSkill : parentSkills) { @@ -784,12 +837,12 @@ public class McMMOPlayer implements Identified { */ private float modifyXpGain(PrimarySkillType primarySkillType, float xp) { //TODO: A rare situation can occur where the default Power Level cap can prevent a player with one skill edited to something silly like Integer.MAX_VALUE from gaining XP in any skill, we may need to represent power level with another data type - if ((primarySkillType.getMaxLevel() <= getSkillLevel(primarySkillType)) + if ((mcMMO.p.getGeneralConfig().getLevelCap(primarySkillType) <= getSkillLevel(primarySkillType)) || (mcMMO.p.getGeneralConfig().getPowerLevelCap() <= getPowerLevel())) { return 0; } - xp = (float) (xp / primarySkillType.getXpModifier() * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()); + xp = (float) (xp / ExperienceConfig.getInstance().getFormulaSkillModifier(primarySkillType) * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()); if (mcMMO.p.getGeneralConfig().getToolModsEnabled()) { CustomTool tool = mcMMO.getModManager().getTool(player.getInventory().getItemInMainHand()); @@ -820,35 +873,36 @@ public class McMMOPlayer implements Identified { /** * Check to see if an ability can be activated. * - * @param skill The skill the ability is based on + * @param primarySkillType The skill the ability is based on */ - public void checkAbilityActivation(PrimarySkillType skill) { - ToolType tool = skill.getTool(); - SuperAbilityType ability = skill.getAbility(); + public void checkAbilityActivation(PrimarySkillType primarySkillType) { + ToolType tool = mcMMO.p.getSkillTools().getPrimarySkillToolType(primarySkillType); + SuperAbilityType superAbilityType = mcMMO.p.getSkillTools().getSuperAbility(primarySkillType); + SubSkillType subSkillType = superAbilityType.getSubSkillTypeDefinition(); - if (getAbilityMode(ability) || !ability.getPermissions(player)) { + if (getAbilityMode(superAbilityType) || !superAbilityType.getPermissions(player)) { return; } //TODO: This is hacky and temporary solution until skills are move to the new system //Potential problems with this include skills with two super abilities (ie mining) - if(!skill.isSuperAbilityUnlocked(getPlayer())) + if(!RankUtils.hasUnlockedSubskill(player, subSkillType)) { - int diff = RankUtils.getSuperAbilityUnlockRequirement(skill.getAbility()) - getSkillLevel(skill); + int diff = RankUtils.getSuperAbilityUnlockRequirement(superAbilityType) - getSkillLevel(primarySkillType); //Inform the player they are not yet skilled enough - NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_COOLDOWN, "Skills.AbilityGateRequirementFail", String.valueOf(diff), skill.getName()); + NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_COOLDOWN, "Skills.AbilityGateRequirementFail", String.valueOf(diff), mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType)); return; } - int timeRemaining = calculateTimeRemaining(ability); + int timeRemaining = calculateTimeRemaining(superAbilityType); if (timeRemaining > 0) { /* * Axes and Woodcutting are odd because they share the same tool. * We show them the too tired message when they take action. */ - if (skill == PrimarySkillType.WOODCUTTING || skill == PrimarySkillType.AXES) { + if (primarySkillType == PrimarySkillType.WOODCUTTING || primarySkillType == PrimarySkillType.AXES) { NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_COOLDOWN, "Skills.TooTired", String.valueOf(timeRemaining)); //SoundManager.sendSound(player, player.getLocation(), SoundType.TIRED); } @@ -856,7 +910,7 @@ public class McMMOPlayer implements Identified { return; } - if (EventUtils.callPlayerAbilityActivateEvent(player, skill).isCancelled()) { + if (EventUtils.callPlayerAbilityActivateEvent(player, primarySkillType).isCancelled()) { return; } @@ -869,37 +923,37 @@ public class McMMOPlayer implements Identified { //Ability cap of 0 or below means no cap if(abilityLengthCap > 0) { - ticks = PerksUtils.handleActivationPerks(player, 2 + (Math.min(abilityLengthCap, getSkillLevel(skill)) / abilityLengthVar), ability.getMaxLength()); + ticks = PerksUtils.handleActivationPerks(player, 2 + (Math.min(abilityLengthCap, getSkillLevel(primarySkillType)) / abilityLengthVar), superAbilityType.getMaxLength()); } else { - ticks = PerksUtils.handleActivationPerks(player, 2 + (getSkillLevel(skill) / abilityLengthVar), ability.getMaxLength()); + ticks = PerksUtils.handleActivationPerks(player, 2 + (getSkillLevel(primarySkillType) / abilityLengthVar), superAbilityType.getMaxLength()); } if (useChatNotifications()) { - NotificationManager.sendPlayerInformation(player, NotificationType.SUPER_ABILITY, ability.getAbilityOn()); + NotificationManager.sendPlayerInformation(player, NotificationType.SUPER_ABILITY, superAbilityType.getAbilityOn()); //player.sendMessage(ability.getAbilityOn()); } if (mcMMO.p.getAdvancedConfig().sendAbilityNotificationToOtherPlayers()) { - SkillUtils.sendSkillMessage(player, NotificationType.SUPER_ABILITY_ALERT_OTHERS, ability.getAbilityPlayer()); + SkillUtils.sendSkillMessage(player, NotificationType.SUPER_ABILITY_ALERT_OTHERS, superAbilityType.getAbilityPlayer()); } //Sounds SoundManager.worldSendSound(player.getWorld(), player.getLocation(), SoundType.ABILITY_ACTIVATED_GENERIC); // Enable the ability - profile.setAbilityDATS(ability, System.currentTimeMillis() + (ticks * Misc.TIME_CONVERSION_FACTOR)); - setAbilityMode(ability, true); + profile.setAbilityDATS(superAbilityType, System.currentTimeMillis() + (ticks * Misc.TIME_CONVERSION_FACTOR)); + setAbilityMode(superAbilityType, true); - if (ability == SuperAbilityType.SUPER_BREAKER || ability == SuperAbilityType.GIGA_DRILL_BREAKER) { + if (superAbilityType == SuperAbilityType.SUPER_BREAKER || superAbilityType == SuperAbilityType.GIGA_DRILL_BREAKER) { SkillUtils.handleAbilitySpeedIncrease(player); } setToolPreparationMode(tool, false); - new AbilityDisableTask(this, ability).runTaskLater(mcMMO.p, ticks * Misc.TICK_CONVERSION_FACTOR); + new AbilityDisableTask(this, superAbilityType).runTaskLater(mcMMO.p, ticks * Misc.TICK_CONVERSION_FACTOR); } - public void processAbilityActivation(PrimarySkillType skill) { - if (!skill.getPermissions(getPlayer())) { + public void processAbilityActivation(@NotNull PrimarySkillType primarySkillType) { + if (!Permissions.skillEnabled(getPlayer(), primarySkillType)) { return; } @@ -923,15 +977,15 @@ public class McMMOPlayer implements Identified { } } - SuperAbilityType ability = skill.getAbility(); - ToolType tool = skill.getTool(); + SuperAbilityType ability = mcMMO.p.getSkillTools().getSuperAbility(primarySkillType); + ToolType tool = mcMMO.p.getSkillTools().getPrimarySkillToolType(primarySkillType); /* * Woodcutting & Axes need to be treated differently. * Basically the tool always needs to ready and we check to see if the cooldown is over when the user takes action */ if (tool.inHand(inHand) && !getToolPreparationMode(tool)) { - if (skill != PrimarySkillType.WOODCUTTING && skill != PrimarySkillType.AXES) { + if (primarySkillType != PrimarySkillType.WOODCUTTING && primarySkillType != PrimarySkillType.AXES) { int timeRemaining = calculateTimeRemaining(ability); if (isAbilityOnCooldown(ability)) { @@ -993,7 +1047,7 @@ public class McMMOPlayer implements Identified { String allCDStr = aSuperAbilityCD + ", " + bSuperAbilityCD; NotificationManager.sendPlayerInformation(player, NotificationType.TOOL, "Skills.TooTired.Extra", - primarySkillType.getName(), + mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType), allCDStr); } diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java index eaad9f299..0b2b3cbb9 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java @@ -6,7 +6,6 @@ import com.gmail.nossr50.datatypes.experience.FormulaType; import com.gmail.nossr50.datatypes.experience.SkillXpGain; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; -import com.gmail.nossr50.datatypes.skills.interfaces.Skill; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.player.PlayerProfileSaveTask; import com.gmail.nossr50.skills.child.FamilyTree; @@ -15,7 +14,7 @@ import com.google.common.collect.ImmutableMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.HashMap; +import java.util.EnumMap; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -33,14 +32,14 @@ public class PlayerProfile { private int saveAttempts = 0; /* Skill Data */ - private final Map skills = new HashMap<>(); // Skill & Level - private final Map skillsXp = new HashMap<>(); // Skill & XP - private final Map abilityDATS = new HashMap<>(); // Ability & Cooldown - private final Map uniquePlayerData = new HashMap<>(); //Misc data that doesn't fit into other categories (chimaera wing, etc..) + private final Map skills = new EnumMap<>(PrimarySkillType.class); // Skill & Level + private final Map skillsXp = new EnumMap<>(PrimarySkillType.class); // Skill & XP + private final Map abilityDATS = new EnumMap(SuperAbilityType.class); // Ability & Cooldown + private final Map uniquePlayerData = new EnumMap(UniqueDataType.class); //Misc data that doesn't fit into other categories (chimaera wing, etc..) // Store previous XP gains for diminished returns private final DelayQueue gainedSkillsXp = new DelayQueue<>(); - private final HashMap rollingSkillsXp = new HashMap<>(); + private final Map rollingSkillsXp = new EnumMap(PrimarySkillType.class); @Deprecated public PlayerProfile(String playerName) { @@ -58,7 +57,7 @@ public class PlayerProfile { abilityDATS.put(superAbilityType, 0); } - for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { skills.put(primarySkillType, mcMMO.p.getAdvancedConfig().getStartingLevel()); skillsXp.put(primarySkillType, 0F); } @@ -78,7 +77,7 @@ public class PlayerProfile { this.loaded = isLoaded; } - public PlayerProfile(@NotNull String playerName, UUID uuid, Map levelData, Map xpData, Map cooldownData, @Nullable MobHealthbarType mobHealthbarType, int scoreboardTipsShown, Map uniqueProfileData) { + public PlayerProfile(@NotNull String playerName, UUID uuid, Map levelData, Map xpData, Map cooldownData, @Nullable MobHealthbarType mobHealthbarType, int scoreboardTipsShown, Map uniqueProfileData) { this.playerName = playerName; this.uuid = uuid; mobHealthbarType = mcMMO.p.getGeneralConfig().getMobHealthbarDefault(); @@ -257,7 +256,7 @@ public class PlayerProfile { */ public int getSkillLevel(PrimarySkillType skill) { - return skill.isChildSkill() ? getChildSkillLevel(skill) : skills.get(skill); + return mcMMO.p.getSkillTools().isChildSkill(skill) ? getChildSkillLevel(skill) : skills.get(skill); } public float getSkillXpLevelRaw(PrimarySkillType skill) { @@ -265,7 +264,7 @@ public class PlayerProfile { } public int getSkillXpLevel(PrimarySkillType skill) { - if(skill.isChildSkill()) { + if(mcMMO.p.getSkillTools().isChildSkill(skill)) { return 0; } @@ -273,7 +272,7 @@ public class PlayerProfile { } public void setSkillXpLevel(PrimarySkillType skill, float xpLevel) { - if (skill.isChildSkill()) { + if (mcMMO.p.getSkillTools().isChildSkill(skill)) { return; } @@ -300,7 +299,7 @@ public class PlayerProfile { * @param xp Amount of xp to remove */ public void removeXp(PrimarySkillType skill, int xp) { - if (skill.isChildSkill()) { + if (mcMMO.p.getSkillTools().isChildSkill(skill)) { return; } @@ -310,7 +309,7 @@ public class PlayerProfile { } public void removeXp(PrimarySkillType skill, float xp) { - if (skill.isChildSkill()) { + if (mcMMO.p.getSkillTools().isChildSkill(skill)) { return; } @@ -326,7 +325,7 @@ public class PlayerProfile { * @param level New level value for the skill */ public void modifySkill(PrimarySkillType skill, int level) { - if (skill.isChildSkill()) { + if (mcMMO.p.getSkillTools().isChildSkill(skill)) { return; } @@ -359,7 +358,7 @@ public class PlayerProfile { public void addXp(PrimarySkillType skill, float xp) { markProfileDirty(); - if (skill.isChildSkill()) { + if (mcMMO.p.getSkillTools().isChildSkill(skill)) { Set parentSkills = FamilyTree.getParents(skill); float dividedXP = (xp / parentSkills.size()); @@ -418,7 +417,7 @@ public class PlayerProfile { * @return the total amount of Xp until next level */ public int getXpToLevel(PrimarySkillType primarySkillType) { - if(primarySkillType.isChildSkill()) { + if(mcMMO.p.getSkillTools().isChildSkill(primarySkillType)) { return 0; } @@ -433,7 +432,7 @@ public class PlayerProfile { int sum = 0; for (PrimarySkillType parent : parents) { - sum += Math.min(getSkillLevel(parent), parent.getMaxLevel()); + sum += Math.min(getSkillLevel(parent), mcMMO.p.getGeneralConfig().getLevelCap(parent)); } return sum / parents.size(); diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java index fa8fd41c6..1e46c2ad2 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java @@ -1,239 +1,259 @@ package com.gmail.nossr50.datatypes.skills; -import com.gmail.nossr50.config.experience.ExperienceConfig; -import com.gmail.nossr50.datatypes.skills.interfaces.Skill; -import com.gmail.nossr50.locale.LocaleLoader; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.skills.SkillManager; -import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager; -import com.gmail.nossr50.skills.alchemy.AlchemyManager; -import com.gmail.nossr50.skills.archery.ArcheryManager; -import com.gmail.nossr50.skills.axes.AxesManager; -import com.gmail.nossr50.skills.excavation.ExcavationManager; -import com.gmail.nossr50.skills.fishing.FishingManager; -import com.gmail.nossr50.skills.herbalism.HerbalismManager; -import com.gmail.nossr50.skills.mining.MiningManager; -import com.gmail.nossr50.skills.repair.RepairManager; -import com.gmail.nossr50.skills.salvage.SalvageManager; -import com.gmail.nossr50.skills.smelting.SmeltingManager; -import com.gmail.nossr50.skills.swords.SwordsManager; -import com.gmail.nossr50.skills.taming.TamingManager; -import com.gmail.nossr50.skills.unarmed.UnarmedManager; -import com.gmail.nossr50.skills.woodcutting.WoodcuttingManager; -import com.gmail.nossr50.util.Permissions; -import com.gmail.nossr50.util.skills.RankUtils; -import com.gmail.nossr50.util.text.StringUtils; -import com.google.common.collect.ImmutableList; -import org.bukkit.Color; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; -import org.bukkit.entity.Tameable; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public enum PrimarySkillType implements Skill { - ACROBATICS(AcrobaticsManager.class, Color.WHITE, - ImmutableList.of(SubSkillType.ACROBATICS_DODGE, SubSkillType.ACROBATICS_ROLL)), - ALCHEMY(AlchemyManager.class, Color.FUCHSIA, - ImmutableList.of(SubSkillType.ALCHEMY_CATALYSIS, SubSkillType.ALCHEMY_CONCOCTIONS)), - ARCHERY(ArcheryManager.class, Color.MAROON, - ImmutableList.of(SubSkillType.ARCHERY_DAZE, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK, SubSkillType.ARCHERY_ARROW_RETRIEVAL, SubSkillType.ARCHERY_SKILL_SHOT)), - AXES(AxesManager.class, Color.AQUA, SuperAbilityType.SKULL_SPLITTER, ToolType.AXE, - ImmutableList.of(SubSkillType.AXES_SKULL_SPLITTER, SubSkillType.AXES_AXES_LIMIT_BREAK, SubSkillType.AXES_ARMOR_IMPACT, SubSkillType.AXES_AXE_MASTERY, SubSkillType.AXES_CRITICAL_STRIKES, SubSkillType.AXES_GREATER_IMPACT)), - EXCAVATION(ExcavationManager.class, Color.fromRGB(139, 69, 19), SuperAbilityType.GIGA_DRILL_BREAKER, ToolType.SHOVEL, - ImmutableList.of(SubSkillType.EXCAVATION_GIGA_DRILL_BREAKER, SubSkillType.EXCAVATION_ARCHAEOLOGY)), - FISHING(FishingManager.class, Color.NAVY, - ImmutableList.of(SubSkillType.FISHING_FISHERMANS_DIET, SubSkillType.FISHING_TREASURE_HUNTER, SubSkillType.FISHING_ICE_FISHING, SubSkillType.FISHING_MAGIC_HUNTER, SubSkillType.FISHING_MASTER_ANGLER, SubSkillType.FISHING_SHAKE)), - HERBALISM(HerbalismManager.class, Color.GREEN, SuperAbilityType.GREEN_TERRA, ToolType.HOE, - ImmutableList.of(SubSkillType.HERBALISM_GREEN_TERRA, SubSkillType.HERBALISM_FARMERS_DIET, SubSkillType.HERBALISM_GREEN_THUMB, SubSkillType.HERBALISM_DOUBLE_DROPS, SubSkillType.HERBALISM_HYLIAN_LUCK, SubSkillType.HERBALISM_SHROOM_THUMB)), - MINING(MiningManager.class, Color.GRAY, SuperAbilityType.SUPER_BREAKER, ToolType.PICKAXE, - ImmutableList.of(SubSkillType.MINING_SUPER_BREAKER, SubSkillType.MINING_DEMOLITIONS_EXPERTISE, SubSkillType.MINING_BIGGER_BOMBS, SubSkillType.MINING_BLAST_MINING, SubSkillType.MINING_DOUBLE_DROPS)), - REPAIR(RepairManager.class, Color.SILVER, - ImmutableList.of(SubSkillType.REPAIR_ARCANE_FORGING, SubSkillType.REPAIR_REPAIR_MASTERY, SubSkillType.REPAIR_SUPER_REPAIR)), - SALVAGE(SalvageManager.class, Color.ORANGE, - ImmutableList.of(SubSkillType.SALVAGE_SCRAP_COLLECTOR, SubSkillType.SALVAGE_ARCANE_SALVAGE)), - SMELTING(SmeltingManager.class, Color.YELLOW, - ImmutableList.of(SubSkillType.SMELTING_UNDERSTANDING_THE_ART, /*SubSkillType.SMELTING_FLUX_MINING,*/ SubSkillType.SMELTING_FUEL_EFFICIENCY, SubSkillType.SMELTING_SECOND_SMELT)), - SWORDS(SwordsManager.class, Color.fromRGB(178, 34, 34), SuperAbilityType.SERRATED_STRIKES, ToolType.SWORD, - ImmutableList.of(SubSkillType.SWORDS_SERRATED_STRIKES, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK, SubSkillType.SWORDS_STAB, SubSkillType.SWORDS_RUPTURE, SubSkillType.SWORDS_COUNTER_ATTACK)), - TAMING(TamingManager.class, Color.PURPLE, - ImmutableList.of(SubSkillType.TAMING_BEAST_LORE, SubSkillType.TAMING_CALL_OF_THE_WILD, SubSkillType.TAMING_ENVIRONMENTALLY_AWARE, SubSkillType.TAMING_FAST_FOOD_SERVICE, SubSkillType.TAMING_GORE, SubSkillType.TAMING_HOLY_HOUND, SubSkillType.TAMING_SHARPENED_CLAWS, SubSkillType.TAMING_SHOCK_PROOF, SubSkillType.TAMING_THICK_FUR, SubSkillType.TAMING_PUMMEL)), - UNARMED(UnarmedManager.class, Color.BLACK, SuperAbilityType.BERSERK, ToolType.FISTS, - ImmutableList.of(SubSkillType.UNARMED_BERSERK, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK, SubSkillType.UNARMED_BLOCK_CRACKER, SubSkillType.UNARMED_ARROW_DEFLECT, SubSkillType.UNARMED_DISARM, SubSkillType.UNARMED_STEEL_ARM_STYLE, SubSkillType.UNARMED_IRON_GRIP)), - WOODCUTTING(WoodcuttingManager.class, Color.OLIVE, SuperAbilityType.TREE_FELLER, ToolType.AXE, - ImmutableList.of(SubSkillType.WOODCUTTING_LEAF_BLOWER, SubSkillType.WOODCUTTING_TREE_FELLER, SubSkillType.WOODCUTTING_HARVEST_LUMBER, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)); - - private final Class managerClass; - private final Color skillColor; - private final SuperAbilityType ability; - private final ToolType tool; - private final List subSkillTypes; - - public static final List SKILL_NAMES; - public static final List SUBSKILL_NAMES; - - public static final List CHILD_SKILLS; - public static final List NON_CHILD_SKILLS; - - public static final List COMBAT_SKILLS = ImmutableList.of(ARCHERY, AXES, SWORDS, TAMING, UNARMED); - public static final List GATHERING_SKILLS = ImmutableList.of(EXCAVATION, FISHING, HERBALISM, MINING, WOODCUTTING); - public static final List MISC_SKILLS = ImmutableList.of(ACROBATICS, ALCHEMY, REPAIR, SALVAGE, SMELTING); - - static { - List childSkills = new ArrayList<>(); - List nonChildSkills = new ArrayList<>(); - ArrayList names = new ArrayList<>(); - ArrayList subSkillNames = new ArrayList<>(); - - for (PrimarySkillType skill : values()) { - if (skill.isChildSkill()) { - childSkills.add(skill); - } - else { - nonChildSkills.add(skill); - } - - for(SubSkillType subSkillType : skill.subSkillTypes) { - subSkillNames.add(subSkillType.getNiceNameNoSpaces(subSkillType)); - } - - names.add(skill.getName()); - } - - Collections.sort(names); - SKILL_NAMES = ImmutableList.copyOf(names); - SUBSKILL_NAMES = ImmutableList.copyOf(subSkillNames); - - CHILD_SKILLS = ImmutableList.copyOf(childSkills); - NON_CHILD_SKILLS = ImmutableList.copyOf(nonChildSkills); - } - - PrimarySkillType(Class managerClass, Color skillColor, List subSkillTypes) { - this(managerClass, skillColor, null, null, subSkillTypes); - } - - PrimarySkillType(Class managerClass, Color skillColor, SuperAbilityType ability, ToolType tool, List subSkillTypes) { - this.managerClass = managerClass; - this.skillColor = skillColor; - this.ability = ability; - this.tool = tool; - this.subSkillTypes = subSkillTypes; - } - - public PrimarySkillType getPrimarySkill() { - return this; - } - - public String getPrimaryKeyName() { - return StringUtils.getCapitalized(this.toString()); - } - - public Class getManagerClass() { - return managerClass; - } - - public SuperAbilityType getAbility() { - return ability; - } - - /** - * Get the max level of this skill. - * - * @return the max level of this skill - */ - public int getMaxLevel() { - return mcMMO.p.getGeneralConfig().getLevelCap(this); - } - - public boolean isSuperAbilityUnlocked(Player player) { return RankUtils.getRank(player, getAbility().getSubSkillTypeDefinition()) >= 1; } - - public boolean getPVPEnabled() { - return mcMMO.p.getGeneralConfig().getPVPEnabled(this); - } - - public boolean getPVEEnabled() { - return mcMMO.p.getGeneralConfig().getPVEEnabled(this); - } - - public boolean getDoubleDropsDisabled() { - return mcMMO.p.getGeneralConfig().getDoubleDropsDisabled(this); - } - - public boolean getHardcoreStatLossEnabled() { - return mcMMO.p.getGeneralConfig().getHardcoreStatLossEnabled(this); - } - - public void setHardcoreStatLossEnabled(boolean enable) { - mcMMO.p.getGeneralConfig().setHardcoreStatLossEnabled(this, enable); - } - - public boolean getHardcoreVampirismEnabled() { - return mcMMO.p.getGeneralConfig().getHardcoreVampirismEnabled(this); - } - - public void setHardcoreVampirismEnabled(boolean enable) { - mcMMO.p.getGeneralConfig().setHardcoreVampirismEnabled(this, enable); - } - - public ToolType getTool() { - return tool; - } - - public List getSkillAbilities() { - return subSkillTypes; - } - - public double getXpModifier() { - return ExperienceConfig.getInstance().getFormulaSkillModifier(this); - } - - public static PrimarySkillType getSkill(String skillName) { - if (!mcMMO.p.getGeneralConfig().getLocale().equalsIgnoreCase("en_US")) { - for (PrimarySkillType type : values()) { - if (skillName.equalsIgnoreCase(LocaleLoader.getString(StringUtils.getCapitalized(type.name()) + ".SkillName"))) { - return type; - } - } - } - - for (PrimarySkillType type : values()) { - if (type.name().equalsIgnoreCase(skillName)) { - return type; - } - } - - if (!skillName.equalsIgnoreCase("all")) { - mcMMO.p.getLogger().warning("Invalid mcMMO skill (" + skillName + ")"); //TODO: Localize - } - - return null; - } - - // TODO: This is a little "hacky", we probably need to add something to distinguish child skills in the enum, or to use another enum for them - public boolean isChildSkill() { - switch (this) { - case SALVAGE: - case SMELTING: - return true; - - default: - return false; - } - } - - public String getName() { - return StringUtils.getCapitalized(LocaleLoader.getString(StringUtils.getCapitalized(this.toString()) + ".SkillName")); - } - - public boolean getPermissions(Player player) { - return Permissions.skillEnabled(player, this); - } - - public boolean shouldProcess(Entity target) { - return (target instanceof Player || (target instanceof Tameable && ((Tameable) target).isTamed())) ? getPVPEnabled() : getPVEEnabled(); - } - - +public enum PrimarySkillType { + ACROBATICS, + ALCHEMY, + ARCHERY, + AXES, + EXCAVATION, + FISHING, + HERBALISM, + MINING, + REPAIR, + SALVAGE, + SMELTING, + SWORDS, + TAMING, + UNARMED, + WOODCUTTING } + +//package com.gmail.nossr50.datatypes.skills; +// +//import com.gmail.nossr50.config.experience.ExperienceConfig; +//import com.gmail.nossr50.datatypes.skills.interfaces.Skill; +//import com.gmail.nossr50.locale.LocaleLoader; +//import com.gmail.nossr50.mcMMO; +//import com.gmail.nossr50.skills.SkillManager; +//import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager; +//import com.gmail.nossr50.skills.alchemy.AlchemyManager; +//import com.gmail.nossr50.skills.archery.ArcheryManager; +//import com.gmail.nossr50.skills.axes.AxesManager; +//import com.gmail.nossr50.skills.excavation.ExcavationManager; +//import com.gmail.nossr50.skills.fishing.FishingManager; +//import com.gmail.nossr50.skills.herbalism.HerbalismManager; +//import com.gmail.nossr50.skills.mining.MiningManager; +//import com.gmail.nossr50.skills.repair.RepairManager; +//import com.gmail.nossr50.skills.salvage.SalvageManager; +//import com.gmail.nossr50.skills.smelting.SmeltingManager; +//import com.gmail.nossr50.skills.swords.SwordsManager; +//import com.gmail.nossr50.skills.taming.TamingManager; +//import com.gmail.nossr50.skills.unarmed.UnarmedManager; +//import com.gmail.nossr50.skills.woodcutting.WoodcuttingManager; +//import com.gmail.nossr50.util.Permissions; +//import com.gmail.nossr50.util.skills.RankUtils; +//import com.gmail.nossr50.util.text.StringUtils; +//import com.google.common.collect.ImmutableList; +//import org.bukkit.Color; +//import org.bukkit.entity.Entity; +//import org.bukkit.entity.Player; +//import org.bukkit.entity.Tameable; +// +//import java.util.ArrayList; +//import java.util.Collections; +//import java.util.List; +// +//public enum PrimarySkillType implements Skill { +// ACROBATICS(AcrobaticsManager.class, Color.WHITE, +// ImmutableList.of(SubSkillType.ACROBATICS_DODGE, SubSkillType.ACROBATICS_ROLL)), +// ALCHEMY(AlchemyManager.class, Color.FUCHSIA, +// ImmutableList.of(SubSkillType.ALCHEMY_CATALYSIS, SubSkillType.ALCHEMY_CONCOCTIONS)), +// ARCHERY(ArcheryManager.class, Color.MAROON, +// ImmutableList.of(SubSkillType.ARCHERY_DAZE, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK, SubSkillType.ARCHERY_ARROW_RETRIEVAL, SubSkillType.ARCHERY_SKILL_SHOT)), +// AXES(AxesManager.class, Color.AQUA, SuperAbilityType.SKULL_SPLITTER, ToolType.AXE, +// ImmutableList.of(SubSkillType.AXES_SKULL_SPLITTER, SubSkillType.AXES_AXES_LIMIT_BREAK, SubSkillType.AXES_ARMOR_IMPACT, SubSkillType.AXES_AXE_MASTERY, SubSkillType.AXES_CRITICAL_STRIKES, SubSkillType.AXES_GREATER_IMPACT)), +// EXCAVATION(ExcavationManager.class, Color.fromRGB(139, 69, 19), SuperAbilityType.GIGA_DRILL_BREAKER, ToolType.SHOVEL, +// ImmutableList.of(SubSkillType.EXCAVATION_GIGA_DRILL_BREAKER, SubSkillType.EXCAVATION_ARCHAEOLOGY)), +// FISHING(FishingManager.class, Color.NAVY, +// ImmutableList.of(SubSkillType.FISHING_FISHERMANS_DIET, SubSkillType.FISHING_TREASURE_HUNTER, SubSkillType.FISHING_ICE_FISHING, SubSkillType.FISHING_MAGIC_HUNTER, SubSkillType.FISHING_MASTER_ANGLER, SubSkillType.FISHING_SHAKE)), +// HERBALISM(HerbalismManager.class, Color.GREEN, SuperAbilityType.GREEN_TERRA, ToolType.HOE, +// ImmutableList.of(SubSkillType.HERBALISM_GREEN_TERRA, SubSkillType.HERBALISM_FARMERS_DIET, SubSkillType.HERBALISM_GREEN_THUMB, SubSkillType.HERBALISM_DOUBLE_DROPS, SubSkillType.HERBALISM_HYLIAN_LUCK, SubSkillType.HERBALISM_SHROOM_THUMB)), +// MINING(MiningManager.class, Color.GRAY, SuperAbilityType.SUPER_BREAKER, ToolType.PICKAXE, +// ImmutableList.of(SubSkillType.MINING_SUPER_BREAKER, SubSkillType.MINING_DEMOLITIONS_EXPERTISE, SubSkillType.MINING_BIGGER_BOMBS, SubSkillType.MINING_BLAST_MINING, SubSkillType.MINING_DOUBLE_DROPS)), +// REPAIR(RepairManager.class, Color.SILVER, +// ImmutableList.of(SubSkillType.REPAIR_ARCANE_FORGING, SubSkillType.REPAIR_REPAIR_MASTERY, SubSkillType.REPAIR_SUPER_REPAIR)), +// SALVAGE(SalvageManager.class, Color.ORANGE, +// ImmutableList.of(SubSkillType.SALVAGE_SCRAP_COLLECTOR, SubSkillType.SALVAGE_ARCANE_SALVAGE)), +// SMELTING(SmeltingManager.class, Color.YELLOW, +// ImmutableList.of(SubSkillType.SMELTING_UNDERSTANDING_THE_ART, /*SubSkillType.SMELTING_FLUX_MINING,*/ SubSkillType.SMELTING_FUEL_EFFICIENCY, SubSkillType.SMELTING_SECOND_SMELT)), +// SWORDS(SwordsManager.class, Color.fromRGB(178, 34, 34), SuperAbilityType.SERRATED_STRIKES, ToolType.SWORD, +// ImmutableList.of(SubSkillType.SWORDS_SERRATED_STRIKES, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK, SubSkillType.SWORDS_STAB, SubSkillType.SWORDS_RUPTURE, SubSkillType.SWORDS_COUNTER_ATTACK)), +// TAMING(TamingManager.class, Color.PURPLE, +// ImmutableList.of(SubSkillType.TAMING_BEAST_LORE, SubSkillType.TAMING_CALL_OF_THE_WILD, SubSkillType.TAMING_ENVIRONMENTALLY_AWARE, SubSkillType.TAMING_FAST_FOOD_SERVICE, SubSkillType.TAMING_GORE, SubSkillType.TAMING_HOLY_HOUND, SubSkillType.TAMING_SHARPENED_CLAWS, SubSkillType.TAMING_SHOCK_PROOF, SubSkillType.TAMING_THICK_FUR, SubSkillType.TAMING_PUMMEL)), +// UNARMED(UnarmedManager.class, Color.BLACK, SuperAbilityType.BERSERK, ToolType.FISTS, +// ImmutableList.of(SubSkillType.UNARMED_BERSERK, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK, SubSkillType.UNARMED_BLOCK_CRACKER, SubSkillType.UNARMED_ARROW_DEFLECT, SubSkillType.UNARMED_DISARM, SubSkillType.UNARMED_STEEL_ARM_STYLE, SubSkillType.UNARMED_IRON_GRIP)), +// WOODCUTTING(WoodcuttingManager.class, Color.OLIVE, SuperAbilityType.TREE_FELLER, ToolType.AXE, +// ImmutableList.of(SubSkillType.WOODCUTTING_LEAF_BLOWER, SubSkillType.WOODCUTTING_TREE_FELLER, SubSkillType.WOODCUTTING_HARVEST_LUMBER, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)); +// +// private final Class managerClass; +// private final Color skillColor; +// private final SuperAbilityType ability; +// private final ToolType tool; +// private final List subSkillTypes; +// +// public static final List SKILL_NAMES; +// public static final List SUBSKILL_NAMES; +// +// public static final List CHILD_SKILLS; +// public static final List NON_CHILD_SKILLS; +// +// public static final List COMBAT_SKILLS = ImmutableList.of(ARCHERY, AXES, SWORDS, TAMING, UNARMED); +// public static final List GATHERING_SKILLS = ImmutableList.of(EXCAVATION, FISHING, HERBALISM, MINING, WOODCUTTING); +// public static final List MISC_SKILLS = ImmutableList.of(ACROBATICS, ALCHEMY, REPAIR, SALVAGE, SMELTING); +// +// static { +// List childSkills = new ArrayList<>(); +// List nonChildSkills = new ArrayList<>(); +// ArrayList names = new ArrayList<>(); +// ArrayList subSkillNames = new ArrayList<>(); +// +// for (PrimarySkillType skill : values()) { +// if (mcMMO.p.getSkillTools().isChildSkill(skill)) { +// childSkills.add(skill); +// } +// else { +// nonChildSkills.add(skill); +// } +// +// for(SubSkillType subSkillType : skill.subSkillTypes) { +// subSkillNames.add(subSkillType.getNiceNameNoSpaces(subSkillType)); +// } +// +// names.add(mcMMO.p.getSkillTools().getLocalizedSkillName(skill)); +// } +// +// Collections.sort(names); +// SKILL_NAMES = ImmutableList.copyOf(names); +// SUBSKILL_NAMES = ImmutableList.copyOf(subSkillNames); +// +// CHILD_SKILLS = ImmutableList.copyOf(childSkills); +// NON_CHILD_SKILLS = ImmutableList.copyOf(nonChildSkills); +// } +// +// PrimarySkillType(Class managerClass, Color skillColor, List subSkillTypes) { +// this(managerClass, skillColor, null, null, subSkillTypes); +// } +// +// PrimarySkillType(Class managerClass, Color skillColor, SuperAbilityType ability, ToolType tool, List subSkillTypes) { +// this.managerClass = managerClass; +// this.skillColor = skillColor; +// this.ability = ability; +// this.tool = tool; +// this.subSkillTypes = subSkillTypes; +// } +// +// public PrimarySkillType getPrimarySkill() { +// return this; +// } +// +// public String getPrimaryKeyName() { +// return StringUtils.getCapitalized(this.toString()); +// } +// +// public Class getManagerClass() { +// return managerClass; +// } +// +// public SuperAbilityType getAbility() { +// return ability; +// } +// +// /** +// * Get the max level of this skill. +// * +// * @return the max level of this skill +// */ +// public int getMaxLevel() { +// return mcMMO.p.getGeneralConfig().getLevelCap(this); +// } +// +// public boolean isSuperAbilityUnlocked(Player player) { return RankUtils.getRank(player, getAbility().getSubSkillTypeDefinition()) >= 1; } +// +// public boolean getPVPEnabled() { +// return mcMMO.p.getGeneralConfig().getPVPEnabled(this); +// } +// +// public boolean getPVEEnabled() { +// return mcMMO.p.getGeneralConfig().getPVEEnabled(this); +// } +// +// public boolean getDoubleDropsDisabled() { +// return mcMMO.p.getGeneralConfig().getDoubleDropsDisabled(this); +// } +// +// public boolean getHardcoreStatLossEnabled() { +// return mcMMO.p.getGeneralConfig().getHardcoreStatLossEnabled(this); +// } +// +// public void setHardcoreStatLossEnabled(boolean enable) { +// mcMMO.p.getGeneralConfig().setHardcoreStatLossEnabled(this, enable); +// } +// +// public boolean getHardcoreVampirismEnabled() { +// return mcMMO.p.getGeneralConfig().getHardcoreVampirismEnabled(this); +// } +// +// public void setHardcoreVampirismEnabled(boolean enable) { +// mcMMO.p.getGeneralConfig().setHardcoreVampirismEnabled(this, enable); +// } +// +// public ToolType getTool() { +// return tool; +// } +// +// public List getSkillAbilities() { +// return subSkillTypes; +// } +// +// public double getXpModifier() { +// return ExperienceConfig.getInstance().getFormulaSkillModifier(this); +// } +// +// public static PrimarySkillType getSkill(String skillName) { +// if (!mcMMO.p.getGeneralConfig().getLocale().equalsIgnoreCase("en_US")) { +// for (PrimarySkillType type : values()) { +// if (skillName.equalsIgnoreCase(LocaleLoader.getString(StringUtils.getCapitalized(type.name()) + ".SkillName"))) { +// return type; +// } +// } +// } +// +// for (PrimarySkillType type : values()) { +// if (type.name().equalsIgnoreCase(skillName)) { +// return type; +// } +// } +// +// if (!skillName.equalsIgnoreCase("all")) { +// mcMMO.p.getLogger().warning("Invalid mcMMO skill (" + skillName + ")"); //TODO: Localize +// } +// +// return null; +// } +// +// // TODO: This is a little "hacky", we probably need to add something to distinguish child skills in the enum, or to use another enum for them +// public boolean isChildSkill() { +// switch (this) { +// case SALVAGE: +// case SMELTING: +// return true; +// +// default: +// return false; +// } +// } +// +// public String getName() { +// return StringUtils.getCapitalized(LocaleLoader.getString(StringUtils.getCapitalized(this.toString()) + ".SkillName")); +// } +// +// public boolean getPermissions(Player player) { +// return Permissions.skillEnabled(player, this); +// } +// +// public boolean shouldProcess(Entity target) { +// return (target instanceof Player || (target instanceof Tameable && ((Tameable) target).isTamed())) ? getPVPEnabled() : getPVEEnabled(); +// } +// +// +//} diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java index 67b256a47..44d98b789 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java @@ -2,6 +2,7 @@ package com.gmail.nossr50.datatypes.skills; import com.gmail.nossr50.datatypes.skills.interfaces.Skill; import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.text.StringUtils; import java.util.Locale; @@ -136,7 +137,7 @@ public enum SubSkillType { * If we add skills, those immutable lists need to be updated * @return */ - public PrimarySkillType getParentSkill() { return Skill.bySecondaryAbility(this); } + public PrimarySkillType getParentSkill() { return mcMMO.p.getSkillTools().getPrimarySkillBySubSkill(this); } /** * Returns the root address for this skill in the advanced.yml file diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Skill.java b/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Skill.java index a0487e0df..e2fdd0457 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Skill.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Skill.java @@ -26,88 +26,4 @@ public interface Skill { * @return config file key name */ String getPrimaryKeyName(); - - Class getManagerClass(); - - SuperAbilityType getAbility(); - - /** - * Get the max level of this skill. - * - * @return the max level of this skill - */ - int getMaxLevel(); - - boolean isSuperAbilityUnlocked(Player player); - - boolean getPVPEnabled(); - - boolean getPVEEnabled(); - - boolean getDoubleDropsDisabled(); - - boolean getHardcoreStatLossEnabled(); - - void setHardcoreStatLossEnabled(boolean enable); - - boolean getHardcoreVampirismEnabled(); - - void setHardcoreVampirismEnabled(boolean enable); - - ToolType getTool(); - - List getSkillAbilities(); - - double getXpModifier(); - - // TODO: This is a little "hacky", we probably need to add something to distinguish child skills in the enum, or to use another enum for them - boolean isChildSkill(); - - static PrimarySkillType bySecondaryAbility(SubSkillType subSkillType) { - for (PrimarySkillType type : PrimarySkillType.values()) { - if (type.getSkillAbilities().contains(subSkillType)) { - return type; - } - } - - return null; - } - - static PrimarySkillType byAbility(SuperAbilityType ability) { - for (PrimarySkillType type : PrimarySkillType.values()) { - if (type.getAbility() == ability) { - return type; - } - } - - return null; - } - - static PrimarySkillType getSkill(@NotNull String skillName) { - if (!mcMMO.p.getGeneralConfig().getLocale().equalsIgnoreCase("en_US")) { - for (PrimarySkillType type : PrimarySkillType.values()) { - if (skillName.equalsIgnoreCase(LocaleLoader.getString(StringUtils.getCapitalized(type.name()) + ".SkillName"))) { - return type; - } - } - } - - for (PrimarySkillType type : PrimarySkillType.values()) { - if (type.name().equalsIgnoreCase(skillName)) { - return type; - } - } - - if (!skillName.equalsIgnoreCase("all")) { - mcMMO.p.getLogger().warning("Invalid mcMMO skill (" + skillName + ")"); //TODO: Localize - } - - return null; - } - - String getName(); - - boolean getPermissions(Player player); - - boolean shouldProcess(Entity target); } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java index d81320761..4ce3a8671 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java @@ -441,97 +441,4 @@ public class Roll extends AcrobaticsSubSkill { return player.getLocation().getBlock().getLocation(); } - public String getPrimaryKeyName() { - return getPrimarySkill().getPrimaryKeyName(); - } - - @Override - public Class getManagerClass() { - return getPrimarySkill().getManagerClass(); - } - - @Override - public SuperAbilityType getAbility() { - return getPrimarySkill().getAbility(); - } - - @Override - public int getMaxLevel() { - return getPrimarySkill().getMaxLevel(); - } - - @Override - public boolean isSuperAbilityUnlocked(Player player) { - return getPrimarySkill().isSuperAbilityUnlocked(player); - } - - @Override - public boolean getPVPEnabled() { - return getPrimarySkill().getPVPEnabled(); - } - - @Override - public boolean getPVEEnabled() { - return getPrimarySkill().getPVEEnabled(); - } - - @Override - public boolean getDoubleDropsDisabled() { - return getPrimarySkill().getDoubleDropsDisabled(); - } - - @Override - public boolean getHardcoreStatLossEnabled() { - return getPrimarySkill().getHardcoreStatLossEnabled(); - } - - @Override - public void setHardcoreStatLossEnabled(boolean enable) { - getPrimarySkill().setHardcoreStatLossEnabled(enable); - } - - @Override - public boolean getHardcoreVampirismEnabled() { - return getPrimarySkill().getHardcoreVampirismEnabled(); - } - - @Override - public void setHardcoreVampirismEnabled(boolean enable) { - getPrimarySkill().setHardcoreVampirismEnabled(enable); - } - - @Override - public ToolType getTool() { - return getPrimarySkill().getTool(); - } - - @Override - public List getSkillAbilities() { - return getPrimarySkill().getSkillAbilities(); - } - - @Override - public double getXpModifier() { - return getPrimarySkill().getXpModifier(); - } - - @Override - public boolean isChildSkill() { - return getPrimarySkill().isChildSkill(); - } - - @Override - public String getName() { - return getPrimarySkill().getName(); - } - - @Override - public boolean getPermissions(Player player) { - return getPrimarySkill().getPermissions(player); - } - - @Override - public boolean shouldProcess(Entity target) { - return getPrimarySkill().shouldProcess(target); - } } diff --git a/src/main/java/com/gmail/nossr50/events/skills/abilities/McMMOPlayerAbilityEvent.java b/src/main/java/com/gmail/nossr50/events/skills/abilities/McMMOPlayerAbilityEvent.java index 706055df3..08d7dc2b2 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/abilities/McMMOPlayerAbilityEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/abilities/McMMOPlayerAbilityEvent.java @@ -3,6 +3,7 @@ package com.gmail.nossr50.events.skills.abilities; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.events.skills.McMMOPlayerSkillEvent; +import com.gmail.nossr50.mcMMO; import org.bukkit.entity.Player; public class McMMOPlayerAbilityEvent extends McMMOPlayerSkillEvent { @@ -10,7 +11,7 @@ public class McMMOPlayerAbilityEvent extends McMMOPlayerSkillEvent { protected McMMOPlayerAbilityEvent(Player player, PrimarySkillType skill) { super(player, skill); - ability = skill.getAbility(); + ability = mcMMO.p.getSkillTools().getSuperAbility(skill); } public SuperAbilityType getAbility() { diff --git a/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java b/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java index 215a7f224..7c0fb4ea9 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java @@ -4,6 +4,7 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.interfaces.Skill; import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.events.skills.McMMOPlayerSkillEvent; +import com.gmail.nossr50.mcMMO; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; @@ -20,7 +21,7 @@ public class SubSkillEvent extends McMMOPlayerSkillEvent implements Cancellable */ @Deprecated public SubSkillEvent(Player player, SubSkillType subSkillType) { - super(player, Skill.bySecondaryAbility(subSkillType)); + super(player, mcMMO.p.getSkillTools().getPrimarySkillBySubSkill(subSkillType)); this.subSkillType = subSkillType; } @@ -33,7 +34,7 @@ public class SubSkillEvent extends McMMOPlayerSkillEvent implements Cancellable */ @Deprecated public SubSkillEvent(Player player, SubSkillType subSkillType, double resultModifier) { - super(player, Skill.bySecondaryAbility(subSkillType)); + super(player, mcMMO.p.getSkillTools().getPrimarySkillBySubSkill(subSkillType)); this.subSkillType = subSkillType; this.resultModifier = resultModifier; } diff --git a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java index 33b68076c..f72a9409f 100644 --- a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java @@ -228,10 +228,10 @@ public class BlockListener implements Listener { if(mcMMOPlayer == null) return; - if (blockState.getType() == Repair.anvilMaterial && PrimarySkillType.REPAIR.getPermissions(player)) { + if (blockState.getType() == Repair.anvilMaterial && Permissions.skillEnabled(player, PrimarySkillType.REPAIR)) { mcMMOPlayer.getRepairManager().placedAnvilCheck(); } - else if (blockState.getType() == Salvage.anvilMaterial && PrimarySkillType.SALVAGE.getPermissions(player)) { + else if (blockState.getType() == Salvage.anvilMaterial && Permissions.skillEnabled(player, PrimarySkillType.SALVAGE)) { mcMMOPlayer.getSalvageManager().placedAnvilCheck(); } } @@ -333,7 +333,7 @@ public class BlockListener implements Listener { * We don't check the block store here because herbalism has too many unusual edge cases. * Instead, we check it inside the drops handler. */ - if (PrimarySkillType.HERBALISM.getPermissions(player)) { + if (Permissions.skillEnabled(player, PrimarySkillType.HERBALISM)) { herbalismManager.processHerbalismBlockBreakEvent(event); } /* @@ -344,13 +344,13 @@ public class BlockListener implements Listener { } /* MINING */ - else if (BlockUtils.affectedBySuperBreaker(blockState) && ItemUtils.isPickaxe(heldItem) && PrimarySkillType.MINING.getPermissions(player) && !mcMMO.getPlaceStore().isTrue(blockState)) { + else if (BlockUtils.affectedBySuperBreaker(blockState) && ItemUtils.isPickaxe(heldItem) && Permissions.skillEnabled(player, PrimarySkillType.MINING) && !mcMMO.getPlaceStore().isTrue(blockState)) { MiningManager miningManager = mcMMOPlayer.getMiningManager(); miningManager.miningBlockCheck(blockState); } /* WOOD CUTTING */ - else if (BlockUtils.hasWoodcuttingXP(blockState) && ItemUtils.isAxe(heldItem) && PrimarySkillType.WOODCUTTING.getPermissions(player) && !mcMMO.getPlaceStore().isTrue(blockState)) { + else if (BlockUtils.hasWoodcuttingXP(blockState) && ItemUtils.isAxe(heldItem) && Permissions.skillEnabled(player, PrimarySkillType.WOODCUTTING) && !mcMMO.getPlaceStore().isTrue(blockState)) { WoodcuttingManager woodcuttingManager = mcMMOPlayer.getWoodcuttingManager(); if (woodcuttingManager.canUseTreeFeller(heldItem)) { woodcuttingManager.processTreeFeller(blockState); @@ -365,7 +365,7 @@ public class BlockListener implements Listener { } /* EXCAVATION */ - else if (BlockUtils.affectedByGigaDrillBreaker(blockState) && ItemUtils.isShovel(heldItem) && PrimarySkillType.EXCAVATION.getPermissions(player) && !mcMMO.getPlaceStore().isTrue(blockState)) { + else if (BlockUtils.affectedByGigaDrillBreaker(blockState) && ItemUtils.isShovel(heldItem) && Permissions.skillEnabled(player, PrimarySkillType.EXCAVATION) && !mcMMO.getPlaceStore().isTrue(blockState)) { ExcavationManager excavationManager = mcMMOPlayer.getExcavationManager(); excavationManager.excavationBlockCheck(blockState); diff --git a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java index 53e40ca14..16a50182b 100644 --- a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java @@ -273,7 +273,7 @@ public class PlayerListener implements Listener { return; } - if (!UserManager.hasPlayerDataKey(player) || !PrimarySkillType.FISHING.getPermissions(player)) { + if (!UserManager.hasPlayerDataKey(player) || !Permissions.skillEnabled(player, PrimarySkillType.FISHING)) { return; } @@ -359,7 +359,7 @@ public class PlayerListener implements Listener { return; } - if (!UserManager.hasPlayerDataKey(player) || !PrimarySkillType.FISHING.getPermissions(player)) { + if (!UserManager.hasPlayerDataKey(player) || !Permissions.skillEnabled(player, PrimarySkillType.FISHING)) { return; } @@ -654,7 +654,7 @@ public class PlayerListener implements Listener { if (!mcMMO.p.getGeneralConfig().getAbilitiesOnlyActivateWhenSneaking() || player.isSneaking()) { /* REPAIR CHECKS */ if (type == Repair.anvilMaterial - && PrimarySkillType.REPAIR.getPermissions(player) + && Permissions.skillEnabled(player, PrimarySkillType.REPAIR) && mcMMO.getRepairableManager().isRepairable(heldItem) && heldItem.getAmount() <= 1) { RepairManager repairManager = mcMMOPlayer.getRepairManager(); @@ -668,7 +668,7 @@ public class PlayerListener implements Listener { } /* SALVAGE CHECKS */ else if (type == Salvage.anvilMaterial - && PrimarySkillType.SALVAGE.getPermissions(player) + && Permissions.skillEnabled(player, PrimarySkillType.SALVAGE) && RankUtils.hasUnlockedSubskill(player, SubSkillType.SALVAGE_SCRAP_COLLECTOR) && mcMMO.getSalvageableManager().isSalvageable(heldItem) && heldItem.getAmount() <= 1) { @@ -701,7 +701,7 @@ public class PlayerListener implements Listener { if (!mcMMO.p.getGeneralConfig().getAbilitiesOnlyActivateWhenSneaking() || player.isSneaking()) { /* REPAIR CHECKS */ - if (type == Repair.anvilMaterial && PrimarySkillType.REPAIR.getPermissions(player) && mcMMO.getRepairableManager().isRepairable(heldItem)) { + if (type == Repair.anvilMaterial && Permissions.skillEnabled(player, PrimarySkillType.REPAIR) && mcMMO.getRepairableManager().isRepairable(heldItem)) { RepairManager repairManager = mcMMOPlayer.getRepairManager(); // Cancel repairing an enchanted item @@ -711,7 +711,7 @@ public class PlayerListener implements Listener { } } /* SALVAGE CHECKS */ - else if (type == Salvage.anvilMaterial && PrimarySkillType.SALVAGE.getPermissions(player) && mcMMO.getSalvageableManager().isSalvageable(heldItem)) { + else if (type == Salvage.anvilMaterial && Permissions.skillEnabled(player, PrimarySkillType.SALVAGE) && mcMMO.getSalvageableManager().isSalvageable(heldItem)) { SalvageManager salvageManager = mcMMOPlayer.getSalvageManager(); // Cancel salvaging an enchanted item @@ -958,7 +958,7 @@ public class PlayerListener implements Listener { // Do these ACTUALLY have to be lower case to work properly? for (PrimarySkillType skill : PrimarySkillType.values()) { String skillName = skill.toString().toLowerCase(Locale.ENGLISH); - String localizedName = skill.getName().toLowerCase(Locale.ENGLISH); + String localizedName = mcMMO.p.getSkillTools().getLocalizedSkillName(skill).toLowerCase(Locale.ENGLISH); if (lowerCaseCommand.equals(localizedName)) { event.setMessage(message.replace(command, skillName)); diff --git a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java index 5bd3f5ec0..10da03550 100644 --- a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java @@ -132,7 +132,7 @@ public class SelfListener implements Listener { return; } - if (primarySkillType.isChildSkill()) { + if (mcMMO.p.getSkillTools().isChildSkill(primarySkillType)) { return; } @@ -140,7 +140,7 @@ public class SelfListener implements Listener { float guaranteedMinimum = ExperienceConfig.getInstance().getDiminishedReturnsCap() * rawXp; - float modifiedThreshold = (float) (threshold / primarySkillType.getXpModifier() * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()); + float modifiedThreshold = (float) (threshold / ExperienceConfig.getInstance().getFormulaSkillModifier(primarySkillType) * ExperienceConfig.getInstance().getExperienceGainsGlobalMultiplier()); float difference = (mcMMOPlayer.getProfile().getRegisteredXpGain(primarySkillType) - modifiedThreshold) / modifiedThreshold; if (difference > 0) { diff --git a/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java b/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java index a3b285689..2cfcc4052 100644 --- a/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java +++ b/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java @@ -129,6 +129,7 @@ public final class LocaleLoader { if (bundle == null) { Locale.setDefault(new Locale("en", "US")); Locale locale = null; + String[] myLocale = mcMMO.p.getGeneralConfig().getLocale().split("[-_ ]"); if (myLocale.length == 1) { diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index ef3ead515..2b19e5761 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -49,6 +49,7 @@ import com.gmail.nossr50.util.player.PlayerLevelUtils; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.gmail.nossr50.util.skills.RankUtils; +import com.gmail.nossr50.util.skills.SkillTools; import com.gmail.nossr50.util.skills.SmeltingTracker; import com.gmail.nossr50.util.upgrade.UpgradeManager; import com.gmail.nossr50.worldguard.WorldGuardManager; @@ -90,6 +91,9 @@ public class mcMMO extends JavaPlugin { private static ChatManager chatManager; private static CommandManager commandManager; //ACF private static TransientEntityTracker transientEntityTracker; + + private @NotNull SkillTools skillTools; + private static boolean serverShutdownExecuted = false; /* Adventure */ @@ -172,8 +176,10 @@ public class mcMMO extends JavaPlugin { @Override public void onEnable() { try { + generalConfig = new GeneralConfig(getDataFolder()); //Load before skillTools + skillTools = new SkillTools(this); //Load after general config + //Init configs - generalConfig = new GeneralConfig(getDataFolder()); advancedConfig = new AdvancedConfig(getDataFolder()); //Store this value so other plugins can check it @@ -767,6 +773,10 @@ public class mcMMO extends JavaPlugin { return purgeTime; } + public @NotNull SkillTools getSkillTools() { + return skillTools; + } + public @NotNull GeneralConfig getGeneralConfig() { return generalConfig; } diff --git a/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java b/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java index 1640d9301..28d09f8aa 100644 --- a/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java @@ -46,13 +46,13 @@ public class McrankCommandDisplayTask extends BukkitRunnable { sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Heading")); sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Player", playerName)); - for (PrimarySkillType skill : PrimarySkillType.NON_CHILD_SKILLS) { -// if (!skill.getPermissions(player)) { + for (PrimarySkillType skill : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { +// if (!Permissions.skillEnabled(player, skill)) { // continue; // } rank = skills.get(skill); - sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Skill", skill.getName(), (rank == null ? LocaleLoader.getString("Commands.mcrank.Unranked") : rank))); + sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Skill", mcMMO.p.getSkillTools().getLocalizedSkillName(skill), (rank == null ? LocaleLoader.getString("Commands.mcrank.Unranked") : rank))); } rank = skills.get(null); diff --git a/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java b/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java index 82ab947dd..babae32fd 100644 --- a/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java @@ -60,10 +60,10 @@ public class MctopCommandDisplayTask extends BukkitRunnable { } else { if(sender instanceof Player) { - sender.sendMessage(LocaleLoader.getString("Commands.Skill.Leaderboard", skill.getName())); + sender.sendMessage(LocaleLoader.getString("Commands.Skill.Leaderboard", mcMMO.p.getSkillTools().getLocalizedSkillName(skill))); } else { - sender.sendMessage(ChatColor.stripColor(LocaleLoader.getString("Commands.Skill.Leaderboard", skill.getName()))); + sender.sendMessage(ChatColor.stripColor(LocaleLoader.getString("Commands.Skill.Leaderboard", mcMMO.p.getSkillTools().getLocalizedSkillName(skill)))); } } diff --git a/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java b/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java index 5447feb64..056b17dea 100644 --- a/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java @@ -58,7 +58,7 @@ public class FormulaConversionTask extends BukkitRunnable { private void editValues(PlayerProfile profile) { mcMMO.p.debug("========================================================================"); mcMMO.p.debug("Conversion report for " + profile.getPlayerName() + ":"); - for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { int oldLevel = profile.getSkillLevel(primarySkillType); int oldXPLevel = profile.getSkillXpLevel(primarySkillType); int totalOldXP = mcMMO.getFormulaManager().calculateTotalExperience(oldLevel, oldXPLevel); diff --git a/src/main/java/com/gmail/nossr50/runnables/skills/AbilityDisableTask.java b/src/main/java/com/gmail/nossr50/runnables/skills/AbilityDisableTask.java index cce276fc2..e8cd9f70b 100644 --- a/src/main/java/com/gmail/nossr50/runnables/skills/AbilityDisableTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/skills/AbilityDisableTask.java @@ -63,7 +63,9 @@ public class AbilityDisableTask extends BukkitRunnable { if (mcMMO.p.getAdvancedConfig().sendAbilityNotificationToOtherPlayers()) { SkillUtils.sendSkillMessage(player, NotificationType.SUPER_ABILITY_ALERT_OTHERS, ability.getAbilityPlayerOff()); } - new AbilityCooldownTask(mcMMOPlayer, ability).runTaskLater(mcMMO.p, PerksUtils.handleCooldownPerks(player, ability.getCooldown()) * Misc.TICK_CONVERSION_FACTOR); + if(!mcMMO.isServerShutdownExecuted()) { + new AbilityCooldownTask(mcMMOPlayer, ability).runTaskLater(mcMMO.p, PerksUtils.handleCooldownPerks(player, ability.getCooldown()) * Misc.TICK_CONVERSION_FACTOR); + } } private void resendChunkRadiusAt(Player player) { diff --git a/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java b/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java index a4903e123..9641e6804 100644 --- a/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java @@ -72,7 +72,7 @@ public class AcrobaticsManager extends SkillManager { return false; } - return skill.shouldProcess(damager); + return mcMMO.p.getSkillTools().canCombatSkillsTrigger(skill, damager); } return false; diff --git a/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java b/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java index 7aaa1844d..8cb825f48 100644 --- a/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java +++ b/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java @@ -48,7 +48,6 @@ public final class Alchemy { public static final int INGREDIENT_SLOT = 3; - public static int catalysisUnlockLevel = RankUtils.getUnlockLevel(SubSkillType.ALCHEMY_CATALYSIS); public static int catalysisMaxBonusLevel = mcMMO.p.getAdvancedConfig().getCatalysisMaxBonusLevel(); public static double catalysisMinSpeed = mcMMO.p.getAdvancedConfig().getCatalysisMinSpeed(); public static double catalysisMaxSpeed = mcMMO.p.getAdvancedConfig().getCatalysisMaxSpeed(); diff --git a/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyManager.java b/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyManager.java index 92050ae77..16b1dd2ac 100644 --- a/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyManager.java +++ b/src/main/java/com/gmail/nossr50/skills/alchemy/AlchemyManager.java @@ -45,11 +45,11 @@ public class AlchemyManager extends SkillManager { public double calculateBrewSpeed(boolean isLucky) { int skillLevel = getSkillLevel(); - if (skillLevel < Alchemy.catalysisUnlockLevel) { + if (skillLevel < RankUtils.getUnlockLevel(SubSkillType.ALCHEMY_CATALYSIS)) { return Alchemy.catalysisMinSpeed; } - return Math.min(Alchemy.catalysisMaxSpeed, Alchemy.catalysisMinSpeed + (Alchemy.catalysisMaxSpeed - Alchemy.catalysisMinSpeed) * (skillLevel - Alchemy.catalysisUnlockLevel) / (Alchemy.catalysisMaxBonusLevel - Alchemy.catalysisUnlockLevel)) * (isLucky ? LUCKY_MODIFIER : 1.0); + return Math.min(Alchemy.catalysisMaxSpeed, Alchemy.catalysisMinSpeed + (Alchemy.catalysisMaxSpeed - Alchemy.catalysisMinSpeed) * (skillLevel - RankUtils.getUnlockLevel(SubSkillType.ALCHEMY_CATALYSIS)) / (Alchemy.catalysisMaxBonusLevel - RankUtils.getUnlockLevel(SubSkillType.ALCHEMY_CATALYSIS))) * (isLucky ? LUCKY_MODIFIER : 1.0); } public void handlePotionBrewSuccesses(PotionStage potionStage, int amount) { diff --git a/src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java b/src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java index 66e3b48e6..3ac703ec8 100644 --- a/src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java +++ b/src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java @@ -2,6 +2,7 @@ package com.gmail.nossr50.skills.child; import com.gmail.nossr50.config.AutoUpdateConfigLoader; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.text.StringUtils; import org.bukkit.configuration.file.YamlConfiguration; @@ -20,7 +21,7 @@ public class ChildConfig extends AutoUpdateConfigLoader { FamilyTree.clearRegistrations(); // when reloading, need to clear statics - for (PrimarySkillType skill : PrimarySkillType.CHILD_SKILLS) { + for (PrimarySkillType skill : mcMMO.p.getSkillTools().CHILD_SKILLS) { plugin.debug("Finding parents of " + skill.name()); EnumSet parentSkills = EnumSet.noneOf(PrimarySkillType.class); diff --git a/src/main/java/com/gmail/nossr50/skills/child/FamilyTree.java b/src/main/java/com/gmail/nossr50/skills/child/FamilyTree.java index af0fbf95e..7a5639dc2 100644 --- a/src/main/java/com/gmail/nossr50/skills/child/FamilyTree.java +++ b/src/main/java/com/gmail/nossr50/skills/child/FamilyTree.java @@ -1,6 +1,7 @@ package com.gmail.nossr50.skills.child; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.mcMMO; import java.util.Collections; import java.util.EnumSet; @@ -40,13 +41,13 @@ public class FamilyTree { } protected static void enforceChildSkill(PrimarySkillType skill) { - if (!skill.isChildSkill()) { + if (!mcMMO.p.getSkillTools().isChildSkill(skill)) { throw new IllegalArgumentException(skill.name() + " is not a child skill!"); } } protected static void enforceNotChildSkill(PrimarySkillType skill) { - if (skill.isChildSkill()) { + if (mcMMO.p.getSkillTools().isChildSkill(skill)) { throw new IllegalArgumentException(skill.name() + " is a child skill!"); } } diff --git a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java index b1ffd853a..9cad29d7b 100644 --- a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java +++ b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java @@ -80,7 +80,7 @@ public class MiningManager extends SkillManager { return; } - if (mmoPlayer.getAbilityMode(skill.getAbility())) { + if (mmoPlayer.getAbilityMode(mcMMO.p.getSkillTools().getSuperAbility(skill))) { SkillUtils.handleDurabilityChange(getPlayer().getInventory().getItemInMainHand(), mcMMO.p.getGeneralConfig().getAbilityToolDamage()); } @@ -94,7 +94,7 @@ public class MiningManager extends SkillManager { //TODO: Make this readable if (RandomChanceUtil.checkRandomChanceExecutionSuccess(getPlayer(), SubSkillType.MINING_DOUBLE_DROPS, true)) { - boolean useTriple = mmoPlayer.getAbilityMode(skill.getAbility()) && mcMMO.p.getAdvancedConfig().getAllowMiningTripleDrops(); + boolean useTriple = mmoPlayer.getAbilityMode(mcMMO.p.getSkillTools().getSuperAbility(skill)) && mcMMO.p.getAdvancedConfig().getAllowMiningTripleDrops(); BlockUtils.markDropsAsBonus(blockState, useTriple); } } diff --git a/src/main/java/com/gmail/nossr50/util/EventUtils.java b/src/main/java/com/gmail/nossr50/util/EventUtils.java index c2d181063..d97c1c0ad 100644 --- a/src/main/java/com/gmail/nossr50/util/EventUtils.java +++ b/src/main/java/com/gmail/nossr50/util/EventUtils.java @@ -406,7 +406,7 @@ public final class EventUtils { experienceChanged = event.getExperienceChanged(); PlayerProfile playerProfile = UserManager.getPlayer(player).getProfile(); - for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { String skillName = primarySkillType.toString(); int playerSkillLevel = playerProfile.getSkillLevel(primarySkillType); int threshold = mcMMO.p.getGeneralConfig().getHardcoreDeathStatPenaltyLevelThreshold(); @@ -455,7 +455,7 @@ public final class EventUtils { PlayerProfile victimProfile = UserManager.getPlayer(victim).getProfile(); - for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { String skillName = primarySkillType.toString(); int victimSkillLevel = victimProfile.getSkillLevel(primarySkillType); @@ -479,7 +479,7 @@ public final class EventUtils { } public static McMMOPlayerAbilityDeactivateEvent callAbilityDeactivateEvent(Player player, SuperAbilityType ability) { - McMMOPlayerAbilityDeactivateEvent event = new McMMOPlayerAbilityDeactivateEvent(player, Skill.byAbility(ability)); + McMMOPlayerAbilityDeactivateEvent event = new McMMOPlayerAbilityDeactivateEvent(player, mcMMO.p.getSkillTools().getPrimarySkillBySuperAbility(ability)); mcMMO.p.getServer().getPluginManager().callEvent(event); return event; diff --git a/src/main/java/com/gmail/nossr50/util/HardcoreManager.java b/src/main/java/com/gmail/nossr50/util/HardcoreManager.java index 4e6152b1c..3c2abfc38 100644 --- a/src/main/java/com/gmail/nossr50/util/HardcoreManager.java +++ b/src/main/java/com/gmail/nossr50/util/HardcoreManager.java @@ -34,8 +34,8 @@ public final class HardcoreManager { HashMap levelChanged = new HashMap<>(); HashMap experienceChanged = new HashMap<>(); - for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { - if (!primarySkillType.getHardcoreStatLossEnabled()) { + for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + if (!mcMMO.p.getGeneralConfig().getHardcoreStatLossEnabled(primarySkillType)) { levelChanged.put(primarySkillType.toString(), 0); experienceChanged.put(primarySkillType.toString(), 0F); continue; @@ -86,8 +86,8 @@ public final class HardcoreManager { HashMap levelChanged = new HashMap<>(); HashMap experienceChanged = new HashMap<>(); - for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { - if (!primarySkillType.getHardcoreVampirismEnabled()) { + for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + if (!mcMMO.p.getGeneralConfig().getHardcoreVampirismEnabled(primarySkillType)) { levelChanged.put(primarySkillType.toString(), 0); experienceChanged.put(primarySkillType.toString(), 0F); continue; @@ -135,8 +135,8 @@ public final class HardcoreManager { public static boolean isStatLossEnabled() { boolean enabled = false; - for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { - if (primarySkillType.getHardcoreStatLossEnabled()) { + for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + if (mcMMO.p.getGeneralConfig().getHardcoreStatLossEnabled(primarySkillType)) { enabled = true; break; } @@ -153,8 +153,8 @@ public final class HardcoreManager { public static boolean isVampirismEnabled() { boolean enabled = false; - for (PrimarySkillType primarySkillType : PrimarySkillType.NON_CHILD_SKILLS) { - if (primarySkillType.getHardcoreVampirismEnabled()) { + for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + if (mcMMO.p.getGeneralConfig().getHardcoreVampirismEnabled(primarySkillType)) { enabled = true; break; } diff --git a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java b/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java index ed98345a1..83d305486 100644 --- a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java +++ b/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java @@ -34,7 +34,7 @@ public final class CommandRegistrationManager { private static void registerSkillCommands() { for (PrimarySkillType skill : PrimarySkillType.values()) { String commandName = skill.toString().toLowerCase(Locale.ENGLISH); - String localizedName = skill.getName().toLowerCase(Locale.ENGLISH); + String localizedName = mcMMO.p.getSkillTools().getLocalizedSkillName(skill).toLowerCase(Locale.ENGLISH); PluginCommand command; diff --git a/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java b/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java index e7cee3107..0ccee19be 100644 --- a/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java +++ b/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java @@ -6,6 +6,7 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.StringUtils; @@ -25,7 +26,7 @@ public final class CommandUtils { private CommandUtils() {} public static boolean isChildSkill(CommandSender sender, PrimarySkillType skill) { - if (skill == null || !skill.isChildSkill()) { + if (skill == null || !mcMMO.p.getSkillTools().isChildSkill(skill)) { return false; } @@ -169,7 +170,7 @@ public final class CommandUtils { * @param display The sender to display stats to */ public static void printGatheringSkills(Player inspect, CommandSender display) { - printGroupedSkillData(inspect, display, LocaleLoader.getString("Stats.Header.Gathering"), PrimarySkillType.GATHERING_SKILLS); + printGroupedSkillData(inspect, display, LocaleLoader.getString("Stats.Header.Gathering"), mcMMO.p.getSkillTools().GATHERING_SKILLS); } public static void printGatheringSkills(Player player) { @@ -183,7 +184,7 @@ public final class CommandUtils { * @param display The sender to display stats to */ public static void printCombatSkills(Player inspect, CommandSender display) { - printGroupedSkillData(inspect, display, LocaleLoader.getString("Stats.Header.Combat"), PrimarySkillType.COMBAT_SKILLS); + printGroupedSkillData(inspect, display, LocaleLoader.getString("Stats.Header.Combat"), mcMMO.p.getSkillTools().COMBAT_SKILLS); } public static void printCombatSkills(Player player) { @@ -197,7 +198,7 @@ public final class CommandUtils { * @param display The sender to display stats to */ public static void printMiscSkills(Player inspect, CommandSender display) { - printGroupedSkillData(inspect, display, LocaleLoader.getString("Stats.Header.Misc"), PrimarySkillType.MISC_SKILLS); + printGroupedSkillData(inspect, display, LocaleLoader.getString("Stats.Header.Misc"), mcMMO.p.getSkillTools().getMiscSkills()); } public static void printMiscSkills(Player player) { @@ -205,7 +206,7 @@ public final class CommandUtils { } public static String displaySkill(PlayerProfile profile, PrimarySkillType skill) { - if (skill.isChildSkill()) { + if (mcMMO.p.getSkillTools().isChildSkill(skill)) { return LocaleLoader.getString("Skills.ChildStats", LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".Listener") + " ", profile.getSkillLevel(skill)); } if (profile.getSkillLevel(skill) == mcMMO.p.getGeneralConfig().getLevelCap(skill)){ @@ -214,18 +215,18 @@ public final class CommandUtils { return LocaleLoader.getString("Skills.Stats", LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".Listener") + " ", profile.getSkillLevel(skill), profile.getSkillXpLevel(skill), profile.getXpToLevel(skill)); } - private static void printGroupedSkillData(Player inspect, CommandSender display, String header, List skillGroup) { - if(UserManager.getPlayer(inspect) == null) + private static void printGroupedSkillData(Player inspectTarget, CommandSender display, String header, List skillGroup) { + if(UserManager.getPlayer(inspectTarget) == null) return; - PlayerProfile profile = UserManager.getPlayer(inspect).getProfile(); + PlayerProfile profile = UserManager.getPlayer(inspectTarget).getProfile(); List displayData = new ArrayList<>(); displayData.add(header); - for (PrimarySkillType skill : skillGroup) { - if (skill.getPermissions(inspect)) { - displayData.add(displaySkill(profile, skill)); + for (PrimarySkillType primarySkillType : skillGroup) { + if (Permissions.skillEnabled(inspectTarget, primarySkillType)) { + displayData.add(displaySkill(profile, primarySkillType)); } } diff --git a/src/main/java/com/gmail/nossr50/util/experience/ExperienceBarManager.java b/src/main/java/com/gmail/nossr50/util/experience/ExperienceBarManager.java index 7a49a1260..ccc09be80 100644 --- a/src/main/java/com/gmail/nossr50/util/experience/ExperienceBarManager.java +++ b/src/main/java/com/gmail/nossr50/util/experience/ExperienceBarManager.java @@ -146,10 +146,10 @@ public class ExperienceBarManager { disabledBars.add(PrimarySkillType.SMELTING); } - private void informPlayer(@NotNull ExperienceBarManager.@NotNull XPBarSettingTarget settingTarget, @Nullable PrimarySkillType skillType) { + private void informPlayer(@NotNull ExperienceBarManager.@NotNull XPBarSettingTarget settingTarget, @Nullable PrimarySkillType primarySkillType) { //Inform player of setting change if(settingTarget != XPBarSettingTarget.RESET) { - NotificationManager.sendPlayerInformationChatOnlyPrefixed(mcMMOPlayer.getPlayer(), "Commands.XPBar.SettingChanged", skillType.getName(), settingTarget.toString()); + NotificationManager.sendPlayerInformationChatOnlyPrefixed(mcMMOPlayer.getPlayer(), "Commands.XPBar.SettingChanged", mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType), settingTarget.toString()); } else { NotificationManager.sendPlayerInformationChatOnlyPrefixed(mcMMOPlayer.getPlayer(), "Commands.XPBar.Reset"); } diff --git a/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java b/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java index fc7de2b28..fb46db146 100644 --- a/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java +++ b/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java @@ -289,10 +289,10 @@ public class NotificationManager { .append(Component.newline()) .append(Component.text(LocalDate.now().toString())) .append(Component.newline()) - .append(Component.text(primarySkillType.getName()+" reached level "+level)).color(TextColor.fromHexString(HEX_BEIGE_COLOR)) + .append(Component.text(mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType)+" reached level "+level)).color(TextColor.fromHexString(HEX_BEIGE_COLOR)) .asHoverEvent(); - String localeMessage = LocaleLoader.getString("Broadcasts.LevelUpMilestone", mmoPlayer.getPlayer().getDisplayName(), level, primarySkillType.getName()); + String localeMessage = LocaleLoader.getString("Broadcasts.LevelUpMilestone", mmoPlayer.getPlayer().getDisplayName(), level, mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType)); Component message = Component.text(localeMessage).hoverEvent(levelMilestoneHover); Bukkit.getScheduler().runTaskLater(mcMMO.p, () -> audience.sendMessage(Identity.nil(), message), 0); 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 5ec4381b6..9e081bcd6 100644 --- a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java +++ b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java @@ -91,14 +91,14 @@ public class ScoreboardManager { Collections.shuffle(colors, Misc.getRandom()); int i = 0; - for (PrimarySkillType type : PrimarySkillType.values()) { + for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { // Include child skills - skillLabelBuilder.put(type, getShortenedName(colors.get(i) + type.getName(), false)); + skillLabelBuilder.put(primarySkillType, getShortenedName(colors.get(i) + mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType), false)); - if (type.getAbility() != null) { - abilityLabelBuilder.put(type.getAbility(), getShortenedName(colors.get(i) + type.getAbility().getLocalizedName())); + if (mcMMO.p.getSkillTools().getSuperAbility(primarySkillType) != null) { + abilityLabelBuilder.put(mcMMO.p.getSkillTools().getSuperAbility(primarySkillType), getShortenedName(colors.get(i) + mcMMO.p.getSkillTools().getSuperAbility(primarySkillType).getLocalizedName())); - if (type == PrimarySkillType.MINING) { + if (primarySkillType == PrimarySkillType.MINING) { abilityLabelBuilder.put(SuperAbilityType.BLAST_MINING, getShortenedName(colors.get(i) + SuperAbilityType.BLAST_MINING.getLocalizedName())); } } @@ -113,14 +113,14 @@ public class ScoreboardManager { * Stylizes the targetBoard using our normal color scheme */ else { - for (PrimarySkillType type : PrimarySkillType.values()) { + for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { // Include child skills - skillLabelBuilder.put(type, getShortenedName(ChatColor.GREEN + type.getName())); + skillLabelBuilder.put(primarySkillType, getShortenedName(ChatColor.GREEN + mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType))); - if (type.getAbility() != null) { - abilityLabelBuilder.put(type.getAbility(), formatAbility(type.getAbility().getLocalizedName())); + if (mcMMO.p.getSkillTools().getSuperAbility(primarySkillType) != null) { + abilityLabelBuilder.put(mcMMO.p.getSkillTools().getSuperAbility(primarySkillType), formatAbility(mcMMO.p.getSkillTools().getSuperAbility(primarySkillType).getLocalizedName())); - if (type == PrimarySkillType.MINING) { + if (primarySkillType == PrimarySkillType.MINING) { abilityLabelBuilder.put(SuperAbilityType.BLAST_MINING, formatAbility(SuperAbilityType.BLAST_MINING.getLocalizedName())); } } 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 20f3d4d97..cee2d135a 100644 --- a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java +++ b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java @@ -13,6 +13,7 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.child.FamilyTree; import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager.SidebarType; @@ -488,7 +489,7 @@ public class ScoreboardWrapper { case SKILL_BOARD: Validate.notNull(targetSkill); - if (!targetSkill.isChildSkill()) { + if (!mcMMO.p.getSkillTools().isChildSkill(targetSkill)) { int currentXP = mcMMOPlayer.getSkillXpLevel(targetSkill); sidebarObjective.getScore(ScoreboardManager.LABEL_CURRENT_XP).setScore(currentXP); @@ -502,7 +503,7 @@ public class ScoreboardWrapper { sidebarObjective.getScore(ScoreboardManager.LABEL_LEVEL).setScore(mcMMOPlayer.getSkillLevel(targetSkill)); - if (targetSkill.getAbility() != null) { + if (mcMMO.p.getSkillTools().getSuperAbility(targetSkill) != null) { boolean stopUpdating; if (targetSkill == PrimarySkillType.MINING) { @@ -518,7 +519,7 @@ public class ScoreboardWrapper { stopUpdating = (secondsSB == 0 && secondsBM == 0); } else { - SuperAbilityType ability = targetSkill.getAbility(); + SuperAbilityType ability = mcMMO.p.getSkillTools().getSuperAbility(targetSkill); Score cooldown = sidebarObjective.getScore(ScoreboardManager.abilityLabelsSkill.get(ability)); int seconds = Math.max(mcMMOPlayer.calculateTimeRemaining(ability), 0); @@ -573,13 +574,13 @@ public class ScoreboardWrapper { // Calculate power level here int powerLevel = 0; - for (PrimarySkillType skill : PrimarySkillType.NON_CHILD_SKILLS) { // Don't include child skills, makes the list too long + for (PrimarySkillType skill : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { // Don't include child skills, makes the list too long int level = newProfile.getSkillLevel(skill); powerLevel += level; // TODO: Verify that this is what we want - calculated in power level but not displayed - if (!skill.getPermissions(player)) { + if (!Permissions.skillEnabled(player, skill)) { continue; } @@ -606,8 +607,8 @@ public class ScoreboardWrapper { Integer rank; Player player = mcMMO.p.getServer().getPlayerExact(playerName); - for (PrimarySkillType skill : PrimarySkillType.NON_CHILD_SKILLS) { - if (!skill.getPermissions(player)) { + for (PrimarySkillType skill : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + if (!Permissions.skillEnabled(player, skill)) { continue; } diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index e3dcf0e6f..2c9820a2c 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -342,7 +342,7 @@ public final class CombatUtils { } if (ItemUtils.isSword(player.getInventory().getItemInMainHand())) { - if (!PrimarySkillType.SWORDS.shouldProcess(target)) { + if (!mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.SWORDS, target)) { return; } @@ -380,30 +380,30 @@ public final class CombatUtils { } if (ItemUtils.isSword(heldItem)) { - if (!PrimarySkillType.SWORDS.shouldProcess(target)) { + if (!mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.SWORDS, target)) { return; } - if (PrimarySkillType.SWORDS.getPermissions(player)) { + if (Permissions.skillEnabled(player, PrimarySkillType.SWORDS)) { processSwordCombat(target, player, event); } } else if (ItemUtils.isAxe(heldItem)) { - if (!PrimarySkillType.AXES.shouldProcess(target)) { + if (!mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.AXES, target)) { return; } - if (PrimarySkillType.AXES.getPermissions(player)) { + if (Permissions.skillEnabled(player, PrimarySkillType.AXES)) { processAxeCombat(target, player, event); } } else if (ItemUtils.isUnarmed(heldItem)) { - if (!PrimarySkillType.UNARMED.shouldProcess(target)) { + if (!mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.UNARMED, target)) { return; } - if (PrimarySkillType.UNARMED.getPermissions(player)) { + if (Permissions.skillEnabled(player, PrimarySkillType.UNARMED)) { processUnarmedCombat(target, player, event); } } @@ -413,10 +413,10 @@ public final class CombatUtils { Wolf wolf = (Wolf) painSource; AnimalTamer tamer = wolf.getOwner(); - if (tamer instanceof Player && PrimarySkillType.TAMING.shouldProcess(target)) { + if (tamer instanceof Player && mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.TAMING, target)) { Player master = (Player) tamer; - if (!Misc.isNPCEntityExcludingVillagers(master) && PrimarySkillType.TAMING.getPermissions(master)) { + if (!Misc.isNPCEntityExcludingVillagers(master) && Permissions.skillEnabled(master, PrimarySkillType.TAMING)) { processTamingCombat(target, master, wolf, event); } } @@ -425,17 +425,17 @@ public final class CombatUtils { Projectile arrow = (Projectile) painSource; ProjectileSource projectileSource = arrow.getShooter(); - if (projectileSource instanceof Player && PrimarySkillType.ARCHERY.shouldProcess(target)) { + if (projectileSource instanceof Player && mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.ARCHERY, target)) { Player player = (Player) projectileSource; - if (!Misc.isNPCEntityExcludingVillagers(player) && PrimarySkillType.ARCHERY.getPermissions(player)) { + if (!Misc.isNPCEntityExcludingVillagers(player) && Permissions.skillEnabled(player, PrimarySkillType.ARCHERY)) { processArcheryCombat(target, player, event, arrow); } else { //Cleanup Arrow cleanupArrowMetadata(arrow); } - if (target.getType() != EntityType.CREEPER && !Misc.isNPCEntityExcludingVillagers(player) && PrimarySkillType.TAMING.getPermissions(player)) { + if (target.getType() != EntityType.CREEPER && !Misc.isNPCEntityExcludingVillagers(player) && Permissions.skillEnabled(player, PrimarySkillType.TAMING)) { McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); if(mcMMOPlayer == null) diff --git a/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java b/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java index f35239eec..697e20e30 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java @@ -7,6 +7,7 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.listeners.InteractionManager; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.skills.SkillUnlockNotificationTask; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; @@ -28,7 +29,7 @@ public class RankUtils { */ public static void executeSkillUnlockNotifications(Plugin plugin, McMMOPlayer mcMMOPlayer, PrimarySkillType primarySkillType, int newLevel) { - for(SubSkillType subSkillType : primarySkillType.getSkillAbilities()) + for(SubSkillType subSkillType : mcMMO.p.getSkillTools().getSubSkills(primarySkillType)) { int playerRankInSkill = getRank(mcMMOPlayer.getPlayer(), subSkillType); diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java new file mode 100644 index 000000000..4fe98d5f7 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java @@ -0,0 +1,450 @@ +package com.gmail.nossr50.util.skills; + +import com.gmail.nossr50.api.exceptions.InvalidSkillException; +import com.gmail.nossr50.config.experience.ExperienceConfig; +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.datatypes.skills.SuperAbilityType; +import com.gmail.nossr50.datatypes.skills.ToolType; +import com.gmail.nossr50.locale.LocaleLoader; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.text.StringUtils; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Tameable; +import org.jetbrains.annotations.NotNull; + +import java.util.*; + +public class SkillTools { + private final mcMMO pluginRef; + + //TODO: Should these be hash sets instead of lists? + //TODO: Figure out which ones we don't need, this was copy pasted from a diff branch + public final ImmutableList LOCALIZED_SKILL_NAMES; + public final ImmutableList FORMATTED_SUBSKILL_NAMES; + public final ImmutableSet EXACT_SUBSKILL_NAMES; + public final List CHILD_SKILLS; + public final ImmutableList NON_CHILD_SKILLS; + public final ImmutableList COMBAT_SKILLS; + public final ImmutableList GATHERING_SKILLS; + public final ImmutableList MISC_SKILLS; + + private EnumMap subSkillParentRelationshipMap; //TODO: This disgusts me, but it will have to do until the new skill system is in place + private EnumMap superAbilityParentRelationshipMap; //TODO: This disgusts me, but it will have to do until the new skill system is in place + private EnumMap> primarySkillChildrenMap; //TODO: This disgusts me, but it will have to do until the new skill system is in place + + // The map below is for the super abilities which require readying a tool, its everything except blast mining + private EnumMap mainActivatedAbilityChildMap; //TODO: This disgusts me, but it will have to do until the new skill system is in place + private EnumMap primarySkillToolMap; //TODO: Christ.. + + public SkillTools(@NotNull mcMMO pluginRef) { + this.pluginRef = pluginRef; + + initSubSkillRelationshipMap(); + initPrimaryChildMap(); + initPrimaryToolMap(); + initSuperAbilityParentRelationships(); + + List childSkills = new ArrayList<>(); + List nonChildSkills = new ArrayList<>(); + + for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { + if (isChildSkill(primarySkillType)) { + childSkills.add(primarySkillType); + } else { + nonChildSkills.add(primarySkillType); + } + } + + COMBAT_SKILLS = ImmutableList.of(PrimarySkillType.ARCHERY, PrimarySkillType.AXES, PrimarySkillType.SWORDS, PrimarySkillType.TAMING, PrimarySkillType.UNARMED); + GATHERING_SKILLS = ImmutableList.of(PrimarySkillType.EXCAVATION, PrimarySkillType.FISHING, PrimarySkillType.HERBALISM, PrimarySkillType.MINING, PrimarySkillType.WOODCUTTING); + MISC_SKILLS = ImmutableList.of(PrimarySkillType.ACROBATICS, PrimarySkillType.ALCHEMY, PrimarySkillType.REPAIR, PrimarySkillType.SALVAGE, PrimarySkillType.SMELTING); + + LOCALIZED_SKILL_NAMES = ImmutableList.copyOf(buildLocalizedPrimarySkillNames()); + FORMATTED_SUBSKILL_NAMES = ImmutableList.copyOf(buildFormattedSubSkillNameList()); + EXACT_SUBSKILL_NAMES = ImmutableSet.copyOf(buildExactSubSkillNameList()); + + CHILD_SKILLS = ImmutableList.copyOf(childSkills); + NON_CHILD_SKILLS = ImmutableList.copyOf(nonChildSkills); + } + + //TODO: What is with this design? + private void initPrimaryToolMap() { + primarySkillToolMap = new EnumMap(PrimarySkillType.class); + + primarySkillToolMap.put(PrimarySkillType.AXES, ToolType.AXE); + primarySkillToolMap.put(PrimarySkillType.WOODCUTTING, ToolType.AXE); + primarySkillToolMap.put(PrimarySkillType.UNARMED, ToolType.FISTS); + primarySkillToolMap.put(PrimarySkillType.SWORDS, ToolType.SWORD); + primarySkillToolMap.put(PrimarySkillType.EXCAVATION, ToolType.SHOVEL); + primarySkillToolMap.put(PrimarySkillType.HERBALISM, ToolType.HOE); + primarySkillToolMap.put(PrimarySkillType.MINING, ToolType.PICKAXE); + } + + private void initSuperAbilityParentRelationships() { + superAbilityParentRelationshipMap = new EnumMap(SuperAbilityType.class); + mainActivatedAbilityChildMap = new EnumMap(PrimarySkillType.class); + + for(SuperAbilityType superAbilityType : SuperAbilityType.values()) { + try { + PrimarySkillType parent = getSuperAbilityParent(superAbilityType); + superAbilityParentRelationshipMap.put(superAbilityType, parent); + + if(superAbilityType != SuperAbilityType.BLAST_MINING) { + //This map is used only for abilities that have a tool readying phase, so blast mining is ignored + mainActivatedAbilityChildMap.put(parent, superAbilityType); + } + } catch (InvalidSkillException e) { + e.printStackTrace(); + } + } + } + + private PrimarySkillType getSuperAbilityParent(SuperAbilityType superAbilityType) throws InvalidSkillException { + switch(superAbilityType) { + case BERSERK: + return PrimarySkillType.UNARMED; + case GREEN_TERRA: + return PrimarySkillType.HERBALISM; + case TREE_FELLER: + return PrimarySkillType.WOODCUTTING; + case SUPER_BREAKER: + case BLAST_MINING: + return PrimarySkillType.MINING; + case SKULL_SPLITTER: + return PrimarySkillType.AXES; + case SERRATED_STRIKES: + return PrimarySkillType.SWORDS; + case GIGA_DRILL_BREAKER: + return PrimarySkillType.EXCAVATION; + default: + throw new InvalidSkillException("No parent defined for super ability! "+superAbilityType.toString()); + } + } + + /** + * Builds a list of localized {@link PrimarySkillType} names + * @return list of localized {@link PrimarySkillType} names + */ + private ArrayList buildLocalizedPrimarySkillNames() { + ArrayList localizedSkillNameList = new ArrayList<>(); + + for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { + localizedSkillNameList.add(getLocalizedSkillName(primarySkillType)); + } + + Collections.sort(localizedSkillNameList); + + return localizedSkillNameList; + } + + /** + * Builds a map containing a HashSet of SubSkillTypes considered Children of PrimarySkillType + * Disgusting Hacky Fix until the new skill system is in place + */ + private void initPrimaryChildMap() { + primarySkillChildrenMap = new EnumMap>(PrimarySkillType.class); + + //Init the empty Hash Sets + for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { + primarySkillChildrenMap.put(primarySkillType, new HashSet()); + } + + //Fill in the hash sets + for(SubSkillType subSkillType : SubSkillType.values()) { + PrimarySkillType parentSkill = subSkillParentRelationshipMap.get(subSkillType); + + //Add this subskill as a child + primarySkillChildrenMap.get(parentSkill).add(subSkillType); + } + } + + /** + * Makes a list of the "nice" version of sub skill names + * Used in tab completion mostly + * @return a list of formatted sub skill names + */ + private ArrayList buildFormattedSubSkillNameList() { + ArrayList subSkillNameList = new ArrayList<>(); + + for(SubSkillType subSkillType : SubSkillType.values()) { + subSkillNameList.add(subSkillType.getNiceNameNoSpaces(subSkillType)); + } + + return subSkillNameList; + } + + private HashSet buildExactSubSkillNameList() { + HashSet subSkillNameExactSet = new HashSet<>(); + + for(SubSkillType subSkillType : SubSkillType.values()) { + subSkillNameExactSet.add(subSkillType.toString()); + } + + return subSkillNameExactSet; + } + + /** + * Builds a map containing the relationships of SubSkillTypes to PrimarySkillTypes + * Disgusting Hacky Fix until the new skill system is in place + */ + private void initSubSkillRelationshipMap() { + subSkillParentRelationshipMap = new EnumMap(SubSkillType.class); + + //Super hacky and disgusting + for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { + for(SubSkillType subSkillType : SubSkillType.values()) { + String[] splitSubSkillName = subSkillType.toString().split("_"); + + if(primarySkillType.toString().equalsIgnoreCase(splitSubSkillName[0])) { + //Parent Skill Found + subSkillParentRelationshipMap.put(subSkillType, primarySkillType); + } + } + } + } + + /** + * Matches a string of a skill to a skill + * This is NOT case sensitive + * First it checks the locale file and tries to match by the localized name of the skill + * Then if nothing is found it checks against the hard coded "name" of the skill, which is just its name in English + * + * @param skillName target skill name + * @return the matching PrimarySkillType if one is found, otherwise null + */ + public PrimarySkillType matchSkill(String skillName) { + if (!pluginRef.getGeneralConfig().getLocale().equalsIgnoreCase("en_US")) { + for (PrimarySkillType type : PrimarySkillType.values()) { + if (skillName.equalsIgnoreCase(LocaleLoader.getString(StringUtils.getCapitalized(type.name()) + ".SkillName"))) { + return type; + } + } + } + + for (PrimarySkillType type : PrimarySkillType.values()) { + if (type.name().equalsIgnoreCase(skillName)) { + return type; + } + } + + if (!skillName.equalsIgnoreCase("all")) { + pluginRef.getLogger().warning("Invalid mcMMO skill (" + skillName + ")"); //TODO: Localize + } + + return null; + } + + /** + * Gets the PrimarySkillStype to which a SubSkillType belongs + * Return null if it does not belong to one.. which should be impossible in most circumstances + * @param subSkillType target subskill + * @return the PrimarySkillType of this SubSkill, null if it doesn't exist + */ + public PrimarySkillType getPrimarySkillBySubSkill(SubSkillType subSkillType) { + return subSkillParentRelationshipMap.get(subSkillType); + } + + /** + * Gets the PrimarySkillStype to which a SuperAbilityType belongs + * Return null if it does not belong to one.. which should be impossible in most circumstances + * @param superAbilityType target super ability + * @return the PrimarySkillType of this SuperAbilityType, null if it doesn't exist + */ + public PrimarySkillType getPrimarySkillBySuperAbility(SuperAbilityType superAbilityType) { + return superAbilityParentRelationshipMap.get(superAbilityType); + } + + public SuperAbilityType getSuperAbility(PrimarySkillType primarySkillType) { + if(mainActivatedAbilityChildMap.get(primarySkillType) == null) + return null; + + return mainActivatedAbilityChildMap.get(primarySkillType); + } + + public boolean isSuperAbilityUnlocked(PrimarySkillType primarySkillType, Player player) { + return RankUtils.getRank(player, getSuperAbility(primarySkillType).getSubSkillTypeDefinition()) >= 1; + } + + public boolean getPVPEnabled(PrimarySkillType primarySkillType) { + return pluginRef.getGeneralConfig().getPVPEnabled(primarySkillType); + } + + public boolean getPVEEnabled(PrimarySkillType primarySkillType) { + return pluginRef.getGeneralConfig().getPVEEnabled(primarySkillType); + } + + public boolean getHardcoreStatLossEnabled(PrimarySkillType primarySkillType) { + return pluginRef.getGeneralConfig().getHardcoreStatLossEnabled(primarySkillType); + } + + public boolean getHardcoreVampirismEnabled(PrimarySkillType primarySkillType) { + return pluginRef.getGeneralConfig().getHardcoreVampirismEnabled(primarySkillType); + } + + public ToolType getPrimarySkillToolType(PrimarySkillType primarySkillType) { + return primarySkillToolMap.get(primarySkillType); + } + + public List getSubSkills(PrimarySkillType primarySkillType) { + //TODO: Cache this! + return new ArrayList<>(primarySkillChildrenMap.get(primarySkillType)); + } + + public double getXpModifier(PrimarySkillType primarySkillType) { + return ExperienceConfig.getInstance().getFormulaSkillModifier(primarySkillType); + } + + // TODO: This is a little "hacky", we probably need to add something to distinguish child skills in the enum, or to use another enum for them + public boolean isChildSkill(PrimarySkillType primarySkillType) { + switch (primarySkillType) { + case SALVAGE: + case SMELTING: + return true; + + default: + return false; + } + } + + /** + * Get the localized name for a {@link PrimarySkillType} + * @param primarySkillType target {@link PrimarySkillType} + * @return the localized name for a {@link PrimarySkillType} + */ + public String getLocalizedSkillName(PrimarySkillType primarySkillType) { + //TODO: Replace with current impl + return StringUtils.getCapitalized(LocaleLoader.getString(StringUtils.getCapitalized(primarySkillType.toString()) + ".SkillName")); + } + + public boolean doesPlayerHaveSkillPermission(PrimarySkillType primarySkillType, Player player) { + return Permissions.skillEnabled(player, primarySkillType); + } + + public boolean canCombatSkillsTrigger(PrimarySkillType primarySkillType, Entity target) { + return (target instanceof Player || (target instanceof Tameable && ((Tameable) target).isTamed())) ? getPVPEnabled(primarySkillType) : getPVEEnabled(primarySkillType); + } + + public String getCapitalizedPrimarySkillName(PrimarySkillType primarySkillType) { + return StringUtils.getCapitalized(primarySkillType.toString()); + } + + public int getSuperAbilityCooldown(SuperAbilityType superAbilityType) { + return pluginRef.getGeneralConfig().getCooldown(superAbilityType); + } + + public int getSuperAbilityMaxLength(SuperAbilityType superAbilityType) { + return pluginRef.getGeneralConfig().getMaxLength(superAbilityType); + } + + public String getSuperAbilityOnLocaleKey(SuperAbilityType superAbilityType) { + return "SuperAbility." + StringUtils.getPrettyCamelCaseName(superAbilityType) + ".On"; + } + + public String getSuperAbilityOffLocaleKey(SuperAbilityType superAbilityType) { + return "SuperAbility." + StringUtils.getPrettyCamelCaseName(superAbilityType) + ".Off"; + } + + public String getSuperAbilityOtherPlayerActivationLocaleKey(SuperAbilityType superAbilityType) { + return "SuperAbility." + StringUtils.getPrettyCamelCaseName(superAbilityType) + ".Other.On"; + } + + public String getSuperAbilityOtherPlayerDeactivationLocaleKey(SuperAbilityType superAbilityType) { + return "SuperAbility." + StringUtils.getPrettyCamelCaseName(superAbilityType) + "Other.Off"; + } + + public String getSuperAbilityRefreshedLocaleKey(SuperAbilityType superAbilityType) { + return "SuperAbility." + StringUtils.getPrettyCamelCaseName(superAbilityType) + ".Refresh"; + } + + /** + * Get the permissions for this ability. + * + * @param player Player to check permissions for + * @param superAbilityType target super ability + * @return true if the player has permissions, false otherwise + */ + public boolean superAbilityPermissionCheck(SuperAbilityType superAbilityType, Player player) { + switch (superAbilityType) { + case BERSERK: + return Permissions.berserk(player); + + case BLAST_MINING: + return Permissions.remoteDetonation(player); + + case GIGA_DRILL_BREAKER: + return Permissions.gigaDrillBreaker(player); + + case GREEN_TERRA: + return Permissions.greenTerra(player); + + case SERRATED_STRIKES: + return Permissions.serratedStrikes(player); + + case SKULL_SPLITTER: + return Permissions.skullSplitter(player); + + case SUPER_BREAKER: + return Permissions.superBreaker(player); + + case TREE_FELLER: + return Permissions.treeFeller(player); + + default: + return false; + } + } + + public @NotNull List getChildSkills() { + return CHILD_SKILLS; + } + + public @NotNull ImmutableList getNonChildSkills() { + return NON_CHILD_SKILLS; + } + + public @NotNull ImmutableList getCombatSkills() { + return COMBAT_SKILLS; + } + + public @NotNull ImmutableList getGatheringSkills() { + return GATHERING_SKILLS; + } + + public @NotNull ImmutableList getMiscSkills() { + return MISC_SKILLS; + } + + // /** +// * Check if a block is affected by this ability. +// * +// * @param blockState the block to check +// * @param superAbilityType target super ability +// * @return true if the block is affected by this ability, false otherwise +// */ +// public boolean superAbilityBlockCheck(SuperAbilityType superAbilityType, BlockState blockState) { +// switch (superAbilityType) { +// case BERSERK: +// return (BlockUtils.affectedByGigaDrillBreaker(blockState) || blockState.getType() == Material.SNOW); +// +// case GIGA_DRILL_BREAKER: +// return BlockUtils.affectedByGigaDrillBreaker(blockState); +// +// case GREEN_TERRA: +// return BlockUtils.canMakeMossy(blockState); +// +// case SUPER_BREAKER: +// return BlockUtils.affectedBySuperBreaker(blockState); +// +// case TREE_FELLER: +// dfss +// +// default: +// return false; +// } +// } +} diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java index 434828dca..938ca2343 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java @@ -53,7 +53,7 @@ public final class SkillUtils { */ public static String[] calculateLengthDisplayValues(Player player, float skillValue, PrimarySkillType skill) { - int maxLength = skill.getAbility().getMaxLength(); + int maxLength = mcMMO.p.getSkillTools().getSuperAbilityMaxLength(mcMMO.p.getSkillTools().getSuperAbility(skill)); int abilityLengthVar = mcMMO.p.getAdvancedConfig().getAbilityLength(); int abilityLengthCap = mcMMO.p.getAdvancedConfig().getAbilityLengthCap(); @@ -123,7 +123,7 @@ public final class SkillUtils { * @return true if this is a valid skill, false otherwise */ public static boolean isSkill(String skillName) { - return mcMMO.p.getGeneralConfig().getLocale().equalsIgnoreCase("en_US") ? PrimarySkillType.getSkill(skillName) != null : isLocalizedSkill(skillName); + return mcMMO.p.getGeneralConfig().getLocale().equalsIgnoreCase("en_US") ? mcMMO.p.getSkillTools().matchSkill(skillName) != null : isLocalizedSkill(skillName); } public static void sendSkillMessage(Player player, NotificationType notificationType, String key) { @@ -189,10 +189,10 @@ public final class SkillUtils { if(abilityLengthCap > 0) { ticks = PerksUtils.handleActivationPerks(player, Math.min(abilityLengthCap, 2 + (mcMMOPlayer.getSkillLevel(skill) / abilityLengthVar)), - skill.getAbility().getMaxLength()) * Misc.TICK_CONVERSION_FACTOR; + mcMMO.p.getSkillTools().getSuperAbilityMaxLength(mcMMO.p.getSkillTools().getSuperAbility(skill))) * Misc.TICK_CONVERSION_FACTOR; } else { ticks = PerksUtils.handleActivationPerks(player, 2 + ((mcMMOPlayer.getSkillLevel(skill)) / abilityLengthVar), - skill.getAbility().getMaxLength()) * Misc.TICK_CONVERSION_FACTOR; + mcMMO.p.getSkillTools().getSuperAbilityMaxLength(mcMMO.p.getSkillTools().getSuperAbility(skill))) * Misc.TICK_CONVERSION_FACTOR; } PotionEffect abilityBuff = new PotionEffect(PotionEffectType.FAST_DIGGING, duration + ticks, amplifier + 10); diff --git a/src/main/java/com/gmail/nossr50/util/text/StringUtils.java b/src/main/java/com/gmail/nossr50/util/text/StringUtils.java index db53feb31..34aac4fc8 100644 --- a/src/main/java/com/gmail/nossr50/util/text/StringUtils.java +++ b/src/main/java/com/gmail/nossr50/util/text/StringUtils.java @@ -31,6 +31,35 @@ public class StringUtils { return shortDecimal.format(ticks / 20); } + public static String convertToCamelCaseString(String baseString, String splitBy) { + String[] substrings = baseString.split(splitBy); + String prettyString = ""; + int size = 1; + + for (String string : substrings) { + prettyString = prettyString.concat(getCapitalized(string)); + + if (size < substrings.length) { + prettyString = prettyString.concat(""); + } + + size++; + } + + return prettyString; + } + + public static String getPrettyCamelCaseName(Object o) { + return StringUtils.convertToCamelCaseString(o.toString(), "_"); + } + + public static String getPrettySuperAbilityName(SuperAbilityType superAbilityType) { + return StringUtils.getPrettySuperAbilityString(superAbilityType); + } + + public static String getPrettySuperAbilityString(SuperAbilityType ability) { + return createPrettyString(ability.toString()); + } /** * Creates a string from an array skipping the first n elements diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index 99a019c0d..97b235b65 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -6,7 +6,6 @@ import com.google.common.io.Files; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; From 241df06707d04b8efd85b0f720f9c927c85d4596 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 8 Apr 2021 13:22:20 -0700 Subject: [PATCH 03/57] Don't need this anymore --- .../datatypes/skills/PrimarySkillType.java | 242 +----------------- 1 file changed, 1 insertion(+), 241 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java index 1e46c2ad2..ceb75d12f 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java @@ -16,244 +16,4 @@ public enum PrimarySkillType { TAMING, UNARMED, WOODCUTTING -} - -//package com.gmail.nossr50.datatypes.skills; -// -//import com.gmail.nossr50.config.experience.ExperienceConfig; -//import com.gmail.nossr50.datatypes.skills.interfaces.Skill; -//import com.gmail.nossr50.locale.LocaleLoader; -//import com.gmail.nossr50.mcMMO; -//import com.gmail.nossr50.skills.SkillManager; -//import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager; -//import com.gmail.nossr50.skills.alchemy.AlchemyManager; -//import com.gmail.nossr50.skills.archery.ArcheryManager; -//import com.gmail.nossr50.skills.axes.AxesManager; -//import com.gmail.nossr50.skills.excavation.ExcavationManager; -//import com.gmail.nossr50.skills.fishing.FishingManager; -//import com.gmail.nossr50.skills.herbalism.HerbalismManager; -//import com.gmail.nossr50.skills.mining.MiningManager; -//import com.gmail.nossr50.skills.repair.RepairManager; -//import com.gmail.nossr50.skills.salvage.SalvageManager; -//import com.gmail.nossr50.skills.smelting.SmeltingManager; -//import com.gmail.nossr50.skills.swords.SwordsManager; -//import com.gmail.nossr50.skills.taming.TamingManager; -//import com.gmail.nossr50.skills.unarmed.UnarmedManager; -//import com.gmail.nossr50.skills.woodcutting.WoodcuttingManager; -//import com.gmail.nossr50.util.Permissions; -//import com.gmail.nossr50.util.skills.RankUtils; -//import com.gmail.nossr50.util.text.StringUtils; -//import com.google.common.collect.ImmutableList; -//import org.bukkit.Color; -//import org.bukkit.entity.Entity; -//import org.bukkit.entity.Player; -//import org.bukkit.entity.Tameable; -// -//import java.util.ArrayList; -//import java.util.Collections; -//import java.util.List; -// -//public enum PrimarySkillType implements Skill { -// ACROBATICS(AcrobaticsManager.class, Color.WHITE, -// ImmutableList.of(SubSkillType.ACROBATICS_DODGE, SubSkillType.ACROBATICS_ROLL)), -// ALCHEMY(AlchemyManager.class, Color.FUCHSIA, -// ImmutableList.of(SubSkillType.ALCHEMY_CATALYSIS, SubSkillType.ALCHEMY_CONCOCTIONS)), -// ARCHERY(ArcheryManager.class, Color.MAROON, -// ImmutableList.of(SubSkillType.ARCHERY_DAZE, SubSkillType.ARCHERY_ARCHERY_LIMIT_BREAK, SubSkillType.ARCHERY_ARROW_RETRIEVAL, SubSkillType.ARCHERY_SKILL_SHOT)), -// AXES(AxesManager.class, Color.AQUA, SuperAbilityType.SKULL_SPLITTER, ToolType.AXE, -// ImmutableList.of(SubSkillType.AXES_SKULL_SPLITTER, SubSkillType.AXES_AXES_LIMIT_BREAK, SubSkillType.AXES_ARMOR_IMPACT, SubSkillType.AXES_AXE_MASTERY, SubSkillType.AXES_CRITICAL_STRIKES, SubSkillType.AXES_GREATER_IMPACT)), -// EXCAVATION(ExcavationManager.class, Color.fromRGB(139, 69, 19), SuperAbilityType.GIGA_DRILL_BREAKER, ToolType.SHOVEL, -// ImmutableList.of(SubSkillType.EXCAVATION_GIGA_DRILL_BREAKER, SubSkillType.EXCAVATION_ARCHAEOLOGY)), -// FISHING(FishingManager.class, Color.NAVY, -// ImmutableList.of(SubSkillType.FISHING_FISHERMANS_DIET, SubSkillType.FISHING_TREASURE_HUNTER, SubSkillType.FISHING_ICE_FISHING, SubSkillType.FISHING_MAGIC_HUNTER, SubSkillType.FISHING_MASTER_ANGLER, SubSkillType.FISHING_SHAKE)), -// HERBALISM(HerbalismManager.class, Color.GREEN, SuperAbilityType.GREEN_TERRA, ToolType.HOE, -// ImmutableList.of(SubSkillType.HERBALISM_GREEN_TERRA, SubSkillType.HERBALISM_FARMERS_DIET, SubSkillType.HERBALISM_GREEN_THUMB, SubSkillType.HERBALISM_DOUBLE_DROPS, SubSkillType.HERBALISM_HYLIAN_LUCK, SubSkillType.HERBALISM_SHROOM_THUMB)), -// MINING(MiningManager.class, Color.GRAY, SuperAbilityType.SUPER_BREAKER, ToolType.PICKAXE, -// ImmutableList.of(SubSkillType.MINING_SUPER_BREAKER, SubSkillType.MINING_DEMOLITIONS_EXPERTISE, SubSkillType.MINING_BIGGER_BOMBS, SubSkillType.MINING_BLAST_MINING, SubSkillType.MINING_DOUBLE_DROPS)), -// REPAIR(RepairManager.class, Color.SILVER, -// ImmutableList.of(SubSkillType.REPAIR_ARCANE_FORGING, SubSkillType.REPAIR_REPAIR_MASTERY, SubSkillType.REPAIR_SUPER_REPAIR)), -// SALVAGE(SalvageManager.class, Color.ORANGE, -// ImmutableList.of(SubSkillType.SALVAGE_SCRAP_COLLECTOR, SubSkillType.SALVAGE_ARCANE_SALVAGE)), -// SMELTING(SmeltingManager.class, Color.YELLOW, -// ImmutableList.of(SubSkillType.SMELTING_UNDERSTANDING_THE_ART, /*SubSkillType.SMELTING_FLUX_MINING,*/ SubSkillType.SMELTING_FUEL_EFFICIENCY, SubSkillType.SMELTING_SECOND_SMELT)), -// SWORDS(SwordsManager.class, Color.fromRGB(178, 34, 34), SuperAbilityType.SERRATED_STRIKES, ToolType.SWORD, -// ImmutableList.of(SubSkillType.SWORDS_SERRATED_STRIKES, SubSkillType.SWORDS_SWORDS_LIMIT_BREAK, SubSkillType.SWORDS_STAB, SubSkillType.SWORDS_RUPTURE, SubSkillType.SWORDS_COUNTER_ATTACK)), -// TAMING(TamingManager.class, Color.PURPLE, -// ImmutableList.of(SubSkillType.TAMING_BEAST_LORE, SubSkillType.TAMING_CALL_OF_THE_WILD, SubSkillType.TAMING_ENVIRONMENTALLY_AWARE, SubSkillType.TAMING_FAST_FOOD_SERVICE, SubSkillType.TAMING_GORE, SubSkillType.TAMING_HOLY_HOUND, SubSkillType.TAMING_SHARPENED_CLAWS, SubSkillType.TAMING_SHOCK_PROOF, SubSkillType.TAMING_THICK_FUR, SubSkillType.TAMING_PUMMEL)), -// UNARMED(UnarmedManager.class, Color.BLACK, SuperAbilityType.BERSERK, ToolType.FISTS, -// ImmutableList.of(SubSkillType.UNARMED_BERSERK, SubSkillType.UNARMED_UNARMED_LIMIT_BREAK, SubSkillType.UNARMED_BLOCK_CRACKER, SubSkillType.UNARMED_ARROW_DEFLECT, SubSkillType.UNARMED_DISARM, SubSkillType.UNARMED_STEEL_ARM_STYLE, SubSkillType.UNARMED_IRON_GRIP)), -// WOODCUTTING(WoodcuttingManager.class, Color.OLIVE, SuperAbilityType.TREE_FELLER, ToolType.AXE, -// ImmutableList.of(SubSkillType.WOODCUTTING_LEAF_BLOWER, SubSkillType.WOODCUTTING_TREE_FELLER, SubSkillType.WOODCUTTING_HARVEST_LUMBER, SubSkillType.WOODCUTTING_KNOCK_ON_WOOD)); -// -// private final Class managerClass; -// private final Color skillColor; -// private final SuperAbilityType ability; -// private final ToolType tool; -// private final List subSkillTypes; -// -// public static final List SKILL_NAMES; -// public static final List SUBSKILL_NAMES; -// -// public static final List CHILD_SKILLS; -// public static final List NON_CHILD_SKILLS; -// -// public static final List COMBAT_SKILLS = ImmutableList.of(ARCHERY, AXES, SWORDS, TAMING, UNARMED); -// public static final List GATHERING_SKILLS = ImmutableList.of(EXCAVATION, FISHING, HERBALISM, MINING, WOODCUTTING); -// public static final List MISC_SKILLS = ImmutableList.of(ACROBATICS, ALCHEMY, REPAIR, SALVAGE, SMELTING); -// -// static { -// List childSkills = new ArrayList<>(); -// List nonChildSkills = new ArrayList<>(); -// ArrayList names = new ArrayList<>(); -// ArrayList subSkillNames = new ArrayList<>(); -// -// for (PrimarySkillType skill : values()) { -// if (mcMMO.p.getSkillTools().isChildSkill(skill)) { -// childSkills.add(skill); -// } -// else { -// nonChildSkills.add(skill); -// } -// -// for(SubSkillType subSkillType : skill.subSkillTypes) { -// subSkillNames.add(subSkillType.getNiceNameNoSpaces(subSkillType)); -// } -// -// names.add(mcMMO.p.getSkillTools().getLocalizedSkillName(skill)); -// } -// -// Collections.sort(names); -// SKILL_NAMES = ImmutableList.copyOf(names); -// SUBSKILL_NAMES = ImmutableList.copyOf(subSkillNames); -// -// CHILD_SKILLS = ImmutableList.copyOf(childSkills); -// NON_CHILD_SKILLS = ImmutableList.copyOf(nonChildSkills); -// } -// -// PrimarySkillType(Class managerClass, Color skillColor, List subSkillTypes) { -// this(managerClass, skillColor, null, null, subSkillTypes); -// } -// -// PrimarySkillType(Class managerClass, Color skillColor, SuperAbilityType ability, ToolType tool, List subSkillTypes) { -// this.managerClass = managerClass; -// this.skillColor = skillColor; -// this.ability = ability; -// this.tool = tool; -// this.subSkillTypes = subSkillTypes; -// } -// -// public PrimarySkillType getPrimarySkill() { -// return this; -// } -// -// public String getPrimaryKeyName() { -// return StringUtils.getCapitalized(this.toString()); -// } -// -// public Class getManagerClass() { -// return managerClass; -// } -// -// public SuperAbilityType getAbility() { -// return ability; -// } -// -// /** -// * Get the max level of this skill. -// * -// * @return the max level of this skill -// */ -// public int getMaxLevel() { -// return mcMMO.p.getGeneralConfig().getLevelCap(this); -// } -// -// public boolean isSuperAbilityUnlocked(Player player) { return RankUtils.getRank(player, getAbility().getSubSkillTypeDefinition()) >= 1; } -// -// public boolean getPVPEnabled() { -// return mcMMO.p.getGeneralConfig().getPVPEnabled(this); -// } -// -// public boolean getPVEEnabled() { -// return mcMMO.p.getGeneralConfig().getPVEEnabled(this); -// } -// -// public boolean getDoubleDropsDisabled() { -// return mcMMO.p.getGeneralConfig().getDoubleDropsDisabled(this); -// } -// -// public boolean getHardcoreStatLossEnabled() { -// return mcMMO.p.getGeneralConfig().getHardcoreStatLossEnabled(this); -// } -// -// public void setHardcoreStatLossEnabled(boolean enable) { -// mcMMO.p.getGeneralConfig().setHardcoreStatLossEnabled(this, enable); -// } -// -// public boolean getHardcoreVampirismEnabled() { -// return mcMMO.p.getGeneralConfig().getHardcoreVampirismEnabled(this); -// } -// -// public void setHardcoreVampirismEnabled(boolean enable) { -// mcMMO.p.getGeneralConfig().setHardcoreVampirismEnabled(this, enable); -// } -// -// public ToolType getTool() { -// return tool; -// } -// -// public List getSkillAbilities() { -// return subSkillTypes; -// } -// -// public double getXpModifier() { -// return ExperienceConfig.getInstance().getFormulaSkillModifier(this); -// } -// -// public static PrimarySkillType getSkill(String skillName) { -// if (!mcMMO.p.getGeneralConfig().getLocale().equalsIgnoreCase("en_US")) { -// for (PrimarySkillType type : values()) { -// if (skillName.equalsIgnoreCase(LocaleLoader.getString(StringUtils.getCapitalized(type.name()) + ".SkillName"))) { -// return type; -// } -// } -// } -// -// for (PrimarySkillType type : values()) { -// if (type.name().equalsIgnoreCase(skillName)) { -// return type; -// } -// } -// -// if (!skillName.equalsIgnoreCase("all")) { -// mcMMO.p.getLogger().warning("Invalid mcMMO skill (" + skillName + ")"); //TODO: Localize -// } -// -// return null; -// } -// -// // TODO: This is a little "hacky", we probably need to add something to distinguish child skills in the enum, or to use another enum for them -// public boolean isChildSkill() { -// switch (this) { -// case SALVAGE: -// case SMELTING: -// return true; -// -// default: -// return false; -// } -// } -// -// public String getName() { -// return StringUtils.getCapitalized(LocaleLoader.getString(StringUtils.getCapitalized(this.toString()) + ".SkillName")); -// } -// -// public boolean getPermissions(Player player) { -// return Permissions.skillEnabled(player, this); -// } -// -// public boolean shouldProcess(Entity target) { -// return (target instanceof Player || (target instanceof Tameable && ((Tameable) target).isTamed())) ? getPVPEnabled() : getPVEEnabled(); -// } -// -// -//} +} \ No newline at end of file From 74d0d2c3f91a2a79880676f3464d78f425bb8d79 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 8 Apr 2021 13:22:46 -0700 Subject: [PATCH 04/57] Comment these out for now --- src/main/java/com/gmail/nossr50/mcMMO.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index 2b19e5761..766bd3b8a 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -156,15 +156,15 @@ public class mcMMO extends JavaPlugin { private GeneralConfig generalConfig; private AdvancedConfig advancedConfig; - private RepairConfig repairConfig; - private SalvageConfig salvageConfig; - private PersistentDataConfig persistentDataConfig; - private ChatConfig chatConfig; - private CoreSkillsConfig coreSkillsConfig; - private RankConfig rankConfig; - private TreasureConfig treasureConfig; - private FishingTreasureConfig fishingTreasureConfig; - private SoundConfig soundConfig; +// private RepairConfig repairConfig; +// private SalvageConfig salvageConfig; +// private PersistentDataConfig persistentDataConfig; +// private ChatConfig chatConfig; +// private CoreSkillsConfig coreSkillsConfig; +// private RankConfig rankConfig; +// private TreasureConfig treasureConfig; +// private FishingTreasureConfig fishingTreasureConfig; +// private SoundConfig soundConfig; public mcMMO() { p = this; From 80aac93fd2223fc5f65a3a99b2d194408df7a8c1 Mon Sep 17 00:00:00 2001 From: lexikiq Date: Thu, 8 Apr 2021 16:25:24 -0400 Subject: [PATCH 05/57] Fix death messages losing formatting (#4482) --- .../nossr50/listeners/PlayerListener.java | 56 ++++++++++++------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java index 16a50182b..74e155622 100644 --- a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java @@ -12,6 +12,7 @@ import com.gmail.nossr50.events.fake.FakePlayerAnimationEvent; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.party.ShareHandler; +import com.gmail.nossr50.runnables.MobHealthDisplayUpdaterTask; import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask; import com.gmail.nossr50.skills.fishing.FishingManager; import com.gmail.nossr50.skills.herbalism.HerbalismManager; @@ -35,6 +36,7 @@ import org.bukkit.GameMode; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockState; +import org.bukkit.conversations.Conversation; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.*; import org.bukkit.entity.minecart.PoweredMinecart; @@ -43,11 +45,13 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; +import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityPickupItemEvent; import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.player.*; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; import java.util.Locale; @@ -104,36 +108,46 @@ public class PlayerListener implements Listener { UserManager.getPlayer(player).actualizeTeleportATS(); } + /** - * Handle PlayerDeathEvents at the lowest priority. + * Handle {@link EntityDamageByEntityEvent} at the highest priority. *

- * These events are used to modify the death message of a player when - * needed to correct issues potentially caused by the custom naming used - * for mob healthbars. + * This handler is used to clear the names of mobs with health bars to + * fix death messages showing mob health bars on death. * - * @param event The event to modify + * @param event the event to listen to */ - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - public void onPlayerDeathLowest(PlayerDeathEvent event) { - /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onEntityDamageByEntityHighest(EntityDamageByEntityEvent event) { + // we only care about players as this is for fixing player death messages + if (!(event.getEntity() instanceof Player)) + return; + if (!(event.getDamager() instanceof LivingEntity)) + return; + // world blacklist check + if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) + return; + // world guard main flag check + if (WorldGuardUtils.isWorldGuardLoaded() && !WorldGuardManager.getInstance().hasMainFlag((Player) event.getEntity())) return; - String deathMessage = event.getDeathMessage(); + Player player = (Player) event.getEntity(); + LivingEntity attacker = (LivingEntity) event.getDamager(); - /* WORLD GUARD MAIN FLAG CHECK */ - if(WorldGuardUtils.isWorldGuardLoaded()) - { - if(!WorldGuardManager.getInstance().hasMainFlag(event.getEntity())) - return; - } - - if (deathMessage == null) { + // we only want to handle player deaths + if ((player.getHealth() - event.getFinalDamage()) > 0) return; - } - Player player = event.getEntity(); - event.setDeathMessage(MobHealthbarUtils.fixDeathMessage(deathMessage, player)); + // temporarily clear the mob's name + new MobHealthDisplayUpdaterTask(attacker).run(); + + // set the name back + new BukkitRunnable() { + @Override + public void run() { + MobHealthbarUtils.handleMobHealthbars(attacker, 0, mcMMO.p); + } + }.runTaskLater(mcMMO.p, 1); } /** From 611705bce1bdfbb4e9e62d98a1d977fc043755d1 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 8 Apr 2021 13:26:22 -0700 Subject: [PATCH 06/57] Update changelog --- Changelog.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Changelog.txt b/Changelog.txt index 7e251df2a..6cb8262d3 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,6 +1,7 @@ Version 2.1.189 + Fixed a bug that would remove components from death messages when players were killed by mobs (thanks lexikiq) Removed MHD command (it didn't do anything for a while now) - Removed UP warning + Removed UltraPermissions warning Updated pl locale (Thanks Mich3l3k) Fixed an IllegalPluginAccessException error that could happen during server shutdown Minor performance optimizations to FlatFile database From ccf5f3001132f02d143d7f629b06eed76193d72c Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 8 Apr 2021 13:31:07 -0700 Subject: [PATCH 07/57] Add a test to FlatFileDatabaseManagerTest (more to come) --- .../database/FlatFileDatabaseManagerTest.java | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index 97b235b65..f8eaa4ff2 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -6,6 +6,7 @@ import com.google.common.io.Files; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.junit.After; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -16,7 +17,6 @@ import java.io.*; import java.util.logging.Logger; -@PrepareForTest({GeneralConfig.class}) @RunWith(PowerMockRunner.class) public class FlatFileDatabaseManagerTest { @@ -28,14 +28,12 @@ public class FlatFileDatabaseManagerTest { @Before public void init() { - logger.info("Preparing new test..."); tempDir = Files.createTempDir(); flatFileDatabaseManager = new FlatFileDatabaseManager(tempDir.getPath() + File.separator + TEST_FILE_NAME, logger, PURGE_TIME, 0); } @After public void tearDown() { - logger.info("Tearing down after test..."); TestUtil.recursiveDelete(tempDir); flatFileDatabaseManager = null; } @@ -55,11 +53,10 @@ public class FlatFileDatabaseManagerTest { @Test public void testPurgePowerlessUsers() { -// logger.info("testPurgePowerlessUsers"); -// Assert.assertNotNull(flatFileDatabaseManager); -// addDataToFile(flatFileDatabaseManager, normalDatabaseData); -// int purgeCount = flatFileDatabaseManager.purgePowerlessUsers(); -// Assert.assertEquals(purgeCount, 1); //1 User should have been purged + Assert.assertNotNull(flatFileDatabaseManager); + addDataToFile(flatFileDatabaseManager, normalDatabaseData); + int purgeCount = flatFileDatabaseManager.purgePowerlessUsers(); + Assert.assertEquals(purgeCount, 1); //1 User should have been purged } private void addDataToFile(@NotNull FlatFileDatabaseManager flatFileDatabaseManager, @NotNull String[] dataEntries) { @@ -68,7 +65,6 @@ public class FlatFileDatabaseManagerTest { FileWriter out = null; try { - StringBuilder writer = new StringBuilder(); for(String data : dataEntries) { @@ -79,7 +75,7 @@ public class FlatFileDatabaseManagerTest { out.write(writer.toString()); } catch (FileNotFoundException e) { e.printStackTrace(); - logger.severe("File not found"); + System.out.println("File not found"); } catch (IOException e) { e.printStackTrace(); } finally { @@ -94,12 +90,12 @@ public class FlatFileDatabaseManagerTest { } try { - logger.info("Added the following lines to the FlatFileDatabase for the purposes of the test..."); + System.out.println("Added the following lines to the FlatFileDatabase for the purposes of the test..."); // Open the file in = new BufferedReader(new FileReader(filePath)); String line; while ((line = in.readLine()) != null) { - logger.info(line); + System.out.println(line); } } catch (IOException e) { e.printStackTrace(); From e76fb9ab1badc9759c06bbecd59c437f1e020549 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 8 Apr 2021 13:36:18 -0700 Subject: [PATCH 08/57] Update changelog --- Changelog.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog.txt b/Changelog.txt index 6cb8262d3..a8a6d90af 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -6,6 +6,8 @@ Version 2.1.189 Fixed an IllegalPluginAccessException error that could happen during server shutdown Minor performance optimizations to FlatFile database Refactored a lot of code + (API) PrimarySkillType is now just an enum with nothing special going on, SkillTools will facilitate what it used to do - see mcMMO::getSkillTools + Added unit tests for FlatFileDatabaseManager NOTES: Ultra Permissions is SAFE to use with mcMMO From 56f9341f8e4be8d4c41be1cb85f8d8154f04381c Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 9 Apr 2021 07:54:34 -0700 Subject: [PATCH 09/57] Add mcMMO_Region_System.Enabled to persistent_data.yml (removed from hidden config) --- Changelog.txt | 2 ++ .../nossr50/commands/skills/MmoInfoCommand.java | 1 - .../java/com/gmail/nossr50/config/HiddenConfig.java | 5 ----- .../gmail/nossr50/config/PersistentDataConfig.java | 5 +++++ .../gmail/nossr50/datatypes/skills/SubSkillType.java | 1 - .../nossr50/datatypes/skills/interfaces/Skill.java | 12 ------------ .../datatypes/skills/subskills/acrobatics/Roll.java | 5 ----- .../skills/secondaryabilities/SubSkillEvent.java | 1 - .../com/gmail/nossr50/listeners/PlayerListener.java | 1 - src/main/java/com/gmail/nossr50/mcMMO.java | 2 -- .../com/gmail/nossr50/skills/alchemy/Alchemy.java | 2 -- src/main/java/com/gmail/nossr50/util/EventUtils.java | 1 - .../nossr50/util/blockmeta/ChunkManagerFactory.java | 5 ++--- src/main/resources/persistent_data.yml | 7 ++++++- .../database/FlatFileDatabaseManagerTest.java | 2 -- 15 files changed, 15 insertions(+), 37 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index a8a6d90af..fdfa4aa63 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,4 +1,6 @@ Version 2.1.189 + The setting to disable the mcMMO user block tracker has been moved from our "hidden config" to persistent_data.yml + Added 'mcMMO_Region_System.Enabled' to persistent_data.yml (don't touch this setting unless you know what you are doing) Fixed a bug that would remove components from death messages when players were killed by mobs (thanks lexikiq) Removed MHD command (it didn't do anything for a while now) Removed UltraPermissions warning diff --git a/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java index 0c6436bf1..d3090f46b 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/MmoInfoCommand.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.commands.skills; -import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.listeners.InteractionManager; import com.gmail.nossr50.locale.LocaleLoader; diff --git a/src/main/java/com/gmail/nossr50/config/HiddenConfig.java b/src/main/java/com/gmail/nossr50/config/HiddenConfig.java index d4b646fd3..54cdf0ff0 100644 --- a/src/main/java/com/gmail/nossr50/config/HiddenConfig.java +++ b/src/main/java/com/gmail/nossr50/config/HiddenConfig.java @@ -9,7 +9,6 @@ public class HiddenConfig { private static HiddenConfig instance; private final String fileName; private YamlConfiguration config; - private boolean chunkletsEnabled; private int conversionRate; private boolean useEnchantmentBuffs; @@ -30,15 +29,11 @@ public class HiddenConfig { InputStreamReader reader = mcMMO.p.getResourceAsReader(fileName); if (reader != null) { config = YamlConfiguration.loadConfiguration(reader); - chunkletsEnabled = config.getBoolean("Options.Chunklets", true); conversionRate = config.getInt("Options.ConversionRate", 1); useEnchantmentBuffs = config.getBoolean("Options.EnchantmentBuffs", true); } } - public boolean getChunkletsEnabled() { - return chunkletsEnabled; - } public int getConversionRate() { return conversionRate; diff --git a/src/main/java/com/gmail/nossr50/config/PersistentDataConfig.java b/src/main/java/com/gmail/nossr50/config/PersistentDataConfig.java index 10a7adcfc..2f9a23066 100644 --- a/src/main/java/com/gmail/nossr50/config/PersistentDataConfig.java +++ b/src/main/java/com/gmail/nossr50/config/PersistentDataConfig.java @@ -34,4 +34,9 @@ public class PersistentDataConfig extends AutoUpdateConfigLoader { return config.getBoolean(key, false); } + public boolean useBlockTracker() { + return config.getBoolean("mcMMO_Region_System.Enabled", true); + } + + } \ No newline at end of file diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java index 44d98b789..fc3ad681f 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.datatypes.skills; -import com.gmail.nossr50.datatypes.skills.interfaces.Skill; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.text.StringUtils; diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Skill.java b/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Skill.java index e2fdd0457..68cf7180e 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Skill.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/interfaces/Skill.java @@ -1,18 +1,6 @@ package com.gmail.nossr50.datatypes.skills.interfaces; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -import com.gmail.nossr50.datatypes.skills.SubSkillType; -import com.gmail.nossr50.datatypes.skills.SuperAbilityType; -import com.gmail.nossr50.datatypes.skills.ToolType; -import com.gmail.nossr50.locale.LocaleLoader; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.skills.SkillManager; -import com.gmail.nossr50.util.text.StringUtils; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; - -import java.util.List; public interface Skill { /** diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java index 4ce3a8671..1a1c99fc9 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java @@ -7,11 +7,8 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; -import com.gmail.nossr50.datatypes.skills.SuperAbilityType; -import com.gmail.nossr50.datatypes.skills.ToolType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.EventUtils; import com.gmail.nossr50.util.ItemUtils; import com.gmail.nossr50.util.Permissions; @@ -31,14 +28,12 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.SoundCategory; import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.inventory.ItemStack; -import java.util.List; import java.util.Locale; public class Roll extends AcrobaticsSubSkill { diff --git a/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java b/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java index 7c0fb4ea9..7aefb003e 100644 --- a/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java +++ b/src/main/java/com/gmail/nossr50/events/skills/secondaryabilities/SubSkillEvent.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.events.skills.secondaryabilities; import com.gmail.nossr50.datatypes.skills.SubSkillType; -import com.gmail.nossr50.datatypes.skills.interfaces.Skill; import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.events.skills.McMMOPlayerSkillEvent; import com.gmail.nossr50.mcMMO; diff --git a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java index 74e155622..5bd715662 100644 --- a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java @@ -36,7 +36,6 @@ import org.bukkit.GameMode; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockState; -import org.bukkit.conversations.Conversation; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.*; import org.bukkit.entity.minecart.PoweredMinecart; diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index 766bd3b8a..719883444 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -9,9 +9,7 @@ import com.gmail.nossr50.config.mods.BlockConfigManager; import com.gmail.nossr50.config.mods.EntityConfigManager; import com.gmail.nossr50.config.mods.ToolConfigManager; import com.gmail.nossr50.config.skills.alchemy.PotionConfig; -import com.gmail.nossr50.config.skills.repair.RepairConfig; import com.gmail.nossr50.config.skills.repair.RepairConfigManager; -import com.gmail.nossr50.config.skills.salvage.SalvageConfig; import com.gmail.nossr50.config.skills.salvage.SalvageConfigManager; import com.gmail.nossr50.config.treasure.FishingTreasureConfig; import com.gmail.nossr50.config.treasure.TreasureConfig; diff --git a/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java b/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java index 8cb825f48..387a35550 100644 --- a/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java +++ b/src/main/java/com/gmail/nossr50/skills/alchemy/Alchemy.java @@ -1,9 +1,7 @@ package com.gmail.nossr50.skills.alchemy; -import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.skills.AlchemyBrewTask; -import com.gmail.nossr50.util.skills.RankUtils; import org.bukkit.Location; import java.util.ArrayList; diff --git a/src/main/java/com/gmail/nossr50/util/EventUtils.java b/src/main/java/com/gmail/nossr50/util/EventUtils.java index d97c1c0ad..e6d697852 100644 --- a/src/main/java/com/gmail/nossr50/util/EventUtils.java +++ b/src/main/java/com/gmail/nossr50/util/EventUtils.java @@ -8,7 +8,6 @@ import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; -import com.gmail.nossr50.datatypes.skills.interfaces.Skill; import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill; import com.gmail.nossr50.events.experience.McMMOPlayerLevelChangeEvent; import com.gmail.nossr50.events.experience.McMMOPlayerLevelDownEvent; diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/ChunkManagerFactory.java b/src/main/java/com/gmail/nossr50/util/blockmeta/ChunkManagerFactory.java index e2c47662e..a1e61fd5c 100644 --- a/src/main/java/com/gmail/nossr50/util/blockmeta/ChunkManagerFactory.java +++ b/src/main/java/com/gmail/nossr50/util/blockmeta/ChunkManagerFactory.java @@ -1,13 +1,12 @@ package com.gmail.nossr50.util.blockmeta; -import com.gmail.nossr50.config.HiddenConfig; +import com.gmail.nossr50.config.PersistentDataConfig; import org.jetbrains.annotations.NotNull; public class ChunkManagerFactory { public static @NotNull ChunkManager getChunkManager() { - HiddenConfig hConfig = HiddenConfig.getInstance(); - if (hConfig.getChunkletsEnabled()) { + if (PersistentDataConfig.getInstance().useBlockTracker()) { return new HashChunkManager(); } diff --git a/src/main/resources/persistent_data.yml b/src/main/resources/persistent_data.yml index 6b39879cd..8508ab84f 100644 --- a/src/main/resources/persistent_data.yml +++ b/src/main/resources/persistent_data.yml @@ -29,4 +29,9 @@ Persistent_Data: Saved_To_Disk: false # By default mcMMO gives 0 XP for this type of mob, not adjustable currently PLAYER_TAMED_MOB: - Saved_To_Disk: false \ No newline at end of file + Saved_To_Disk: false +# When players put down a block we track it, the system used to track player blocks is super efficient and has been coded extremely well +# It is never recommended to turn this off as it allows exploits such as player dupes etc +# We use our own file system for this outside of NBT which has been programmed to be lightning fast +mcMMO_Region_System: + Enabled: true \ No newline at end of file diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index f8eaa4ff2..57efb3381 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.database; import com.gmail.nossr50.TestUtil; -import com.gmail.nossr50.config.GeneralConfig; import com.google.common.io.Files; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -10,7 +9,6 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import java.io.*; From e7978a6ad9468d9e09a3bd528e95a91cb5a3576f Mon Sep 17 00:00:00 2001 From: lexikiq Date: Fri, 9 Apr 2021 10:59:42 -0400 Subject: [PATCH 10/57] Fix deaths from skeletons showing health bars (#4483) * Fix deaths from skeletons showing health bars * Ignore human attackers --- .../nossr50/listeners/PlayerListener.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java index 5bd715662..f487a09ef 100644 --- a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java @@ -121,8 +121,21 @@ public class PlayerListener implements Listener { // we only care about players as this is for fixing player death messages if (!(event.getEntity() instanceof Player)) return; - if (!(event.getDamager() instanceof LivingEntity)) + Player player = (Player) event.getEntity(); + + // get the attacker + LivingEntity attacker; + if (event.getDamager() instanceof LivingEntity) + attacker = (LivingEntity) event.getDamager(); + // attempt to find creator of a projectile + else if (event.getDamager() instanceof Projectile && ((Projectile) event.getDamager()).getShooter() instanceof LivingEntity) + attacker = (LivingEntity) ((Projectile) event.getDamager()).getShooter(); + else return; + + if (attacker instanceof HumanEntity) + return; + // world blacklist check if (WorldBlacklist.isWorldBlacklisted(event.getEntity().getWorld())) return; @@ -130,9 +143,6 @@ public class PlayerListener implements Listener { if (WorldGuardUtils.isWorldGuardLoaded() && !WorldGuardManager.getInstance().hasMainFlag((Player) event.getEntity())) return; - Player player = (Player) event.getEntity(); - LivingEntity attacker = (LivingEntity) event.getDamager(); - // we only want to handle player deaths if ((player.getHealth() - event.getFinalDamage()) > 0) return; From 6d057c577e7e91c163a57309d10b746926f576f0 Mon Sep 17 00:00:00 2001 From: Anseba <80766583+xAnseba@users.noreply.github.com> Date: Fri, 9 Apr 2021 18:37:21 +0200 Subject: [PATCH 11/57] Fixed minor mistakes in locale_de.properties (#4484) * Update locale_de.properties --- .../resources/locale/locale_de.properties | 140 +++++++++--------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/src/main/resources/locale/locale_de.properties b/src/main/resources/locale/locale_de.properties index 87cfc4240..74333581c 100644 --- a/src/main/resources/locale/locale_de.properties +++ b/src/main/resources/locale/locale_de.properties @@ -94,10 +94,10 @@ Broadcasts.LevelUpMilestone = &6(&amcMMO&6) {0}&7 hat nun Level &a{1}&7 mit der Chat.Channel.Off = &6(&amcMMO-Chat&6) &7Deine Nachrichten werden nicht l\u00E4nger automatisch an die spezifischen Kan\u00E4le versendet. Chat.Channel.On = &6(&amcMMO-Chat&6) &eDeine Nachrichten werden nun automatisch an den &a{0}&e Kanal gesendet. Chat.Identity.Console = &6* Konsole * -Chat.Spy.Party = &6[&eSPION&6-&a{2}&6] &r{0} &b\u2192�� &r{1} -Chat.Style.Admin = &b(A) &r{0} &b\u2192�� &r{1} -Chat.Style.Party = &a(P) &r{0} &a\u2192�� &r{1} -Chat.Style.Party.Leader = &a(P) &r{0} &6\u2192�� &r{1} +Chat.Spy.Party = &6[&eSPION&6-&a{2}&6] &r{0} &b\u2192 &r{1} +Chat.Style.Admin = &b(A) &r{0} &b\u2192 &r{1} +Chat.Style.Party = &a(P) &r{0} &a\u2192 &r{1} +Chat.Style.Party.Leader = &a(P) &r{0} &6\u2192 &r{1} Combat.ArrowDeflect = &a&o**Pfeil abgelenkt** Combat.BeastLore = &a&o**Biestkunde** @@ -112,9 +112,9 @@ Combat.TouchedFuzzy = &a&o**Du wurdest ungl\u00FCcklich ber\u00FChrt, ein Schwin Commands.Ability.Off = F\u00E4higkeiten Benutzung &cdeaktiviert Commands.Ability.On = F\u00E4higkeiten Benutzung &aaktiviert -Commands.Ability.Toggle = Benutzung von F\u00E4higkeiten wurde f\u00FCr &e{0} ge\u00E4ndert -Commands.AdminChat.Off = Exklusiver Admin-Chat wurde &c deaktiviert -Commands.AdminChat.On = Exklusiver Admin-Chat wurde &a aktiviert +Commands.Ability.Toggle = Benutzung von F\u00E4higkeiten wurde f\u00FCr &e{0} ge\u00E4ndert. +Commands.AdminChat.Off = Exklusiver Admin-Chat wurde &c deaktiviert. +Commands.AdminChat.On = Exklusiver Admin-Chat wurde &a aktiviert. Commands.AdminChatSpy.Chat = &6[Spy: &a{0}&6] &f{1} Commands.AdminChatSpy.Disabled = mcMMO Party Chat-Spy deaktiviert Commands.AdminChatSpy.Enabled = mcMMO Party Chat-Spy aktiviert @@ -137,7 +137,7 @@ Commands.Description.mcability = Schalte die Bereitschaft von F\u00E4higkeiten b Commands.Description.mcchatspy = Schalte den Party Chat-Spy an oder aus. Commands.Description.mcconvert = Konvertiert Datenbanktypen oder Erfahrungsformeln. Commands.Description.mccooldown = Sieh alle F\u00E4higkeiten-Cooldowns. -Commands.Description.mcgod = Schalte mcMMO godmode an oder aus. +Commands.Description.mcgod = Schalte mcMMO Godmode an oder aus. Commands.Description.mchud = \u00C4ndere deinen HUD Stil. Commands.Description.mcmmo = Zeige eine kurze Beschreibung \u00FCber mcMMO. Commands.Description.mcnotify = Schalte F\u00E4higkeiten-Hinweise im Chat an oder aus. @@ -151,7 +151,7 @@ Commands.Description.mctop = Zeige die Skill-Bestenlisten. Commands.Description.mmocompat = Informationen dar\u00FCber, ob mcMMO im Kompatibilit\u00E4tsmodus oder voll funktionsf\u00E4hig ist. Commands.Description.mmodebug = (De)aktiviere den Debugging-Modus, welcher n\u00FCtzliche Informationen ausgibt, wenn du einen Block schl\u00E4gst. Commands.Description.mmoedit = Editiere die Skill-Level eines Spielers. -Commands.Description.mmoinfo = Lese Details \u00FCber einen Skill oder andere Funktionen. +Commands.Description.mmoinfo = Zeige Details \u00FCber einen Skill oder andere Funktionen. Commands.Description.mmoshowdb = Zeige den Namen der aktuellen Datenbank (zur Benutzung mit /mmoupdate). Commands.Description.mmoupdate = Kopiere Daten von einer alten Datenbank zur aktuell benutzen. Commands.Description.mmoxpbar = Spielereinstellungen f\u00FCr die mcMMO Erfahrungsleisten. @@ -174,7 +174,7 @@ Commands.GodMode.Forbidden = [mcMMO] Der Godmode ist in dieser Welt nicht erlaub Commands.GodMode.Toggle = Godmode wurde f\u00FCr &e{0} aktiviert. Commands.Healthbars.Changed.BAR = [mcMMO] Deine Lebensanzeige wurde zu &eK\u00E4stchen&f ge\u00E4ndert. Commands.Healthbars.Changed.DISABLED = [mcMMO] Die Mob-Lebensanzeige wurde &7deaktiviert&f. -Commands.Healthbars.Changed.HEARTS = [mcMMO]Deine Lebensanzeige wurde zu &cHerzen&f ge\u00E4ndert. +Commands.Healthbars.Changed.HEARTS = [mcMMO] Deine Lebensanzeige wurde zu &cHerzen&f ge\u00E4ndert. Commands.Healthbars.Invalid = Ung\u00FCltiger Lebensanzeige-Typ! Commands.Inspect = &a- Siehe detaillierte Spielerinformationen Commands.Invite.Success = &aEinladung erfolgreich gesendet. @@ -184,25 +184,25 @@ Commands.MmoInfo.Header = &3-=[]=====[]&6 MMO Info &3[]=====[]=- Commands.MmoInfo.Mechanics = &3-=[]=====[]&6 Funktionen &3[]=====[]=- Commands.MmoInfo.Mystery = &7Diese F\u00E4higkeit hast du noch nicht freigeschaltet, wenn du das tust, kannst du hier Details \u00FCber diese finden! Commands.MmoInfo.NoMatch = Diese F\u00E4higkeit existiert nicht! -Commands.MmoInfo.OldSkill = &7mcMMO skills are being converted into an improved modular skill system, unfortunately this skill has not been converted yet and lacks detailed stats. The new system will allow for faster release times for new mcMMO skills and greater flexibility with existing skills. -Commands.MmoInfo.Stats = STATS: {0} +Commands.MmoInfo.OldSkill = &7mcMMO Skills werden in ein verbessertes und modulares Skill-System konvertiert - wovon dieser Skill jedoch noch nicht betroffen ist, weswegen detaillierte Statistiken fehlen. Das neue System erm\u00F6glicht eine schnellere Ver\u00F6ffentlichung neuer mcMMO-Skills und eine gr\u00F6ßere Flexibilit\u00E4t mit bereits existenten Skills. +Commands.MmoInfo.Stats = Statistik: {0} Commands.MmoInfo.SubSkillHeader = &6Name:&e {0} Commands.Mmodebug.Toggle = Der mcMMO Debugging-Modus ist nun &6{0}&7, benutze den Befehl erneut, um dies r\u00FCckg\u00E4ngig zu machen. Wenn der Debugging-Modus aktiviert wurde kannst du Bl\u00F6cke schlagen, um n\u00FCtzliche Informationen zu erhalten. Dies ist f\u00FCr den Support sehr n\u00FCtzlich. Commands.ModDescription = &a- Kurze Modbeschreibung Commands.NegativeNumberWarn = Benutze keine negativen Zahlen! Commands.NoConsole = Dieser Befehl kann nicht aus der Konsole verwendet werden. Commands.NotLoaded = Spielerprofil wurde noch nicht geladen. -Commands.Notifications.Off = F\u00E4higkeiten Hinweise wurden &cdeaktiviert -Commands.Notifications.On = F\u00E4higkeiten Hinweise wurden &aaktiviert +Commands.Notifications.Off = F\u00E4higkeiten Hinweise wurden &cdeaktiviert. +Commands.Notifications.On = F\u00E4higkeiten Hinweise wurden &aaktiviert. Commands.Offline = Dieser Befehl funktioniert nur bei eingeloggten Spielern. Commands.Other = ---[]&aBesondere Befehle&c[]--- Commands.Party.Accept = &a- Nimm Party-Einladung an Commands.Party.Alliance.Ally = &f{0} &8Ist verb\u00FCndet mit: &f{1} -Commands.Party.Alliance.AlreadyAllies = Deine Party ist bereits in einem B\u00FCndnis. Trenne es mit&3/party alliance disband +Commands.Party.Alliance.AlreadyAllies = Deine Party ist bereits in einem B\u00FCndnis. Trenne es mit&3/party alliance disband&e. Commands.Party.Alliance.Header = -----[]&aParty-B\u00FCndnisse&c[]----- Commands.Party.Alliance.Help.0 = Diese Party ist in keinem B\u00FCndnis. Lade einen Party-Anf\u00FChrer ein. -Commands.Party.Alliance.Help.1 = &c um zu verb\u00FCnden &3/party alliance invite &c. -Commands.Party.Alliance.Invite.0 = ALERT: &aDu hast eine B\u00FCndnis-Anfrage f\u00FCr {0} von {1} erhalten. +Commands.Party.Alliance.Help.1 = &c Zum Verb\u00FCnden: &3/party alliance invite &c. +Commands.Party.Alliance.Invite.0 = ACHTUNG: &aDu hast eine B\u00FCndnis-Anfrage f\u00FCr {0} von {1} erhalten. Commands.Party.Alliance.Invite.1 = Tippe &a/party alliance accept&e um die Anfrage anzunehmen. Commands.Party.Alliance.Invite.Accepted = &aB\u00FCndnis-Anfrage angenommen Commands.Party.Alliance.Members.Header = -----[]&aB\u00FCndnis-Mitglieder&c[]----- @@ -216,7 +216,7 @@ Commands.Party.ExpShare = &7Erfahrung &3({0}) Commands.Party.Features.Header = -----[]&aFunktionen&c[]----- Commands.Party.Header = &c-----[]&aParty&c[]----- Commands.Party.Invite = &a- Sende eine Party-Einladung -Commands.Party.Invite.0 = ALERT: &aDu hast eine Party-Einladung f\u00FCr {0} von {1} erhalten. +Commands.Party.Invite.0 = ACHTUNG: &aDu hast eine Party-Einladung f\u00FCr {0} von {1} erhalten. Commands.Party.Invite.1 = &eBenutze &a/party accept&e um die Einladung anzunehmen. Commands.Party.Invite.Accepted = &aEinladung angenommen. Du bist der {0} Party beigetreten. Commands.Party.ItemShare = &7Item &3({0}) @@ -231,7 +231,7 @@ Commands.Party.PartyFull = &6{0}&c ist voll! Commands.Party.PartyFull.Invite = Du kannst &e{0}&c nicht zur Party &a{1}&c einladen, weil sie schon &3{2}&c Spieler hat! Commands.Party.PartyFull.InviteAccept = Du kannst der Party &a{0}&c nicht beitreten, weil sie schon &3{1}&c Spieler hat! Commands.Party.Quit = &a- Verlasse deine aktuelle Party. -Commands.Party.Rename = &7Party Name wurde zu &f{0} &7ver\u00E4ndert +Commands.Party.Rename = &7Party Name wurde zu &f{0} &7ver\u00E4ndert. Commands.Party.SetSharing = &7Party {0} teilen: &3{1} Commands.Party.ShareMode = &8Teilen-Modus: Commands.Party.Status = &8Name: &f{0} {1} &8Level: &3{2} @@ -245,11 +245,11 @@ Commands.Party2 = &a- Tritt der Party eines Spielers bei. Commands.PowerLevel = &4Gesamtlevel: &a{0} Commands.PowerLevel.Capped = &4Gesamtlevel: &a{0} &4H\u00F6chstlevel: &e{1} Commands.PowerLevel.Leaderboard = --mcMMO&9 Power-Level &eBestenliste-- -Commands.Reset = &a- Setze ein Skilllevel auf 0 -Commands.Reset.All = &aAlle deine Skilllevel wurden erfolgreich zur\u00FCckgesetzt. -Commands.Reset.Single = &aDein {0} Skilllevel wurde erfolgreich zur\u00FCckgesetzt. +Commands.Reset = &a- Setze ein Skill-Level auf 0 +Commands.Reset.All = &aAlle deine Skill-Level wurden erfolgreich zur\u00FCckgesetzt. +Commands.Reset.Single = &aDein {0} Skill-Level wurde erfolgreich zur\u00FCckgesetzt. Commands.Scoreboard.Clear = &3Das Scoreboard wurde ausgeblendet. -Commands.Scoreboard.Help.0 = &6 == &aHilfe f\u00FCr&c/mcscoreboard&6 == +Commands.Scoreboard.Help.0 = &6 == &aHilfe f\u00FCr&c /mcscoreboard&6 == Commands.Scoreboard.Help.1 = &3/mcscoreboard&b clear &f - blende die \u00DCbersicht aus Commands.Scoreboard.Help.2 = &3/mcscoreboard&b keep &f - behalte die \u00DCbersicht offen Commands.Scoreboard.Help.3 = &3/mcscoreboard&b time [n] &f - blende die \u00DCbersicht nach &dn&f Sekunden aus @@ -281,10 +281,10 @@ Commands.Usage.Rate = Rate Commands.Usage.Skill = Skill Commands.Usage.SubSkill = F\u00E4higkeit Commands.Usage.XP = Erfahrung -Commands.XPBar.DisableAll = &6Alle mcMMO Erfahrungsleisten wurden deaktiviert, benutze /mmoxpbar reset um die Standardeinstellungen wiederherzustellen. +Commands.XPBar.DisableAll = &6Alle mcMMO Erfahrungsleisten wurden deaktiviert, benutze &c/mmoxpbar reset&6 um die Standardeinstellungen wiederherzustellen. Commands.XPBar.Reset = &6Die Erfahrungsleisten-Einstellungen f\u00FCr mcMMO wurden zur\u00FCckgesetzt. Commands.XPBar.SettingChanged = &6Die Erfahrungsleisten-Einstellungen f\u00FCr &a{0}&6 wurden gesetzt auf: &a{1} -Commands.XPBar.Usage = Die korrekte Verwendung ist /mmoxpbar +Commands.XPBar.Usage = Die korrekte Verwendung ist &a/mmoxpbar Commands.XPGain = &8XP-Zuwachs: &f{0} Commands.XPGain.Acrobatics = Fallen Commands.XPGain.Alchemy = Tr\u00E4nke brauen @@ -316,7 +316,7 @@ Commands.mcconvert.Experience.Finish = &7Konvertierung vollendet - es wird jetzt Commands.mcconvert.Experience.Invalid = Unbekannter Formeltyp! G\u00FCltige Typen sind: &aLINEAR &cund &aEXPONENTIAL. Commands.mcconvert.Experience.Same = Formeltyp {0} wird bereits verwendet. Commands.mcconvert.Experience.Start = &7Beginne Konvertierung von Kurve {0} zu Kurve {1}. -Commands.mcgod = &a- Schalte Godmode um +Commands.mcgod = &a- Schalte den Godmode um Commands.mchud.Invalid = Das ist kein g\u00FCltiger HUD Typ. Commands.mcpurge.Success = &aDie Datenbank wurde erfolgreich ges\u00E4ubert! Commands.mcrank.Heading = &6-=Pers\u00F6nliche Rangliste=- @@ -339,19 +339,19 @@ Commands.ptp.Enabled = Party-Teleportierung &aaktiviert Commands.ptp.NoRequests = Du hast aktuell keine Teleportierungsanfragen. Commands.ptp.NoWorldPermissions = &c[mcMMO] Du hast nicht die n\u00F6tigen Rechte um dich in die Welt {0} zu teleportieren. Commands.ptp.Request1 = {0} &am\u00F6chte sich zu dir teleportieren. -Commands.ptp.Request2 = &aUm zu teleportieren tippe &e/ptp accept&a. Die Anfrage l\u00E4uft in &c{0} &aSekunden aus. +Commands.ptp.Request2 = &aZum Teleportieren tippe &e/ptp accept&a. Die Anfrage l\u00E4uft in &c{0} &aSekunden aus. Commands.ptp.RequestExpired = &cParty-Teleportierungsanfrage ist ausgelaufen. Commands.xplock.locked = &6Deine Erfahrungsanzeige ist nun auf {0} festgesetzt! Commands.xplock.unlocked = &6Deine Erfahrungsanzeige ist nun wieder &afreigeschaltet&6! Commands.xprate.modified = Die Erfahrungsrate wurde auf {0} gesetzt! Commands.xprate.over = Das Bonuserfahrungs-Event f\u00FCr Skills ist vor\u00FCber! -Commands.xprate.proper.0 = &cKorrekte Eingabe f\u00FCr Erfahrungs Raten Wechsel: /xprate -Commands.xprate.proper.1 = &cKorrekte Eingabe f\u00FCr R\u00FCcksetzung auf Standard Erfahrungs Rate: /xprate reset +Commands.xprate.proper.0 = &cKorrekte Eingabe f\u00FCr Erfahrungsratenwechsel: /xprate +Commands.xprate.proper.1 = &cKorrekte Eingabe f\u00FCr R\u00FCcksetzung auf Standard-Erfahrungsrate: /xprate reset Commands.xprate.proper.2 = &cBitte entscheide mit true/false ob dies ein XP-Event ist oder nicht. Commands.xprate.started.0 = &6Ein Bonuserfahrungs-Event f\u00FCr Skills hat begonnen! Commands.xprate.started.1 = &6Die Erfahrungsrate f\u00FCr Skills liegt jetzt bei {0}x! -Compatibility.Layer.PartialSupport = &6Diese Version besitzt keine vollst\u00E4ndige Unterst\u00FCtzung f\u00FCr &a{0}&6, jedoch verwendet mcMMO ein System, was die fehlenden Features versucht zu emulieren. +Compatibility.Layer.PartialSupport = &6Diese Version besitzt keine vollst\u00E4ndige Unterst\u00FCtzung f\u00FCr &a{0}&6, jedoch verwendet mcMMO ein System, welches versucht die fehlenden Features zu emulieren. Compatibility.Layer.Unsupported = &6Diese Version von Minecraft ist nicht kompatibel mit &a{0}&6. Effects.Child.Overhaul = &3Unterskill Level&e {0}&3: {1} @@ -375,7 +375,7 @@ Excavation.SubSkill.Archaeology.Description = Ergrabe die Sch\u00E4tze der Unter Excavation.SubSkill.Archaeology.Name = Arch\u00E4ologie Excavation.SubSkill.Archaeology.Stat = Arch\u00E4ologie Erfahrungspunkte-Chance Excavation.SubSkill.Archaeology.Stat.Extra = Arch\u00E4ologie Erfahrungspunkte-Anzahl -Excavation.SubSkill.GigaDrillBreaker.Description = Dreifache Droprate, dreifache Erfahrung und Bonus-Geschwindigkeit. +Excavation.SubSkill.GigaDrillBreaker.Description = Dreifache Droprate, dreifache Erfahrung und Bonus-Abbaugeschwindigkeit. Excavation.SubSkill.GigaDrillBreaker.Name = Gigabohrer Excavation.SubSkill.GigaDrillBreaker.Stat = Gigabohrer-Dauer @@ -395,8 +395,8 @@ Fishing.Scared = &7&oHektische Bewegungen ver\u00E4ngstigen Fische! Fishing.SkillName = Angeln Fishing.SubSkill.FishermansDiet.Description = Verbessert den N\u00E4hrwert von geangelter Nahrung. Fishing.SubSkill.FishermansDiet.Name = Fischers-Di\u00E4t -Fishing.SubSkill.FishermansDiet.Stat = Fishers-Di\u00E4t:&a Rang {0} -Fishing.SubSkill.IceFishing.Description = Erm\u00F6glicht dir in Eisbiomen zu angeln. +Fishing.SubSkill.FishermansDiet.Stat = Fischers-Di\u00E4t:&a Rang {0} +Fishing.SubSkill.IceFishing.Description = Erm\u00F6glicht es dir in Eisbiomen zu angeln. Fishing.SubSkill.IceFishing.Name = Eisangeln Fishing.SubSkill.IceFishing.Stat = Eisangeln Fishing.SubSkill.MagicHunter.Description = Finde verzauberte Gegenst\u00E4nde. @@ -406,7 +406,7 @@ Fishing.SubSkill.MasterAngler.Description = Fische k\u00F6nnen h\u00E4ufiger gef Fishing.SubSkill.MasterAngler.Name = Superangel Fishing.SubSkill.MasterAngler.Stat = Mindestwartezeit beim Angeln reduziert um: &a-{0} Sekunden Fishing.SubSkill.MasterAngler.Stat.Extra = Maximalwartezeit beim Angeln reduziert um: &a-{0} Sekunden -Fishing.SubSkill.Shake.Description = Rei\u00DFe mit deiner Angel Gegenst\u00E4nde weg von Lebewesen und Spielern. +Fishing.SubSkill.Shake.Description = Entrei\u00DFe Lebewesen und Spielern mit deiner Angel Gegenst\u00E4nde. Fishing.SubSkill.Shake.Name = Rei\u00DFen Fishing.SubSkill.Shake.Stat = Rei\u00DFen Chance Fishing.SubSkill.TreasureHunter.Description = Angle verschiedene Objekte. @@ -414,10 +414,10 @@ Fishing.SubSkill.TreasureHunter.Name = Schatz-J\u00E4ger Fishing.SubSkill.TreasureHunter.Stat = Schatz-J\u00E4ger Rang: &a{0}&3/&a{1} Fishing.SubSkill.TreasureHunter.Stat.Extra = Drop-Rate: &7\u00DCblich: &e{0} &aUn\u00FCblich: &e{1}\n&9Selten: &e{2} &dEpisch: &e{3} &6Legend\u00E4r: &e{4} &bMythic: &e{5} -Guides.Acrobatics.Section.0 = &3\u00DCber Akrobatik:\n&eAkrobatik ist die Kunst sich anmutig fortzubewegen.\n&eFall- und Kampfschaden werden reduziert\n\n&3XP GAIN:\n&eErfahrung sammelst du indem du in K\u00E4mpfen\n&eausweichst oder St\u00FCrze aus gro\u00DFen H\u00F6hen \u00FCberlebst. +Guides.Acrobatics.Section.0 = &3\u00DCber Akrobatik:\n&eAkrobatik ist die Kunst sich anmutig fortzubewegen.\n&eFall- und Kampfschaden werden reduziert.\n\n&3XP-Zuwachs:\n&eErfahrung sammelst du indem du in K\u00E4mpfen\n&eausweichst oder St\u00FCrze aus gro\u00DFen H\u00F6hen \u00FCberlebst. Guides.Acrobatics.Section.1 = &3Wie funktioniert Abrollen?\n&eAb und zu rollst du beim Fallen ab und der Fallschaden wird\n&ereduziert. Wenn du die Schleichen-Taste w\u00E4hrend dem Fallen\n&eh\u00E4ltst, verdoppelt sich die Chance abzurollen.\n&eIn dem Fall rollst du anmutig ab.\n&eAnmutige Rollen sind wie normale Rollen, nur dass\n&esie \u00F6fter passieren und damit mehr Schutz vor St\u00FCrzen\n&eliefern. Guides.Acrobatics.Section.2 = &3Wie funktioniert Ausweichen?\n&eAusweichen ist eine passive F\u00E4higkeit\n&edie ab und zu den Schaden in K\u00E4mpfen halbiert.\n&eDie Chance auszuweichen ist abh\u00E4ngig vom \n&eAkrobatiklevel. -Guides.Alchemy.Section.0 = &3\u00DCber Alchemie:\n&eIn Alchemie musst du Tr\u00E4nke brauen.\n&eMit h\u00F6herem Level werden die Tr\u00E4nke schneller\n&egebraut und neue Zutaten f\u00FCr zun\u00E4chst unerh\u00E4ltliche Tr\u00E4nke \n&efreigeschaltet.\n\n&3XP ZUWACHS:\n&eTr\u00E4nke brauen. +Guides.Alchemy.Section.0 = &3\u00DCber Alchemie:\n&eIn Alchemie musst du Tr\u00E4nke brauen.\n&eMit h\u00F6herem Level werden die Tr\u00E4nke schneller\n&egebraut und neue Zutaten f\u00FCr zun\u00E4chst unerh\u00E4ltliche Tr\u00E4nke \n&efreigeschaltet.\n\n&3XP-Zuwachs:\n&eTr\u00E4nke brauen. Guides.Alchemy.Section.1 = &3Wie funktioniert Katalyse?\n&eKatalyse beschleunigt das Brauen von Tr\u00E4nken bis\n&ezu 4-facher Geschwindigkeit bei Level 1000. Guides.Alchemy.Section.2 = &3Wie funktioniert Gebr\u00E4u?\n&eGebr\u00E4u erm\u00F6glich das Brauen weiterer Tr\u00E4nke mit neuen\n&eZutaten.\n&eWelche Zutaten m\u00F6glich sind, h\u00E4ngt vom Rang ab.\n&eInsgesamt gibt es 8 R\u00E4nge freizuschalten. Guides.Alchemy.Section.3 = &3Gebr\u00E4u Tier 1 Zutaten:\n&eLohnenstaub, Fermentierte Spinnenaugen, Ghast Tr\u00E4nen,\n&eRedstone, Glowstonestaub, Zucker, Glitzernde Melone,\n&eGoldene Karotte, Magma Creme, Netherwarzen, Spinnenaugen, \n&eSchwarzpulver, Seerose, Kugelfisch (Vanilla Tr\u00E4nke) @@ -425,23 +425,23 @@ Guides.Alchemy.Section.4 = &3Gebr\u00E4u Tier 2 Zutaten:\n&eKarotte (Eile)\n&eSc Guides.Alchemy.Section.5 = &3Gebr\u00E4u Tier 4 Zutaten:\n&eApfel (Gesundheitsboost)\n&eVerrottetes Fleisch (Hunger)\n\n&3Gebr\u00E4u Tier 5 Zutaten:\n&eBrauner Pilz(\u00DCbelkeit)\n&eTintensack (Blindheit) Guides.Alchemy.Section.6 = &3Gebr\u00E4u Tier 6 Zutaten:\n&eGras (S\u00E4ttigung)\n\n&3Gebr\u00E4u Tier 7 Zutaten:\n&eGiftige Kartoffel (Verwesung)\n\n&3Gebr\u00E4u Tier 8 Zutaten:\n&eNormaler Goldener Apfel (Resistenz) Guides.Archery.Section.0 = &3\u00DCber Bogenschie\u00DFen:\n&eIn Bogenschie\u00DFen geht es um die Verwendung von Pfeil und\n&eBogen.\n\n&eEs gibt unterschiedliche Kampfboni, wie Zusatzschaden,\n&eder mit dem Level steigt und der F\u00E4higkeit Feinde im PVP\n&ezu bet\u00E4uben. Zus\u00E4tzlich kannst du einige verschossene\n&ePfeile aus den Leichen deiner Feinde wiedergewinnen. -Guides.Archery.Section.1 = &3XP ZUWACHS:\n&eXP erh\u00E4ltst du durch das Abschie\u00DFen von Monstern und\n&eanderen Spielern. +Guides.Archery.Section.1 = &3XP-Zuwachs:\n&eXP erh\u00E4ltst du durch das Abschie\u00DFen von Monstern und\n&eanderen Spielern. Guides.Archery.Section.2 = &3Wie funktioniert der Kunstschuss?\n&eKunstschuss erh\u00F6ht den Schaden deines Schusses.\n&eDer Zusatzschaden steigt mit deinem Bogen-Level.\n&eIn den Standardeinstellungen steigt der Schaden um 10%\n&ealle 50 Level, mit einem Maximum von 200% extra. Guides.Archery.Section.3 = &3Wie Funktioniert Bet\u00E4ubung?\n&eDu hast eine passive Chance andere Spieler\n&ezu bet\u00E4uben wenn du sie anschie\u00DFt. Der Spieler wird\n&egezwungen f\u00FCr eine kurze Weile senkrecht nach oben zu\n&eschauen.\n&eEin Bet\u00E4ubungsschuss f\u00FCgt au\u00DFerdem 4 Schadenspunkte \n&e(2 Herzen) extra zu. Guides.Available = &7Anleitung f\u00FCr {0} vorhanden - tippe /{1} ? [Seite] Guides.Axes.Section.0 = &3\u00DCber Axt:\n&eMit dem Axt-Skill kannst du die Axt f\u00FCr viel mehr als\n&enur abholzen verwenden! Du kannst Monster und Spieler\n&esprichw\u00F6rtlich weghacken und ihnen t\u00F6dliche\n&eSchl\u00E4ge verpassen oder sie zur\u00FCckweichen lassen.\n&eDeine Axt zerst\u00F6rt au\u00DFerdem sehr gut R\u00FCstungen,\n&ewas mit h\u00F6herem Level noch mehr ansteigt. -Guides.Axes.Section.1 = &3XP ZUWACHS:\n&eUm XP zu bekommen musst du Spieler oder Monster \n&emit einer Axt schlagen. +Guides.Axes.Section.1 = &3XP-Zuwachs:\n&eUm XP zu bekommen musst du Spieler oder Monster \n&emit einer Axt schlagen. Guides.Axes.Section.2 = &3Wie funktioniert der Sch\u00E4delspalter?\n&eDiese F\u00E4higkeit erlaubt dir einen Angriff mit Fl\u00E4chenschaden\n&eauszuf\u00FChren.\n&eDer Fl\u00E4chenschaden ist halb so gro\u00DF wie der \n&eHauptangriff, also perfekt f\u00FCr gro\u00DFe Ansammlungen von Mobs. -Guides.Axes.Section.3 = &3Wie funktionieren kritische Treffer?\n&eKritische Treffer sind eine passive F\u00E4higkeit\n&edie ab und zu Zusatzschaden zuf\u00FCgen.\n&eIn den Standardeinstellungen wird alle 2 Level \n&edie Chance um 0.1% erh\u00F6ht. Das f\u00FCgt Mobs\n&edoppelten und anderen Spielern 1,5 fachen Schaden zu. +Guides.Axes.Section.3 = &3Wie funktionieren kritische Treffer?\n&eKritische Treffer sind eine passive F\u00E4higkeit\n&edie ab und zu Zusatzschaden zuf\u00FCgen.\n&eIn den Standardeinstellungen wird alle 2 Level \n&edie Chance um 0.1% erh\u00F6ht. Das f\u00FCgt Mobs\n&edoppelten und anderen Spielern 1,5-fachen Schaden zu. Guides.Axes.Section.4 = &3Wie funktioniert die Axt-Beherrschung?\n&eAxt-Beherrschung ist eine passive F\u00E4higkeit die deinen\n&eAxt-Schl\u00E4gen Zusatzschaden hinzuf\u00FCgt.\n&eStandardm\u00E4\u00DFig steigt der Schaden um 1 alle 50 Level,\n&emaximal auf 4 Extraschaden bei Level 200. Guides.Axes.Section.5 = &3Wie funktioniert Wucht?\n&eSchlage m\u00E4chtig zu und zerst\u00F6re R\u00FCstungen!\n&eWucht hat eine passive Chance gegnerische\n&eR\u00FCstung zu besch\u00E4digen. Dieser Schaden steigt mit deinem Axt-\n&eLevel. -Guides.Excavation.Section.0 = &3\u00DCber Graben:\n&eGraben ist die F\u00E4higkeit Sch\u00E4tze im Dreck zu finden.\n&eDurch Aufgraben des Landes wirst du Sch\u00E4tze finden.\n&eJe l\u00E4nger du das tust, desto mehr Sch\u00E4tze findest du.\n\n&3XP ZUWACHS:\n&eXP erh\u00E4ltst du durch Schaufeln.\n&eNur bestimmte Materialen geben XP und Sch\u00E4tze. +Guides.Excavation.Section.0 = &3\u00DCber Graben:\n&eGraben ist die F\u00E4higkeit Sch\u00E4tze im Dreck zu finden.\n&eDurch Aufgraben des Landes wirst du Sch\u00E4tze finden.\n&eJe l\u00E4nger du das tust, desto mehr Sch\u00E4tze findest du.\n\n&3XP-Zuwachs:\n&eXP erh\u00E4ltst du durch Schaufeln.\n&eNur bestimmte Materialen geben XP und Sch\u00E4tze. Guides.Excavation.Section.1 = &3Kompatible Materialien:\n&eGras, Erde, Sand, Lehm, Kies, Myzel, Seelensand, Schnee Guides.Excavation.Section.2 = &3Wie funktioniert der Giga-Bohrer?\n&eHalte eine Schaufel in der Hand und mach Rechtsklick.\n&eVon nun an hast du ca. 4 Sekunden um einen kompatiblem\n&eBlock abzubauen.\n&eDaraufhin wird der Giga-Bohrer aktiviert. Guides.Excavation.Section.3 = &3Was ist der Giga-Bohrer?\n&eGiga-Bohrer ist eine F\u00E4higkeit deren Dauer vom Graben-Skill\n&eabh\u00E4ngt.\n&eEs verdreifacht die Chance Sch\u00E4tze zu finden\n&eund erm\u00F6glicht sofortiges Abbauen kompatibler Materialien. Guides.Excavation.Section.4 = &3Wie funktioniert der Schatz-J\u00E4ger?\n&eJeder m\u00F6gliche Schatz hat seine eigene Level-Voraussetzung\n&eum zu erscheinen, folglich ist es schwer&ezu sagen inwiefern es \n&edir hilft ein h\u00F6heres Level zu haben.\n&eJe h\u00F6her das Level, desto mehr Sch\u00E4tze k\u00F6nnen gefunden\n&ewerden. Guides.Excavation.Section.5 = Beachte au\u00DFerdem, dass jedes kompatible Material seine\n&eeigenen einzigartigen Sch\u00E4tze hat.\n&eAnders ausgedr\u00FCckt: Sch\u00E4tze die du in Kies findest\n&egibt es nicht zwingend in Erde. -Guides.Fishing.Section.0 = &3\u00DCber Angeln:\n&eMit dem Angeln-Skill ist Angeln wieder aufregend!\n&eFinde versteckte Sch\u00E4tze oder rei\u00DFe Items von Monstern.\n\n&3XP ZUWACHS:\n&eFang Fische. +Guides.Fishing.Section.0 = &3\u00DCber Angeln:\n&eMit dem Angeln-Skill ist Angeln wieder aufregend!\n&eFinde versteckte Sch\u00E4tze oder rei\u00DFe Items von Monstern.\n\n&3XP-Zuwachs:\n&eFange Fische. Guides.Fishing.Section.1 = &3Wie funktioniert der Schatz-J\u00E4ger?\n&eMit dieser F\u00E4higkeit kannst du beim Angeln Sch\u00E4tze finden.\n&eDiese k\u00F6nnen sogar verzaubert sein!\n&eJeder m\u00F6gliche Schatz kann mit jedem Level gefunden\n&ewerden. Die H\u00E4ufigkeit h\u00E4ngt von dem Wert des Items ab.\n&eJe h\u00F6her der Angeln-Skill ist, desto einfacher wird es\n&ewertvolle Sch\u00E4tze zu finden. Guides.Fishing.Section.2 = &3Wie funktioniert Eisangeln?\n&eMit dieser F\u00E4higkeit kannst du in Eisseen angeln!\n&eWirf deine Angeln in einem Eissee aus\n&eum ein kleines Loch zum Angeln zu erstellen. Guides.Fishing.Section.3 = &3Wie funktioniert die Profiangel?\n&eMit dieser passiven F\u00E4higkeit bei\u00DFen mehr Fische an.\n&eSobald die F\u00E4higkeit freigeschaltet ist bringt das Angeln\n&ein einem Boot oder Ozean die doppelte \n&eAnbei\u00DFchance. @@ -449,15 +449,15 @@ Guides.Fishing.Section.4 = &3Wie funktioniert Rei\u00DFen?\n&eDiese F\u00E4higke Guides.Fishing.Section.5 = &3Wie funktioniert die Fischer-Mahlzeit?\n&eDu wirst beim Essen von Fisch besser satt. Guides.Fishing.Section.6 = &3Bemerkung zum Angeln:\n&eAngel-Drops sind vollkommen anpassbar.\n&eErgebnisse unterscheiden sich deshalb von Server zu Server. Guides.Header = &6-=&a{0} Anleitung&6=- -Guides.Herbalism.Section.0 = &3\u00DCber Kr\u00E4uterkunde\n&eIn Kr\u00E4uterkunde geht es um das Ernten.\n\n&3XP ZUWACHS:\n&eErnte Pflanzen. +Guides.Herbalism.Section.0 = &3\u00DCber Kr\u00E4uterkunde\n&eIn Kr\u00E4uterkunde geht es um das Ernten.\n\n&3XP-Zuwachs:\n&eErnte Pflanzen. Guides.Herbalism.Section.1 = &3Kompatible Pflanzen:\n&eWeizen, Kartoffeln, Karotten, Melonen, K\u00FCrbisse,\n&eZuckerrohr, Kakaobohnen, Blumen, Kakteen,\n&ePilze, Netherwarzen, Seerosen und Ranken. Guides.Herbalism.Section.2 = &3Wie funktioniert Gr\u00FCnes Land?\n&eGr\u00FCnes Land ist eine aktive F\u00E4higkeit die du aktivierst indem du\n&emit einer Harke in der Hand rechtsklickst.\n&eGr\u00FCnes Land erm\u00F6glicht einen 3-fachen Ertrag beim Ernten.\n&eAu\u00DFerdem erm\u00F6glich es Leben einzuhauchen und sie\n&emithilfe von Samen aus dem Inventar zu verwandeln. Guides.Herbalism.Section.3 = &3Wie funktioniert der Gr\u00FCne Daumen (Samen)?\n&eDiese passive F\u00E4higkeit pflanz automatisch beim Ernten nach.\n&eDer Erfolg h\u00E4ngt vom Kr\u00E4uterkunde Level ab. -Guides.Herbalism.Section.4 = &3Wie funktioniert der Gr\u00FCne Daumen(Blocks)?\n&eDiese aktive F\u00E4higkeit erm\u00F6glich es Bl\u00F6cke in ihre \n&e"naturverwandte" Form zu verwandeln. Klicke dazu mit der\n&erechten Maustaste auf einen Block, w\u00E4hrend du Samen in\n&eder Hand h\u00E4ltst. \n&ePro Versuch kostet es dich einen Samen.\n&eDer Erfolg h\u00E4ngt vom Kr\u00E4uterkunde-Level ab. +Guides.Herbalism.Section.4 = &3Wie funktioniert der Gr\u00FCne Daumen (Bl\u00F6cke)?\n&eDiese aktive F\u00E4higkeit erm\u00F6glich es Bl\u00F6cke in ihre \n&e"naturverwandte" Form zu verwandeln. Klicke dazu mit der\n&erechten Maustaste auf einen Block, w\u00E4hrend du Samen in\n&eder Hand h\u00E4ltst. \n&ePro Versuch kostet es dich einen Samen.\n&eDer Erfolg h\u00E4ngt vom Kr\u00E4uterkunde-Level ab. Guides.Herbalism.Section.5 = &3Wie funktioniert das Bauernfr\u00FChst\u00FCck?\n&eDu wirst beim Essen von Brot, Keksen, Melonen, Pilzsuppe,\n&eKarotten und Kartoffeln satter. Guides.Herbalism.Section.6 = &3Wie funktioniert Hylians Gl\u00FCck?\n&eDiese passive F\u00E4higkeit gibt dir eine Chance Items zu finden\n&ewenn du bestimmte Bl\u00F6cke mit dem Schwert abbaust. Guides.Herbalism.Section.7 = &3Wie funktionieren Doppeldrops?\n&eDu erh\u00E4ltst beim Ernten mehr Ertrag. -Guides.Mining.Section.0 = &3\u00DCber Bergbau:\n&eIm Bergbau musst du Steine und Erze sammeln. Du erh\u00E4ltst\n&eab und zu zus\u00E4tzliche Drops.\n\n&3XP ZUWACHS:\n&eUm Erfahrung zu sammeln musst du mit der Spitzhacke abbauen.\n&eNur bestimmte Bl\u00F6cke geben XP. +Guides.Mining.Section.0 = &3\u00DCber Bergbau:\n&eIm Bergbau musst du Steine und Erze sammeln. Du erh\u00E4ltst\n&eab und zu zus\u00E4tzliche Drops.\n\n&3XP-Zuwachs:\n&eUm Erfahrung zu sammeln musst du mit der Spitzhacke abbauen.\n&eNur bestimmte Bl\u00F6cke geben XP. Guides.Mining.Section.1 = &3Kompatible Materialien:\n&eStein, Kohleerz, Eisenerz, Golderz, Diamanterz, Redstoneerz,\n&eLapiserz, Obsidian, Bemooster Bruchstein, Endstein,\n&eGlowstone, und Netherrack. Guides.Mining.Section.2 = &3Wie funktioniert der Super-Brecher?:\n&eMache einen Rechtsklick w\u00E4hrend du eine Spitzhacke in der\n&eHand h\u00E4ltst.\n&eVon nun an hast du ungef\u00E4hr 4 Sekunden um ein mit Bergbau\n&ekompatibles Material abzubauen, daraufhin wird der Super-Brecher\n&eaktiviert. Guides.Mining.Section.3 = &3Was ist der Super-Brecher?\n&eSuper-Brecher ist eine F\u00E4higkeit deren Dauer\n&evom Bergbau-Skill abh\u00E4ngt. Es verdreifacht die \n&eChance Sch\u00E4tze zu finden und erm\u00F6glicht\n&esofortiges Abbauen kompatibler Materialien. @@ -465,45 +465,45 @@ Guides.Mining.Section.4 = &3Wie benutzt man Z\u00FCndstoff?:\n&eHalte eine Spitz Guides.Mining.Section.5 = &3Wie funktioniert Z\u00FCndstoff?\n&eZ\u00FCndstoff ist eine F\u00E4higkeit mit einer Abklingzeit, deren St\u00E4rke\n&evom Level abh\u00E4ngt. Sie erlaubt dir beim Abbauen mit TNT dieses\n&eaus der Ferne zu z\u00FCnden. Z\u00FCndstoff besteht aus 3 Teilen.\n&eErstens dem Sprengmeister mit gr\u00F6\u00DFeren Explosionen.\n&eZweitens dem Explosions-Experten, der Schaden von TNT\n&ereduziert.\n&eDie dritte F\u00E4higkeit erh\u00F6ht einfach den Erzertrag\n&eund reduziert den Schutt. Guides.Page.Invalid = Keine g\u00FCltige Seitenzahl! Guides.Page.OutOfRange = Es gibt nur insgesamt {0} Seiten. -Guides.Repair.Section.0 = &3\u00DCber Reparatur:\n&eReparatur erlaubt dir an einem Eisenblock Werkzeuge und\n&eWaffen zu reparieren.\n\n&3XP ZUWACHS:\n&eRepariere Werkzeuge am Eisenblock-Amboss\n&cAchtung: &eDas ist nicht der normale Minecraft Amboss! +Guides.Repair.Section.0 = &3\u00DCber Reparatur:\n&eReparatur erlaubt dir an einem Eisenblock Werkzeuge und\n&eWaffen zu reparieren.\n\n&3XP-Zuwachs:\n&eRepariere Werkzeuge am Eisenblock-Amboss\n&cAchtung: &eDas ist nicht der normale Minecraft Amboss! Guides.Repair.Section.1 = &3Wie kann ich Reparatur verwenden?\n&ePlatziere einen mcMMO Amboss, halte das zu reparierende Item\n&ein der Hand und klicke mit der rechten Maustaste auf ihn. Zum\n&eReparieren ben\u00F6tigst du die Ausgangsmaterialien im Inventar,\n&ediese werden dir im Zuge der Reparatur abgezogen. Guides.Repair.Section.2 = &3Wie funktioniert der Reparatur Meister?\n&eMit dem Reparatur Meister wird dein Werkzeug ein bisschen\n&ebesser als normalerweise repariert.\n&eDer Bonus ist abh\u00E4ngig vom Reparatur Level. Guides.Repair.Section.3 = &3Wie funktioniert Super-Reparatur?\n&eMit Super-Reparatur werden ab und zu deine Items\n&edoppelt so gut repariert. Guides.Repair.Section.4 = &3Wie funktioniert Arkanes Schmieden?\n&eDiese F\u00E4higkeit erm\u00F6glicht dir mit einer gewissen\n&eChance Verzauberungen auf Items zu erhalten.\n&eVerzauberungen k\u00F6nnen erhalten werden, vermindert werden oder\n&eganz verloren gehen. -Guides.Salvage.Section.0 = &3\u00DCber Verwerten:\n&eMit einem Goldamboss kannst du R\u00FCstungen und\n&eWerkzeuge verwerten.\n\n&3XP ZUWACHS:\n&eVerwerten ist ein vom Angeln und Reparieren abh\u00E4ngiger Skill.\n&eSein Level ist die H\u00E4lfte von deren Summe. +Guides.Salvage.Section.0 = &3\u00DCber Verwerten:\n&eMit einem Goldamboss kannst du R\u00FCstungen und\n&eWerkzeuge verwerten.\n\n&3XP-Zuwachs:\n&eVerwerten ist ein vom Angeln und Reparieren abh\u00E4ngiger Skill.\n&eSein Level ist die H\u00E4lfte von deren Summe. Guides.Salvage.Section.1 = &3Wie funktioniert Verwerten?\n&ePlatziere einen Goldamboss und rechtsklicke mit dem Item in\n&eder Hand. Das Item wird zerst\u00F6rt und in seine\n&eBestandteile zerlegt.\n\n&eBeispielsweise gibt eine Eisenaxt Eisenbarren. Guides.Salvage.Section.2 = &3Wie funktioniert Fortgeschrittenes Verwerten?\n&eSobald freigeschaltet, kannst du besch\u00E4digte Items verwerten.\n&eDer Ertrag steigt mit dem Level.\n&eDer Mindestertrag ist immer 1 Item, ansonsten kannst du nicht\n&everwerten. Guides.Salvage.Section.3 = &3Zur Verbildlichung ein Beispiel:\n&eVerwerten wir eine Goldspitzhacke mit 80%\n&eHaltbarkeit, bedeutet das, dass wir nur 2 Gold bekommen\n&ek\u00F6nnen (Spitzhacke=3 Goldbarren, also jeder 33,33%\n&eHaltbarkeit) was 66% entspricht. Wenn dein\n&eErtragsprozentsatz unter 66% liegt wirst du keine 2 Barren\n&ebekommen k\u00F6nnen. Wenn sie dar\u00FCber ist, kannst du den\n&e"gesamten Betrag" bekommen, der aus 2 Eisenbarren besteht. Guides.Salvage.Section.4 = &3Wie funktioniert Arkanes Verwerten?\n&eDiese F\u00E4higkeit erm\u00F6glicht es verzauberte B\u00FCcher beim\n&eVerwerten von verzauberten Items zu bekommen.\n&eVerzauberungen k\u00F6nnen vollkommen oder teilweise extrahiert\n&ewerden.\n&eBei einer teilweisen Extraktion wird das Verzauberungslevel\n&ereduziert. Guides.Smelting.Section.0 = Kommt irgendwann mal... -Guides.Swords.Section.0 = &3\u00DCber Schwerter:\n&eDiese F\u00E4higkeit gibt Kampfboni bei Benutzung\n&edes Schwertes.\n\n&3XP ZUWACHS:\n&eVerletze Monster und Spieler mit dem Schwert. +Guides.Swords.Section.0 = &3\u00DCber Schwerter:\n&eDiese F\u00E4higkeit gibt Kampfboni bei Benutzung\n&edes Schwertes.\n\n&3XP-Zuwachs:\n&eVerletze Monster und Spieler mit dem Schwert. Guides.Swords.Section.1 = &3Wie funktioniert der S\u00E4gezahnschlag?\n&eS\u00E4gezahnschlag ist eine aktive F\u00E4higkeit die du mit Rechtsklick \n&eaktivierst.\n&eMit dieser F\u00E4higkeit kannst du Fl\u00E4chenschaden verteilen.\n&eAu\u00DFerdem blutet das Ziel f\u00FCr kurze Zeit. Guides.Swords.Section.2 = &3Wie funktioniert der Gegenangriff?\n&eGegenangriff ist eine aktive F\u00E4higkeit,\n&ebei der Angriffe von Monstern beim Blocken um bis zu 50%\n&edes erhaltenen Schadens reflektiert werden k\u00F6nnen. Guides.Swords.Section.3 = &3Wie funktioniert Blutung?\n&eBlutung f\u00FCgt den Gegnern alle 2 Sekunden Schaden zu. Das\n&eBluten geht solange bis die F\u00E4higkeit ausl\u00E4uft oder der\n&eGegner stirbt.\n&eDie Dauer der Blutung erh\u00F6ht sich mit dem Schwert-Skill. -Guides.Taming.Section.0 = &3\u00DCber Z\u00E4hmen:\n&eZ\u00E4hmen gibt dem Spieler diverse Kampfboni beim Kampf mit\n&egez\u00E4hmten W\u00F6lfen.\n\n&3XP ZUWACHS:\n&eUm XP zu bekommen musst du Tiere z\u00E4hmen oder mit\n&edeinen W\u00F6lfen k\u00E4mpfen. +Guides.Taming.Section.0 = &3\u00DCber Z\u00E4hmen:\n&eZ\u00E4hmen gibt dem Spieler diverse Kampfboni beim Kampf mit\n&egez\u00E4hmten W\u00F6lfen.\n\n&3XP-Zuwachs:\n&eUm XP zu bekommen musst du Tiere z\u00E4hmen oder mit\n&edeinen W\u00F6lfen k\u00E4mpfen. Guides.Taming.Section.1 = &3Wie funktioniert Ruf der Wildnis?\n&eRuf der Wildnis ist eine aktive F\u00E4higkeit die dir erlaubt\n&eeinen Wolf, einen Ozelot oder ein Pferd an deine Seite zu\n&erufen.\n&eDas tust du, indem du linksklickst w\u00E4hrend du Knochen, Fisch\n&eoder \u00C4pfel in der Hand h\u00E4ltst. Guides.Taming.Section.2 = &3Wie funktioniert Bestienkunde?\n&eBestienkunde erlaubt es die Haustiere zu inspizieren.\n&eHalte einen Knochen in der Hand und klick mit linker Maustaste\n&eauf das Haustier um Bestienkunde zu aktivieren. Guides.Taming.Section.3 = &3Wie funktioniert Aufschlitzen?\n&eAufschlitzen ist eine passive F\u00E4higkeit die beim Ziel\n&edes Wolfes Blutungen hervorrufen kann. Der Erfolg h\u00E4ngt\n&evom Z\u00E4hmen-Level ab. -Guides.Taming.Section.4 = &3Wie funktionieren gesch\u00E4rfte Klauen?\n&eGesch\u00E4rfte Klauen geben Zusatzschaden in Abh\u00E4ngigkeit\n&evom Z\u00E4hmen Level. +Guides.Taming.Section.4 = &3Wie funktionieren gesch\u00E4rfte Klauen?\n&eGesch\u00E4rfte Klauen geben Zusatzschaden in Abh\u00E4ngigkeit\n&evom Z\u00E4hmen-Level. Guides.Taming.Section.5 = &3Wie funktioniert Umweltbewusst?\n&eDiese passive F\u00E4higkeit erm\u00F6glich W\u00F6lfen sich zu dir zu\n&eteleportieren wenn sie in die N\u00E4he von Gefahren wie\n&eKakteen/Lava kommen.\n&eZus\u00E4tzlich sind W\u00F6lfe immun gegen Fallschaden. Guides.Taming.Section.6 = &3Wie funktioniert Dicker Pelz?\n&eDiese passive F\u00E4higkeit reduziert Schaden und\n&emacht W\u00F6lfe feuerresistent. Guides.Taming.Section.7 = &3Wie funktioniert Schocksicher?\n&eDiese passive F\u00E4higkeit reduziert den Schaden\n&edurch Explosionen. Guides.Taming.Section.8 = &3Wie funktioniert Schnell-Imbiss?\n&eDiese passive F\u00E4higkeit gibt dem Wolf eine Chance sich zu\n&eerholen wann immer er einen Gegner verletzt. -Guides.Unarmed.Section.0 = &3\u00DCber Unbewaffnet:\n&eMit Unbewaffnet kann der echte Mann endlich mit seinen\n&eF\u00E4usten angemessen zuschlagen.\n\n&3XP ZUWACHS:\n&eK\u00E4mpfe unbewaffnet gegen Monster und andere Spieler. +Guides.Unarmed.Section.0 = &3\u00DCber Unbewaffnet:\n&eMit Unbewaffnet kann der echte Mann endlich mit seinen\n&eF\u00E4usten angemessen zuschlagen.\n\n&3XP-Zuwachs:\n&eK\u00E4mpfe unbewaffnet gegen Monster und andere Spieler. Guides.Unarmed.Section.1 = &3Wie funktioniert Berserker?\n&eBerserker ist eine aktive F\u00E4higkeit die mit Rechtsklick\n&eaktiviert wird.\n&eIm Berserker-Modus f\u00FCgst du 50% mehr Schaden zu und\n&ekannst weiche Materialien wie Gras und Erde sofort abbauen. Guides.Unarmed.Section.2 = &3Wie funktioniert der Eiserne Arm?\n&eEiserner Arm erh\u00F6ht den Monstern und Spielern mit den\n&eF\u00E4usten zugef\u00FCgten Schaden. Guides.Unarmed.Section.3 = &3Wie funktioniert Pfeilablenkung?\n&ePfeilablenkung ist eine passive F\u00E4higkeit die ab und zu\n&ePfeile von Skeletten und angreifenden Spielern ablenkt.\n&eDiese Pfeile prallen einfach ab und fallen auf den Boden. Guides.Unarmed.Section.4 = &3Wie funktioniert der Eiserne Griff?\n&eEiserner Griff ist eine passive F\u00E4higkeit die Entwaffnung\n&everhindert. Mit h\u00F6herem Level ist es umso einfacher\n&eEntwaffnung zu verhindern. Guides.Unarmed.Section.5 = &3Wie funktioniert Entwaffnen?\n&eDiese passive F\u00E4higkeit erm\u00F6glich es den Gegner zu\n&eentwaffnen, sodass seine Waffe auf den Boden f\u00E4llt. Guides.Usage = Der Befehl ist /{0} ? [Seite] -Guides.Woodcutting.Section.0 = &3\u00DCber Holzf\u00E4ller:\n&eIm Holzf\u00E4llen geht es um das F\u00E4llen von B\u00E4umen.\n\n&3XP ZUWACHS:\n&eDu bekommst XP f\u00FCr das Abholzen von Baumst\u00E4mmen. +Guides.Woodcutting.Section.0 = &3\u00DCber Holzf\u00E4ller:\n&eIm Holzf\u00E4llen geht es um das F\u00E4llen von B\u00E4umen.\n\n&3XP-Zuwachs:\n&eDu bekommst XP f\u00FCr das Abholzen von Baumst\u00E4mmen. Guides.Woodcutting.Section.1 = &3Wie funktioniert der Baumf\u00E4ller?\n&eBaumf\u00E4ller ist eine aktive F\u00E4higkeit. Mache mit der Axt in der\n&eHand einen Rechtsklick um sie zu aktivieren. Der Baum\n&ewird sofortig gef\u00E4llt und alle St\u00E4mme abgebaut. Guides.Woodcutting.Section.2 = &3Wie funktioniert Bl\u00E4ttersturm?\n&eBl\u00E4ttersturm ist eine passive F\u00E4higkeit die Bl\u00E4tter\n&ebei Ber\u00FChrung mit der Axt sofortig bricht. Standardm\u00E4\u00DFig\n&ewird diese F\u00E4higkeit bei Level 100 freigeschaltet. Guides.Woodcutting.Section.3 = &3Wie funktionieren Doppel-Drops?\n&eDiese passive F\u00E4higkeit gibt dir ab und zu doppelten\n&eErtrag f\u00FCr jeden Stamm den du f\u00E4llst. Hardcore.DeathStatLoss.Name = Skillverlust bei Tod: Hardcore.DeathStatLoss.PercentageChanged = &6[mcMMO] Der Verlustprozentsatz wurde auf {0} ge\u00E4ndert. -Hardcore.DeathStatLoss.PlayerDeath = &6[mcMMO] &4Du hast durch den Tod&9{0}&4 Level verloren. +Hardcore.DeathStatLoss.PlayerDeath = &6[mcMMO] &4Du hast durch den Tod &9{0}&4 Level verloren. Hardcore.Mode.Disabled = &6[mcMMO] Hardcore Modus {0} deaktiviert f\u00FCr {1}. Hardcore.Mode.Enabled = &6[mcMMO] Hardcore Modus {0} aktiviert f\u00FCr {1}. Hardcore.Vampirism.Killer.Failure = &6[mcMMO] &e{0}&7 war nicht erfahren genug um dir Wissen zu hinterlassen. @@ -511,14 +511,14 @@ Hardcore.Vampirism.Killer.Success = &6[mcMMO] &3Du hast &9{0}&3 Level von &e{1} Hardcore.Vampirism.Name = Vampirismus Hardcore.Vampirism.PercentageChanged = &6[mcMMO] Der Vampirismus Prozentsatz wurde auf {0} ge\u00E4ndert. Hardcore.Vampirism.Victim.Failure = &6[mcMMO] &e{0}&7 hat es nicht geschafft Wissen von dir zu stehlen! -Hardcore.Vampirism.Victim.Success = &6[mcMMO] &e{0}&4 hat&9{1}&4 Level von dir gestohlen! +Hardcore.Vampirism.Victim.Success = &6[mcMMO] &e{0}&4 hat &9{1}&4 Level von dir gestohlen! Herbalism.Ability.GTe.NeedMore = Du brauchst mehr Samen um Gr\u00FCnes Land zu verbreiten. Herbalism.Ability.GTh = &a**Gr\u00FCner Daumen** Herbalism.Ability.GTh.Fail = **Gr\u00FCner Daumen gescheitert** Herbalism.Ability.Lower = &7&o**Du senkst deine Harke.** Herbalism.Ability.Ready = &a&o**Du hebst deine Harke...** -Herbalism.Ability.ShroomThumb.Fail = **Gr\u00FCne Zehe gescheitert** +Herbalism.Ability.ShroomThumb.Fail = **Gr\u00FCner Daumen gescheitert** Herbalism.Effect.4 = Gr\u00FCner Daumen Herbalism.HylianLuck = &aHeute ist das Gl\u00FCck von Hyrule mit dir! Herbalism.Listener = Kr\u00E4uterkunde: @@ -546,10 +546,10 @@ Herbalism.SubSkill.HylianLuck.Description = Gibt eine kleine M\u00F6glichkeit, s Herbalism.SubSkill.HylianLuck.Name = Hylian Gl\u00FCck Herbalism.SubSkill.HylianLuck.Stat = Hylian Gl\u00FCck Chance Herbalism.SubSkill.ShroomThumb.Description = Verbreite Myzel auf Gras und Erde. -Herbalism.SubSkill.ShroomThumb.Name = Pilz-Zehe -Herbalism.SubSkill.ShroomThumb.Stat = Pilz-Zehe Chance +Herbalism.SubSkill.ShroomThumb.Name = Pilz-Daumen +Herbalism.SubSkill.ShroomThumb.Stat = Pilz-Daumen Chance -Holiday.Anniversary = &9Alles gute zu mcMMO's {0} j\u00E4hrigen Geburtstag!\n&9In Ehren von nossr50 und all den anderen flei\u00DFigen Entwicklern, hier ist eine kleine Feuerwerk Show! +Holiday.Anniversary = &9Alles Gute zu mcMMO's {0} j\u00E4hrigen Geburtstag!\n&9In Ehren von nossr50 und all den anderen flei\u00DFigen Entwicklern ist hier eine kleine Feuerwerk-Show! Holiday.AprilFools.Levelup = &6{0} ist jetzt Level &a{1}&6! Inspect.Offline = &cDu hast nicht die Rechte um Offline-Spieler zu inspizieren! @@ -561,7 +561,7 @@ Item.ChimaeraWing.Fail = &c**Chimaera Fl\u00FCgel gescheitert!** Item.ChimaeraWing.Lore = &7Teleportiert dich zu deinem Bett. Item.ChimaeraWing.Name = Chimaera Fl\u00FCgel Item.ChimaeraWing.NotEnough = Du ben\u00F6tigst &e{0}&c weitere &6{1}&c! -Item.ChimaeraWing.Pass = **CHIMAERA FL\u00DCGEL* +Item.ChimaeraWing.Pass = **Chimarea Fl\u00FCgel** Item.FluxPickaxe.Lore.1 = &7Hat eine Chance Erze sofort zu schmelzen. Item.FluxPickaxe.Lore.2 = &7Ben\u00F6tigt Schmelzen-Level {0} oder mehr. Item.FluxPickaxe.Name = Schmelzhacke @@ -620,14 +620,14 @@ JSON.Woodcutting = Holzf\u00E4llen LevelCap.PowerLevel = &6(&amcMMO&6) &eDu hast das Level-Limit von &c{0}&e erreicht. Du kannst deine F\u00E4higkeiten nun nicht mehr weiter verbessern. LevelCap.Skill = &6(&amcMMO&6) &eDu hast das Level-Limit von &c{0}&e f\u00FCr &6{1}&e erreicht. Du kannst diese F\u00E4higkeit von nun an nicht mehr weiter verbessern. -Locale.Reloaded = &aDie Sprachdateien wurden neugeladen! +Locale.Reloaded = &aDie Sprachdateien wurden neu geladen! MOTD.Donate = &3Spenden Info: MOTD.Hardcore.DeathStatLoss.Stats = &6[mcMMO] &3Skillverlust bei Tod: &4{0}% MOTD.Hardcore.Enabled = &6[mcMMO] &3Hardcore Modus aktiviert: &4{0} MOTD.Hardcore.Vampirism.Stats = &6[mcMMO] &3Vampirismus Prozentsatz: &4{0}% MOTD.PerksPrefix = &6[mcMMO Boni] -MOTD.Version = &6[mcMMO] Verwende Version&3{0} +MOTD.Version = &6[mcMMO] Verwende Version &3{0} MOTD.Version.Overhaul = &6[mcMMO] &3\u00DCberholungs Era&6 - &3{0} MOTD.Website = &6[mcMMO] &a{0}&e - mcMMO Website @@ -648,7 +648,7 @@ Mining.Skills.SuperBreaker.On = &a&o**Super-Brecher aktiviert** Mining.Skills.SuperBreaker.Other.Off = {0}s &cSuper-Brecher&a ist &aausgelaufen. Mining.Skills.SuperBreaker.Other.On = &a{0}&2 benutzte &cSuper-Brecher! Mining.Skills.SuperBreaker.Refresh = &aDein &eSuper-Brecher &aist wieder bereit! -Mining.SubSkill.BiggerBombs.Description = Erh\u00F6ht den Explosions-Radius. +Mining.SubSkill.BiggerBombs.Description = Erh\u00F6ht den Explosionsradius. Mining.SubSkill.BiggerBombs.Name = Sprengmeister Mining.SubSkill.BlastMining.Description = Bonus beim Abbauen mit TNT. Mining.SubSkill.BlastMining.Name = Z\u00FCndstoff @@ -785,7 +785,7 @@ Profile.Loading.FailurePlayer = &cmcMMO hat Probleme beim Laden deiner Daten nac Profile.Loading.Success = &aDein Profil wurde geladen. Profile.PendingLoad = &cDeine mcMMO Daten wurden noch nicht geladen. -Reminder.Squelched = &7Erinnerung: Du erh\u00E4lst aktuell keinerlei Benachrichtigungen von mcMMO, um dies zu \u00E4ndern, nutze den /mcnotify Befehl. Dies ist eine st\u00FCndliche, automatische Erinnerung. +Reminder.Squelched = &7Erinnerung: Du erh\u00E4ltst aktuell keinerlei Benachrichtigungen von mcMMO, um dies zu \u00E4ndern, nutze den /mcnotify Befehl. Dies ist eine st\u00FCndliche, automatische Erinnerung. Repair.Arcane.Downgrade = Zauber-Wert des Gegenstands vermindert. Repair.Arcane.Fail = Der Gegenstands wurde entzaubert. @@ -863,7 +863,7 @@ Scoreboard.Misc.CurrentXP = &aAktuelle XP Scoreboard.Misc.Level = &3Level Scoreboard.Misc.Overall = &6Insgesamt Scoreboard.Misc.PowerLevel = &6Gesamt-Level -Scoreboard.Misc.RemainingXP = Verbliebene XP +Scoreboard.Misc.RemainingXP = Verbleibende XP Server.ConsoleName = &e[Server] @@ -890,7 +890,7 @@ Smelting.Effect.4 = Vanilla XP-Boost Smelting.Effect.5 = Erh\u00F6ht die erhaltene Erfahrung beim Schmelzen. Smelting.Listener = Schmelzen: Smelting.SkillName = Schmelzen -Smelting.SubSkill.FluxMining.Description = M\u00F6glichkeit, Erze direkt beim Abbauen zu schmelzen. +Smelting.SubSkill.FluxMining.Description = M\u00F6glichkeit, um Erze direkt beim Abbauen zu schmelzen. Smelting.SubSkill.FluxMining.Name = Schmelztiegel Smelting.SubSkill.FluxMining.Stat = Schmelztiegel Chance Smelting.SubSkill.FuelEfficiency.Description = Erh\u00F6he die Brenndauer des Brennstoffes in \u00D6fen. @@ -936,7 +936,7 @@ Swords.SubSkill.Rupture.Stat.Extra = Entzweiung: &a{0} ticks [{1} Schaden gegen Swords.SubSkill.SerratedStrikes.Description = {0} Fl\u00E4chenschaden, Fl\u00E4chenblutung+ Swords.SubSkill.SerratedStrikes.Name = S\u00E4gezahnschlag Swords.SubSkill.SerratedStrikes.Stat = S\u00E4gezahnschlag L\u00E4nge -Swords.SubSkill.Stab.Description = F\u00FCgt extra Schaden zu deinem Angriff hinzu. +Swords.SubSkill.Stab.Description = F\u00FCgt deinem Angriff extra Schaden hinzu. Swords.SubSkill.Stab.Name = Erstechen Swords.SubSkill.Stab.Stat = Schaden durch Erstechen Swords.SubSkill.SwordsLimitBreak.Description = \u00DCberschreite deine Grenzen. @@ -946,7 +946,7 @@ Swords.SubSkill.SwordsLimitBreak.Stat = Bonus-Schaden durch \u00DCberwindung Taming.Ability.Bonus.0 = Umweltbewusst Taming.Ability.Bonus.1 = W\u00F6lfe weichen Gefahren aus. Taming.Ability.Bonus.10 = Heiliger Hund -Taming.Ability.Bonus.11 = Regenerierung auch mit Tr\u00E4nken und Zaubern m\u00F6glich. +Taming.Ability.Bonus.11 = Regenerierung ist auch mit Tr\u00E4nken und Zaubern m\u00F6glich. Taming.Ability.Bonus.2 = Dicker Pelz Taming.Ability.Bonus.3 = 1/{0} Schaden, Feuer-Resistent Taming.Ability.Bonus.4 = Schock-Sicher @@ -968,7 +968,7 @@ Taming.SkillName = Z\u00C4HMEN Taming.SubSkill.BeastLore.Description = Knochenschlag inspiziert W\u00F6lfe und Ozelots. Taming.SubSkill.BeastLore.Name = Bestienkunde Taming.SubSkill.CallOfTheWild.Description = Beschw\u00F6re ein Tier an deine Seite. -Taming.SubSkill.CallOfTheWild.Description.2 = &7RdW: B\u00FCcken und Linksklick mit {0} {1} (Ozelot), {2} {3} (Wolf), {4} {5} (Pferd) +Taming.SubSkill.CallOfTheWild.Description.2 = &7Ruf der Wildnis: B\u00FCcken und Linksklick mit {0} {1} (Ozelot), {2} {3} (Wolf), {4} {5} (Pferd) Taming.SubSkill.CallOfTheWild.Name = Ruf der Wildnis Taming.SubSkill.EnvironmentallyAware.Description = Kaktus/Lava-Furcht, Immun gegen Fallschaden Taming.SubSkill.EnvironmentallyAware.Name = Umweltbewusst @@ -1004,11 +1004,11 @@ Unarmed.Ability.Bonus.1 = +{0} Schadens-Bonus Unarmed.Ability.IronGrip.Attacker = Dein Gegner hat einen eisernen Griff! Unarmed.Ability.IronGrip.Defender = &aDein eiserner Griff hat dich vor Entwaffnung gesch\u00FCtzt! Unarmed.Ability.Lower = &7&o**Du senkst deine F\u00E4uste.** -Unarmed.Ability.Ready = &a&o**Du hebste deine F\u00E4uste...** +Unarmed.Ability.Ready = &a&o**Du hebst deine F\u00E4uste...** Unarmed.Listener = Faustkampf: Unarmed.SkillName = Faustkampf Unarmed.Skills.Berserk.Off = **Berserker ausgelaufen** -Unarmed.Skills.Berserk.On = &a**Berserker aktiviertT** +Unarmed.Skills.Berserk.On = &a**Berserker aktiviert** Unarmed.Skills.Berserk.Other.Off = {0}s &cBerserker&a ist &aausgelaufen. Unarmed.Skills.Berserk.Other.On = &a{0}&2 benutzte &cBerserker! Unarmed.Skills.Berserk.Refresh = &aDein &eBerserker &aist wieder bereit! @@ -1020,7 +1020,7 @@ Unarmed.SubSkill.Berserk.Name = Berserker Unarmed.SubSkill.Berserk.Stat = Berserker L\u00E4nge Unarmed.SubSkill.BlockCracker.Description = Durchbreche Stein mit deinen F\u00E4usten. Unarmed.SubSkill.BlockCracker.Name = Schwarzgurt -Unarmed.SubSkill.Disarm.Description = L\u00E4sst Gegenstand aus der Hand des Feindes fallen. +Unarmed.SubSkill.Disarm.Description = L\u00E4sst den Gegenstand aus der Hand des Feindes fallen. Unarmed.SubSkill.Disarm.Name = Entwaffnen Unarmed.SubSkill.Disarm.Stat = Entwaffnen Chance Unarmed.SubSkill.IronGrip.Description = Sch\u00FCtzt dich davor, entwaffnet zu werden. From c1c32cb1fd745f799c4a8f0af5f456d75253e253 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 9 Apr 2021 10:19:34 -0700 Subject: [PATCH 12/57] Fix mcMMO saving copies of config files into the main server directory instead of the correct place --- .../config/AutoUpdateConfigLoader.java | 24 +++++++++----- .../gmail/nossr50/config/ConfigLoader.java | 33 ++++++++++--------- .../com/gmail/nossr50/config/RankConfig.java | 8 ++--- .../com/gmail/nossr50/config/SoundConfig.java | 5 +-- .../config/mods/CustomArmorConfig.java | 5 +-- .../config/mods/CustomBlockConfig.java | 3 +- .../config/mods/CustomEntityConfig.java | 7 ++-- .../nossr50/config/mods/CustomToolConfig.java | 5 +-- .../config/skills/repair/RepairConfig.java | 2 +- .../config/skills/salvage/SalvageConfig.java | 6 ++-- .../treasure/FishingTreasureConfig.java | 2 +- .../nossr50/skills/child/ChildConfig.java | 8 ++--- .../nossr50/util/upgrade/UpgradeManager.java | 5 +-- 13 files changed, 64 insertions(+), 49 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/config/AutoUpdateConfigLoader.java b/src/main/java/com/gmail/nossr50/config/AutoUpdateConfigLoader.java index 30fa038cb..f2c936a56 100644 --- a/src/main/java/com/gmail/nossr50/config/AutoUpdateConfigLoader.java +++ b/src/main/java/com/gmail/nossr50/config/AutoUpdateConfigLoader.java @@ -1,5 +1,6 @@ package com.gmail.nossr50.config; +import com.gmail.nossr50.mcMMO; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.jetbrains.annotations.NotNull; @@ -31,7 +32,7 @@ public abstract class AutoUpdateConfigLoader extends ConfigLoader { protected void saveConfig() { try { - plugin.getLogger().info("Saving changes to config file - "+fileName); + mcMMO.p.getLogger().info("Saving changes to config file - "+fileName); config.save(configFile); } catch (IOException e) { e.printStackTrace(); @@ -39,13 +40,13 @@ public abstract class AutoUpdateConfigLoader extends ConfigLoader { } protected @NotNull FileConfiguration getInternalConfig() { - return YamlConfiguration.loadConfiguration(plugin.getResourceAsReader(fileName)); + return YamlConfiguration.loadConfiguration(mcMMO.p.getResourceAsReader(fileName)); } @Override protected void loadFile() { super.loadFile(); - FileConfiguration internalConfig = YamlConfiguration.loadConfiguration(plugin.getResourceAsReader(fileName)); + FileConfiguration internalConfig = YamlConfiguration.loadConfiguration(mcMMO.p.getResourceAsReader(fileName)); Set configKeys = config.getKeys(true); Set internalConfigKeys = internalConfig.getKeys(true); @@ -65,12 +66,12 @@ public abstract class AutoUpdateConfigLoader extends ConfigLoader { } // // for (String key : oldKeys) { -// plugin.debug("Detected potentially unused key: " + key); +// mcMMO.p.debug("Detected potentially unused key: " + key); // //config.set(key, null); // } for (String key : newKeys) { - plugin.debug("Adding new key: " + key + " = " + internalConfig.get(key)); + mcMMO.p.debug("Adding new key: " + key + " = " + internalConfig.get(key)); config.set(key, internalConfig.get(key)); } @@ -89,7 +90,7 @@ public abstract class AutoUpdateConfigLoader extends ConfigLoader { // Read the internal config to get comments, then put them in the new one try { // Read internal - BufferedReader reader = new BufferedReader(new InputStreamReader(plugin.getResource(fileName))); + BufferedReader reader = new BufferedReader(new InputStreamReader(mcMMO.p.getResource(fileName))); LinkedHashMap comments = new LinkedHashMap<>(); StringBuilder temp = new StringBuilder(); @@ -139,14 +140,21 @@ public abstract class AutoUpdateConfigLoader extends ConfigLoader { } // Save it + if(dataFolder == null) { + mcMMO.p.getLogger().severe("Data folder should never be null!"); + return; + } + try { String saveName = fileName; // At this stage we cannot guarantee that Config has been loaded, so we do the check directly here - if (!plugin.getConfig().getBoolean("General.Config_Update_Overwrite", true)) { + if (!mcMMO.p.getConfig().getBoolean("General.Config_Update_Overwrite", true)) { saveName += ".new"; } - BufferedWriter writer = new BufferedWriter(new FileWriter(new File(dataFolder, saveName))); + File newSaveFile = new File(dataFolder, saveName); + FileWriter fileWriter = new FileWriter(newSaveFile.getAbsolutePath()); + BufferedWriter writer = new BufferedWriter(fileWriter); writer.write(output); writer.flush(); writer.close(); diff --git a/src/main/java/com/gmail/nossr50/config/ConfigLoader.java b/src/main/java/com/gmail/nossr50/config/ConfigLoader.java index 4a168fa50..a1c75058d 100644 --- a/src/main/java/com/gmail/nossr50/config/ConfigLoader.java +++ b/src/main/java/com/gmail/nossr50/config/ConfigLoader.java @@ -9,11 +9,10 @@ import java.io.File; import java.util.List; public abstract class ConfigLoader { - protected static final mcMMO plugin = mcMMO.p; protected String fileName; protected final File configFile; protected FileConfiguration config; - protected @NotNull File dataFolder; + protected @NotNull final File dataFolder; public ConfigLoader(String relativePath, String fileName, @NotNull File dataFolder) { this.fileName = fileName; @@ -33,6 +32,7 @@ public abstract class ConfigLoader { public ConfigLoader(String relativePath, String fileName) { this.fileName = fileName; configFile = new File(mcMMO.p.getDataFolder(), relativePath + File.separator + fileName); + this.dataFolder = mcMMO.p.getDataFolder(); loadFile(); } @@ -40,22 +40,23 @@ public abstract class ConfigLoader { public ConfigLoader(String fileName) { this.fileName = fileName; configFile = new File(mcMMO.p.getDataFolder(), fileName); + this.dataFolder = mcMMO.p.getDataFolder(); loadFile(); } protected void loadFile() { if (!configFile.exists()) { - plugin.debug("Creating mcMMO " + fileName + " File..."); + mcMMO.p.debug("Creating mcMMO " + fileName + " File..."); try { - plugin.saveResource(fileName, false); // Normal files + mcMMO.p.saveResource(fileName, false); // Normal files } catch (IllegalArgumentException ex) { - plugin.saveResource(configFile.getParentFile().getName() + File.separator + fileName, false); // Mod files + mcMMO.p.saveResource(configFile.getParentFile().getName() + File.separator + fileName, false); // Mod files } } else { - plugin.debug("Loading mcMMO " + fileName + " File..."); + mcMMO.p.debug("Loading mcMMO " + fileName + " File..."); } config = YamlConfiguration.loadConfiguration(configFile); @@ -69,7 +70,7 @@ public abstract class ConfigLoader { protected boolean noErrorsInConfig(List issues) { for (String issue : issues) { - plugin.getLogger().warning(issue); + mcMMO.p.getLogger().warning(issue); } return issues.isEmpty(); @@ -77,12 +78,12 @@ public abstract class ConfigLoader { protected void validate() { if (validateKeys()) { - plugin.debug("No errors found in " + fileName + "!"); + mcMMO.p.debug("No errors found in " + fileName + "!"); } else { - plugin.getLogger().warning("Errors were found in " + fileName + "! mcMMO was disabled!"); - plugin.getServer().getPluginManager().disablePlugin(plugin); - plugin.noErrorsInConfigFiles = false; + mcMMO.p.getLogger().warning("Errors were found in " + fileName + "! mcMMO was disabled!"); + mcMMO.p.getServer().getPluginManager().disablePlugin(mcMMO.p); + mcMMO.p.noErrorsInConfigFiles = false; } } @@ -91,16 +92,16 @@ public abstract class ConfigLoader { } public void backup() { - plugin.getLogger().warning("You are using an old version of the " + fileName + " file."); - plugin.getLogger().warning("Your old file has been renamed to " + fileName + ".old and has been replaced by an updated version."); + mcMMO.p.getLogger().warning("You are using an old version of the " + fileName + " file."); + mcMMO.p.getLogger().warning("Your old file has been renamed to " + fileName + ".old and has been replaced by an updated version."); configFile.renameTo(new File(configFile.getPath() + ".old")); - if (plugin.getResource(fileName) != null) { - plugin.saveResource(fileName, true); + if (mcMMO.p.getResource(fileName) != null) { + mcMMO.p.saveResource(fileName, true); } - plugin.getLogger().warning("Reloading " + fileName + " with new values..."); + mcMMO.p.getLogger().warning("Reloading " + fileName + " with new values..."); loadFile(); loadKeys(); } diff --git a/src/main/java/com/gmail/nossr50/config/RankConfig.java b/src/main/java/com/gmail/nossr50/config/RankConfig.java index 9bdf00947..d164d64ca 100644 --- a/src/main/java/com/gmail/nossr50/config/RankConfig.java +++ b/src/main/java/com/gmail/nossr50/config/RankConfig.java @@ -127,7 +127,7 @@ public class RankConfig extends AutoUpdateConfigLoader { String key = getRankAddressKey(subSkillType, rank, retroMode); int defaultValue = getInternalConfig().getInt(key); config.set(key, defaultValue); - plugin.getLogger().info(key +" SET -> " + defaultValue); + mcMMO.p.getLogger().info(key +" SET -> " + defaultValue); } /** @@ -145,10 +145,10 @@ public class RankConfig extends AutoUpdateConfigLoader { if(badSkillSetup.isEmpty()) return; - plugin.getLogger().info("(FIXING CONFIG) mcMMO is correcting a few mistakes found in your skill rank config setup"); + mcMMO.p.getLogger().info("(FIXING CONFIG) mcMMO is correcting a few mistakes found in your skill rank config setup"); for(SubSkillType subSkillType : badSkillSetup) { - plugin.getLogger().info("(FIXING CONFIG) Resetting rank config settings for skill named - "+subSkillType.toString()); + mcMMO.p.getLogger().info("(FIXING CONFIG) Resetting rank config settings for skill named - "+subSkillType.toString()); fixBadEntries(subSkillType); } } @@ -180,7 +180,7 @@ public class RankConfig extends AutoUpdateConfigLoader { if(prevRank > curRank) { //We're going to allow this but we're going to warn them - plugin.getLogger().info("(CONFIG ISSUE) You have the ranks for the subskill "+ subSkillType.toString()+" set up poorly, sequential ranks should have ascending requirements"); + mcMMO.p.getLogger().info("(CONFIG ISSUE) You have the ranks for the subskill "+ subSkillType.toString()+" set up poorly, sequential ranks should have ascending requirements"); badSkillSetup.add(subSkillType); } } diff --git a/src/main/java/com/gmail/nossr50/config/SoundConfig.java b/src/main/java/com/gmail/nossr50/config/SoundConfig.java index 734e770aa..61960803d 100644 --- a/src/main/java/com/gmail/nossr50/config/SoundConfig.java +++ b/src/main/java/com/gmail/nossr50/config/SoundConfig.java @@ -1,5 +1,6 @@ package com.gmail.nossr50.config; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.sounds.SoundType; public class SoundConfig extends AutoUpdateConfigLoader { @@ -31,7 +32,7 @@ public class SoundConfig extends AutoUpdateConfigLoader { { if(config.getDouble("Sounds."+soundType.toString()+".Volume") < 0) { - plugin.getLogger().info("[mcMMO] Sound volume cannot be below 0 for "+soundType.toString()); + mcMMO.p.getLogger().info("[mcMMO] Sound volume cannot be below 0 for "+soundType.toString()); return false; } @@ -40,7 +41,7 @@ public class SoundConfig extends AutoUpdateConfigLoader { { if(config.getDouble("Sounds."+soundType.toString()+".Pitch") < 0) { - plugin.getLogger().info("[mcMMO] Sound pitch cannot be below 0 for "+soundType.toString()); + mcMMO.p.getLogger().info("[mcMMO] Sound pitch cannot be below 0 for "+soundType.toString()); return false; } } diff --git a/src/main/java/com/gmail/nossr50/config/mods/CustomArmorConfig.java b/src/main/java/com/gmail/nossr50/config/mods/CustomArmorConfig.java index 76686f82d..94c30580a 100644 --- a/src/main/java/com/gmail/nossr50/config/mods/CustomArmorConfig.java +++ b/src/main/java/com/gmail/nossr50/config/mods/CustomArmorConfig.java @@ -3,6 +3,7 @@ package com.gmail.nossr50.config.mods; import com.gmail.nossr50.config.ConfigLoader; import com.gmail.nossr50.datatypes.skills.ItemType; import com.gmail.nossr50.datatypes.skills.MaterialType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.repair.repairables.Repairable; import com.gmail.nossr50.skills.repair.repairables.RepairableFactory; import org.bukkit.Material; @@ -62,7 +63,7 @@ public class CustomArmorConfig extends ConfigLoader { Material armorMaterial = Material.matchMaterial(armorName); if (armorMaterial == null) { - plugin.getLogger().warning("Invalid material name. This item will be skipped. - " + armorName); + mcMMO.p.getLogger().warning("Invalid material name. This item will be skipped. - " + armorName); continue; } @@ -70,7 +71,7 @@ public class CustomArmorConfig extends ConfigLoader { Material repairMaterial = Material.matchMaterial(config.getString(armorType + "." + armorName + ".Repair_Material", "")); if (repairable && (repairMaterial == null)) { - plugin.getLogger().warning("Incomplete repair information. This item will be unrepairable. - " + armorName); + mcMMO.p.getLogger().warning("Incomplete repair information. This item will be unrepairable. - " + armorName); repairable = false; } diff --git a/src/main/java/com/gmail/nossr50/config/mods/CustomBlockConfig.java b/src/main/java/com/gmail/nossr50/config/mods/CustomBlockConfig.java index 2b30ec0cf..881b483fe 100644 --- a/src/main/java/com/gmail/nossr50/config/mods/CustomBlockConfig.java +++ b/src/main/java/com/gmail/nossr50/config/mods/CustomBlockConfig.java @@ -2,6 +2,7 @@ package com.gmail.nossr50.config.mods; import com.gmail.nossr50.config.ConfigLoader; import com.gmail.nossr50.datatypes.mods.CustomBlock; +import com.gmail.nossr50.mcMMO; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; @@ -66,7 +67,7 @@ public class CustomBlockConfig extends ConfigLoader { Material blockMaterial = Material.matchMaterial(blockInfo[0]); if (blockMaterial == null) { - plugin.getLogger().warning("Invalid material name. This item will be skipped. - " + blockInfo[0]); + mcMMO.p.getLogger().warning("Invalid material name. This item will be skipped. - " + blockInfo[0]); continue; } diff --git a/src/main/java/com/gmail/nossr50/config/mods/CustomEntityConfig.java b/src/main/java/com/gmail/nossr50/config/mods/CustomEntityConfig.java index 549836152..64155043d 100644 --- a/src/main/java/com/gmail/nossr50/config/mods/CustomEntityConfig.java +++ b/src/main/java/com/gmail/nossr50/config/mods/CustomEntityConfig.java @@ -2,6 +2,7 @@ package com.gmail.nossr50.config.mods; import com.gmail.nossr50.config.ConfigLoader; import com.gmail.nossr50.datatypes.mods.CustomEntity; +import com.gmail.nossr50.mcMMO; import org.apache.commons.lang.ClassUtils; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -32,8 +33,8 @@ public class CustomEntityConfig extends ConfigLoader { clazz = ClassUtils.getClass(className); } catch (ClassNotFoundException e) { - plugin.getLogger().warning("Invalid class (" + className + ") detected for " + entityName + "."); - plugin.getLogger().warning("This custom entity may not function properly."); + mcMMO.p.getLogger().warning("Invalid class (" + className + ") detected for " + entityName + "."); + mcMMO.p.getLogger().warning("This custom entity may not function properly."); } String entityTypeName = entityName.replace("_", "."); @@ -48,7 +49,7 @@ public class CustomEntityConfig extends ConfigLoader { int callOfTheWildAmount = config.getInt(entityName + ".COTW_Material_Amount"); if (canBeSummoned && (callOfTheWildMaterial == null || callOfTheWildAmount == 0)) { - plugin.getLogger().warning("Incomplete Call of the Wild information. This entity will not be able to be summoned by Call of the Wild."); + mcMMO.p.getLogger().warning("Incomplete Call of the Wild information. This entity will not be able to be summoned by Call of the Wild."); canBeSummoned = false; } diff --git a/src/main/java/com/gmail/nossr50/config/mods/CustomToolConfig.java b/src/main/java/com/gmail/nossr50/config/mods/CustomToolConfig.java index 104fb3726..28dd85b58 100644 --- a/src/main/java/com/gmail/nossr50/config/mods/CustomToolConfig.java +++ b/src/main/java/com/gmail/nossr50/config/mods/CustomToolConfig.java @@ -4,6 +4,7 @@ import com.gmail.nossr50.config.ConfigLoader; import com.gmail.nossr50.datatypes.mods.CustomTool; import com.gmail.nossr50.datatypes.skills.ItemType; import com.gmail.nossr50.datatypes.skills.MaterialType; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.repair.repairables.Repairable; import com.gmail.nossr50.skills.repair.repairables.RepairableFactory; import org.bukkit.Material; @@ -70,7 +71,7 @@ public class CustomToolConfig extends ConfigLoader { Material toolMaterial = Material.matchMaterial(toolName); if (toolMaterial == null) { - plugin.getLogger().warning("Invalid material name. This item will be skipped. - " + toolName); + mcMMO.p.getLogger().warning("Invalid material name. This item will be skipped. - " + toolName); continue; } @@ -78,7 +79,7 @@ public class CustomToolConfig extends ConfigLoader { Material repairMaterial = Material.matchMaterial(config.getString(toolType + "." + toolName + ".Repair_Material", "")); if (repairable && (repairMaterial == null)) { - plugin.getLogger().warning("Incomplete repair information. This item will be unrepairable. - " + toolName); + mcMMO.p.getLogger().warning("Incomplete repair information. This item will be unrepairable. - " + toolName); repairable = false; } diff --git a/src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfig.java b/src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfig.java index c5ff8846c..02066fc98 100644 --- a/src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfig.java +++ b/src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfig.java @@ -182,7 +182,7 @@ public class RepairConfig extends ConfigLoader { private boolean noErrorsInRepairable(List issues) { for (String issue : issues) { - plugin.getLogger().warning(issue); + mcMMO.p.getLogger().warning(issue); } return issues.isEmpty(); diff --git a/src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfig.java b/src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfig.java index 66e107d09..47bc7acea 100644 --- a/src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfig.java +++ b/src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfig.java @@ -200,12 +200,12 @@ public class SalvageConfig extends ConfigLoader { private boolean noErrorsInSalvageable(List issues) { if (!issues.isEmpty()) { - plugin.getLogger().warning("Errors have been found in: " + fileName); - plugin.getLogger().warning("The following issues were found:"); + mcMMO.p.getLogger().warning("Errors have been found in: " + fileName); + mcMMO.p.getLogger().warning("The following issues were found:"); } for (String issue : issues) { - plugin.getLogger().warning(issue); + mcMMO.p.getLogger().warning(issue); } return issues.isEmpty(); diff --git a/src/main/java/com/gmail/nossr50/config/treasure/FishingTreasureConfig.java b/src/main/java/com/gmail/nossr50/config/treasure/FishingTreasureConfig.java index bfd814889..dc129344d 100755 --- a/src/main/java/com/gmail/nossr50/config/treasure/FishingTreasureConfig.java +++ b/src/main/java/com/gmail/nossr50/config/treasure/FishingTreasureConfig.java @@ -348,7 +348,7 @@ public class FishingTreasureConfig extends ConfigLoader { Enchantment enchantment = EnchantmentUtils.getByName(enchantmentName); if (enchantment == null) { - plugin.getLogger().warning("Skipping invalid enchantment in " + FILENAME + ": " + enchantmentName); + mcMMO.p.getLogger().warning("Skipping invalid enchantment in " + FILENAME + ": " + enchantmentName); continue; } diff --git a/src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java b/src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java index 3ac703ec8..4944fb97c 100644 --- a/src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java +++ b/src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java @@ -17,12 +17,12 @@ public class ChildConfig extends AutoUpdateConfigLoader { @Override protected void loadKeys() { - config.setDefaults(YamlConfiguration.loadConfiguration(plugin.getResourceAsReader("child.yml"))); + config.setDefaults(YamlConfiguration.loadConfiguration(mcMMO.p.getResourceAsReader("child.yml"))); FamilyTree.clearRegistrations(); // when reloading, need to clear statics for (PrimarySkillType skill : mcMMO.p.getSkillTools().CHILD_SKILLS) { - plugin.debug("Finding parents of " + skill.name()); + mcMMO.p.debug("Finding parents of " + skill.name()); EnumSet parentSkills = EnumSet.noneOf(PrimarySkillType.class); boolean useDefaults = false; // If we had an error we back out and use defaults @@ -34,7 +34,7 @@ public class ChildConfig extends AutoUpdateConfigLoader { parentSkills.add(parentSkill); } catch (IllegalArgumentException ex) { - plugin.getLogger().warning(name + " is not a valid skill type, or is a child skill!"); + mcMMO.p.getLogger().warning(name + " is not a valid skill type, or is a child skill!"); useDefaults = true; break; } @@ -53,7 +53,7 @@ public class ChildConfig extends AutoUpdateConfigLoader { // Register them for (PrimarySkillType parentSkill : parentSkills) { - plugin.debug("Registering " + parentSkill.name() + " as parent of " + skill.name()); + mcMMO.p.debug("Registering " + parentSkill.name() + " as parent of " + skill.name()); FamilyTree.registerParent(skill, parentSkill); } } diff --git a/src/main/java/com/gmail/nossr50/util/upgrade/UpgradeManager.java b/src/main/java/com/gmail/nossr50/util/upgrade/UpgradeManager.java index 55c747ffd..3ed01d378 100644 --- a/src/main/java/com/gmail/nossr50/util/upgrade/UpgradeManager.java +++ b/src/main/java/com/gmail/nossr50/util/upgrade/UpgradeManager.java @@ -2,6 +2,7 @@ package com.gmail.nossr50.util.upgrade; import com.gmail.nossr50.config.ConfigLoader; import com.gmail.nossr50.datatypes.database.UpgradeType; +import com.gmail.nossr50.mcMMO; import java.util.Arrays; import java.util.EnumSet; @@ -40,7 +41,7 @@ public class UpgradeManager extends ConfigLoader { return; } - plugin.debug("Saving upgrade status for type " + type.toString() + "..."); + mcMMO.p.debug("Saving upgrade status for type " + type.toString() + "..."); config.set("Upgrades_Finished." + type.toString(), true); @@ -60,6 +61,6 @@ public class UpgradeManager extends ConfigLoader { } } - plugin.debug("Needed upgrades: " + Arrays.toString(setNeededUpgrades.toArray(new UpgradeType[setNeededUpgrades.size()]))); + mcMMO.p.debug("Needed upgrades: " + Arrays.toString(setNeededUpgrades.toArray(new UpgradeType[setNeededUpgrades.size()]))); } } From 29613bc3243dec61ca5b27cb8e5d7b2a32a808a3 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 9 Apr 2021 10:46:12 -0700 Subject: [PATCH 13/57] Add back and deprecate most of the members of PrimarySkillType --- Changelog.txt | 3 +- .../datatypes/skills/PrimarySkillType.java | 216 +++++++++++++++++- .../nossr50/listeners/BlockListener.java | 3 +- .../gmail/nossr50/util/skills/SkillTools.java | 37 +-- 4 files changed, 226 insertions(+), 33 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index fdfa4aa63..e801e84f4 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -8,7 +8,8 @@ Version 2.1.189 Fixed an IllegalPluginAccessException error that could happen during server shutdown Minor performance optimizations to FlatFile database Refactored a lot of code - (API) PrimarySkillType is now just an enum with nothing special going on, SkillTools will facilitate what it used to do - see mcMMO::getSkillTools + (API) PrimarySkillType will soon be just an enum with nothing special going on + (API) Deprecated the members of PrimarySkillType use mcMMO::getSkillTools instead, deprecated members will be removed in Tridents & Crossbows (due soon) Added unit tests for FlatFileDatabaseManager NOTES: diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java index ceb75d12f..24f215191 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java @@ -1,5 +1,15 @@ package com.gmail.nossr50.datatypes.skills; +import com.gmail.nossr50.config.GeneralConfig; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.skills.SkillTools; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + public enum PrimarySkillType { ACROBATICS, ALCHEMY, @@ -15,5 +25,209 @@ public enum PrimarySkillType { SWORDS, TAMING, UNARMED, - WOODCUTTING + WOODCUTTING; + + /* + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + * Everything below here will be removed in 2.2 (Tridents & Crossbows) + */ + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#getLevelCap(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public int getMaxLevel() { + return mcMMO.p.getSkillTools().getLevelCap(this); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#isSuperAbilityUnlocked(com.gmail.nossr50.datatypes.skills.PrimarySkillType, org.bukkit.entity.Player) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public boolean isSuperAbilityUnlocked(@NotNull Player player) { return mcMMO.p.getSkillTools().isSuperAbilityUnlocked(this, player); } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#getPVPEnabled(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public boolean getPVPEnabled() { + return mcMMO.p.getSkillTools().getPVPEnabled(this); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#getPVEEnabled(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public boolean getPVEEnabled() { + return mcMMO.p.getSkillTools().getPVEEnabled(this); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see GeneralConfig#getDoubleDropsDisabled(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public boolean getDoubleDropsDisabled() { + return mcMMO.p.getGeneralConfig().getDoubleDropsDisabled(this); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#getHardcoreStatLossEnabled(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public boolean getHardcoreStatLossEnabled() { + return mcMMO.p.getSkillTools().getHardcoreStatLossEnabled(this); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#getHardcoreVampirismEnabled(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public boolean getHardcoreVampirismEnabled() { + return mcMMO.p.getSkillTools().getHardcoreVampirismEnabled(this); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#getPrimarySkillToolType(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public ToolType getTool() { + return mcMMO.p.getSkillTools().getPrimarySkillToolType(this); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#getSubSkills(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public List getSkillAbilities() { + return mcMMO.p.getSkillTools().getSubSkills(this); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#getXpModifier(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public double getXpModifier() { + return mcMMO.p.getSkillTools().getXpModifier(this); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#matchSkill(java.lang.String) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public static PrimarySkillType getSkill(String skillName) { + return mcMMO.p.getSkillTools().matchSkill(skillName); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#isChildSkill(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public boolean isChildSkill() { + return mcMMO.p.getSkillTools().isChildSkill(this); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#getPrimarySkillBySubSkill(com.gmail.nossr50.datatypes.skills.SubSkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public static PrimarySkillType bySecondaryAbility(SubSkillType subSkillType) { + return mcMMO.p.getSkillTools().getPrimarySkillBySubSkill(subSkillType); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#getPrimarySkillBySuperAbility(com.gmail.nossr50.datatypes.skills.SuperAbilityType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public static PrimarySkillType byAbility(SuperAbilityType superAbilityType) { + return mcMMO.p.getSkillTools().getPrimarySkillBySuperAbility(superAbilityType); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#getLocalizedSkillName(com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public String getName() { + return mcMMO.p.getSkillTools().getLocalizedSkillName(this); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see Permissions#skillEnabled(org.bukkit.permissions.Permissible, com.gmail.nossr50.datatypes.skills.PrimarySkillType) + * @deprecated this is being removed in an upcoming update + */ + @Deprecated + public boolean getPermissions(Player player) { + return Permissions.skillEnabled(player, this); + } + + /** + * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + * @return the max level of this skill + * @see SkillTools#canCombatSkillsTrigger(com.gmail.nossr50.datatypes.skills.PrimarySkillType, org.bukkit.entity.Entity) + * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead + */ + @Deprecated + public boolean shouldProcess(Entity target) { + return mcMMO.p.getSkillTools().canCombatSkillsTrigger(this, target); + } } \ No newline at end of file diff --git a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java index f72a9409f..bdcb2833f 100644 --- a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java @@ -350,7 +350,8 @@ public class BlockListener implements Listener { } /* WOOD CUTTING */ - else if (BlockUtils.hasWoodcuttingXP(blockState) && ItemUtils.isAxe(heldItem) && Permissions.skillEnabled(player, PrimarySkillType.WOODCUTTING) && !mcMMO.getPlaceStore().isTrue(blockState)) { + else if (BlockUtils.hasWoodcuttingXP(blockState) && ItemUtils.isAxe(heldItem) + && Permissions.skillEnabled(player, PrimarySkillType.WOODCUTTING) && !mcMMO.getPlaceStore().isTrue(blockState)) { WoodcuttingManager woodcuttingManager = mcMMOPlayer.getWoodcuttingManager(); if (woodcuttingManager.canUseTreeFeller(heldItem)) { woodcuttingManager.processTreeFeller(blockState); diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java index 4fe98d5f7..846c7c413 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java @@ -267,7 +267,9 @@ public class SkillTools { } public boolean isSuperAbilityUnlocked(PrimarySkillType primarySkillType, Player player) { - return RankUtils.getRank(player, getSuperAbility(primarySkillType).getSubSkillTypeDefinition()) >= 1; + SuperAbilityType superAbilityType = mcMMO.p.getSkillTools().getSuperAbility(primarySkillType); + SubSkillType subSkillType = superAbilityType.getSubSkillTypeDefinition(); + return RankUtils.hasUnlockedSubskill(player, subSkillType); } public boolean getPVPEnabled(PrimarySkillType primarySkillType) { @@ -361,6 +363,10 @@ public class SkillTools { return "SuperAbility." + StringUtils.getPrettyCamelCaseName(superAbilityType) + ".Refresh"; } + public int getLevelCap(@NotNull PrimarySkillType primarySkillType) { + return mcMMO.p.getGeneralConfig().getLevelCap(primarySkillType); + } + /** * Get the permissions for this ability. * @@ -418,33 +424,4 @@ public class SkillTools { public @NotNull ImmutableList getMiscSkills() { return MISC_SKILLS; } - - // /** -// * Check if a block is affected by this ability. -// * -// * @param blockState the block to check -// * @param superAbilityType target super ability -// * @return true if the block is affected by this ability, false otherwise -// */ -// public boolean superAbilityBlockCheck(SuperAbilityType superAbilityType, BlockState blockState) { -// switch (superAbilityType) { -// case BERSERK: -// return (BlockUtils.affectedByGigaDrillBreaker(blockState) || blockState.getType() == Material.SNOW); -// -// case GIGA_DRILL_BREAKER: -// return BlockUtils.affectedByGigaDrillBreaker(blockState); -// -// case GREEN_TERRA: -// return BlockUtils.canMakeMossy(blockState); -// -// case SUPER_BREAKER: -// return BlockUtils.affectedBySuperBreaker(blockState); -// -// case TREE_FELLER: -// dfss -// -// default: -// return false; -// } -// } } From cfdcc9dee5a50f8d6c169578d5aa46280aa33de4 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 9 Apr 2021 10:48:08 -0700 Subject: [PATCH 14/57] Shorten notes --- Changelog.txt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index e801e84f4..49a67eaaa 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -7,22 +7,17 @@ Version 2.1.189 Updated pl locale (Thanks Mich3l3k) Fixed an IllegalPluginAccessException error that could happen during server shutdown Minor performance optimizations to FlatFile database + Minor performance optimizations to misc parts of the codebase Refactored a lot of code (API) PrimarySkillType will soon be just an enum with nothing special going on (API) Deprecated the members of PrimarySkillType use mcMMO::getSkillTools instead, deprecated members will be removed in Tridents & Crossbows (due soon) + (API) Some members of PrimarySkillType were removed and not deprecated (such as the field constants) Added unit tests for FlatFileDatabaseManager NOTES: Ultra Permissions is SAFE to use with mcMMO After getting in contact with the UltraPermissions devs and exhaustive testing, I have concluded that using UltraPermissions is completely safe with mcMMO. The users who had an issue with performance currently have an unknown cause, potentially it is from a plugin using the UltraPermissions API I really can't say without more data. My apologies to the UltraPermissions team for reporting an issue between our two plugins directly, as that is not the case. I would have tested it myself sooner but UltraPermissions was closed source and premium so I wasn't particularly motivated to do so, however I have been given access to the binaries so now I can do all the testing I want if future issues ever arise which I have zero expectations that they will. - UltraPermissions is as efficient as LuckPerms - I have done a lot of profiling of UltraPermissions via Spark in the last few hours, I also compared it to LuckPerms. I wasn't expecting it, but UltraPermissions runs just as fast as LuckPerms if not faster. So it has no performance issues whatsoever from my point of view. - - Use whatever permission plugin you like, there will be no difference between using LuckPerms or UltraPermissions with mcMMO. - - If you had issues with UltraPermissions please contact the UP devs - If you experience lag with mcMMO and UltraPermissions, we are trying to determine the culprit. It is likely the culprit is from another plugin doing bad things with the UltraPermissions API. Please get in contact with the UltraPermission devs if you run into issues ( @MATRIX | Timo K. & @Liz3 ). Neither I nor they can replicate it so we need you guys to provide more data. Version 2.1.188 Updated default entries in treasures.yml to use "Level_Requirement" instead of "Drop_Level" Fixed a bug where excavation treasures only required level 0 instead of loading the value from the config From be44c0e417768c847b6460bea03587cd958847f4 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 9 Apr 2021 11:13:27 -0700 Subject: [PATCH 15/57] Update SkillTools --- .../com/gmail/nossr50/api/ExperienceAPI.java | 2 +- .../nossr50/database/SQLDatabaseManager.java | 2 +- .../nossr50/datatypes/player/McMMOPlayer.java | 14 ++-- .../datatypes/player/PlayerProfile.java | 2 +- .../datatypes/skills/PrimarySkillType.java | 5 +- .../datatypes/skills/SuperAbilityType.java | 2 +- .../skills/subskills/acrobatics/Roll.java | 2 +- .../nossr50/listeners/BlockListener.java | 12 +-- .../nossr50/listeners/PlayerListener.java | 12 +-- .../commands/McrankCommandDisplayTask.java | 2 +- .../nossr50/util/commands/CommandUtils.java | 5 +- .../util/experience/FormulaManager.java | 2 +- .../util/scoreboards/ScoreboardWrapper.java | 5 +- .../nossr50/util/skills/CombatUtils.java | 12 +-- .../gmail/nossr50/util/skills/SkillTools.java | 73 +++++++++++-------- .../nossr50/util/skills/SmeltingTracker.java | 3 +- 16 files changed, 81 insertions(+), 74 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java index 81873a699..bc15b7043 100644 --- a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java +++ b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java @@ -802,7 +802,7 @@ public final class ExperienceAPI { * @throws InvalidSkillException if the given skill is not valid */ public static int getLevelCap(String skillType) { - return mcMMO.p.getGeneralConfig().getLevelCap(getSkillType(skillType)); + return mcMMO.p.getSkillTools().getLevelCap(getSkillType(skillType)); } /** diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index c218401a2..462fd6d66 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -936,7 +936,7 @@ public final class SQLDatabaseManager implements DatabaseManager { if (mcMMO.p.getGeneralConfig().getTruncateSkills()) { for (PrimarySkillType skill : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { - int cap = mcMMO.p.getGeneralConfig().getLevelCap(skill); + int cap = mcMMO.p.getSkillTools().getLevelCap(skill); if (cap != Integer.MAX_VALUE) { statement = connection.prepareStatement("UPDATE `" + tablePrefix + "skills` SET `" + skill.name().toLowerCase(Locale.ENGLISH) + "` = " + cap + " WHERE `" + skill.name().toLowerCase(Locale.ENGLISH) + "` > " + cap); statement.executeUpdate(); diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index 64f482fea..e851fb110 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -252,7 +252,7 @@ public class McMMOPlayer implements Identified { NotificationManager.sendPlayerInformationChatOnly(player, "LevelCap.PowerLevel", String.valueOf(mcMMO.p.getGeneralConfig().getPowerLevelCap())); } else if(hasReachedLevelCap(primarySkillType)) { NotificationManager.sendPlayerInformationChatOnly(player, "LevelCap.Skill", - String.valueOf(mcMMO.p.getGeneralConfig().getLevelCap(primarySkillType)), + String.valueOf(mcMMO.p.getSkillTools().getLevelCap(primarySkillType)), mcMMO.p.getSkillTools().getLocalizedSkillName(primarySkillType)); } @@ -570,7 +570,7 @@ public class McMMOPlayer implements Identified { int powerLevel = 0; for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { - if (Permissions.skillEnabled(player, primarySkillType)) { + if (mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, primarySkillType)) { powerLevel += getSkillLevel(primarySkillType); } } @@ -588,7 +588,7 @@ public class McMMOPlayer implements Identified { if(hasReachedPowerLevelCap()) return true; - return getSkillLevel(primarySkillType) >= mcMMO.p.getGeneralConfig().getLevelCap(primarySkillType); + return getSkillLevel(primarySkillType) >= mcMMO.p.getSkillTools().getLevelCap(primarySkillType); } /** @@ -616,7 +616,7 @@ public class McMMOPlayer implements Identified { float splitXp = xp / parentSkills.size(); for (PrimarySkillType parentSkill : parentSkills) { - if (Permissions.skillEnabled(player, parentSkill)) { + if (mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, parentSkill)) { beginXpGain(parentSkill, splitXp, xpGainReason, xpGainSource); } } @@ -660,7 +660,7 @@ public class McMMOPlayer implements Identified { * @param xp Experience amount to add */ public void applyXpGain(PrimarySkillType primarySkillType, float xp, XPGainReason xpGainReason, XPGainSource xpGainSource) { - if (!Permissions.skillEnabled(player, primarySkillType)) { + if (!mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, primarySkillType)) { return; } @@ -837,7 +837,7 @@ public class McMMOPlayer implements Identified { */ private float modifyXpGain(PrimarySkillType primarySkillType, float xp) { //TODO: A rare situation can occur where the default Power Level cap can prevent a player with one skill edited to something silly like Integer.MAX_VALUE from gaining XP in any skill, we may need to represent power level with another data type - if ((mcMMO.p.getGeneralConfig().getLevelCap(primarySkillType) <= getSkillLevel(primarySkillType)) + if ((mcMMO.p.getSkillTools().getLevelCap(primarySkillType) <= getSkillLevel(primarySkillType)) || (mcMMO.p.getGeneralConfig().getPowerLevelCap() <= getPowerLevel())) { return 0; } @@ -953,7 +953,7 @@ public class McMMOPlayer implements Identified { } public void processAbilityActivation(@NotNull PrimarySkillType primarySkillType) { - if (!Permissions.skillEnabled(getPlayer(), primarySkillType)) { + if (!mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(getPlayer(), primarySkillType)) { return; } diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java index 0b2b3cbb9..3fc0d6d70 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java @@ -432,7 +432,7 @@ public class PlayerProfile { int sum = 0; for (PrimarySkillType parent : parents) { - sum += Math.min(getSkillLevel(parent), mcMMO.p.getGeneralConfig().getLevelCap(parent)); + sum += Math.min(getSkillLevel(parent), mcMMO.p.getSkillTools().getLevelCap(parent)); } return sum / parents.size(); diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java index 24f215191..cad2245c1 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java @@ -8,6 +8,7 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; import java.util.List; public enum PrimarySkillType { @@ -140,7 +141,7 @@ public enum PrimarySkillType { */ @Deprecated public List getSkillAbilities() { - return mcMMO.p.getSkillTools().getSubSkills(this); + return new ArrayList<>(mcMMO.p.getSkillTools().getSubSkills(this)); } /** @@ -217,7 +218,7 @@ public enum PrimarySkillType { */ @Deprecated public boolean getPermissions(Player player) { - return Permissions.skillEnabled(player, this); + return mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, this); } /** diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java index 72c9fee69..6e4de8d78 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/SuperAbilityType.java @@ -111,7 +111,7 @@ public enum SuperAbilityType { } public int getCooldown() { - return mcMMO.p.getGeneralConfig().getCooldown(this); + return mcMMO.p.getSkillTools().getSuperAbilityCooldown(this); } public int getMaxLength() { diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java index 1a1c99fc9..64a3a14fb 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java @@ -83,7 +83,7 @@ public class Roll extends AcrobaticsSubSkill { entityDamageEvent.setCancelled(true); return true; } - } else if(Permissions.skillEnabled(player, PrimarySkillType.ACROBATICS)) { + } else if(mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.ACROBATICS)) { //Give XP Anyways SkillUtils.applyXpGain(mcMMOPlayer, getPrimarySkill(), calculateRollXP(player, ((EntityDamageEvent) event).getFinalDamage(), false), XPGainReason.PVE); } diff --git a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java index bdcb2833f..4ac4cec47 100644 --- a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java @@ -228,10 +228,10 @@ public class BlockListener implements Listener { if(mcMMOPlayer == null) return; - if (blockState.getType() == Repair.anvilMaterial && Permissions.skillEnabled(player, PrimarySkillType.REPAIR)) { + if (blockState.getType() == Repair.anvilMaterial && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.REPAIR)) { mcMMOPlayer.getRepairManager().placedAnvilCheck(); } - else if (blockState.getType() == Salvage.anvilMaterial && Permissions.skillEnabled(player, PrimarySkillType.SALVAGE)) { + else if (blockState.getType() == Salvage.anvilMaterial && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.SALVAGE)) { mcMMOPlayer.getSalvageManager().placedAnvilCheck(); } } @@ -333,7 +333,7 @@ public class BlockListener implements Listener { * We don't check the block store here because herbalism has too many unusual edge cases. * Instead, we check it inside the drops handler. */ - if (Permissions.skillEnabled(player, PrimarySkillType.HERBALISM)) { + if (mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.HERBALISM)) { herbalismManager.processHerbalismBlockBreakEvent(event); } /* @@ -344,14 +344,14 @@ public class BlockListener implements Listener { } /* MINING */ - else if (BlockUtils.affectedBySuperBreaker(blockState) && ItemUtils.isPickaxe(heldItem) && Permissions.skillEnabled(player, PrimarySkillType.MINING) && !mcMMO.getPlaceStore().isTrue(blockState)) { + else if (BlockUtils.affectedBySuperBreaker(blockState) && ItemUtils.isPickaxe(heldItem) && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.MINING) && !mcMMO.getPlaceStore().isTrue(blockState)) { MiningManager miningManager = mcMMOPlayer.getMiningManager(); miningManager.miningBlockCheck(blockState); } /* WOOD CUTTING */ else if (BlockUtils.hasWoodcuttingXP(blockState) && ItemUtils.isAxe(heldItem) - && Permissions.skillEnabled(player, PrimarySkillType.WOODCUTTING) && !mcMMO.getPlaceStore().isTrue(blockState)) { + && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.WOODCUTTING) && !mcMMO.getPlaceStore().isTrue(blockState)) { WoodcuttingManager woodcuttingManager = mcMMOPlayer.getWoodcuttingManager(); if (woodcuttingManager.canUseTreeFeller(heldItem)) { woodcuttingManager.processTreeFeller(blockState); @@ -366,7 +366,7 @@ public class BlockListener implements Listener { } /* EXCAVATION */ - else if (BlockUtils.affectedByGigaDrillBreaker(blockState) && ItemUtils.isShovel(heldItem) && Permissions.skillEnabled(player, PrimarySkillType.EXCAVATION) && !mcMMO.getPlaceStore().isTrue(blockState)) { + else if (BlockUtils.affectedByGigaDrillBreaker(blockState) && ItemUtils.isShovel(heldItem) && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.EXCAVATION) && !mcMMO.getPlaceStore().isTrue(blockState)) { ExcavationManager excavationManager = mcMMOPlayer.getExcavationManager(); excavationManager.excavationBlockCheck(blockState); diff --git a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java index f487a09ef..40c57adf7 100644 --- a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java @@ -296,7 +296,7 @@ public class PlayerListener implements Listener { return; } - if (!UserManager.hasPlayerDataKey(player) || !Permissions.skillEnabled(player, PrimarySkillType.FISHING)) { + if (!UserManager.hasPlayerDataKey(player) || !mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.FISHING)) { return; } @@ -382,7 +382,7 @@ public class PlayerListener implements Listener { return; } - if (!UserManager.hasPlayerDataKey(player) || !Permissions.skillEnabled(player, PrimarySkillType.FISHING)) { + if (!UserManager.hasPlayerDataKey(player) || !mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.FISHING)) { return; } @@ -677,7 +677,7 @@ public class PlayerListener implements Listener { if (!mcMMO.p.getGeneralConfig().getAbilitiesOnlyActivateWhenSneaking() || player.isSneaking()) { /* REPAIR CHECKS */ if (type == Repair.anvilMaterial - && Permissions.skillEnabled(player, PrimarySkillType.REPAIR) + && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.REPAIR) && mcMMO.getRepairableManager().isRepairable(heldItem) && heldItem.getAmount() <= 1) { RepairManager repairManager = mcMMOPlayer.getRepairManager(); @@ -691,7 +691,7 @@ public class PlayerListener implements Listener { } /* SALVAGE CHECKS */ else if (type == Salvage.anvilMaterial - && Permissions.skillEnabled(player, PrimarySkillType.SALVAGE) + && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.SALVAGE) && RankUtils.hasUnlockedSubskill(player, SubSkillType.SALVAGE_SCRAP_COLLECTOR) && mcMMO.getSalvageableManager().isSalvageable(heldItem) && heldItem.getAmount() <= 1) { @@ -724,7 +724,7 @@ public class PlayerListener implements Listener { if (!mcMMO.p.getGeneralConfig().getAbilitiesOnlyActivateWhenSneaking() || player.isSneaking()) { /* REPAIR CHECKS */ - if (type == Repair.anvilMaterial && Permissions.skillEnabled(player, PrimarySkillType.REPAIR) && mcMMO.getRepairableManager().isRepairable(heldItem)) { + if (type == Repair.anvilMaterial && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.REPAIR) && mcMMO.getRepairableManager().isRepairable(heldItem)) { RepairManager repairManager = mcMMOPlayer.getRepairManager(); // Cancel repairing an enchanted item @@ -734,7 +734,7 @@ public class PlayerListener implements Listener { } } /* SALVAGE CHECKS */ - else if (type == Salvage.anvilMaterial && Permissions.skillEnabled(player, PrimarySkillType.SALVAGE) && mcMMO.getSalvageableManager().isSalvageable(heldItem)) { + else if (type == Salvage.anvilMaterial && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.SALVAGE) && mcMMO.getSalvageableManager().isSalvageable(heldItem)) { SalvageManager salvageManager = mcMMOPlayer.getSalvageManager(); // Cancel salvaging an enchanted item diff --git a/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java b/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java index 28d09f8aa..b589357c0 100644 --- a/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java @@ -47,7 +47,7 @@ public class McrankCommandDisplayTask extends BukkitRunnable { sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Player", playerName)); for (PrimarySkillType skill : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { -// if (!Permissions.skillEnabled(player, skill)) { +// if (!mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, skill)) { // continue; // } diff --git a/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java b/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java index 0ccee19be..adb2d4851 100644 --- a/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java +++ b/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java @@ -6,7 +6,6 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; -import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.StringUtils; @@ -209,7 +208,7 @@ public final class CommandUtils { if (mcMMO.p.getSkillTools().isChildSkill(skill)) { return LocaleLoader.getString("Skills.ChildStats", LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".Listener") + " ", profile.getSkillLevel(skill)); } - if (profile.getSkillLevel(skill) == mcMMO.p.getGeneralConfig().getLevelCap(skill)){ + if (profile.getSkillLevel(skill) == mcMMO.p.getSkillTools().getLevelCap(skill)){ return LocaleLoader.getString("Skills.Stats", LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".Listener") + " ", profile.getSkillLevel(skill), profile.getSkillXpLevel(skill), LocaleLoader.getString("Skills.MaxXP")); } return LocaleLoader.getString("Skills.Stats", LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".Listener") + " ", profile.getSkillLevel(skill), profile.getSkillXpLevel(skill), profile.getXpToLevel(skill)); @@ -225,7 +224,7 @@ public final class CommandUtils { displayData.add(header); for (PrimarySkillType primarySkillType : skillGroup) { - if (Permissions.skillEnabled(inspectTarget, primarySkillType)) { + if (mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(inspectTarget, primarySkillType)) { displayData.add(displaySkill(profile, primarySkillType)); } } diff --git a/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java b/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java index c82a6e00e..f7478e24c 100644 --- a/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java +++ b/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java @@ -88,7 +88,7 @@ public class FormulaManager { public int[] calculateNewLevel(PrimarySkillType primarySkillType, int experience, FormulaType formulaType) { int newLevel = 0; int remainder = 0; - int maxLevel = mcMMO.p.getGeneralConfig().getLevelCap(primarySkillType); + int maxLevel = mcMMO.p.getSkillTools().getLevelCap(primarySkillType); while (experience > 0 && newLevel < maxLevel) { int experienceToNextLevel = getXPtoNextLevel(newLevel, formulaType); diff --git a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java index cee2d135a..9c23627da 100644 --- a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java +++ b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java @@ -13,7 +13,6 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.child.FamilyTree; import com.gmail.nossr50.util.Misc; -import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager.SidebarType; @@ -580,7 +579,7 @@ public class ScoreboardWrapper { powerLevel += level; // TODO: Verify that this is what we want - calculated in power level but not displayed - if (!Permissions.skillEnabled(player, skill)) { + if (!mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, skill)) { continue; } @@ -608,7 +607,7 @@ public class ScoreboardWrapper { Player player = mcMMO.p.getServer().getPlayerExact(playerName); for (PrimarySkillType skill : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { - if (!Permissions.skillEnabled(player, skill)) { + if (!mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, skill)) { continue; } diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index 2c9820a2c..934a3e07b 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -384,7 +384,7 @@ public final class CombatUtils { return; } - if (Permissions.skillEnabled(player, PrimarySkillType.SWORDS)) { + if (mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.SWORDS)) { processSwordCombat(target, player, event); } @@ -394,7 +394,7 @@ public final class CombatUtils { return; } - if (Permissions.skillEnabled(player, PrimarySkillType.AXES)) { + if (mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.AXES)) { processAxeCombat(target, player, event); } } @@ -403,7 +403,7 @@ public final class CombatUtils { return; } - if (Permissions.skillEnabled(player, PrimarySkillType.UNARMED)) { + if (mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.UNARMED)) { processUnarmedCombat(target, player, event); } } @@ -416,7 +416,7 @@ public final class CombatUtils { if (tamer instanceof Player && mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.TAMING, target)) { Player master = (Player) tamer; - if (!Misc.isNPCEntityExcludingVillagers(master) && Permissions.skillEnabled(master, PrimarySkillType.TAMING)) { + if (!Misc.isNPCEntityExcludingVillagers(master) && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(master, PrimarySkillType.TAMING)) { processTamingCombat(target, master, wolf, event); } } @@ -428,14 +428,14 @@ public final class CombatUtils { if (projectileSource instanceof Player && mcMMO.p.getSkillTools().canCombatSkillsTrigger(PrimarySkillType.ARCHERY, target)) { Player player = (Player) projectileSource; - if (!Misc.isNPCEntityExcludingVillagers(player) && Permissions.skillEnabled(player, PrimarySkillType.ARCHERY)) { + if (!Misc.isNPCEntityExcludingVillagers(player) && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.ARCHERY)) { processArcheryCombat(target, player, event, arrow); } else { //Cleanup Arrow cleanupArrowMetadata(arrow); } - if (target.getType() != EntityType.CREEPER && !Misc.isNPCEntityExcludingVillagers(player) && Permissions.skillEnabled(player, PrimarySkillType.TAMING)) { + if (target.getType() != EntityType.CREEPER && !Misc.isNPCEntityExcludingVillagers(player) && mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.TAMING)) { McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player); if(mcMMOPlayer == null) diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java index 846c7c413..cf61f7b96 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java @@ -11,6 +11,7 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.text.StringUtils; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; @@ -27,19 +28,19 @@ public class SkillTools { public final ImmutableList LOCALIZED_SKILL_NAMES; public final ImmutableList FORMATTED_SUBSKILL_NAMES; public final ImmutableSet EXACT_SUBSKILL_NAMES; - public final List CHILD_SKILLS; + public final ImmutableList CHILD_SKILLS; public final ImmutableList NON_CHILD_SKILLS; public final ImmutableList COMBAT_SKILLS; public final ImmutableList GATHERING_SKILLS; public final ImmutableList MISC_SKILLS; - private EnumMap subSkillParentRelationshipMap; //TODO: This disgusts me, but it will have to do until the new skill system is in place - private EnumMap superAbilityParentRelationshipMap; //TODO: This disgusts me, but it will have to do until the new skill system is in place - private EnumMap> primarySkillChildrenMap; //TODO: This disgusts me, but it will have to do until the new skill system is in place + private ImmutableMap subSkillParentRelationshipMap; + private ImmutableMap superAbilityParentRelationshipMap; + private ImmutableMap> primarySkillChildrenMap; // The map below is for the super abilities which require readying a tool, its everything except blast mining - private EnumMap mainActivatedAbilityChildMap; //TODO: This disgusts me, but it will have to do until the new skill system is in place - private EnumMap primarySkillToolMap; //TODO: Christ.. + private ImmutableMap mainActivatedAbilityChildMap; + private ImmutableMap primarySkillToolMap; public SkillTools(@NotNull mcMMO pluginRef) { this.pluginRef = pluginRef; @@ -72,39 +73,43 @@ public class SkillTools { NON_CHILD_SKILLS = ImmutableList.copyOf(nonChildSkills); } - //TODO: What is with this design? private void initPrimaryToolMap() { - primarySkillToolMap = new EnumMap(PrimarySkillType.class); + EnumMap tempToolMap = new EnumMap(PrimarySkillType.class); - primarySkillToolMap.put(PrimarySkillType.AXES, ToolType.AXE); - primarySkillToolMap.put(PrimarySkillType.WOODCUTTING, ToolType.AXE); - primarySkillToolMap.put(PrimarySkillType.UNARMED, ToolType.FISTS); - primarySkillToolMap.put(PrimarySkillType.SWORDS, ToolType.SWORD); - primarySkillToolMap.put(PrimarySkillType.EXCAVATION, ToolType.SHOVEL); - primarySkillToolMap.put(PrimarySkillType.HERBALISM, ToolType.HOE); - primarySkillToolMap.put(PrimarySkillType.MINING, ToolType.PICKAXE); + tempToolMap.put(PrimarySkillType.AXES, ToolType.AXE); + tempToolMap.put(PrimarySkillType.WOODCUTTING, ToolType.AXE); + tempToolMap.put(PrimarySkillType.UNARMED, ToolType.FISTS); + tempToolMap.put(PrimarySkillType.SWORDS, ToolType.SWORD); + tempToolMap.put(PrimarySkillType.EXCAVATION, ToolType.SHOVEL); + tempToolMap.put(PrimarySkillType.HERBALISM, ToolType.HOE); + tempToolMap.put(PrimarySkillType.MINING, ToolType.PICKAXE); + + primarySkillToolMap = ImmutableMap.copyOf(tempToolMap); } private void initSuperAbilityParentRelationships() { - superAbilityParentRelationshipMap = new EnumMap(SuperAbilityType.class); - mainActivatedAbilityChildMap = new EnumMap(PrimarySkillType.class); + EnumMap tempAbilityParentRelationshipMap = new EnumMap(SuperAbilityType.class); + EnumMap tempMainActivatedAbilityChildMap = new EnumMap(PrimarySkillType.class); for(SuperAbilityType superAbilityType : SuperAbilityType.values()) { try { PrimarySkillType parent = getSuperAbilityParent(superAbilityType); - superAbilityParentRelationshipMap.put(superAbilityType, parent); + tempAbilityParentRelationshipMap.put(superAbilityType, parent); if(superAbilityType != SuperAbilityType.BLAST_MINING) { //This map is used only for abilities that have a tool readying phase, so blast mining is ignored - mainActivatedAbilityChildMap.put(parent, superAbilityType); + tempMainActivatedAbilityChildMap.put(parent, superAbilityType); } } catch (InvalidSkillException e) { e.printStackTrace(); } } + + superAbilityParentRelationshipMap = ImmutableMap.copyOf(tempAbilityParentRelationshipMap); + mainActivatedAbilityChildMap = ImmutableMap.copyOf(tempMainActivatedAbilityChildMap); } - private PrimarySkillType getSuperAbilityParent(SuperAbilityType superAbilityType) throws InvalidSkillException { + private @NotNull PrimarySkillType getSuperAbilityParent(SuperAbilityType superAbilityType) throws InvalidSkillException { switch(superAbilityType) { case BERSERK: return PrimarySkillType.UNARMED; @@ -130,7 +135,7 @@ public class SkillTools { * Builds a list of localized {@link PrimarySkillType} names * @return list of localized {@link PrimarySkillType} names */ - private ArrayList buildLocalizedPrimarySkillNames() { + private @NotNull ArrayList buildLocalizedPrimarySkillNames() { ArrayList localizedSkillNameList = new ArrayList<>(); for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { @@ -147,11 +152,11 @@ public class SkillTools { * Disgusting Hacky Fix until the new skill system is in place */ private void initPrimaryChildMap() { - primarySkillChildrenMap = new EnumMap>(PrimarySkillType.class); + EnumMap> tempPrimaryChildMap = new EnumMap>(PrimarySkillType.class); //Init the empty Hash Sets for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { - primarySkillChildrenMap.put(primarySkillType, new HashSet()); + tempPrimaryChildMap.put(primarySkillType, new HashSet<>()); } //Fill in the hash sets @@ -159,8 +164,10 @@ public class SkillTools { PrimarySkillType parentSkill = subSkillParentRelationshipMap.get(subSkillType); //Add this subskill as a child - primarySkillChildrenMap.get(parentSkill).add(subSkillType); + tempPrimaryChildMap.get(parentSkill).add(subSkillType); } + + primarySkillChildrenMap = ImmutableMap.copyOf(tempPrimaryChildMap); } /** @@ -168,7 +175,7 @@ public class SkillTools { * Used in tab completion mostly * @return a list of formatted sub skill names */ - private ArrayList buildFormattedSubSkillNameList() { + private @NotNull ArrayList buildFormattedSubSkillNameList() { ArrayList subSkillNameList = new ArrayList<>(); for(SubSkillType subSkillType : SubSkillType.values()) { @@ -178,7 +185,7 @@ public class SkillTools { return subSkillNameList; } - private HashSet buildExactSubSkillNameList() { + private @NotNull HashSet buildExactSubSkillNameList() { HashSet subSkillNameExactSet = new HashSet<>(); for(SubSkillType subSkillType : SubSkillType.values()) { @@ -193,7 +200,7 @@ public class SkillTools { * Disgusting Hacky Fix until the new skill system is in place */ private void initSubSkillRelationshipMap() { - subSkillParentRelationshipMap = new EnumMap(SubSkillType.class); + EnumMap tempSubParentMap = new EnumMap(SubSkillType.class); //Super hacky and disgusting for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { @@ -202,10 +209,12 @@ public class SkillTools { if(primarySkillType.toString().equalsIgnoreCase(splitSubSkillName[0])) { //Parent Skill Found - subSkillParentRelationshipMap.put(subSkillType, primarySkillType); + tempSubParentMap.put(subSkillType, primarySkillType); } } } + + subSkillParentRelationshipMap = ImmutableMap.copyOf(tempSubParentMap); } /** @@ -292,9 +301,9 @@ public class SkillTools { return primarySkillToolMap.get(primarySkillType); } - public List getSubSkills(PrimarySkillType primarySkillType) { + public Set getSubSkills(PrimarySkillType primarySkillType) { //TODO: Cache this! - return new ArrayList<>(primarySkillChildrenMap.get(primarySkillType)); + return primarySkillChildrenMap.get(primarySkillType); } public double getXpModifier(PrimarySkillType primarySkillType) { @@ -323,7 +332,7 @@ public class SkillTools { return StringUtils.getCapitalized(LocaleLoader.getString(StringUtils.getCapitalized(primarySkillType.toString()) + ".SkillName")); } - public boolean doesPlayerHaveSkillPermission(PrimarySkillType primarySkillType, Player player) { + public boolean doesPlayerHaveSkillPermission(Player player, PrimarySkillType primarySkillType) { return Permissions.skillEnabled(player, primarySkillType); } @@ -364,7 +373,7 @@ public class SkillTools { } public int getLevelCap(@NotNull PrimarySkillType primarySkillType) { - return mcMMO.p.getGeneralConfig().getLevelCap(primarySkillType); + return mcMMO.p.getSkillTools().getLevelCap(primarySkillType); } /** diff --git a/src/main/java/com/gmail/nossr50/util/skills/SmeltingTracker.java b/src/main/java/com/gmail/nossr50/util/skills/SmeltingTracker.java index 630991341..dfa313181 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SmeltingTracker.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SmeltingTracker.java @@ -3,7 +3,6 @@ package com.gmail.nossr50.util.skills; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.player.UserManager; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -89,7 +88,7 @@ public class SmeltingTracker { } public void processFurnaceOwnership(Furnace furnace, Player player) { - if(!Permissions.skillEnabled(player, PrimarySkillType.SMELTING)) + if(!mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, PrimarySkillType.SMELTING)) return; //Don't swap ownership if its the same player From 323f4964203d1aacab87a5d9fa6ddb9fa7afdb18 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 9 Apr 2021 11:15:07 -0700 Subject: [PATCH 16/57] Fix infinite loop --- src/main/java/com/gmail/nossr50/util/skills/SkillTools.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java index cf61f7b96..280eb1db1 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java @@ -373,7 +373,7 @@ public class SkillTools { } public int getLevelCap(@NotNull PrimarySkillType primarySkillType) { - return mcMMO.p.getSkillTools().getLevelCap(primarySkillType); + return mcMMO.p.getGeneralConfig().getLevelCap(primarySkillType); } /** From 834ccc946ac4734e4aab373f89fa2ec51590369b Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 9 Apr 2021 16:45:58 -0700 Subject: [PATCH 17/57] FlatFileDatabaseManager refactor + adding tests part 1 --- Changelog.txt | 5 +- .../database/ConvertDatabaseCommand.java | 3 - .../nossr50/database/DatabaseManager.java | 2 - .../gmail/nossr50/database/ExpectedType.java | 12 + .../database/FlatFileDataContainer.java | 5 + .../nossr50/database/FlatFileDataFlag.java | 14 + .../database/FlatFileDataProcessor.java | 303 ++++++++++++++++++ .../database/FlatFileDatabaseManager.java | 148 ++++++--- .../nossr50/database/SQLDatabaseManager.java | 3 - .../flatfile/CategorizedFlatFileData.java | 50 +++ .../CategorizedFlatFileDataBuilder.java | 33 ++ .../datatypes/skills/PrimarySkillType.java | 19 +- src/main/java/com/gmail/nossr50/mcMMO.java | 1 - .../gmail/nossr50/util/skills/SkillTools.java | 187 +++++------ .../database/FlatFileDatabaseManagerTest.java | 80 ++++- .../nossr50/util/skills/SkillToolsTest.java | 16 + 16 files changed, 721 insertions(+), 160 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/database/ExpectedType.java create mode 100644 src/main/java/com/gmail/nossr50/database/FlatFileDataContainer.java create mode 100644 src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java create mode 100644 src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java create mode 100644 src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileData.java create mode 100644 src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileDataBuilder.java create mode 100644 src/test/java/com/gmail/nossr50/util/skills/SkillToolsTest.java diff --git a/Changelog.txt b/Changelog.txt index 49a67eaaa..932a69327 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,4 +1,7 @@ Version 2.1.189 + Rewrote how FlatFileDatabase verifies data integrity + Added unit tests for FlatFileDatabaseManager (see notes) + Fixed a bug where FlatFileDatabaseManager didn't properly upgrade older database entries to the newest schema The setting to disable the mcMMO user block tracker has been moved from our "hidden config" to persistent_data.yml Added 'mcMMO_Region_System.Enabled' to persistent_data.yml (don't touch this setting unless you know what you are doing) Fixed a bug that would remove components from death messages when players were killed by mobs (thanks lexikiq) @@ -12,9 +15,9 @@ Version 2.1.189 (API) PrimarySkillType will soon be just an enum with nothing special going on (API) Deprecated the members of PrimarySkillType use mcMMO::getSkillTools instead, deprecated members will be removed in Tridents & Crossbows (due soon) (API) Some members of PrimarySkillType were removed and not deprecated (such as the field constants) - Added unit tests for FlatFileDatabaseManager NOTES: + The tests added for FlatFileDatabase will help make sure bugs don't result in any loss of data Ultra Permissions is SAFE to use with mcMMO After getting in contact with the UltraPermissions devs and exhaustive testing, I have concluded that using UltraPermissions is completely safe with mcMMO. The users who had an issue with performance currently have an unknown cause, potentially it is from a plugin using the UltraPermissions API I really can't say without more data. My apologies to the UltraPermissions team for reporting an issue between our two plugins directly, as that is not the case. I would have tested it myself sooner but UltraPermissions was closed source and premium so I wasn't particularly motivated to do so, however I have been given access to the binaries so now I can do all the testing I want if future issues ever arise which I have zero expectations that they will. 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 bc383cf99..1667e9111 100644 --- a/src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java @@ -33,8 +33,6 @@ public class ConvertDatabaseCommand implements CommandExecutor { return true; } - oldDatabase.init(); - if (previousType == DatabaseType.CUSTOM) { Class clazz; @@ -47,7 +45,6 @@ public class ConvertDatabaseCommand implements CommandExecutor { } oldDatabase = DatabaseManagerFactory.createCustomDatabaseManager((Class) clazz); - oldDatabase.init(); } catch (Throwable e) { e.printStackTrace(); sender.sendMessage(LocaleLoader.getString("Commands.mcconvert.Database.InvalidType", args[1])); diff --git a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java index 47baafe63..831ec579a 100644 --- a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java @@ -73,8 +73,6 @@ public interface DatabaseManager { */ Map readRank(String playerName); - default void init() {}; - /** * Add a new user to the database. * diff --git a/src/main/java/com/gmail/nossr50/database/ExpectedType.java b/src/main/java/com/gmail/nossr50/database/ExpectedType.java new file mode 100644 index 000000000..57da078fb --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/ExpectedType.java @@ -0,0 +1,12 @@ +package com.gmail.nossr50.database; + +public enum ExpectedType { + STRING, + INTEGER, + BOOLEAN, + FLOAT, + DOUBLE, + UUID, + IGNORED, + OUT_OF_RANGE +} diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDataContainer.java b/src/main/java/com/gmail/nossr50/database/FlatFileDataContainer.java new file mode 100644 index 000000000..5559714a7 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDataContainer.java @@ -0,0 +1,5 @@ +package com.gmail.nossr50.database; + +//Marker interface +public interface FlatFileDataContainer { +} diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java b/src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java new file mode 100644 index 000000000..12dab5a84 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java @@ -0,0 +1,14 @@ +package com.gmail.nossr50.database; + +public enum FlatFileDataFlag { + INCOMPLETE, + BAD_VALUES, + MISSING_NAME, + DUPLICATE_NAME_FIXABLE, + DUPLICATE_NAME_NOT_FIXABLE, + DUPLICATE_UUID, + MISSING_OR_NULL_UUID, + TOO_INCOMPLETE, + JUNK, + EMPTY, +} diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java new file mode 100644 index 000000000..52f2fed51 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java @@ -0,0 +1,303 @@ +package com.gmail.nossr50.database; + +import com.gmail.nossr50.database.flatfile.CategorizedFlatFileData; +import com.gmail.nossr50.database.flatfile.CategorizedFlatFileDataBuilder; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.*; +import java.util.logging.Logger; + +import static com.gmail.nossr50.database.FlatFileDatabaseManager.*; + +public class FlatFileDataProcessor { + public static final String INVALID_OLD_USERNAME = "_INVALID_OLD_USERNAME_"; + private @NotNull List categorizedDataList; + private @NotNull List flatFileDataFlags; + private final @NotNull File userFile; + private final @NotNull Logger logger; + private final HashSet names; + private final HashSet uuids; + private int uniqueProcessingID; + boolean corruptDataFound; + + public FlatFileDataProcessor(@NotNull File userFile, @NotNull Logger logger) { + this.userFile = userFile; + this.logger = logger; + categorizedDataList = new ArrayList<>(); + flatFileDataFlags = new ArrayList<>(); + names = new HashSet<>(); + uuids = new HashSet<>(); + uniqueProcessingID = 0; + } + + public void processData(@NotNull String lineData) { + CategorizedFlatFileDataBuilder builder = new CategorizedFlatFileDataBuilder(lineData, uniqueProcessingID); + uniqueProcessingID++; + + /* + * Is the line empty? + */ + if (lineData.isEmpty()) { + registerData(builder.appendFlag(FlatFileDataFlag.EMPTY)); + return; + } + + //Make sure the data line is "correct" + if(lineData.charAt(lineData.length() - 1) != ':') { + // Length checks depend on last rawSplitData being ':' + // We add it here if it is missing + lineData = lineData.concat(":"); + } + + //Split the data into an array + String[] splitDataLine = lineData.split(":"); + + //This is the minimum size of the split array needed to be considered proper data + if(splitDataLine.length < getMinimumSplitDataLength()) { + //Data is considered junk + if(!corruptDataFound) { + logger.severe("Some corrupt data was found in mcmmo.users and has been repaired, it is possible that some player data has been lost in this process."); + corruptDataFound = true; + } + + if(splitDataLine.length >= 10 //The value here is kind of arbitrary, it shouldn't be too low to avoid false positives, but also we aren't really going to correctly identify when player data has been corrupted or not with 100% accuracy ever + && splitDataLine[0] != null && !splitDataLine[0].isEmpty()) { + if(splitDataLine[0].length() <= 16 && splitDataLine[0].length() >= 3) { + logger.severe("Not enough data found to recover corrupted player data for user: "+splitDataLine[0]); + registerData(builder.appendFlag(FlatFileDataFlag.TOO_INCOMPLETE)); + return; + } + } else { + registerData(builder.appendFlag(FlatFileDataFlag.JUNK)); + return; + } + } + + /* + * Check for duplicate names + */ + + boolean nameIsDupe = false; + boolean invalidUUID = false; + + String name = splitDataLine[USERNAME_INDEX]; + String strOfUUID = splitDataLine[UUID_INDEX]; + + if(name.isEmpty()) { + reportBadDataLine("No name found for data", "[MISSING NAME]", lineData); + builder.appendFlag(FlatFileDataFlag.MISSING_NAME); + } + + if(strOfUUID.isEmpty() || strOfUUID.equalsIgnoreCase("NULL")) { + invalidUUID = true; + reportBadDataLine("Empty/null UUID for user", "Empty/null", lineData); + builder.appendFlag(FlatFileDataFlag.MISSING_OR_NULL_UUID); + } + + UUID uuid = null; + + try { + uuid = UUID.fromString(strOfUUID); + } catch (IllegalArgumentException e) { + invalidUUID = true; + //UUID does not conform + + reportBadDataLine("Invalid UUID data found for user", strOfUUID, lineData); + e.printStackTrace(); + } + + //Duplicate UUID is no good, reject them + if(uuid != null && uuids.contains(uuid)) { + registerData(builder.appendFlag(FlatFileDataFlag.DUPLICATE_UUID)); + return; + } + + if(names.contains(name)) { + //Duplicate entry + nameIsDupe = true; + + //We can accept them if they are a duped name if they have a unique UUID + if(invalidUUID) { + //Reject the data + reportBadDataLine("Duplicate user found and due to a missing UUID their data had to be discarded", name, lineData); + + registerData(builder.appendFlag(FlatFileDataFlag.DUPLICATE_NAME_NOT_FIXABLE)); + return; + } else { + builder.appendFlag(FlatFileDataFlag.DUPLICATE_NAME_FIXABLE); + } + } + + //Make sure the data is up to date schema wise + if(splitDataLine.length < DATA_ENTRY_COUNT) { + String[] correctSizeSplitData = Arrays.copyOf(splitDataLine, DATA_ENTRY_COUNT); + lineData = org.apache.commons.lang.StringUtils.join(correctSizeSplitData, ":") + ":"; + splitDataLine = lineData.split(":"); + builder.appendFlag(FlatFileDataFlag.INCOMPLETE); + builder.setStringDataRepresentation(lineData); + } + + /* + * After establishing this data has at least an identity we check for bad data + * Bad Value checks + */ + + //Check each data for bad values + boolean[] badDataValues = new boolean[DATA_ENTRY_COUNT]; + boolean anyBadData = false; + + for(int i = 0; i < DATA_ENTRY_COUNT; i++) { + if(shouldNotBeEmpty(splitDataLine[i], i)) { + badDataValues[i] = true; + anyBadData = true; + reportBadDataLine("Data is empty when it should not be at index", "[EMPTY]", lineData); + continue; + } + + boolean isCorrectType = isOfExpectedType(splitDataLine[i], getExpectedValueType(i)); + + if(!isCorrectType) { + reportBadDataLine("Data is not of correct type", splitDataLine[i], lineData); + anyBadData = true; + badDataValues[i] = true; + } + } + + if(anyBadData) { + builder.appendFlag(FlatFileDataFlag.BAD_VALUES); + } + } + + public boolean shouldNotBeEmpty(String data, int index) { + if(getExpectedValueType(index) == ExpectedType.IGNORED) { + return false; + } else { + return data.isEmpty(); + } + } + + public boolean isOfExpectedType(@NotNull String data, @NotNull ExpectedType expectedType) { + switch(expectedType) { + case STRING: + return true; + case INTEGER: + try { + Integer.valueOf(data); + return true; + } catch (Exception e) { + return false; + } + case BOOLEAN: + return data.equalsIgnoreCase("true") || data.equalsIgnoreCase("false"); + case FLOAT: + try { + Float.valueOf(data); + return true; + } catch (NumberFormatException e) { + return false; + } + case DOUBLE: + try { + Double.valueOf(data); + return true; + } catch (NumberFormatException e) { + return false; + } + case UUID: + try { + UUID.fromString(data); + return true; + } catch (IllegalArgumentException e) { + return false; + } + case OUT_OF_RANGE: + throw new ArrayIndexOutOfBoundsException("Value matched type OUT_OF_RANGE, this should never happen."); + case IGNORED: + default: + return true; + } + + } + + private void reportBadDataLine(String warning, String context, String dataLine) { + logger.severe("FlatFileDatabaseBuilder Warning: " + warning + " - " + context); + logger.severe("FlatFileDatabaseBuilder: (Line Data) - " + dataLine); + } + + private int getMinimumSplitDataLength() { + return UUID_INDEX + 1; + } + + private void registerData(@NotNull CategorizedFlatFileDataBuilder builder) { + CategorizedFlatFileData categorizedFlatFileData = builder.build(); + categorizedDataList.add(categorizedFlatFileData); + flatFileDataFlags.addAll(categorizedFlatFileData.getDataFlags()); + } + + public @NotNull ExpectedType getExpectedValueType(int dataIndex) { + switch(dataIndex) { + case USERNAME_INDEX: + return ExpectedType.STRING; + case 2: //Used to be for something, no longer used + case 3: //Used to be for something, no longer used + case HEALTHBAR: + return ExpectedType.IGNORED; + case SKILLS_MINING: + case SKILLS_REPAIR: + case SKILLS_UNARMED: + case SKILLS_HERBALISM: + case SKILLS_EXCAVATION: + case SKILLS_ARCHERY: + case SKILLS_SWORDS: + case SKILLS_AXES: + case SKILLS_WOODCUTTING: + case SKILLS_ACROBATICS: + case SKILLS_TAMING: + case SKILLS_FISHING: + case SKILLS_ALCHEMY: + case LAST_LOGIN: + case COOLDOWN_BERSERK: + case COOLDOWN_GIGA_DRILL_BREAKER: + case COOLDOWN_TREE_FELLER: + case COOLDOWN_GREEN_TERRA: + case COOLDOWN_SERRATED_STRIKES: + case COOLDOWN_SKULL_SPLITTER: + case COOLDOWN_SUPER_BREAKER: + case COOLDOWN_BLAST_MINING: + case SCOREBOARD_TIPS: + case COOLDOWN_CHIMAERA_WING: + return ExpectedType.INTEGER; + case EXP_MINING: + case EXP_WOODCUTTING: + case EXP_REPAIR: + case EXP_UNARMED: + case EXP_HERBALISM: + case EXP_EXCAVATION: + case EXP_ARCHERY: + case EXP_SWORDS: + case EXP_AXES: + case EXP_ACROBATICS: + case EXP_TAMING: + case EXP_FISHING: + case EXP_ALCHEMY: + return ExpectedType.FLOAT; + case UUID_INDEX: + return ExpectedType.UUID; + default: + return ExpectedType.OUT_OF_RANGE; + } + } + + public @NotNull List getCategorizedDataList() { + return categorizedDataList; + } + + public @NotNull List getFlatFileDataFlags() { + return flatFileDataFlags; + } + + public int getDataFlagCount() { + return flatFileDataFlags.size(); + } +} diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index 80d3f8ca7..33c88deab 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -32,48 +32,48 @@ public final class FlatFileDatabaseManager implements DatabaseManager { private final @NotNull 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 final int USERNAME_INDEX = 0; + public static final int SKILLS_MINING = 1; + public static final int EXP_MINING = 4; + public static final int SKILLS_WOODCUTTING = 5; + public static final int EXP_WOODCUTTING = 6; + public static final int SKILLS_REPAIR = 7; + public static final int SKILLS_UNARMED = 8; + public static final int SKILLS_HERBALISM = 9; + public static final int SKILLS_EXCAVATION = 10; + public static final int SKILLS_ARCHERY = 11; + public static final int SKILLS_SWORDS = 12; + public static final int SKILLS_AXES = 13; + public static final int SKILLS_ACROBATICS = 14; + public static final int EXP_REPAIR = 15; + public static final int EXP_UNARMED = 16; + public static final int EXP_HERBALISM = 17; + public static final int EXP_EXCAVATION = 18; + public static final int EXP_ARCHERY = 19; + public static final int EXP_SWORDS = 20; + public static final int EXP_AXES = 21; + public static final int EXP_ACROBATICS = 22; + public static final int SKILLS_TAMING = 24; + public static final int EXP_TAMING = 25; + public static final int COOLDOWN_BERSERK = 26; + public static final int COOLDOWN_GIGA_DRILL_BREAKER = 27; + public static final int COOLDOWN_TREE_FELLER = 28; + public static final int COOLDOWN_GREEN_TERRA = 29; + public static final int COOLDOWN_SERRATED_STRIKES = 30; + public static final int COOLDOWN_SKULL_SPLITTER = 31; + public static final int COOLDOWN_SUPER_BREAKER = 32; + public static final int SKILLS_FISHING = 34; + public static final int EXP_FISHING = 35; + public static final int COOLDOWN_BLAST_MINING = 36; + public static final int LAST_LOGIN = 37; + public static final int HEALTHBAR = 38; + public static final int SKILLS_ALCHEMY = 39; + public static final int EXP_ALCHEMY = 40; + public static final int UUID_INDEX = 41; + public static final int SCOREBOARD_TIPS = 42; + public static final int COOLDOWN_CHIMAERA_WING = 43; - public static int DATA_ENTRY_COUNT = COOLDOWN_CHIMAERA_WING + 1; //Update this everytime new data is added + public static final int DATA_ENTRY_COUNT = COOLDOWN_CHIMAERA_WING + 1; //Update this everytime new data is added protected FlatFileDatabaseManager(@NotNull String usersFilePath, @NotNull Logger logger, long purgeTime, int startingLevel) { usersFile = new File(usersFilePath); @@ -81,11 +81,18 @@ public final class FlatFileDatabaseManager implements DatabaseManager { this.logger = logger; this.purgeTime = purgeTime; this.startingLevel = startingLevel; - } - public void init() { - checkStructure(); - updateLeaderboards(); + checkFileHealthAndStructure(); + List flatFileDataFlags = checkFileHealthAndStructure(); + + if(flatFileDataFlags != null) { + if(flatFileDataFlags.size() > 0) { + logger.info("Detected "+flatFileDataFlags.size() + " data entries which need correction."); + } + } + + checkFileHealthAndStructure(); +// updateLeaderboards(); } public int purgePowerlessUsers() { @@ -855,7 +862,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { /** * Update the leader boards. */ - private void updateLeaderboards() { + public void updateLeaderboards() { // Only update FFS leaderboards every 10 minutes.. this puts a lot of strain on the server (depending on the size of the database) and should not be done frequently if (System.currentTimeMillis() < lastUpdate + UPDATE_WAIT_TIME) { return; @@ -958,11 +965,45 @@ public final class FlatFileDatabaseManager implements DatabaseManager { playerStatHash.put(PrimarySkillType.ALCHEMY, alchemy); } + public @Nullable List checkFileHealthAndStructure() { + FlatFileDataProcessor dataProcessor = null; + int dataFlagCount = 0; + + if (usersFile.exists()) { + BufferedReader bufferedReader = null; + + synchronized (fileWritingLock) { + + dataProcessor = new FlatFileDataProcessor(usersFile, logger); + + try { + String currentLine; + bufferedReader = new BufferedReader(new FileReader(usersFilePath)); + while ((currentLine = bufferedReader.readLine()) != null) { + dataProcessor.processData(currentLine); + } + } catch (IOException e) { + e.printStackTrace(); + } + + dataFlagCount = dataProcessor.getDataFlagCount(); + } + } + + if(dataProcessor == null || dataProcessor.getFlatFileDataFlags() == null) { + return null; + } else { + return dataProcessor.getFlatFileDataFlags(); + } + } + + /** * Checks that the file is present and valid */ - private void checkStructure() { + public int checkFileHealthAndStructureOld() { boolean corruptDataFound = false; + boolean oldDataFound = false; if (usersFile.exists()) { BufferedReader in = null; @@ -1030,6 +1071,7 @@ 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 + oldDataFound = true; String[] correctSizeSplitData = Arrays.copyOf(rawSplitData, DATA_ENTRY_COUNT); line = org.apache.commons.lang.StringUtils.join(correctSizeSplitData, ":") + ":"; rawSplitData = line.split(":"); @@ -1070,8 +1112,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { if(corruptDataFound) logger.info("Corrupt data was found and removed, everything should be working fine. It is possible some player data was lost."); - - return; } usersFile.getParentFile().mkdir(); @@ -1083,6 +1123,14 @@ public final class FlatFileDatabaseManager implements DatabaseManager { catch (IOException e) { e.printStackTrace(); } + + if(corruptDataFound) { + return 1; + } else if(oldDataFound) { + return 2; + } else { + return 0; + } } private Integer getPlayerRank(String playerName, List statsList) { @@ -1239,7 +1287,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { return DatabaseType.FLATFILE; } - public File getUsersFile() { + public @NotNull File getUsersFile() { return usersFile; } diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index 462fd6d66..9f09d77f2 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -113,10 +113,7 @@ public final class SQLDatabaseManager implements DatabaseManager { poolProperties.setValidationQuery("SELECT 1"); poolProperties.setValidationInterval(30000); loadPool = new DataSource(poolProperties); - } - @Override - public void init() { checkStructure(); } diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileData.java b/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileData.java new file mode 100644 index 000000000..341d3d949 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileData.java @@ -0,0 +1,50 @@ +package com.gmail.nossr50.database.flatfile; + +import com.gmail.nossr50.database.FlatFileDataContainer; +import com.gmail.nossr50.database.FlatFileDataFlag; +import com.gmail.nossr50.database.FlatFileDatabaseManager; +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; +import java.util.Set; + +public class CategorizedFlatFileData implements FlatFileDataContainer { + private final @NotNull Set dataFlags; + private final @NotNull String stringDataRepresentation; + private final int uniqueProcessingId; + private final boolean[] badDataIndexes; + + protected CategorizedFlatFileData(int uniqueProcessingId, @NotNull HashSet dataFlags, @NotNull String stringDataRepresentation) { + this.uniqueProcessingId = uniqueProcessingId; + this.dataFlags = dataFlags; + this.stringDataRepresentation = stringDataRepresentation; + badDataIndexes = new boolean[FlatFileDatabaseManager.DATA_ENTRY_COUNT]; + } + + protected CategorizedFlatFileData(int uniqueProcessingId, @NotNull HashSet dataFlags, @NotNull String stringDataRepresentation, boolean[] badDataIndexes) { + this.uniqueProcessingId = uniqueProcessingId; + this.dataFlags = dataFlags; + this.stringDataRepresentation = stringDataRepresentation; + this.badDataIndexes = badDataIndexes; + } + + public @NotNull Set getDataFlags() { + return dataFlags; + } + + public @NotNull String getStringDataRepresentation() { + return stringDataRepresentation; + } + + public int getUniqueProcessingId() { + return uniqueProcessingId; + } + + public boolean isHealthyData() { + return dataFlags.size() == 0; + } + + public boolean[] getBadDataIndexes() { + return badDataIndexes; + } +} diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileDataBuilder.java b/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileDataBuilder.java new file mode 100644 index 000000000..205403a3e --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileDataBuilder.java @@ -0,0 +1,33 @@ +package com.gmail.nossr50.database.flatfile; + +import com.gmail.nossr50.database.FlatFileDataFlag; +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; + +public class CategorizedFlatFileDataBuilder { + private final @NotNull HashSet dataFlags; + private @NotNull String stringDataRepresentation; + private final int uniqueProcessingId; + + public CategorizedFlatFileDataBuilder(@NotNull String stringDataRepresentation, int uniqueProcessingId) { + this.uniqueProcessingId = uniqueProcessingId; + this.stringDataRepresentation = stringDataRepresentation; + dataFlags = new HashSet<>(); + } + + public CategorizedFlatFileDataBuilder appendFlag(@NotNull FlatFileDataFlag dataFlag) { + dataFlags.add(dataFlag); + return this; + } + + public CategorizedFlatFileData build() { + assert dataFlags.size() > 0; + return new CategorizedFlatFileData(uniqueProcessingId, dataFlags, stringDataRepresentation); + } + + public CategorizedFlatFileDataBuilder setStringDataRepresentation(@NotNull String stringDataRepresentation) { + this.stringDataRepresentation = stringDataRepresentation; + return this; + } +} diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java index cad2245c1..f8abfa255 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java @@ -27,6 +27,7 @@ public enum PrimarySkillType { TAMING, UNARMED, WOODCUTTING; +// boolean issueWarning = true; /* * Everything below here will be removed in 2.2 (Tridents & Crossbows) @@ -47,6 +48,20 @@ public enum PrimarySkillType { * Everything below here will be removed in 2.2 (Tridents & Crossbows) */ + +// private void processWarning() { +// if(issueWarning) { +// StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); +// Bukkit.getScheduler().scheduleSyncDelayedTask(mcMMO.p, () -> { +// mcMMO.p.getLogger().severe("A plugin that hooks into mcMMO via the mcMMO API is using soon to be deprecated API calls. Contact the plugin author and inform them to update their code before it breaks."); +// mcMMO.p.getLogger().severe("Deprecation Call from: " + stackTraceElements[2].toString()); +// mcMMO.p.getLogger().severe("This warning will not repeat itself. Nothing is broken for now, but in the future it will be."); +// }); +// +// issueWarning = !issueWarning; +// } +// } + /** * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead * @return the max level of this skill @@ -65,7 +80,9 @@ public enum PrimarySkillType { * @deprecated this is being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead */ @Deprecated - public boolean isSuperAbilityUnlocked(@NotNull Player player) { return mcMMO.p.getSkillTools().isSuperAbilityUnlocked(this, player); } + public boolean isSuperAbilityUnlocked(@NotNull Player player) { + return mcMMO.p.getSkillTools().isSuperAbilityUnlocked(this, player); + } /** * WARNING: Being removed in an upcoming update, you should be using mcMMO.getSkillTools() instead diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index 719883444..69982d932 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -231,7 +231,6 @@ public class mcMMO extends JavaPlugin { this.purgeTime = 2630000000L * generalConfig.getOldUsersCutoff(); databaseManager = DatabaseManagerFactory.getDatabaseManager(mcMMO.getUsersFilePath(), getLogger(), purgeTime, mcMMO.p.getAdvancedConfig().getStartingLevel()); - databaseManager.init(); //Check for the newer API and tell them what to do if its missing checkForOutdatedAPI(); diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java index 280eb1db1..ae33665aa 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java @@ -10,6 +10,7 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.text.StringUtils; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -23,57 +24,70 @@ import java.util.*; public class SkillTools { private final mcMMO pluginRef; - //TODO: Should these be hash sets instead of lists? //TODO: Figure out which ones we don't need, this was copy pasted from a diff branch - public final ImmutableList LOCALIZED_SKILL_NAMES; - public final ImmutableList FORMATTED_SUBSKILL_NAMES; - public final ImmutableSet EXACT_SUBSKILL_NAMES; - public final ImmutableList CHILD_SKILLS; - public final ImmutableList NON_CHILD_SKILLS; - public final ImmutableList COMBAT_SKILLS; - public final ImmutableList GATHERING_SKILLS; - public final ImmutableList MISC_SKILLS; + public final @NotNull ImmutableList LOCALIZED_SKILL_NAMES; + public final @NotNull ImmutableList FORMATTED_SUBSKILL_NAMES; + public final @NotNull ImmutableSet EXACT_SUBSKILL_NAMES; + public final @NotNull ImmutableList CHILD_SKILLS; + public final @NotNull ImmutableList NON_CHILD_SKILLS; + public final @NotNull ImmutableList COMBAT_SKILLS; + public final @NotNull ImmutableList GATHERING_SKILLS; + public final @NotNull ImmutableList MISC_SKILLS; - private ImmutableMap subSkillParentRelationshipMap; - private ImmutableMap superAbilityParentRelationshipMap; - private ImmutableMap> primarySkillChildrenMap; + private final @NotNull ImmutableMap subSkillParentRelationshipMap; + private final @NotNull ImmutableMap superAbilityParentRelationshipMap; + private final @NotNull ImmutableMap> primarySkillChildrenMap; // The map below is for the super abilities which require readying a tool, its everything except blast mining - private ImmutableMap mainActivatedAbilityChildMap; - private ImmutableMap primarySkillToolMap; + private final ImmutableMap mainActivatedAbilityChildMap; + private final ImmutableMap primarySkillToolMap; public SkillTools(@NotNull mcMMO pluginRef) { this.pluginRef = pluginRef; - initSubSkillRelationshipMap(); - initPrimaryChildMap(); - initPrimaryToolMap(); - initSuperAbilityParentRelationships(); + /* + * Setup subskill -> parent relationship map + */ + EnumMap tempSubParentMap = new EnumMap(SubSkillType.class); - List childSkills = new ArrayList<>(); - List nonChildSkills = new ArrayList<>(); + //Super hacky and disgusting + for(PrimarySkillType primarySkillType1 : PrimarySkillType.values()) { + for(SubSkillType subSkillType : SubSkillType.values()) { + String[] splitSubSkillName = subSkillType.toString().split("_"); - for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { - if (isChildSkill(primarySkillType)) { - childSkills.add(primarySkillType); - } else { - nonChildSkills.add(primarySkillType); + if(primarySkillType1.toString().equalsIgnoreCase(splitSubSkillName[0])) { + //Parent Skill Found + tempSubParentMap.put(subSkillType, primarySkillType1); + } } } - COMBAT_SKILLS = ImmutableList.of(PrimarySkillType.ARCHERY, PrimarySkillType.AXES, PrimarySkillType.SWORDS, PrimarySkillType.TAMING, PrimarySkillType.UNARMED); - GATHERING_SKILLS = ImmutableList.of(PrimarySkillType.EXCAVATION, PrimarySkillType.FISHING, PrimarySkillType.HERBALISM, PrimarySkillType.MINING, PrimarySkillType.WOODCUTTING); - MISC_SKILLS = ImmutableList.of(PrimarySkillType.ACROBATICS, PrimarySkillType.ALCHEMY, PrimarySkillType.REPAIR, PrimarySkillType.SALVAGE, PrimarySkillType.SMELTING); + subSkillParentRelationshipMap = ImmutableMap.copyOf(tempSubParentMap); - LOCALIZED_SKILL_NAMES = ImmutableList.copyOf(buildLocalizedPrimarySkillNames()); - FORMATTED_SUBSKILL_NAMES = ImmutableList.copyOf(buildFormattedSubSkillNameList()); - EXACT_SUBSKILL_NAMES = ImmutableSet.copyOf(buildExactSubSkillNameList()); + /* + * Setup primary -> (collection) subskill map + */ - CHILD_SKILLS = ImmutableList.copyOf(childSkills); - NON_CHILD_SKILLS = ImmutableList.copyOf(nonChildSkills); - } + EnumMap> tempPrimaryChildMap = new EnumMap>(PrimarySkillType.class); - private void initPrimaryToolMap() { + //Init the empty Hash Sets + for(PrimarySkillType primarySkillType1 : PrimarySkillType.values()) { + tempPrimaryChildMap.put(primarySkillType1, new HashSet<>()); + } + + //Fill in the hash sets + for(SubSkillType subSkillType : SubSkillType.values()) { + PrimarySkillType parentSkill = subSkillParentRelationshipMap.get(subSkillType); + + //Add this subskill as a child + tempPrimaryChildMap.get(parentSkill).add(subSkillType); + } + + primarySkillChildrenMap = ImmutableMap.copyOf(tempPrimaryChildMap); + + /* + * Setup primary -> tooltype map + */ EnumMap tempToolMap = new EnumMap(PrimarySkillType.class); tempToolMap.put(PrimarySkillType.AXES, ToolType.AXE); @@ -85,9 +99,12 @@ public class SkillTools { tempToolMap.put(PrimarySkillType.MINING, ToolType.PICKAXE); primarySkillToolMap = ImmutableMap.copyOf(tempToolMap); - } - private void initSuperAbilityParentRelationships() { + /* + * Setup ability -> primary map + * Setup primary -> ability map + */ + EnumMap tempAbilityParentRelationshipMap = new EnumMap(SuperAbilityType.class); EnumMap tempMainActivatedAbilityChildMap = new EnumMap(PrimarySkillType.class); @@ -107,6 +124,40 @@ public class SkillTools { superAbilityParentRelationshipMap = ImmutableMap.copyOf(tempAbilityParentRelationshipMap); mainActivatedAbilityChildMap = ImmutableMap.copyOf(tempMainActivatedAbilityChildMap); + + /* + * Build child skill and nonchild skill lists + */ + + List childSkills = new ArrayList<>(); + List nonChildSkills = new ArrayList<>(); + + for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { + if (isChildSkill(primarySkillType)) { + childSkills.add(primarySkillType); + } else { + nonChildSkills.add(primarySkillType); + } + } + + CHILD_SKILLS = ImmutableList.copyOf(childSkills); + NON_CHILD_SKILLS = ImmutableList.copyOf(nonChildSkills); + + /* + * Build categorized skill lists + */ + + COMBAT_SKILLS = ImmutableList.of(PrimarySkillType.ARCHERY, PrimarySkillType.AXES, PrimarySkillType.SWORDS, PrimarySkillType.TAMING, PrimarySkillType.UNARMED); + GATHERING_SKILLS = ImmutableList.of(PrimarySkillType.EXCAVATION, PrimarySkillType.FISHING, PrimarySkillType.HERBALISM, PrimarySkillType.MINING, PrimarySkillType.WOODCUTTING); + MISC_SKILLS = ImmutableList.of(PrimarySkillType.ACROBATICS, PrimarySkillType.ALCHEMY, PrimarySkillType.REPAIR, PrimarySkillType.SALVAGE, PrimarySkillType.SMELTING); + + /* + * Build formatted/localized/etc string lists + */ + + LOCALIZED_SKILL_NAMES = ImmutableList.copyOf(buildLocalizedPrimarySkillNames()); + FORMATTED_SUBSKILL_NAMES = ImmutableList.copyOf(buildFormattedSubSkillNameList()); + EXACT_SUBSKILL_NAMES = ImmutableSet.copyOf(buildExactSubSkillNameList()); } private @NotNull PrimarySkillType getSuperAbilityParent(SuperAbilityType superAbilityType) throws InvalidSkillException { @@ -131,45 +182,6 @@ public class SkillTools { } } - /** - * Builds a list of localized {@link PrimarySkillType} names - * @return list of localized {@link PrimarySkillType} names - */ - private @NotNull ArrayList buildLocalizedPrimarySkillNames() { - ArrayList localizedSkillNameList = new ArrayList<>(); - - for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { - localizedSkillNameList.add(getLocalizedSkillName(primarySkillType)); - } - - Collections.sort(localizedSkillNameList); - - return localizedSkillNameList; - } - - /** - * Builds a map containing a HashSet of SubSkillTypes considered Children of PrimarySkillType - * Disgusting Hacky Fix until the new skill system is in place - */ - private void initPrimaryChildMap() { - EnumMap> tempPrimaryChildMap = new EnumMap>(PrimarySkillType.class); - - //Init the empty Hash Sets - for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { - tempPrimaryChildMap.put(primarySkillType, new HashSet<>()); - } - - //Fill in the hash sets - for(SubSkillType subSkillType : SubSkillType.values()) { - PrimarySkillType parentSkill = subSkillParentRelationshipMap.get(subSkillType); - - //Add this subskill as a child - tempPrimaryChildMap.get(parentSkill).add(subSkillType); - } - - primarySkillChildrenMap = ImmutableMap.copyOf(tempPrimaryChildMap); - } - /** * Makes a list of the "nice" version of sub skill names * Used in tab completion mostly @@ -196,25 +208,20 @@ public class SkillTools { } /** - * Builds a map containing the relationships of SubSkillTypes to PrimarySkillTypes - * Disgusting Hacky Fix until the new skill system is in place + * Builds a list of localized {@link PrimarySkillType} names + * @return list of localized {@link PrimarySkillType} names */ - private void initSubSkillRelationshipMap() { - EnumMap tempSubParentMap = new EnumMap(SubSkillType.class); + @VisibleForTesting + private @NotNull ArrayList buildLocalizedPrimarySkillNames() { + ArrayList localizedSkillNameList = new ArrayList<>(); - //Super hacky and disgusting for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { - for(SubSkillType subSkillType : SubSkillType.values()) { - String[] splitSubSkillName = subSkillType.toString().split("_"); - - if(primarySkillType.toString().equalsIgnoreCase(splitSubSkillName[0])) { - //Parent Skill Found - tempSubParentMap.put(subSkillType, primarySkillType); - } - } + localizedSkillNameList.add(getLocalizedSkillName(primarySkillType)); } - subSkillParentRelationshipMap = ImmutableMap.copyOf(tempSubParentMap); + Collections.sort(localizedSkillNameList); + + return localizedSkillNameList; } /** diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index 57efb3381..2603a2aad 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -1,48 +1,62 @@ package com.gmail.nossr50.database; import com.gmail.nossr50.TestUtil; +import com.gmail.nossr50.datatypes.database.DatabaseType; import com.google.common.io.Files; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.modules.junit4.PowerMockRunner; import java.io.*; +import java.util.List; import java.util.logging.Logger; +import static org.junit.Assert.*; + @RunWith(PowerMockRunner.class) public class FlatFileDatabaseManagerTest { public static final @NotNull String TEST_FILE_NAME = "test.mcmmo.users"; + public static final int HEALTHY_RETURN_CODE = 0; private static File tempDir; private final static @NotNull Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); private final long PURGE_TIME = 2630000000L; - private static @Nullable FlatFileDatabaseManager flatFileDatabaseManager; + private static @Nullable FlatFileDatabaseManager db; @Before public void init() { + assertNull(db); tempDir = Files.createTempDir(); - flatFileDatabaseManager = new FlatFileDatabaseManager(tempDir.getPath() + File.separator + TEST_FILE_NAME, logger, PURGE_TIME, 0); + db = new FlatFileDatabaseManager(tempDir.getPath() + File.separator + TEST_FILE_NAME, logger, PURGE_TIME, 0); } @After public void tearDown() { TestUtil.recursiveDelete(tempDir); - flatFileDatabaseManager = null; + db = null; } + //Nothing wrong with this database private static String[] normalDatabaseData = { "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:", "powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:" }; - private static String[] splitDataBadDatabase = { + private static String[] corruptDatabaseData = { + "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", + "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:", + "corruptdataboy:の:::ののの0:2452:0:1983:1937:1790:3042ののののの:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617のののののの583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:d20c6e8d-5615-4284-b8d1-e20b92011530:5:1600906906:", + "のjapaneseuserの:333:::0:2452:0:444:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:25870f0e-7558-4659-9f60-417e24cb3332:5:1600906906:", + "sameUUIDasjapaneseuser:333:::0:442:0:544:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:25870f0e-7558-4659-9f60-417e24cb3332:5:1600906906:", + }; + + private static String[] badDatabaseData = { //First entry here is missing some values "nossr50:1000:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", //Second entry here has an integer value replaced by a string @@ -51,12 +65,60 @@ public class FlatFileDatabaseManagerTest { @Test public void testPurgePowerlessUsers() { - Assert.assertNotNull(flatFileDatabaseManager); - addDataToFile(flatFileDatabaseManager, normalDatabaseData); - int purgeCount = flatFileDatabaseManager.purgePowerlessUsers(); - Assert.assertEquals(purgeCount, 1); //1 User should have been purged + assertNotNull(db); + addDataToFile(db, normalDatabaseData); + int purgeCount = db.purgePowerlessUsers(); + assertEquals(purgeCount, 1); //1 User should have been purged } + @Test + public void testCheckFileHealthAndStructure() { + assertNotNull(db); + + addDataToFile(db, badDatabaseData); + + List dataFlags = db.checkFileHealthAndStructure(); + assertNotNull(dataFlags); + assertNotEquals(dataFlags.size(), 0); + } + + @Test + public void testFindDuplicateNames() { + + } + + @Test + public void testFindDuplicateUUIDs() { + + } + + @Test + public void testFindCorruptData() { + + } + + @Test + public void testFindEmptyNames() { + + } + + @Test + public void testFindBadValues() { + + } + + @Test + public void testFindOutdatedData() { + + } + + @Test + public void testGetDatabaseType() { + assertNotNull(db); + assertEquals(db.getDatabaseType(), DatabaseType.FLATFILE); + } + + private void addDataToFile(@NotNull FlatFileDatabaseManager flatFileDatabaseManager, @NotNull String[] dataEntries) { String filePath = flatFileDatabaseManager.getUsersFile().getAbsolutePath(); BufferedReader in = null; diff --git a/src/test/java/com/gmail/nossr50/util/skills/SkillToolsTest.java b/src/test/java/com/gmail/nossr50/util/skills/SkillToolsTest.java new file mode 100644 index 000000000..4a295d5d3 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/util/skills/SkillToolsTest.java @@ -0,0 +1,16 @@ +//package com.gmail.nossr50.util.skills; +// +//import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +//import com.google.common.collect.ImmutableList; +//import org.junit.Before; +//import org.junit.Test; +//import org.junit.runner.RunWith; +//import org.powermock.core.classloader.annotations.PrepareForTest; +//import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; +//import org.powermock.modules.junit4.PowerMockRunner; +// +//@RunWith(PowerMockRunner.class) +//@PrepareForTest(SkillTools.class) +//public class SkillToolsTest { +// +//} \ No newline at end of file From aca1d6c0b15be0a8e17e1e9b975196884eda4b05 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 12 Apr 2021 09:02:50 -0700 Subject: [PATCH 18/57] Add test to find duplicate names - FlatFileDatabaseManagerTest --- .../nossr50/database/FlatFileDataProcessor.java | 15 ++++++++++++--- .../database/FlatFileDatabaseManager.java | 3 --- .../CategorizedFlatFileDataBuilder.java | 1 - .../database/FlatFileDatabaseManagerTest.java | 17 ++++++++++++++--- 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java index 52f2fed51..6bac0bc1b 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java @@ -113,6 +113,9 @@ public class FlatFileDataProcessor { return; } + uuids.add(uuid); + + if(names.contains(name)) { //Duplicate entry nameIsDupe = true; @@ -129,6 +132,8 @@ public class FlatFileDataProcessor { } } + names.add(name); + //Make sure the data is up to date schema wise if(splitDataLine.length < DATA_ENTRY_COUNT) { String[] correctSizeSplitData = Arrays.copyOf(splitDataLine, DATA_ENTRY_COUNT); @@ -151,7 +156,7 @@ public class FlatFileDataProcessor { if(shouldNotBeEmpty(splitDataLine[i], i)) { badDataValues[i] = true; anyBadData = true; - reportBadDataLine("Data is empty when it should not be at index", "[EMPTY]", lineData); + reportBadDataLine("Data is empty when it should not be at index", "[index=" + i + "]", lineData); continue; } @@ -167,6 +172,8 @@ public class FlatFileDataProcessor { if(anyBadData) { builder.appendFlag(FlatFileDataFlag.BAD_VALUES); } + + registerData(builder); } public boolean shouldNotBeEmpty(String data, int index) { @@ -239,8 +246,10 @@ public class FlatFileDataProcessor { switch(dataIndex) { case USERNAME_INDEX: return ExpectedType.STRING; - case 2: //Used to be for something, no longer used - case 3: //Used to be for something, no longer used + case 2: //Assumption: Used to be for something, no longer used + case 3: //Assumption: Used to be for something, no longer used + case 23: //Assumption: Used to be used for something, no longer used + case 33: //Assumption: Used to be used for something, no longer used case HEALTHBAR: return ExpectedType.IGNORED; case SKILLS_MINING: diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index 33c88deab..41ee427d1 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -967,7 +967,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { public @Nullable List checkFileHealthAndStructure() { FlatFileDataProcessor dataProcessor = null; - int dataFlagCount = 0; if (usersFile.exists()) { BufferedReader bufferedReader = null; @@ -985,8 +984,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } catch (IOException e) { e.printStackTrace(); } - - dataFlagCount = dataProcessor.getDataFlagCount(); } } diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileDataBuilder.java b/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileDataBuilder.java index 205403a3e..0723ff3ef 100644 --- a/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileDataBuilder.java +++ b/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileDataBuilder.java @@ -22,7 +22,6 @@ public class CategorizedFlatFileDataBuilder { } public CategorizedFlatFileData build() { - assert dataFlags.size() > 0; return new CategorizedFlatFileData(uniqueProcessingId, dataFlags, stringDataRepresentation); } diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index 2603a2aad..16ffb2106 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -48,6 +48,11 @@ public class FlatFileDatabaseManagerTest { "powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:" }; + private static String[] duplicateNameDatabaseData = { + "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", + "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:631e3896-da2a-4077-974b-d047859d76bc:0:0:", + }; + private static String[] corruptDatabaseData = { "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:", @@ -66,7 +71,7 @@ public class FlatFileDatabaseManagerTest { @Test public void testPurgePowerlessUsers() { assertNotNull(db); - addDataToFile(db, normalDatabaseData); + replaceDataInFile(db, normalDatabaseData); int purgeCount = db.purgePowerlessUsers(); assertEquals(purgeCount, 1); //1 User should have been purged } @@ -75,7 +80,7 @@ public class FlatFileDatabaseManagerTest { public void testCheckFileHealthAndStructure() { assertNotNull(db); - addDataToFile(db, badDatabaseData); + replaceDataInFile(db, badDatabaseData); List dataFlags = db.checkFileHealthAndStructure(); assertNotNull(dataFlags); @@ -84,7 +89,13 @@ public class FlatFileDatabaseManagerTest { @Test public void testFindDuplicateNames() { + assertNotNull(db); + replaceDataInFile(db, duplicateNameDatabaseData); + + List dataFlags = db.checkFileHealthAndStructure(); + assertNotNull(dataFlags); + assertTrue(dataFlags.contains(FlatFileDataFlag.DUPLICATE_NAME_FIXABLE)); } @Test @@ -119,7 +130,7 @@ public class FlatFileDatabaseManagerTest { } - private void addDataToFile(@NotNull FlatFileDatabaseManager flatFileDatabaseManager, @NotNull String[] dataEntries) { + private void replaceDataInFile(@NotNull FlatFileDatabaseManager flatFileDatabaseManager, @NotNull String[] dataEntries) { String filePath = flatFileDatabaseManager.getUsersFile().getAbsolutePath(); BufferedReader in = null; FileWriter out = null; From 60013c710bce88af76352eef64b8f07fd87c9ad3 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 12 Apr 2021 09:33:43 -0700 Subject: [PATCH 19/57] Add more tests to FlatFileDatabaseManagerTest --- .../nossr50/database/FlatFileDataFlag.java | 2 +- .../database/FlatFileDataProcessor.java | 22 ++++--- .../database/FlatFileDatabaseManagerTest.java | 64 +++++++++++++------ 3 files changed, 60 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java b/src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java index 12dab5a84..deae836b3 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java @@ -10,5 +10,5 @@ public enum FlatFileDataFlag { MISSING_OR_NULL_UUID, TOO_INCOMPLETE, JUNK, - EMPTY, + EMPTY_LINE, } diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java index 6bac0bc1b..fe415fc79 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java @@ -39,7 +39,7 @@ public class FlatFileDataProcessor { * Is the line empty? */ if (lineData.isEmpty()) { - registerData(builder.appendFlag(FlatFileDataFlag.EMPTY)); + registerData(builder.appendFlag(FlatFileDataFlag.EMPTY_LINE)); return; } @@ -61,6 +61,10 @@ public class FlatFileDataProcessor { corruptDataFound = true; } + //Flag as junk (corrupt) + builder.appendFlag(FlatFileDataFlag.JUNK); + + //TODO: This block here is probably pointless if(splitDataLine.length >= 10 //The value here is kind of arbitrary, it shouldn't be too low to avoid false positives, but also we aren't really going to correctly identify when player data has been corrupted or not with 100% accuracy ever && splitDataLine[0] != null && !splitDataLine[0].isEmpty()) { if(splitDataLine[0].length() <= 16 && splitDataLine[0].length() >= 3) { @@ -68,10 +72,10 @@ public class FlatFileDataProcessor { registerData(builder.appendFlag(FlatFileDataFlag.TOO_INCOMPLETE)); return; } - } else { - registerData(builder.appendFlag(FlatFileDataFlag.JUNK)); - return; } + + registerData(builder.appendFlag(FlatFileDataFlag.JUNK)); + return; } /* @@ -132,13 +136,13 @@ public class FlatFileDataProcessor { } } - names.add(name); + if(!name.isEmpty()) + names.add(name); //Make sure the data is up to date schema wise if(splitDataLine.length < DATA_ENTRY_COUNT) { - String[] correctSizeSplitData = Arrays.copyOf(splitDataLine, DATA_ENTRY_COUNT); - lineData = org.apache.commons.lang.StringUtils.join(correctSizeSplitData, ":") + ":"; - splitDataLine = lineData.split(":"); + splitDataLine = Arrays.copyOf(splitDataLine, DATA_ENTRY_COUNT+1); + lineData = org.apache.commons.lang.StringUtils.join(splitDataLine, ":") + ":"; builder.appendFlag(FlatFileDataFlag.INCOMPLETE); builder.setStringDataRepresentation(lineData); } @@ -180,7 +184,7 @@ public class FlatFileDataProcessor { if(getExpectedValueType(index) == ExpectedType.IGNORED) { return false; } else { - return data.isEmpty(); + return data == null || data.isEmpty(); } } diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index 16ffb2106..f9ca5fbf9 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -42,26 +42,50 @@ public class FlatFileDatabaseManagerTest { } //Nothing wrong with this database - private static String[] normalDatabaseData = { + private static final String[] normalDatabaseData = { "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:", "powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:" }; - private static String[] duplicateNameDatabaseData = { + private static final String[] outdatedDatabaseData = { + "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", + "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:", + "powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:" //This user is missing data added after UUID index + }; + + private static final String[] emptyLineDatabaseData = { + "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", + "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:", + "powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:", + "" //EMPTY LINE + }; + + private static final String[] emptyNameDatabaseData = { + ":1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", + "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:", + "powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:" + }; + + private static final String[] duplicateNameDatabaseData = { "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:631e3896-da2a-4077-974b-d047859d76bc:0:0:", }; - private static String[] corruptDatabaseData = { + private static final String[] duplicateUUIDDatabaseData = { "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", + "mrfloris:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", + }; + + private static final String[] corruptDatabaseData = { + "nossr50:1000:::0:100:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:", "corruptdataboy:の:::ののの0:2452:0:1983:1937:1790:3042ののののの:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617のののののの583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:d20c6e8d-5615-4284-b8d1-e20b92011530:5:1600906906:", "のjapaneseuserの:333:::0:2452:0:444:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:25870f0e-7558-4659-9f60-417e24cb3332:5:1600906906:", "sameUUIDasjapaneseuser:333:::0:442:0:544:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:25870f0e-7558-4659-9f60-417e24cb3332:5:1600906906:", }; - private static String[] badDatabaseData = { + private static final String[] badDatabaseData = { //First entry here is missing some values "nossr50:1000:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", //Second entry here has an integer value replaced by a string @@ -70,7 +94,6 @@ public class FlatFileDatabaseManagerTest { @Test public void testPurgePowerlessUsers() { - assertNotNull(db); replaceDataInFile(db, normalDatabaseData); int purgeCount = db.purgePowerlessUsers(); assertEquals(purgeCount, 1); //1 User should have been purged @@ -78,8 +101,6 @@ public class FlatFileDatabaseManagerTest { @Test public void testCheckFileHealthAndStructure() { - assertNotNull(db); - replaceDataInFile(db, badDatabaseData); List dataFlags = db.checkFileHealthAndStructure(); @@ -89,38 +110,37 @@ public class FlatFileDatabaseManagerTest { @Test public void testFindDuplicateNames() { - assertNotNull(db); - - replaceDataInFile(db, duplicateNameDatabaseData); - - List dataFlags = db.checkFileHealthAndStructure(); - assertNotNull(dataFlags); - assertTrue(dataFlags.contains(FlatFileDataFlag.DUPLICATE_NAME_FIXABLE)); + addDataAndCheckForFlag(db, duplicateNameDatabaseData, FlatFileDataFlag.DUPLICATE_NAME_FIXABLE); } @Test public void testFindDuplicateUUIDs() { - + addDataAndCheckForFlag(db, duplicateUUIDDatabaseData, FlatFileDataFlag.DUPLICATE_UUID); } @Test public void testFindCorruptData() { - + addDataAndCheckForFlag(db, corruptDatabaseData, FlatFileDataFlag.JUNK); } @Test public void testFindEmptyNames() { + addDataAndCheckForFlag(db, emptyNameDatabaseData, FlatFileDataFlag.MISSING_NAME); + } + @Test + public void testFindEmptyLine() { + addDataAndCheckForFlag(db, emptyLineDatabaseData, FlatFileDataFlag.EMPTY_LINE); } @Test public void testFindBadValues() { - + addDataAndCheckForFlag(db, badDatabaseData, FlatFileDataFlag.BAD_VALUES); } @Test public void testFindOutdatedData() { - + addDataAndCheckForFlag(db, outdatedDatabaseData, FlatFileDataFlag.INCOMPLETE); } @Test @@ -182,4 +202,12 @@ public class FlatFileDatabaseManagerTest { } } + + private void addDataAndCheckForFlag(@NotNull FlatFileDatabaseManager targetDatabase, @NotNull String[] data, @NotNull FlatFileDataFlag flag) { + replaceDataInFile(targetDatabase, data); + + List dataFlags = targetDatabase.checkFileHealthAndStructure(); + assertNotNull(dataFlags); + assertTrue(dataFlags.contains(flag)); + } } \ No newline at end of file From 85f3221a6057fb709e5cbd3be21e382c8554c6e6 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 12 Apr 2021 12:55:31 -0700 Subject: [PATCH 20/57] FlatFileDataProcessor will handle fixing and repairing the data --- .../database/FlatFileDataContainer.java | 5 - .../nossr50/database/FlatFileDataFlag.java | 5 +- .../database/FlatFileDataProcessor.java | 120 +++++++------ .../database/FlatFileDatabaseManager.java | 168 ++++-------------- .../flatfile/BadCategorizedFlatFileData.java | 42 +++++ .../flatfile/CategorizedFlatFileData.java | 44 +++-- .../CategorizedFlatFileDataBuilder.java | 32 ---- .../flatfile/FlatFileDataBuilder.java | 42 +++++ .../flatfile/FlatFileDataContainer.java | 21 +++ .../flatfile/FlatFileSaveDataProcessor.java | 117 ++++++++++++ .../database/FlatFileDatabaseManagerTest.java | 46 +++-- 11 files changed, 380 insertions(+), 262 deletions(-) delete mode 100644 src/main/java/com/gmail/nossr50/database/FlatFileDataContainer.java create mode 100644 src/main/java/com/gmail/nossr50/database/flatfile/BadCategorizedFlatFileData.java delete mode 100644 src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileDataBuilder.java create mode 100644 src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataBuilder.java create mode 100644 src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataContainer.java create mode 100644 src/main/java/com/gmail/nossr50/database/flatfile/FlatFileSaveDataProcessor.java diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDataContainer.java b/src/main/java/com/gmail/nossr50/database/FlatFileDataContainer.java deleted file mode 100644 index 5559714a7..000000000 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDataContainer.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.gmail.nossr50.database; - -//Marker interface -public interface FlatFileDataContainer { -} diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java b/src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java index deae836b3..58c3f6892 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java @@ -4,10 +4,9 @@ public enum FlatFileDataFlag { INCOMPLETE, BAD_VALUES, MISSING_NAME, - DUPLICATE_NAME_FIXABLE, - DUPLICATE_NAME_NOT_FIXABLE, + DUPLICATE_NAME, DUPLICATE_UUID, - MISSING_OR_NULL_UUID, + BAD_UUID_DATA, //Can be because it is missing, null, or just not compatible data TOO_INCOMPLETE, JUNK, EMPTY_LINE, diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java index fe415fc79..674cfc47b 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java @@ -1,30 +1,27 @@ package com.gmail.nossr50.database; -import com.gmail.nossr50.database.flatfile.CategorizedFlatFileData; -import com.gmail.nossr50.database.flatfile.CategorizedFlatFileDataBuilder; +import com.gmail.nossr50.database.flatfile.FlatFileDataBuilder; +import com.gmail.nossr50.database.flatfile.FlatFileDataContainer; +import com.gmail.nossr50.database.flatfile.FlatFileSaveDataProcessor; import org.jetbrains.annotations.NotNull; -import java.io.File; import java.util.*; import java.util.logging.Logger; import static com.gmail.nossr50.database.FlatFileDatabaseManager.*; public class FlatFileDataProcessor { - public static final String INVALID_OLD_USERNAME = "_INVALID_OLD_USERNAME_"; - private @NotNull List categorizedDataList; - private @NotNull List flatFileDataFlags; - private final @NotNull File userFile; + private final @NotNull List flatFileDataContainers; + private final @NotNull List flatFileDataFlags; private final @NotNull Logger logger; private final HashSet names; private final HashSet uuids; private int uniqueProcessingID; boolean corruptDataFound; - public FlatFileDataProcessor(@NotNull File userFile, @NotNull Logger logger) { - this.userFile = userFile; + public FlatFileDataProcessor(@NotNull Logger logger) { this.logger = logger; - categorizedDataList = new ArrayList<>(); + flatFileDataContainers = new ArrayList<>(); flatFileDataFlags = new ArrayList<>(); names = new HashSet<>(); uuids = new HashSet<>(); @@ -32,16 +29,7 @@ public class FlatFileDataProcessor { } public void processData(@NotNull String lineData) { - CategorizedFlatFileDataBuilder builder = new CategorizedFlatFileDataBuilder(lineData, uniqueProcessingID); - uniqueProcessingID++; - - /* - * Is the line empty? - */ - if (lineData.isEmpty()) { - registerData(builder.appendFlag(FlatFileDataFlag.EMPTY_LINE)); - return; - } + assert !lineData.isEmpty(); //Make sure the data line is "correct" if(lineData.charAt(lineData.length() - 1) != ':') { @@ -53,6 +41,11 @@ public class FlatFileDataProcessor { //Split the data into an array String[] splitDataLine = lineData.split(":"); + FlatFileDataBuilder builder = new FlatFileDataBuilder(splitDataLine, uniqueProcessingID); + uniqueProcessingID++; + boolean[] badDataValues = new boolean[DATA_ENTRY_COUNT]; + boolean anyBadData = false; + //This is the minimum size of the split array needed to be considered proper data if(splitDataLine.length < getMinimumSplitDataLength()) { //Data is considered junk @@ -82,7 +75,6 @@ public class FlatFileDataProcessor { * Check for duplicate names */ - boolean nameIsDupe = false; boolean invalidUUID = false; String name = splitDataLine[USERNAME_INDEX]; @@ -91,12 +83,17 @@ public class FlatFileDataProcessor { if(name.isEmpty()) { reportBadDataLine("No name found for data", "[MISSING NAME]", lineData); builder.appendFlag(FlatFileDataFlag.MISSING_NAME); + anyBadData = true; + badDataValues[USERNAME_INDEX] = true; } if(strOfUUID.isEmpty() || strOfUUID.equalsIgnoreCase("NULL")) { invalidUUID = true; + badDataValues[UUID_INDEX] = true; reportBadDataLine("Empty/null UUID for user", "Empty/null", lineData); - builder.appendFlag(FlatFileDataFlag.MISSING_OR_NULL_UUID); + builder.appendFlag(FlatFileDataFlag.BAD_UUID_DATA); + + anyBadData = true; } UUID uuid = null; @@ -104,36 +101,23 @@ public class FlatFileDataProcessor { try { uuid = UUID.fromString(strOfUUID); } catch (IllegalArgumentException e) { - invalidUUID = true; //UUID does not conform - + invalidUUID = true; + badDataValues[UUID_INDEX] = true; reportBadDataLine("Invalid UUID data found for user", strOfUUID, lineData); - e.printStackTrace(); + builder.appendFlag(FlatFileDataFlag.BAD_UUID_DATA); } //Duplicate UUID is no good, reject them - if(uuid != null && uuids.contains(uuid)) { + if(!invalidUUID && uuid != null && uuids.contains(uuid)) { registerData(builder.appendFlag(FlatFileDataFlag.DUPLICATE_UUID)); return; } uuids.add(uuid); - if(names.contains(name)) { - //Duplicate entry - nameIsDupe = true; - - //We can accept them if they are a duped name if they have a unique UUID - if(invalidUUID) { - //Reject the data - reportBadDataLine("Duplicate user found and due to a missing UUID their data had to be discarded", name, lineData); - - registerData(builder.appendFlag(FlatFileDataFlag.DUPLICATE_NAME_NOT_FIXABLE)); - return; - } else { - builder.appendFlag(FlatFileDataFlag.DUPLICATE_NAME_FIXABLE); - } + builder.appendFlag(FlatFileDataFlag.DUPLICATE_NAME); } if(!name.isEmpty()) @@ -141,10 +125,17 @@ public class FlatFileDataProcessor { //Make sure the data is up to date schema wise if(splitDataLine.length < DATA_ENTRY_COUNT) { - splitDataLine = Arrays.copyOf(splitDataLine, DATA_ENTRY_COUNT+1); - lineData = org.apache.commons.lang.StringUtils.join(splitDataLine, ":") + ":"; + int oldLength = splitDataLine.length; + splitDataLine = Arrays.copyOf(splitDataLine, DATA_ENTRY_COUNT); + int newLength = splitDataLine.length; + + //TODO: Test this + for(int i = oldLength; i < (newLength - 1); i++){ + badDataValues[i] = true; + } + builder.appendFlag(FlatFileDataFlag.INCOMPLETE); - builder.setStringDataRepresentation(lineData); + builder.setSplitStringData(splitDataLine); } /* @@ -153,9 +144,6 @@ public class FlatFileDataProcessor { */ //Check each data for bad values - boolean[] badDataValues = new boolean[DATA_ENTRY_COUNT]; - boolean anyBadData = false; - for(int i = 0; i < DATA_ENTRY_COUNT; i++) { if(shouldNotBeEmpty(splitDataLine[i], i)) { badDataValues[i] = true; @@ -175,6 +163,7 @@ public class FlatFileDataProcessor { if(anyBadData) { builder.appendFlag(FlatFileDataFlag.BAD_VALUES); + builder.appendBadDataValues(badDataValues); } registerData(builder); @@ -240,13 +229,15 @@ public class FlatFileDataProcessor { return UUID_INDEX + 1; } - private void registerData(@NotNull CategorizedFlatFileDataBuilder builder) { - CategorizedFlatFileData categorizedFlatFileData = builder.build(); - categorizedDataList.add(categorizedFlatFileData); - flatFileDataFlags.addAll(categorizedFlatFileData.getDataFlags()); + private void registerData(@NotNull FlatFileDataBuilder builder) { + FlatFileDataContainer flatFileDataContainer = builder.build(); + flatFileDataContainers.add(flatFileDataContainer); + + if(flatFileDataContainer.getDataFlags() != null) + flatFileDataFlags.addAll(flatFileDataContainer.getDataFlags()); } - public @NotNull ExpectedType getExpectedValueType(int dataIndex) { + public @NotNull ExpectedType getExpectedValueType(int dataIndex) throws IndexOutOfBoundsException { switch(dataIndex) { case USERNAME_INDEX: return ExpectedType.STRING; @@ -297,13 +288,13 @@ public class FlatFileDataProcessor { return ExpectedType.FLOAT; case UUID_INDEX: return ExpectedType.UUID; - default: - return ExpectedType.OUT_OF_RANGE; } + + throw new IndexOutOfBoundsException(); } - public @NotNull List getCategorizedDataList() { - return categorizedDataList; + public @NotNull List getFlatFileDataContainers() { + return flatFileDataContainers; } public @NotNull List getFlatFileDataFlags() { @@ -313,4 +304,23 @@ public class FlatFileDataProcessor { public int getDataFlagCount() { return flatFileDataFlags.size(); } + + public @NotNull StringBuilder processDataForSave() { + StringBuilder stringBuilder = new StringBuilder(); + + //Fix our data if needed and prepare it to be saved + + for(FlatFileDataContainer dataContainer : flatFileDataContainers) { + String[] splitData = FlatFileSaveDataProcessor.getPreparedSaveDataLine(dataContainer); + + if(splitData == null) + continue; + + String fromSplit = org.apache.commons.lang.StringUtils.join(splitData, ":") + ":"; + stringBuilder.append(fromSplit).append("\r\n"); + } + + return stringBuilder; + } + } diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index 41ee427d1..37e58b2eb 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -20,6 +20,7 @@ import java.util.logging.Logger; public final class FlatFileDatabaseManager implements DatabaseManager { public static final String IGNORED = "IGNORED"; + public static final String LEGACY_INVALID_OLD_USERNAME = "_INVALID_OLD_USERNAME_'"; private final @NotNull EnumMap> playerStatHash = new EnumMap>(PrimarySkillType.class); private final @NotNull List powerLevels = new ArrayList<>(); private long lastUpdate = 0; @@ -965,24 +966,45 @@ public final class FlatFileDatabaseManager implements DatabaseManager { playerStatHash.put(PrimarySkillType.ALCHEMY, alchemy); } + /** + * Makes sure that the users file has valid entries + * @return + */ public @Nullable List checkFileHealthAndStructure() { FlatFileDataProcessor dataProcessor = null; if (usersFile.exists()) { BufferedReader bufferedReader = null; + FileWriter fileWriter = null; synchronized (fileWritingLock) { - dataProcessor = new FlatFileDataProcessor(usersFile, logger); + dataProcessor = new FlatFileDataProcessor(logger); try { String currentLine; bufferedReader = new BufferedReader(new FileReader(usersFilePath)); + + //Analyze the data while ((currentLine = bufferedReader.readLine()) != null) { + if(currentLine.isEmpty()) + continue; + + //TODO: We are never passing empty lines, should we remove the flag for them? dataProcessor.processData(currentLine); } + + //Only update the file if needed + if(dataProcessor.getFlatFileDataFlags().size() > 0) { + logger.info("Saving the updated and or repaired FlatFile Database..."); + fileWriter = new FileWriter(usersFilePath); + //Write data to file + fileWriter.write(dataProcessor.processDataForSave().toString()); + } } catch (IOException e) { e.printStackTrace(); + } finally { + closeResources(bufferedReader, fileWriter); } } } @@ -994,139 +1016,23 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - - /** - * Checks that the file is present and valid - */ - public int checkFileHealthAndStructureOld() { - boolean corruptDataFound = false; - boolean oldDataFound = false; - - if (usersFile.exists()) { - BufferedReader in = null; - FileWriter out = null; - - synchronized (fileWritingLock) { - try { - - in = new BufferedReader(new FileReader(usersFilePath)); - StringBuilder writer = new StringBuilder(); - String line; - HashSet usernames = new HashSet<>(); - HashSet players = new HashSet<>(); - - while ((line = in.readLine()) != null) { - // Remove empty lines from the file - if (line.isEmpty()) { - continue; - } - - // Length checks depend on last rawSplitData being ':' - if (line.charAt(line.length() - 1) != ':') { - line = line.concat(":"); - } - - String[] rawSplitData = line.split(":"); - - //Not enough data found to be considered a user reliably (NOTE: not foolproof) - if(rawSplitData.length < (UUID_INDEX + 1)) { - if(!corruptDataFound) { - logger.severe("Some corrupt data was found in mcmmo.users and has been repaired, it is possible that some player data has been lost in this process."); - corruptDataFound = true; - } - - if(rawSplitData.length >= 10 //The value here is kind of arbitrary, it shouldn't be too low to avoid false positives, but also we aren't really going to correctly identify when player data has been corrupted or not with 100% accuracy ever - && rawSplitData[0] != null && !rawSplitData[0].isEmpty()) { - if(rawSplitData[0].length() <= 16 && rawSplitData[0].length() >= 3) { - logger.severe("Not enough data found to recover corrupted player data for user: "+rawSplitData[0]); - } - } - //This user may have had a name so declare it - - continue; - } - - // Prevent the same username from being present multiple times - if (!usernames.add(rawSplitData[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")) { - logger.severe("Fixing duplicate player names found in mcmmo.users"); - continue; - } - } - - // Prevent the same player from being present multiple times - if (rawSplitData.length >= (UUID_INDEX + 1) //TODO: Test this condition - && (!rawSplitData[UUID_INDEX].isEmpty() - && !rawSplitData[UUID_INDEX].equals("NULL") && !players.add(rawSplitData[UUID_INDEX]))) { - - logger.severe("Removing duplicate player data from mcmmo.users"); - logger.info("Duplicate Data: "+line); - continue; - } - - //Correctly size the data (null entries for missing values) - if(line.length() < DATA_ENTRY_COUNT) { //TODO: Test this condition - oldDataFound = true; - String[] correctSizeSplitData = Arrays.copyOf(rawSplitData, DATA_ENTRY_COUNT); - 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"); - } - - } - - // Write the new file - out = new FileWriter(usersFilePath); - out.write(writer.toString()); - } - catch (IOException e) { - logger.severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e); - } - finally { - if (in != null) { - try { - in.close(); - } - catch (IOException e) { - e.printStackTrace(); - } - } - if (out != null) { - try { - out.close(); - } - catch (IOException e) { - e.printStackTrace(); - } - } - } + private void closeResources(BufferedReader bufferedReader, FileWriter fileWriter) { + if(bufferedReader != null) { + try { + bufferedReader.close(); + } + catch (IOException e) { + e.printStackTrace(); } - - if(corruptDataFound) - logger.info("Corrupt data was found and removed, everything should be working fine. It is possible some player data was lost."); } - usersFile.getParentFile().mkdir(); - - try { - logger.info("Creating mcmmo.users file..."); - new File(usersFilePath).createNewFile(); - } - catch (IOException e) { - e.printStackTrace(); - } - - if(corruptDataFound) { - return 1; - } else if(oldDataFound) { - return 2; - } else { - return 0; + if (fileWriter != null) { + try { + fileWriter.close(); + } + catch (IOException e) { + e.printStackTrace(); + } } } diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/BadCategorizedFlatFileData.java b/src/main/java/com/gmail/nossr50/database/flatfile/BadCategorizedFlatFileData.java new file mode 100644 index 000000000..fbeaf9c2d --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/flatfile/BadCategorizedFlatFileData.java @@ -0,0 +1,42 @@ +package com.gmail.nossr50.database.flatfile; + +import com.gmail.nossr50.database.FlatFileDataFlag; +import com.google.common.base.Objects; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.HashSet; + +public class BadCategorizedFlatFileData extends CategorizedFlatFileData { + private final boolean[] badDataIndexes; + + protected BadCategorizedFlatFileData(int uniqueProcessingId, @NotNull HashSet dataFlags, @NotNull String[] splitData, boolean[] badDataIndexes) { + super(uniqueProcessingId, dataFlags, splitData); + this.badDataIndexes = badDataIndexes; + } + + public boolean[] getBadDataIndexes() { + return badDataIndexes; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + BadCategorizedFlatFileData that = (BadCategorizedFlatFileData) o; + return Objects.equal(badDataIndexes, that.badDataIndexes); + } + + @Override + public int hashCode() { + return Objects.hashCode(super.hashCode(), badDataIndexes); + } + + @Override + public String toString() { + return "BadCategorizedFlatFileData{" + + "badDataIndexes=" + Arrays.toString(badDataIndexes) + + '}'; + } +} diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileData.java b/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileData.java index 341d3d949..8ed0478cb 100644 --- a/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileData.java +++ b/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileData.java @@ -1,8 +1,7 @@ package com.gmail.nossr50.database.flatfile; -import com.gmail.nossr50.database.FlatFileDataContainer; import com.gmail.nossr50.database.FlatFileDataFlag; -import com.gmail.nossr50.database.FlatFileDatabaseManager; +import com.google.common.base.Objects; import org.jetbrains.annotations.NotNull; import java.util.HashSet; @@ -10,30 +9,21 @@ import java.util.Set; public class CategorizedFlatFileData implements FlatFileDataContainer { private final @NotNull Set dataFlags; - private final @NotNull String stringDataRepresentation; + private final @NotNull String[] splitData; private final int uniqueProcessingId; - private final boolean[] badDataIndexes; - protected CategorizedFlatFileData(int uniqueProcessingId, @NotNull HashSet dataFlags, @NotNull String stringDataRepresentation) { + protected CategorizedFlatFileData(int uniqueProcessingId, @NotNull HashSet dataFlags, @NotNull String[] splitData) { this.uniqueProcessingId = uniqueProcessingId; this.dataFlags = dataFlags; - this.stringDataRepresentation = stringDataRepresentation; - badDataIndexes = new boolean[FlatFileDatabaseManager.DATA_ENTRY_COUNT]; - } - - protected CategorizedFlatFileData(int uniqueProcessingId, @NotNull HashSet dataFlags, @NotNull String stringDataRepresentation, boolean[] badDataIndexes) { - this.uniqueProcessingId = uniqueProcessingId; - this.dataFlags = dataFlags; - this.stringDataRepresentation = stringDataRepresentation; - this.badDataIndexes = badDataIndexes; + this.splitData = splitData; } public @NotNull Set getDataFlags() { return dataFlags; } - public @NotNull String getStringDataRepresentation() { - return stringDataRepresentation; + public @NotNull String[] getSplitData() { + return splitData; } public int getUniqueProcessingId() { @@ -44,7 +34,25 @@ public class CategorizedFlatFileData implements FlatFileDataContainer { return dataFlags.size() == 0; } - public boolean[] getBadDataIndexes() { - return badDataIndexes; + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CategorizedFlatFileData that = (CategorizedFlatFileData) o; + return uniqueProcessingId == that.uniqueProcessingId && Objects.equal(dataFlags, that.dataFlags) && Objects.equal(splitData, that.splitData); + } + + @Override + public int hashCode() { + return Objects.hashCode(dataFlags, splitData, uniqueProcessingId); + } + + @Override + public String toString() { + return "CategorizedFlatFileData{" + + "dataFlags=" + dataFlags + + ", stringDataRepresentation='" + splitData + '\'' + + ", uniqueProcessingId=" + uniqueProcessingId + + '}'; } } diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileDataBuilder.java b/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileDataBuilder.java deleted file mode 100644 index 0723ff3ef..000000000 --- a/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileDataBuilder.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.gmail.nossr50.database.flatfile; - -import com.gmail.nossr50.database.FlatFileDataFlag; -import org.jetbrains.annotations.NotNull; - -import java.util.HashSet; - -public class CategorizedFlatFileDataBuilder { - private final @NotNull HashSet dataFlags; - private @NotNull String stringDataRepresentation; - private final int uniqueProcessingId; - - public CategorizedFlatFileDataBuilder(@NotNull String stringDataRepresentation, int uniqueProcessingId) { - this.uniqueProcessingId = uniqueProcessingId; - this.stringDataRepresentation = stringDataRepresentation; - dataFlags = new HashSet<>(); - } - - public CategorizedFlatFileDataBuilder appendFlag(@NotNull FlatFileDataFlag dataFlag) { - dataFlags.add(dataFlag); - return this; - } - - public CategorizedFlatFileData build() { - return new CategorizedFlatFileData(uniqueProcessingId, dataFlags, stringDataRepresentation); - } - - public CategorizedFlatFileDataBuilder setStringDataRepresentation(@NotNull String stringDataRepresentation) { - this.stringDataRepresentation = stringDataRepresentation; - return this; - } -} diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataBuilder.java b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataBuilder.java new file mode 100644 index 000000000..ed048d5e1 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataBuilder.java @@ -0,0 +1,42 @@ +package com.gmail.nossr50.database.flatfile; + +import com.gmail.nossr50.database.FlatFileDataFlag; +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; + +public class FlatFileDataBuilder { + private final @NotNull HashSet dataFlags; + private @NotNull String[] splitStringData; + private final int uniqueProcessingId; + private boolean[] badDataValues; + + public FlatFileDataBuilder(@NotNull String[] splitStringData, int uniqueProcessingId) { + this.uniqueProcessingId = uniqueProcessingId; + this.splitStringData = splitStringData; + dataFlags = new HashSet<>(); + } + + public @NotNull FlatFileDataBuilder appendFlag(@NotNull FlatFileDataFlag dataFlag) { + dataFlags.add(dataFlag); + return this; + } + + public @NotNull FlatFileDataBuilder appendBadDataValues(boolean[] badDataValues) { + this.badDataValues = badDataValues; + return this; + } + + public @NotNull FlatFileDataContainer build() { + if(dataFlags.contains(FlatFileDataFlag.BAD_VALUES)) { + return new BadCategorizedFlatFileData(uniqueProcessingId, dataFlags, splitStringData, badDataValues); + } + + return new CategorizedFlatFileData(uniqueProcessingId, dataFlags, splitStringData); + } + + public @NotNull FlatFileDataBuilder setSplitStringData(@NotNull String[] splitStringData) { + this.splitStringData = splitStringData; + return this; + } +} diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataContainer.java b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataContainer.java new file mode 100644 index 000000000..e2fb2336c --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataContainer.java @@ -0,0 +1,21 @@ +package com.gmail.nossr50.database.flatfile; + +import com.gmail.nossr50.database.FlatFileDataFlag; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Set; + +public interface FlatFileDataContainer { + default @Nullable Set getDataFlags() { + return null; + } + + @NotNull String[] getSplitData(); + + int getUniqueProcessingId(); + + default boolean isHealthyData() { + return getDataFlags() == null || getDataFlags().size() == 0; + } +} diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileSaveDataProcessor.java b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileSaveDataProcessor.java new file mode 100644 index 000000000..1e109cbcf --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileSaveDataProcessor.java @@ -0,0 +1,117 @@ +package com.gmail.nossr50.database.flatfile; + +import com.gmail.nossr50.database.FlatFileDataFlag; +import com.gmail.nossr50.database.FlatFileDatabaseManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import static com.gmail.nossr50.database.FlatFileDatabaseManager.*; +import static com.gmail.nossr50.database.FlatFileDatabaseManager.UUID_INDEX; + +public class FlatFileSaveDataProcessor { + + public static @Nullable String[] getPreparedSaveDataLine(@NotNull FlatFileDataContainer dataContainer) { + if(dataContainer.getDataFlags() == null) { + return dataContainer.getSplitData(); + } + + //Data of this type is not salvageable + //TODO: Test that we ignore the things we are supposed to ignore + //TODO: Should we even keep track of the bad data or just not even build data containers for it? Making containers for it is only really useful for debugging.. well I suppose operations are typically async so it shouldn't matter + if(dataContainer.getDataFlags().contains(FlatFileDataFlag.JUNK) + || dataContainer.getDataFlags().contains(FlatFileDataFlag.DUPLICATE_UUID) //For now we will not try to fix any issues with UUIDs + || dataContainer.getDataFlags().contains(FlatFileDataFlag.BAD_UUID_DATA) //For now we will not try to fix any issues with UUIDs + || dataContainer.getDataFlags().contains(FlatFileDataFlag.TOO_INCOMPLETE) + || dataContainer.getDataFlags().contains(FlatFileDataFlag.EMPTY_LINE)) { + return null; + } + + String[] splitData; + + /* + * First fix the bad data values if they exist + */ + if(dataContainer instanceof BadCategorizedFlatFileData) { + BadCategorizedFlatFileData badData = (BadCategorizedFlatFileData) dataContainer; + splitData = repairBadData(dataContainer.getSplitData(), badData.getBadDataIndexes()); + } else { + splitData = dataContainer.getSplitData(); + } + + //Make sure we have as many values as we are supposed to + assert splitData.length == FlatFileDatabaseManager.DATA_ENTRY_COUNT; + return splitData; + } + + public static @NotNull String[] repairBadData(@NotNull String[] splitData, boolean[] badDataValues) { + for(int i = 0; i < FlatFileDatabaseManager.DATA_ENTRY_COUNT; i++) { + if(badDataValues[i]) { + //This data value was marked as bad so we zero initialize it + splitData[i] = getZeroInitialisedData(i, 0); + } + } + + return splitData; + } + + /** + * @param index "zero" Initialization will depend on what the index is for + * @return the "zero" initialized data corresponding to the index + */ + public static @NotNull String getZeroInitialisedData(int index, int startingLevel) throws IndexOutOfBoundsException { + switch(index) { + case USERNAME_INDEX: + return LEGACY_INVALID_OLD_USERNAME; //We'll keep using this value for legacy compatibility reasons (not sure if needed but don't care) + case 2: //Assumption: Used to be for something, no longer used + case 3: //Assumption: Used to be for something, no longer used + case 23: //Assumption: Used to be used for something, no longer used + case 33: //Assumption: Used to be used for something, no longer used + case HEALTHBAR: + return "IGNORED"; + case SKILLS_MINING: + case SKILLS_REPAIR: + case SKILLS_UNARMED: + case SKILLS_HERBALISM: + case SKILLS_EXCAVATION: + case SKILLS_ARCHERY: + case SKILLS_SWORDS: + case SKILLS_AXES: + case SKILLS_WOODCUTTING: + case SKILLS_ACROBATICS: + case SKILLS_TAMING: + case SKILLS_FISHING: + case SKILLS_ALCHEMY: + return String.valueOf(startingLevel); + case LAST_LOGIN: + return String.valueOf(System.currentTimeMillis() / 1000); //This is just to shorten the value + case COOLDOWN_BERSERK: + case COOLDOWN_GIGA_DRILL_BREAKER: + case COOLDOWN_TREE_FELLER: + case COOLDOWN_GREEN_TERRA: + case COOLDOWN_SERRATED_STRIKES: + case COOLDOWN_SKULL_SPLITTER: + case COOLDOWN_SUPER_BREAKER: + case COOLDOWN_BLAST_MINING: + case SCOREBOARD_TIPS: + case COOLDOWN_CHIMAERA_WING: + case EXP_MINING: + case EXP_WOODCUTTING: + case EXP_REPAIR: + case EXP_UNARMED: + case EXP_HERBALISM: + case EXP_EXCAVATION: + case EXP_ARCHERY: + case EXP_SWORDS: + case EXP_AXES: + case EXP_ACROBATICS: + case EXP_TAMING: + case EXP_FISHING: + case EXP_ALCHEMY: + return "0"; + case UUID_INDEX: + throw new IndexOutOfBoundsException(); //TODO: Add UUID recovery? Might not even be worth it. + } + + throw new IndexOutOfBoundsException(); + } +} diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index f9ca5fbf9..32a424ea0 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -48,28 +48,34 @@ public class FlatFileDatabaseManagerTest { "powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:" }; + private static final String[] badUUIDDatabaseData = { + "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", + "z750:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:3:5:1600906906:", //This one has an incorrect UUID representation + "powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:" + }; + private static final String[] outdatedDatabaseData = { "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:", - "powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:" //This user is missing data added after UUID index + "electronicboy:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:" //This user is missing data added after UUID index }; private static final String[] emptyLineDatabaseData = { "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:", - "powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:", + "kashike:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:", "" //EMPTY LINE }; private static final String[] emptyNameDatabaseData = { ":1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:", - "powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:" + "aikar:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:" }; private static final String[] duplicateNameDatabaseData = { - "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", - "nossr50:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:631e3896-da2a-4077-974b-d047859d76bc:0:0:", + "mochi:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:0:0:", + "mochi:1000:::0:1000:640:1000:1000:1000:1000:1000:1000:1000:1000:16:0:500:0:0:0:0:0::1000:0:0:0:1593543012:0:0:0:0::1000:0:0:1593806053:HEARTS:1000:0:631e3896-da2a-4077-974b-d047859d76bc:0:0:", }; private static final String[] duplicateUUIDDatabaseData = { @@ -109,38 +115,43 @@ public class FlatFileDatabaseManagerTest { } @Test - public void testFindDuplicateNames() { - addDataAndCheckForFlag(db, duplicateNameDatabaseData, FlatFileDataFlag.DUPLICATE_NAME_FIXABLE); + public void testFindFixableDuplicateNames() { + overwriteDataAndCheckForFlag(db, duplicateNameDatabaseData, FlatFileDataFlag.DUPLICATE_NAME); } @Test public void testFindDuplicateUUIDs() { - addDataAndCheckForFlag(db, duplicateUUIDDatabaseData, FlatFileDataFlag.DUPLICATE_UUID); + overwriteDataAndCheckForFlag(db, duplicateUUIDDatabaseData, FlatFileDataFlag.DUPLICATE_UUID); + } + + @Test() + public void findBadUUIDData() { + overwriteDataAndCheckForFlag(db, badUUIDDatabaseData, FlatFileDataFlag.BAD_UUID_DATA); } @Test public void testFindCorruptData() { - addDataAndCheckForFlag(db, corruptDatabaseData, FlatFileDataFlag.JUNK); + overwriteDataAndCheckForFlag(db, corruptDatabaseData, FlatFileDataFlag.JUNK); } @Test public void testFindEmptyNames() { - addDataAndCheckForFlag(db, emptyNameDatabaseData, FlatFileDataFlag.MISSING_NAME); + overwriteDataAndCheckForFlag(db, emptyNameDatabaseData, FlatFileDataFlag.MISSING_NAME); } - @Test - public void testFindEmptyLine() { - addDataAndCheckForFlag(db, emptyLineDatabaseData, FlatFileDataFlag.EMPTY_LINE); - } +// @Test +// public void testFindEmptyLine() { +// overwriteDataAndCheckForFlag(db, emptyLineDatabaseData, FlatFileDataFlag.EMPTY_LINE); +// } @Test public void testFindBadValues() { - addDataAndCheckForFlag(db, badDatabaseData, FlatFileDataFlag.BAD_VALUES); + overwriteDataAndCheckForFlag(db, badDatabaseData, FlatFileDataFlag.BAD_VALUES); } @Test public void testFindOutdatedData() { - addDataAndCheckForFlag(db, outdatedDatabaseData, FlatFileDataFlag.INCOMPLETE); + overwriteDataAndCheckForFlag(db, outdatedDatabaseData, FlatFileDataFlag.INCOMPLETE); } @Test @@ -149,7 +160,6 @@ public class FlatFileDatabaseManagerTest { assertEquals(db.getDatabaseType(), DatabaseType.FLATFILE); } - private void replaceDataInFile(@NotNull FlatFileDatabaseManager flatFileDatabaseManager, @NotNull String[] dataEntries) { String filePath = flatFileDatabaseManager.getUsersFile().getAbsolutePath(); BufferedReader in = null; @@ -203,7 +213,7 @@ public class FlatFileDatabaseManagerTest { } - private void addDataAndCheckForFlag(@NotNull FlatFileDatabaseManager targetDatabase, @NotNull String[] data, @NotNull FlatFileDataFlag flag) { + private void overwriteDataAndCheckForFlag(@NotNull FlatFileDatabaseManager targetDatabase, @NotNull String[] data, @NotNull FlatFileDataFlag flag) { replaceDataInFile(targetDatabase, data); List dataFlags = targetDatabase.checkFileHealthAndStructure(); From 9f22cef175996cd97dc70135cb158e93da09d1b5 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 12 Apr 2021 13:18:41 -0700 Subject: [PATCH 21/57] More tests --- .../nossr50/database/FlatFileDataFlag.java | 5 +- .../database/FlatFileDataProcessor.java | 51 +++++++++++-------- .../flatfile/CategorizedFlatFileData.java | 2 +- .../flatfile/FlatFileSaveDataProcessor.java | 6 +-- .../database/FlatFileDataProcessorTest.java | 23 +++++++++ .../database/FlatFileDatabaseManagerTest.java | 7 +-- .../FlatFileSaveDataProcessorTest.java | 27 ++++++++++ 7 files changed, 87 insertions(+), 34 deletions(-) create mode 100644 src/test/java/com/gmail/nossr50/database/FlatFileDataProcessorTest.java create mode 100644 src/test/java/com/gmail/nossr50/database/flatfile/FlatFileSaveDataProcessorTest.java diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java b/src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java index 58c3f6892..b67fe2806 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java @@ -6,8 +6,7 @@ public enum FlatFileDataFlag { MISSING_NAME, DUPLICATE_NAME, DUPLICATE_UUID, - BAD_UUID_DATA, //Can be because it is missing, null, or just not compatible data + BAD_UUID_DATA, //Can be because it is missing, null, or corrupted or some other reason TOO_INCOMPLETE, - JUNK, - EMPTY_LINE, + CORRUPTED_OR_UNRECOGNIZABLE, } diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java index 674cfc47b..ddda18143 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java @@ -16,7 +16,7 @@ public class FlatFileDataProcessor { private final @NotNull Logger logger; private final HashSet names; private final HashSet uuids; - private int uniqueProcessingID; + private int uniqueProcessingID; //TODO: Not being used, should we use it? boolean corruptDataFound; public FlatFileDataProcessor(@NotNull Logger logger) { @@ -55,7 +55,7 @@ public class FlatFileDataProcessor { } //Flag as junk (corrupt) - builder.appendFlag(FlatFileDataFlag.JUNK); + builder.appendFlag(FlatFileDataFlag.CORRUPTED_OR_UNRECOGNIZABLE); //TODO: This block here is probably pointless if(splitDataLine.length >= 10 //The value here is kind of arbitrary, it shouldn't be too low to avoid false positives, but also we aren't really going to correctly identify when player data has been corrupted or not with 100% accuracy ever @@ -67,7 +67,7 @@ public class FlatFileDataProcessor { } } - registerData(builder.appendFlag(FlatFileDataFlag.JUNK)); + registerData(builder.appendFlag(FlatFileDataFlag.CORRUPTED_OR_UNRECOGNIZABLE)); return; } @@ -123,20 +123,8 @@ public class FlatFileDataProcessor { if(!name.isEmpty()) names.add(name); - //Make sure the data is up to date schema wise - if(splitDataLine.length < DATA_ENTRY_COUNT) { - int oldLength = splitDataLine.length; - splitDataLine = Arrays.copyOf(splitDataLine, DATA_ENTRY_COUNT); - int newLength = splitDataLine.length; - - //TODO: Test this - for(int i = oldLength; i < (newLength - 1); i++){ - badDataValues[i] = true; - } - - builder.appendFlag(FlatFileDataFlag.INCOMPLETE); - builder.setSplitStringData(splitDataLine); - } + //Make sure the data is up to date schema wise, if it isn't we adjust it to the correct size and flag it for repair + splitDataLine = isDataSchemaUpToDate(splitDataLine, builder, badDataValues); /* * After establishing this data has at least an identity we check for bad data @@ -169,6 +157,26 @@ public class FlatFileDataProcessor { registerData(builder); } + public @NotNull String[] isDataSchemaUpToDate(@NotNull String[] splitDataLine, @NotNull FlatFileDataBuilder builder, boolean[] badDataValues) { + assert splitDataLine.length <= DATA_ENTRY_COUNT; //should NEVER be higher + + if(splitDataLine.length < DATA_ENTRY_COUNT) { + int oldLength = splitDataLine.length; + splitDataLine = Arrays.copyOf(splitDataLine, DATA_ENTRY_COUNT); + int newLength = splitDataLine.length; + + //TODO: Test this + for(int i = oldLength; i < (newLength - 1); i++){ + badDataValues[i] = true; + } + + builder.appendFlag(FlatFileDataFlag.INCOMPLETE); + builder.setSplitStringData(splitDataLine); + } + return splitDataLine; + } + + public boolean shouldNotBeEmpty(String data, int index) { if(getExpectedValueType(index) == ExpectedType.IGNORED) { return false; @@ -221,8 +229,9 @@ public class FlatFileDataProcessor { } private void reportBadDataLine(String warning, String context, String dataLine) { - logger.severe("FlatFileDatabaseBuilder Warning: " + warning + " - " + context); - logger.severe("FlatFileDatabaseBuilder: (Line Data) - " + dataLine); + logger.warning("FlatFileDatabaseBuilder Warning: " + warning + " - " + context); + logger.warning("FlatFileDatabaseBuilder: (Line Data) - " + dataLine); + logger.warning("mcMMO will repair this data if automatically (if it is possible)."); } private int getMinimumSplitDataLength() { @@ -237,7 +246,7 @@ public class FlatFileDataProcessor { flatFileDataFlags.addAll(flatFileDataContainer.getDataFlags()); } - public @NotNull ExpectedType getExpectedValueType(int dataIndex) throws IndexOutOfBoundsException { + public static @NotNull ExpectedType getExpectedValueType(int dataIndex) throws IndexOutOfBoundsException { switch(dataIndex) { case USERNAME_INDEX: return ExpectedType.STRING; @@ -316,6 +325,8 @@ public class FlatFileDataProcessor { if(splitData == null) continue; + //We add a trailing : as it is needed for some reason (is it?) + //TODO: Is the trailing ":" actually necessary? String fromSplit = org.apache.commons.lang.StringUtils.join(splitData, ":") + ":"; stringBuilder.append(fromSplit).append("\r\n"); } diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileData.java b/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileData.java index 8ed0478cb..500be9c4f 100644 --- a/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileData.java +++ b/src/main/java/com/gmail/nossr50/database/flatfile/CategorizedFlatFileData.java @@ -12,7 +12,7 @@ public class CategorizedFlatFileData implements FlatFileDataContainer { private final @NotNull String[] splitData; private final int uniqueProcessingId; - protected CategorizedFlatFileData(int uniqueProcessingId, @NotNull HashSet dataFlags, @NotNull String[] splitData) { + public CategorizedFlatFileData(int uniqueProcessingId, @NotNull HashSet dataFlags, @NotNull String[] splitData) { this.uniqueProcessingId = uniqueProcessingId; this.dataFlags = dataFlags; this.splitData = splitData; diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileSaveDataProcessor.java b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileSaveDataProcessor.java index 1e109cbcf..eb06d1dab 100644 --- a/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileSaveDataProcessor.java +++ b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileSaveDataProcessor.java @@ -6,7 +6,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import static com.gmail.nossr50.database.FlatFileDatabaseManager.*; -import static com.gmail.nossr50.database.FlatFileDatabaseManager.UUID_INDEX; public class FlatFileSaveDataProcessor { @@ -18,11 +17,10 @@ public class FlatFileSaveDataProcessor { //Data of this type is not salvageable //TODO: Test that we ignore the things we are supposed to ignore //TODO: Should we even keep track of the bad data or just not even build data containers for it? Making containers for it is only really useful for debugging.. well I suppose operations are typically async so it shouldn't matter - if(dataContainer.getDataFlags().contains(FlatFileDataFlag.JUNK) + if(dataContainer.getDataFlags().contains(FlatFileDataFlag.CORRUPTED_OR_UNRECOGNIZABLE) || dataContainer.getDataFlags().contains(FlatFileDataFlag.DUPLICATE_UUID) //For now we will not try to fix any issues with UUIDs || dataContainer.getDataFlags().contains(FlatFileDataFlag.BAD_UUID_DATA) //For now we will not try to fix any issues with UUIDs - || dataContainer.getDataFlags().contains(FlatFileDataFlag.TOO_INCOMPLETE) - || dataContainer.getDataFlags().contains(FlatFileDataFlag.EMPTY_LINE)) { + || dataContainer.getDataFlags().contains(FlatFileDataFlag.TOO_INCOMPLETE)) { return null; } diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDataProcessorTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDataProcessorTest.java new file mode 100644 index 000000000..2acbd41f8 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDataProcessorTest.java @@ -0,0 +1,23 @@ +package com.gmail.nossr50.database; + +import org.junit.Test; + +public class FlatFileDataProcessorTest { + + @SuppressWarnings("ResultOfMethodCallIgnored") + @Test + public void testGetExpectedValueType() { + for(int i = 0; i < FlatFileDatabaseManager.DATA_ENTRY_COUNT; i++) { + FlatFileDataProcessor.getExpectedValueType(i); + } + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + @Test(expected = IndexOutOfBoundsException.class) + public void testGetExpectedValueTypeException() { + for(int i = 0; i < FlatFileDatabaseManager.DATA_ENTRY_COUNT+1; i++) { + FlatFileDataProcessor.getExpectedValueType(i); + } + } + +} \ No newline at end of file diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index 32a424ea0..795f89e96 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -131,7 +131,7 @@ public class FlatFileDatabaseManagerTest { @Test public void testFindCorruptData() { - overwriteDataAndCheckForFlag(db, corruptDatabaseData, FlatFileDataFlag.JUNK); + overwriteDataAndCheckForFlag(db, corruptDatabaseData, FlatFileDataFlag.CORRUPTED_OR_UNRECOGNIZABLE); } @Test @@ -139,11 +139,6 @@ public class FlatFileDatabaseManagerTest { overwriteDataAndCheckForFlag(db, emptyNameDatabaseData, FlatFileDataFlag.MISSING_NAME); } -// @Test -// public void testFindEmptyLine() { -// overwriteDataAndCheckForFlag(db, emptyLineDatabaseData, FlatFileDataFlag.EMPTY_LINE); -// } - @Test public void testFindBadValues() { overwriteDataAndCheckForFlag(db, badDatabaseData, FlatFileDataFlag.BAD_VALUES); diff --git a/src/test/java/com/gmail/nossr50/database/flatfile/FlatFileSaveDataProcessorTest.java b/src/test/java/com/gmail/nossr50/database/flatfile/FlatFileSaveDataProcessorTest.java new file mode 100644 index 000000000..8b10772fa --- /dev/null +++ b/src/test/java/com/gmail/nossr50/database/flatfile/FlatFileSaveDataProcessorTest.java @@ -0,0 +1,27 @@ +package com.gmail.nossr50.database.flatfile; + +import com.gmail.nossr50.database.FlatFileDatabaseManager; +import org.junit.Test; + +import java.util.HashSet; + +public class FlatFileSaveDataProcessorTest { + + @Test + public void getPreparedSaveDataLine() { + } + + @Test + public void repairBadData() { + } + + @Test + public void getZeroInitialisedData() { + } + + @Test(expected = AssertionError.class) + public void testTooManyDataEntriesSplitString() { + FlatFileDataContainer dataContainer = new CategorizedFlatFileData(0, new HashSet<>(), new String[FlatFileDatabaseManager.DATA_ENTRY_COUNT + 1]); + FlatFileSaveDataProcessor.getPreparedSaveDataLine(dataContainer); + } +} \ No newline at end of file From 5b4af3f9cedc62839f32e3bbfbe03105b17f622d Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 12 Apr 2021 16:59:35 -0700 Subject: [PATCH 22/57] Add loadFromFile test --- pom.xml | 10 +++ .../database/FlatFileDatabaseManager.java | 32 +++++--- .../database/FlatFileDatabaseManagerTest.java | 79 ++++++++++++++++++- src/test/resources/baddatadb.users | 23 ++++++ 4 files changed, 130 insertions(+), 14 deletions(-) create mode 100644 src/test/resources/baddatadb.users diff --git a/pom.xml b/pom.xml index 577fc927d..c39db8f41 100755 --- a/pom.xml +++ b/pom.xml @@ -65,6 +65,16 @@ + + org.apache.maven.plugins + maven-surefire-plugin + 2.16 + + false + 1 + + + org.apache.maven.plugins maven-release-plugin diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index 37e58b2eb..8d20ef811 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -76,26 +76,29 @@ public final class FlatFileDatabaseManager implements DatabaseManager { public static final int DATA_ENTRY_COUNT = COOLDOWN_CHIMAERA_WING + 1; //Update this everytime new data is added - protected FlatFileDatabaseManager(@NotNull String usersFilePath, @NotNull Logger logger, long purgeTime, int startingLevel) { - usersFile = new File(usersFilePath); - this.usersFilePath = usersFilePath; + protected FlatFileDatabaseManager(@NotNull File usersFile, @NotNull Logger logger, long purgeTime, int startingLevel, boolean testing) { + this.usersFile = usersFile; + this.usersFilePath = usersFile.getPath(); this.logger = logger; this.purgeTime = purgeTime; this.startingLevel = startingLevel; - checkFileHealthAndStructure(); - List flatFileDataFlags = checkFileHealthAndStructure(); + if(!testing) { + List flatFileDataFlags = checkFileHealthAndStructure(); - if(flatFileDataFlags != null) { - if(flatFileDataFlags.size() > 0) { - logger.info("Detected "+flatFileDataFlags.size() + " data entries which need correction."); + if(flatFileDataFlags != null) { + if(flatFileDataFlags.size() > 0) { + logger.info("Detected "+flatFileDataFlags.size() + " data entries which need correction."); + } } } - - checkFileHealthAndStructure(); -// updateLeaderboards(); } + protected FlatFileDatabaseManager(@NotNull String usersFilePath, @NotNull Logger logger, long purgeTime, int startingLevel) { + this(new File(usersFilePath), logger, purgeTime, startingLevel, false); + } + + public int purgePowerlessUsers() { int purgedUsers = 0; @@ -971,6 +974,8 @@ public final class FlatFileDatabaseManager implements DatabaseManager { * @return */ public @Nullable List checkFileHealthAndStructure() { + ArrayList flagsFound = null; + logger.info("(" + usersFile.getPath() + ") Validating database file.."); FlatFileDataProcessor dataProcessor = null; if (usersFile.exists()) { @@ -996,6 +1001,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { //Only update the file if needed if(dataProcessor.getFlatFileDataFlags().size() > 0) { + flagsFound = new ArrayList<>(dataProcessor.getFlatFileDataFlags()); logger.info("Saving the updated and or repaired FlatFile Database..."); fileWriter = new FileWriter(usersFilePath); //Write data to file @@ -1009,10 +1015,10 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - if(dataProcessor == null || dataProcessor.getFlatFileDataFlags() == null) { + if(flagsFound == null || flagsFound.size() == 0) { return null; } else { - return dataProcessor.getFlatFileDataFlags(); + return flagsFound; } } diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index 795f89e96..5fdc3781f 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -9,10 +9,18 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; import org.powermock.modules.junit4.PowerMockRunner; import java.io.*; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.logging.Logger; import static org.junit.Assert.*; @@ -23,6 +31,8 @@ public class FlatFileDatabaseManagerTest { public static final @NotNull String TEST_FILE_NAME = "test.mcmmo.users"; public static final int HEALTHY_RETURN_CODE = 0; + public static final String BAD_FILE_LINE_ONE = "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:"; + public static final String BAD_DATA_FILE_LINE_TWENTY_THREE = "nossr51:baddata:::baddata:baddata:640:baddata:1000:1000:1000:baddata:baddata:baddata:baddata:16:0:500:20273:0:0:0:0::1000:0:0:baddata:1593543012:0:0:0:0::1000:0:0:baddata:IGNORED:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1:0:"; private static File tempDir; private final static @NotNull Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); private final long PURGE_TIME = 2630000000L; @@ -32,7 +42,7 @@ public class FlatFileDatabaseManagerTest { public void init() { assertNull(db); tempDir = Files.createTempDir(); - db = new FlatFileDatabaseManager(tempDir.getPath() + File.separator + TEST_FILE_NAME, logger, PURGE_TIME, 0); + db = new FlatFileDatabaseManager(new File(tempDir.getPath() + File.separator + TEST_FILE_NAME), logger, PURGE_TIME, 0, true); } @After @@ -155,6 +165,73 @@ public class FlatFileDatabaseManagerTest { assertEquals(db.getDatabaseType(), DatabaseType.FLATFILE); } + @Test + public void testLoadFromFile() { + Path resourceDirectory = Paths.get("src","test","resources"); + String absolutePath = resourceDirectory.toFile().getAbsolutePath(); + + ClassLoader classLoader = getClass().getClassLoader(); + URI resourceFileURI = null; + + try { + resourceFileURI = classLoader.getResource("baddatadb.users").toURI(); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + + assertNotNull(resourceFileURI); + File fromResourcesFile = new File(resourceFileURI); + assertNotNull(resourceFileURI); + File copyOfFile = new File(tempDir.getPath() + File.separator + "baddatafile.users"); + + if(copyOfFile.exists()) { + copyOfFile.delete(); + } + + assertTrue(fromResourcesFile.exists()); + + try { + Files.copy(fromResourcesFile, copyOfFile); + } catch (IOException e) { + e.printStackTrace(); + } + + assertNotNull(copyOfFile); + + //This makes sure our private method is working before the tests run afterwards + ArrayList dataFromFile = getSplitDataFromFile(copyOfFile); + System.out.println("File Path: "+copyOfFile.getAbsolutePath()); + assertEquals(BAD_FILE_LINE_ONE.split(":"), dataFromFile.get(0)); + assertEquals(dataFromFile.get(22)[0], "nossr51"); + assertEquals(BAD_DATA_FILE_LINE_TWENTY_THREE.split(":"), dataFromFile.get(22)); + + FlatFileDatabaseManager db_a = new FlatFileDatabaseManager(copyOfFile, logger, PURGE_TIME, 0, true); + List flagsFound = db_a.checkFileHealthAndStructure(); + assertNotNull(flagsFound); + assertTrue(flagsFound.contains(FlatFileDataFlag.BAD_VALUES)); + } + + private @NotNull ArrayList getSplitDataFromFile(@NotNull File file) { + ArrayList splitDataList = new ArrayList<>(); + + try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) { + String line; + + while ((line = bufferedReader.readLine()) != null) { + if (line.isEmpty()) + continue; + + String[] splitData = line.split(":"); + splitDataList.add(splitData); + } + + } catch (Exception e) { + e.printStackTrace(); + } + + return splitDataList; + } + private void replaceDataInFile(@NotNull FlatFileDatabaseManager flatFileDatabaseManager, @NotNull String[] dataEntries) { String filePath = flatFileDatabaseManager.getUsersFile().getAbsolutePath(); BufferedReader in = null; diff --git a/src/test/resources/baddatadb.users b/src/test/resources/baddatadb.users new file mode 100644 index 000000000..12584deca --- /dev/null +++ b/src/test/resources/baddatadb.users @@ -0,0 +1,23 @@ +mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906: +ender_vine:434:::33:93:0:115:115:389:216:88:287:130:468:380:944:150:90:0:0:1948:584::2:0:1584896276:1586477151:1585264062:0:1576456374:1534725135:1577535765::404:4207:0:1616024209:HEARTS:3:0:812c10b0-7bbf-49e5-ac53-3f0521eb504b:5:0: +electronicboy:225:::1876:16:0:99:137:148:308:109:418:193:430:0:854:0:0:0:0:260:2816::19:0:1604048398:1601216462:1563297488:1533836917:1571449594:1601219209:1601215461::406:4207:0:1617465739:HEARTS:7:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:0: +z750:1074:::21081:231:0:280:65:156:463:612:742:550:1060:1000:1751:3666:5834:4871:11278:1943:13642::25:460:1613103021:1610212680:1609278207:0:1610076033:1586744907:1610150046::399:7050:0:1613611193:HEARTS:11:0:1594aa76-6ce0-46f6-90b2-83896a829db8:5:0: +Aikar:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1617623810:HEARTS:0:0:6c4ed41d-9936-45da-9f57-b0f4cfa451b4:0: +wizjany:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1617624693:HEARTS:0:0:0609efd6-e9ae-4f6a-bcff-69a6c890192f:0: +SpottedLeaf:0:::0:0:0:0:0:0:0:0:0:0:21:0:0:0:0:0:0:0:231::0:0:0:0:0:0:0:0:0::0:0:0:1617628585:HEARTS:0:0:6c002484-c964-4627-8026-9955d0d30aaf:0:0: +Cheesy:0:::0:0:0:0:0:0:0:0:0:0:6:0:0:0:0:0:0:0:882::0:0:0:0:0:0:0:0:0::0:0:0:1617636874:HEARTS:0:0:0a5804b3-f127-4962-8b83-f5f3dfe6d8e3:0:0: +Mochi:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1617642310:HEARTS:0:0:468fb276-444f-4c79-bb07-8a7a30f95606:0: +Futan:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1617644058:HEARTS:0:0:98f9e3c2-75ce-448c-b30b-01f93b69f0ca:0: +Dave:0:::0:0:0:0:0:0:0:0:0:0:0:0:61:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1617653877:HEARTS:0:0:23926471-655b-4117-8ee6-7c718677f2e1:0:0: +MomShroom:0:::0:0:0:0:0:0:0:0:0:0:1:0:0:0:0:0:0:0:231::0:0:0:0:0:0:0:0:0::0:0:0:1617700103:HEARTS:0:0:eda1c2d5-7cf6-461c-aced-86954675b905:0:0: +broccolai:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1617736110:HEARTS:0:0:8a4f8f1c-8242-4c52-bd63-3a4f6fe85771:0: +gabizou:0:::0:0:0:0:0:0:0:0:0:0:6:0:0:0:0:0:692:897:231::0:0:0:0:0:0:0:0:0::0:302:0:1617744451:HEARTS:0:0:fd1ad842-8959-4433-9f09-406da1567f98:0:0: +Vera:18:::150:1:769:0:0:0:0:0:0:0:0:0:0:183:0:0:0:540:0::0:0:0:0:0:0:0:0:0::0:0:0:1617744730:HEARTS:0:0:0a95d72c-4316-4b25-a4ad-b0719843d723:0:0: +proxy:0:::189:1:0:1:1:0:0:0:0:1:0:36:96:0:0:0:0:181:0::1:0:0:0:0:0:0:0:0::0:0:0:1617792154:HEARTS:1:0:d8531191-e49b-4132-8223-e3b46f8450d2:0:0: +chew:4:::1011:0:0:0:0:0:2:0:0:0:0:0:61:0:432:0:0:0:651::0:0:0:0:0:0:0:0:0::0:0:0:1617794539:HEARTS:0:0:58cea4a2-1979-48e4-a171-eaa631376835:0:0: +t00thpick1:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1617798657:HEARTS:0:0:1300f1de-0108-43c3-839f-d40d7e0c7027:0: +kashike:1:::756:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1617826439:HEARTS:0:0:891825c2-2ceb-4b69-82c3-f2dfb47f9a6d:0:0: +camm:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1617830574:HEARTS:0:0:5c34f924-f7f6-4547-9e36-4234133e2162:0: +brandonxp4000:0:::0:0:0:0:0:0:0:0:2:0:1:0:181:0:0:0:54:0:231::0:0:0:0:0:0:0:0:0::0:0:0:1617887039:HEARTS:0:0:cbf7122b-0271-4daa-aeaa-3bc44e6dae88:0:0: +Tapola:1:::111:0:0:1:0:0:0:0:3:2:0:111:193:0:0:0:1010:92:0::0:0:0:0:0:0:0:0:0::0:0:0:1617886681:HEARTS:0:0:4a21353a-8ca1-436f-9b5f-d2e522dcf79e:0:0: +nossr51:baddata:::baddata:baddata:640:baddata:1000:1000:1000:baddata:baddata:baddata:baddata:16:0:500:20273:0:0:0:0::1000:0:0:baddata:1593543012:0:0:0:0::1000:0:0:baddata:IGNORED:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1:0: From f7339277f8f78d31c412b3dfca7abb24354552da Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 13 Apr 2021 12:41:23 -0700 Subject: [PATCH 23/57] Add more tests, fix null name bug --- Changelog.txt | 7 +- .../com/gmail/nossr50/api/ExperienceAPI.java | 13 +- .../java/com/gmail/nossr50/api/SkillAPI.java | 3 +- .../experience/ExperienceCommand.java | 7 +- .../experience/SkillresetCommand.java | 3 +- .../commands/hardcore/HardcoreCommand.java | 2 +- .../commands/hardcore/VampirismCommand.java | 2 +- .../nossr50/commands/skills/SkillCommand.java | 5 +- .../nossr50/database/DatabaseManager.java | 8 +- .../database/FlatFileDatabaseManager.java | 106 +++++-- .../nossr50/database/SQLDatabaseManager.java | 28 +- .../nossr50/datatypes/player/McMMOPlayer.java | 9 +- .../datatypes/player/PlayerProfile.java | 64 ++-- .../datatypes/skills/PrimarySkillType.java | 2 +- .../gmail/nossr50/listeners/SelfListener.java | 3 +- .../commands/McrankCommandDisplayTask.java | 3 +- .../database/FormulaConversionTask.java | 3 +- .../nossr50/skills/child/FamilyTree.java | 6 +- .../com/gmail/nossr50/util/EventUtils.java | 5 +- .../gmail/nossr50/util/HardcoreManager.java | 9 +- .../nossr50/util/commands/CommandUtils.java | 5 +- .../util/scoreboards/ScoreboardWrapper.java | 7 +- .../gmail/nossr50/util/skills/SkillTools.java | 26 +- .../database/FlatFileDatabaseManagerTest.java | 290 +++++++++++++++++- src/test/resources/healthydb.users | 3 + 25 files changed, 491 insertions(+), 128 deletions(-) create mode 100644 src/test/resources/healthydb.users diff --git a/Changelog.txt b/Changelog.txt index 932a69327..c11aa9f27 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,5 +1,10 @@ Version 2.1.189 + FlatFileDB now stores the last login of users again (was completely non functional for a while) + Newly created flat file databases (mcmmo.users file) will have a comment line at the top noting the date the database was created + Fixed a bug where FlatFileDatabase users could have their names saved as "null" (names will be fixed the next time the player logs in) Rewrote how FlatFileDatabase verifies data integrity + (API) Added com.gmail.nossr50.database.DatabaseManager.loadPlayerProfile(org.bukkit.OfflinePlayer) + (API) Deprecated com.gmail.nossr50.database.DatabaseManager.loadPlayerProfile(java.util.UUID, java.lang.String) Added unit tests for FlatFileDatabaseManager (see notes) Fixed a bug where FlatFileDatabaseManager didn't properly upgrade older database entries to the newest schema The setting to disable the mcMMO user block tracker has been moved from our "hidden config" to persistent_data.yml @@ -17,7 +22,7 @@ Version 2.1.189 (API) Some members of PrimarySkillType were removed and not deprecated (such as the field constants) NOTES: - The tests added for FlatFileDatabase will help make sure bugs don't result in any loss of data + I spent over 20 hours refactoring FlatFileDB and writing unit tests for it, this will ensure that any changes in the code that could break the database are caught Ultra Permissions is SAFE to use with mcMMO After getting in contact with the UltraPermissions devs and exhaustive testing, I have concluded that using UltraPermissions is completely safe with mcMMO. The users who had an issue with performance currently have an unknown cause, potentially it is from a plugin using the UltraPermissions API I really can't say without more data. My apologies to the UltraPermissions team for reporting an issue between our two plugins directly, as that is not the case. I would have tested it myself sooner but UltraPermissions was closed source and premium so I wasn't particularly motivated to do so, however I have been given access to the binaries so now I can do all the testing I want if future issues ever arise which I have zero expectations that they will. diff --git a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java index bc15b7043..a7055bbb5 100644 --- a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java +++ b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java @@ -12,6 +12,7 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.child.FamilyTree; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.CombatUtils; +import com.gmail.nossr50.util.skills.SkillTools; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.block.BlockState; @@ -80,7 +81,7 @@ public final class ExperienceAPI { public static boolean isNonChildSkill(String skillType) { PrimarySkillType skill = mcMMO.p.getSkillTools().matchSkill(skillType); - return skill != null && !mcMMO.p.getSkillTools().isChildSkill(skill); + return skill != null && !SkillTools.isChildSkill(skill); } @Deprecated @@ -626,7 +627,7 @@ public final class ExperienceAPI { PlayerProfile profile = getOfflineProfile(playerName); PrimarySkillType skill = getSkillType(skillType); - if (mcMMO.p.getSkillTools().isChildSkill(skill)) { + if (SkillTools.isChildSkill(skill)) { Set parentSkills = FamilyTree.getParents(skill); for (PrimarySkillType parentSkill : parentSkills) { @@ -657,7 +658,7 @@ public final class ExperienceAPI { PlayerProfile profile = getOfflineProfile(uuid); PrimarySkillType skill = getSkillType(skillType); - if (mcMMO.p.getSkillTools().isChildSkill(skill)) { + if (SkillTools.isChildSkill(skill)) { Set parentSkills = FamilyTree.getParents(skill); for (PrimarySkillType parentSkill : parentSkills) { @@ -763,7 +764,7 @@ public final class ExperienceAPI { int powerLevel = 0; PlayerProfile profile = getOfflineProfile(playerName); - for (PrimarySkillType type : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + for (PrimarySkillType type : SkillTools.NON_CHILD_SKILLS) { powerLevel += profile.getSkillLevel(type); } @@ -784,7 +785,7 @@ public final class ExperienceAPI { int powerLevel = 0; PlayerProfile profile = getOfflineProfile(uuid); - for (PrimarySkillType type : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + for (PrimarySkillType type : SkillTools.NON_CHILD_SKILLS) { powerLevel += profile.getSkillLevel(type); } @@ -1181,7 +1182,7 @@ public final class ExperienceAPI { private static PrimarySkillType getNonChildSkillType(String skillType) throws InvalidSkillException, UnsupportedOperationException { PrimarySkillType skill = getSkillType(skillType); - if (mcMMO.p.getSkillTools().isChildSkill(skill)) { + if (SkillTools.isChildSkill(skill)) { throw new UnsupportedOperationException("Child skills do not have XP"); } diff --git a/src/main/java/com/gmail/nossr50/api/SkillAPI.java b/src/main/java/com/gmail/nossr50/api/SkillAPI.java index db98ed08a..be8315a28 100644 --- a/src/main/java/com/gmail/nossr50/api/SkillAPI.java +++ b/src/main/java/com/gmail/nossr50/api/SkillAPI.java @@ -2,6 +2,7 @@ package com.gmail.nossr50.api; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.skills.SkillTools; import java.util.ArrayList; import java.util.Arrays; @@ -31,7 +32,7 @@ public final class SkillAPI { * @return a list of strings with valid skill names */ public static List getNonChildSkills() { - return getListFromEnum(mcMMO.p.getSkillTools().NON_CHILD_SKILLS); + return getListFromEnum(SkillTools.NON_CHILD_SKILLS); } /** 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 f43c3e35f..4e84f8bff 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java @@ -7,6 +7,7 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.skills.SkillTools; import com.google.common.collect.ImmutableList; import org.bukkit.OfflinePlayer; import org.bukkit.command.Command; @@ -50,7 +51,7 @@ public abstract class ExperienceCommand implements TabExecutor { skill = null; } - if (skill != null && mcMMO.p.getSkillTools().isChildSkill(skill)) + if (skill != null && SkillTools.isChildSkill(skill)) { sender.sendMessage(LocaleLoader.getString("Commands.Skill.ChildSkill")); return true; @@ -83,7 +84,7 @@ public abstract class ExperienceCommand implements TabExecutor { skill = null; } - if (skill != null && mcMMO.p.getSkillTools().isChildSkill(skill)) + if (skill != null && SkillTools.isChildSkill(skill)) { sender.sendMessage(LocaleLoader.getString("Commands.Skill.ChildSkill")); return true; @@ -171,7 +172,7 @@ public abstract class ExperienceCommand implements TabExecutor { protected void editValues(Player player, PlayerProfile profile, PrimarySkillType skill, int value, boolean isSilent) { if (skill == null) { - for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { handleCommand(player, profile, primarySkillType, value); } diff --git a/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java index 72c1718cd..4b558d422 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java @@ -10,6 +10,7 @@ import com.gmail.nossr50.util.EventUtils; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.skills.SkillTools; import com.google.common.collect.ImmutableList; import org.bukkit.OfflinePlayer; import org.bukkit.command.Command; @@ -167,7 +168,7 @@ public class SkillresetCommand implements TabExecutor { protected void editValues(Player player, PlayerProfile profile, PrimarySkillType skill) { if (skill == null) { - for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { handleCommand(player, profile, primarySkillType); } diff --git a/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreCommand.java b/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreCommand.java index d6b8de57b..4a8656e37 100644 --- a/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreCommand.java @@ -51,7 +51,7 @@ // // private void toggle(boolean enable, PrimarySkillType skill) { // if (skill == null) { -// for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { +// for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { // primarySkillType.setHardcoreStatLossEnabled(enable); // } // } diff --git a/src/main/java/com/gmail/nossr50/commands/hardcore/VampirismCommand.java b/src/main/java/com/gmail/nossr50/commands/hardcore/VampirismCommand.java index fbeaee56b..037c34e11 100644 --- a/src/main/java/com/gmail/nossr50/commands/hardcore/VampirismCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/hardcore/VampirismCommand.java @@ -51,7 +51,7 @@ // // private void toggle(boolean enable, PrimarySkillType skill) { // if (skill == null) { -// for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { +// for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { // primarySkillType.setHardcoreVampirismEnabled(enable); // } // } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java index ab5c027ba..6e2926062 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java @@ -15,6 +15,7 @@ import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.gmail.nossr50.util.skills.PerksUtils; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillActivationType; +import com.gmail.nossr50.util.skills.SkillTools; import com.gmail.nossr50.util.text.StringUtils; import com.gmail.nossr50.util.text.TextComponentFactory; import com.google.common.collect.ImmutableList; @@ -142,7 +143,7 @@ public abstract class SkillCommand implements TabExecutor { player.sendMessage(LocaleLoader.getString("Skills.Overhaul.Header", skillName)); - if(!mcMMO.p.getSkillTools().isChildSkill(skill)) + if(!SkillTools.isChildSkill(skill)) { /* * NON-CHILD SKILLS @@ -188,7 +189,7 @@ public abstract class SkillCommand implements TabExecutor { } /* - if (!mcMMO.p.getSkillTools().isChildSkill(skill)) { + if (!SkillTools.isChildSkill(skill)) { player.sendMessage(LocaleLoader.getString("Skills.Header", skillName)); player.sendMessage(LocaleLoader.getString("Commands.XPGain", LocaleLoader.getString("Commands.XPGain." + StringUtils.getCapitalized(skill.toString())))); player.sendMessage(LocaleLoader.getString("Effects.Level", skillValue, mcMMOPlayer.getSkillXpLevel(skill), mcMMOPlayer.getXpToLevel(skill))); diff --git a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java index 831ec579a..914a35aa2 100644 --- a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java @@ -5,6 +5,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.OfflinePlayer; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -92,12 +93,17 @@ public interface DatabaseManager { */ @NotNull PlayerProfile loadPlayerProfile(@NotNull String playerName); + default @NotNull PlayerProfile loadPlayerProfile(@NotNull OfflinePlayer offlinePlayer) { + return loadPlayerProfile(offlinePlayer.getUniqueId(), offlinePlayer.getName()); + } + /** * Load a player from the database. - * * @param uuid The uuid of the player to load from the database * @return The player's data, or an unloaded PlayerProfile if not found + * @deprecated Use {@link DatabaseManager#loadPlayerProfile(org.bukkit.OfflinePlayer)} if possible */ + @Deprecated @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid, @Nullable String playerName); /** diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index 8d20ef811..42a65c868 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -9,12 +9,15 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.skills.SkillTools; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.*; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.*; import java.util.logging.Logger; @@ -28,6 +31,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { private final @NotNull Logger logger; private final long purgeTime; private final int startingLevel; + private boolean testing; private final long UPDATE_WAIT_TIME = 600000L; // 10 minutes private final @NotNull File usersFile; @@ -82,6 +86,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { this.logger = logger; this.purgeTime = purgeTime; this.startingLevel = startingLevel; + this.testing = testing; if(!testing) { List flatFileDataFlags = checkFileHealthAndStructure(); @@ -218,6 +223,10 @@ public final class FlatFileDatabaseManager implements DatabaseManager { // Write the new file out = new FileWriter(usersFilePath); out.write(writer.toString()); + + if(testing) { + System.out.println(writer.toString()); + } } catch (IOException e) { logger.severe("Exception while reading " + usersFilePath + " (Are you sure you formatted it correctly?)" + e); @@ -321,8 +330,19 @@ public final class FlatFileDatabaseManager implements DatabaseManager { String line; boolean wroteUser = false; + if(testing) { + System.out.println("-- saveUser bufferedreader feed --"); + } // While not at the end of the file while ((line = in.readLine()) != null) { + if(testing) { + System.out.println(line); + } + if(line.startsWith("#")) { + writer.append(line).append("\r\n"); + continue; + } + //Check for incomplete or corrupted data if(!line.contains(":")) { @@ -365,6 +385,11 @@ public final class FlatFileDatabaseManager implements DatabaseManager { writeUserToLine(profile, playerName, uuid, writer); } + if(testing) { + System.out.println("-- saveUser (FileWriter contents before save) --"); + System.out.println(writer.toString()); + } + // Write the new file out = new FileWriter(usersFilePath); out.write(writer.toString()); @@ -445,7 +470,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { public @NotNull List readLeaderboard(@Nullable PrimarySkillType primarySkillType, int pageNumber, int statsPerPage) throws InvalidSkillException { //Fix for a plugin that people are using that is throwing SQL errors - if(primarySkillType != null && mcMMO.p.getSkillTools().isChildSkill(primarySkillType)) { + if(primarySkillType != null && SkillTools.isChildSkill(primarySkillType)) { logger.severe("A plugin hooking into mcMMO is being naughty with our database commands, update all plugins that hook into mcMMO and contact their devs!"); throw new InvalidSkillException("A plugin hooking into mcMMO that you are using is attempting to read leaderboard skills for child skills, child skills do not have leaderboards! This is NOT an mcMMO error!"); } @@ -462,7 +487,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { Map skills = new EnumMap(PrimarySkillType.class); - for (PrimarySkillType skill : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + for (PrimarySkillType skill : SkillTools.NON_CHILD_SKILLS) { skills.put(skill, getPlayerRank(playerName, playerStatHash.get(skill))); } @@ -549,15 +574,19 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } + public @NotNull PlayerProfile loadPlayerProfile(@NotNull OfflinePlayer offlinePlayer) { + return loadPlayerByUUID(offlinePlayer.getUniqueId(), offlinePlayer.getName(), offlinePlayer.isOnline()); + } + public @NotNull PlayerProfile loadPlayerProfile(@NotNull String playerName) { return loadPlayerByName(playerName); } public @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid, @Nullable String playerName) { - return loadPlayerByUUID(uuid, playerName); + return loadPlayerByUUID(uuid, playerName, false); } - private @NotNull PlayerProfile loadPlayerByUUID(@NotNull UUID uuid, @Nullable String playerName) { + private @NotNull PlayerProfile loadPlayerByUUID(@NotNull UUID uuid, @Nullable String playerName, boolean isOnline) { BufferedReader in = null; synchronized (fileWritingLock) { @@ -594,9 +623,13 @@ public final class FlatFileDatabaseManager implements DatabaseManager { /* Check for nickname changes and update since we are here anyways */ - if (!rawSplitData[USERNAME_INDEX].equalsIgnoreCase(playerName)) { - //logger.info("Name updated for player: " + rawSplitData[USERNAME_INDEX] + " => " + playerName); - rawSplitData[USERNAME_INDEX] = playerName; + if(playerName != null) { + if(isOnline) { + if (!rawSplitData[USERNAME_INDEX].equalsIgnoreCase(playerName)) { + //logger.info("Name updated for player: " + rawSplitData[USERNAME_INDEX] + " => " + playerName); + rawSplitData[USERNAME_INDEX] = playerName; + } + } } return loadFromLine(rawSplitData); @@ -969,15 +1002,39 @@ public final class FlatFileDatabaseManager implements DatabaseManager { playerStatHash.put(PrimarySkillType.ALCHEMY, alchemy); } - /** - * Makes sure that the users file has valid entries - * @return - */ + private void initEmptyDB() { + BufferedWriter bufferedWriter = null; + synchronized (fileWritingLock) { + try { + // Open the file to write the player + bufferedWriter = new BufferedWriter(new FileWriter(usersFilePath, true)); + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"); + LocalDateTime localDateTime = LocalDateTime.now(); + bufferedWriter.append("# mcMMO Database created on ").append(localDateTime.format(dateTimeFormatter)).append("\r\n"); //Empty file + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (bufferedWriter != null) { + try { + bufferedWriter.close(); + } + catch (IOException e) { + // Ignore + } + } + } + } + } + public @Nullable List checkFileHealthAndStructure() { ArrayList flagsFound = null; logger.info("(" + usersFile.getPath() + ") Validating database file.."); FlatFileDataProcessor dataProcessor = null; + if(!usersFile.exists()) { + initEmptyDB(); + } + if (usersFile.exists()) { BufferedReader bufferedReader = null; FileWriter fileWriter = null; @@ -988,10 +1045,18 @@ public final class FlatFileDatabaseManager implements DatabaseManager { try { String currentLine; + String dbCommentDate = null; + bufferedReader = new BufferedReader(new FileReader(usersFilePath)); //Analyze the data while ((currentLine = bufferedReader.readLine()) != null) { + //Commented lines + if(currentLine.startsWith("#") && dbCommentDate == null) { //The first commented line in the file is likely to be our note about when the file was created + dbCommentDate = currentLine; + continue; + } + if(currentLine.isEmpty()) continue; @@ -1005,6 +1070,9 @@ public final class FlatFileDatabaseManager implements DatabaseManager { logger.info("Saving the updated and or repaired FlatFile Database..."); fileWriter = new FileWriter(usersFilePath); //Write data to file + if(dbCommentDate != null) + fileWriter.write(dbCommentDate); + fileWriter.write(dataProcessor.processDataForSave().toString()); } } catch (IOException e) { @@ -1078,6 +1146,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { Map skillsDATS = new EnumMap<>(SuperAbilityType.class); // Ability & Cooldown Map uniquePlayerDataMap = new EnumMap<>(UniqueDataType.class); int scoreboardTipsShown; + long lastLogin; String username = character[USERNAME_INDEX]; @@ -1108,13 +1177,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { // Acrobatics - Unused tryLoadSkillCooldownFromRawData(skillsDATS, character, SuperAbilityType.BLAST_MINING, COOLDOWN_BLAST_MINING, username); -// try { -// mobHealthbarType = MobHealthbarType.valueOf(character[HEALTHBAR]); -// } -// catch (Exception e) { -// mobHealthbarType = Config.getInstance().getMobHealthbarDefault(); -// } - UUID uuid; try { uuid = UUID.fromString(character[UUID_INDEX]); @@ -1137,7 +1199,13 @@ public final class FlatFileDatabaseManager implements DatabaseManager { uniquePlayerDataMap.put(UniqueDataType.CHIMAERA_WING_DATS, 0); } - return new PlayerProfile(character[USERNAME_INDEX], uuid, skills, skillsXp, skillsDATS, null, scoreboardTipsShown, uniquePlayerDataMap); + try { + lastLogin = Long.parseLong(character[LAST_LOGIN]); + } catch (Exception e) { + lastLogin = System.currentTimeMillis(); + } + + return new PlayerProfile(character[USERNAME_INDEX], uuid, skills, skillsXp, skillsDATS, scoreboardTipsShown, uniquePlayerDataMap, lastLogin); } private void tryLoadSkillCooldownFromRawData(@NotNull Map cooldownMap, @NotNull String[] character, @NotNull SuperAbilityType superAbilityType, int cooldownSuperBreaker, @NotNull String userName) { diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index 9f09d77f2..6599e707c 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -12,6 +12,7 @@ import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.database.UUIDUpdateAsyncTask; import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.skills.SkillTools; import org.apache.tomcat.jdbc.pool.DataSource; import org.apache.tomcat.jdbc.pool.PoolProperties; import org.bukkit.entity.Player; @@ -174,8 +175,7 @@ public final class SQLDatabaseManager implements DatabaseManager { } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { tryClose(statement); tryClose(connection); massUpdateLock.unlock(); @@ -271,7 +271,7 @@ public final class SQLDatabaseManager implements DatabaseManager { statement.setInt(12, profile.getSkillLevel(PrimarySkillType.FISHING)); statement.setInt(13, profile.getSkillLevel(PrimarySkillType.ALCHEMY)); int total = 0; - for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) total += profile.getSkillLevel(primarySkillType); statement.setInt(14, total); statement.setInt(15, id); @@ -330,7 +330,7 @@ public final class SQLDatabaseManager implements DatabaseManager { } statement = connection.prepareStatement("UPDATE " + tablePrefix + "huds SET mobhealthbar = ?, scoreboardtips = ? WHERE user_id = ?"); - statement.setString(1, profile.getMobHealthbarType() == null ? mcMMO.p.getGeneralConfig().getMobHealthbarDefault().name() : profile.getMobHealthbarType().name()); + statement.setString(1, MobHealthbarType.HEARTS.name()); statement.setInt(2, profile.getScoreboardTipsShown()); statement.setInt(3, id); success = (statement.executeUpdate() != 0); @@ -355,7 +355,7 @@ public final class SQLDatabaseManager implements DatabaseManager { List stats = new ArrayList<>(); //Fix for a plugin that people are using that is throwing SQL errors - if(skill != null && mcMMO.p.getSkillTools().isChildSkill(skill)) { + if(skill != null && SkillTools.isChildSkill(skill)) { mcMMO.p.getLogger().severe("A plugin hooking into mcMMO is being naughty with our database commands, update all plugins that hook into mcMMO and contact their devs!"); throw new InvalidSkillException("A plugin hooking into mcMMO that you are using is attempting to read leaderboard skills for child skills, child skills do not have leaderboards! This is NOT an mcMMO error!"); } @@ -404,7 +404,7 @@ public final class SQLDatabaseManager implements DatabaseManager { try { connection = getConnection(PoolIdentifier.MISC); - for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { String skillName = primarySkillType.name().toLowerCase(Locale.ENGLISH); // Get count of all users with higher skill level than player String sql = "SELECT COUNT(*) AS 'rank' FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE " + skillName + " > 0 " + @@ -932,7 +932,7 @@ public final class SQLDatabaseManager implements DatabaseManager { } if (mcMMO.p.getGeneralConfig().getTruncateSkills()) { - for (PrimarySkillType skill : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + for (PrimarySkillType skill : SkillTools.NON_CHILD_SKILLS) { int cap = mcMMO.p.getSkillTools().getLevelCap(skill); if (cap != Integer.MAX_VALUE) { statement = connection.prepareStatement("UPDATE `" + tablePrefix + "skills` SET `" + skill.name().toLowerCase(Locale.ENGLISH) + "` = " + cap + " WHERE `" + skill.name().toLowerCase(Locale.ENGLISH) + "` > " + cap); @@ -1152,14 +1152,6 @@ public final class SQLDatabaseManager implements DatabaseManager { skillsDATS.put(SuperAbilityType.BLAST_MINING, result.getInt(OFFSET_DATS + 12)); uniqueData.put(UniqueDataType.CHIMAERA_WING_DATS, result.getInt(OFFSET_DATS + 13)); - - try { - mobHealthbarType = MobHealthbarType.valueOf(result.getString(OFFSET_OTHER + 1)); - } - catch (Exception e) { - mobHealthbarType = mcMMO.p.getGeneralConfig().getMobHealthbarDefault(); - } - try { scoreboardTipsShown = result.getInt(OFFSET_OTHER + 2); } @@ -1174,7 +1166,7 @@ public final class SQLDatabaseManager implements DatabaseManager { uuid = null; } - return new PlayerProfile(playerName, uuid, skills, skillsXp, skillsDATS, mobHealthbarType, scoreboardTipsShown, uniqueData); + return new PlayerProfile(playerName, uuid, skills, skillsXp, skillsDATS, scoreboardTipsShown, uniqueData, null); } private void printErrors(SQLException ex) { @@ -1291,10 +1283,10 @@ public final class SQLDatabaseManager implements DatabaseManager { resultSet = statement.executeQuery("SHOW INDEX FROM `" + tablePrefix + "skills` WHERE `Key_name` LIKE 'idx\\_%'"); resultSet.last(); - if (resultSet.getRow() != mcMMO.p.getSkillTools().NON_CHILD_SKILLS.size()) { + if (resultSet.getRow() != SkillTools.NON_CHILD_SKILLS.size()) { mcMMO.p.getLogger().info("Indexing tables, this may take a while on larger databases"); - for (PrimarySkillType skill : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + for (PrimarySkillType skill : SkillTools.NON_CHILD_SKILLS) { String skill_name = skill.name().toLowerCase(Locale.ENGLISH); try { diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index e851fb110..e6c3a22d9 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -51,6 +51,7 @@ import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.gmail.nossr50.util.skills.PerksUtils; import com.gmail.nossr50.util.skills.RankUtils; +import com.gmail.nossr50.util.skills.SkillTools; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.sounds.SoundManager; import com.gmail.nossr50.util.sounds.SoundType; @@ -280,7 +281,7 @@ public class McMMOPlayer implements Identified { public double getProgressInCurrentSkillLevel(PrimarySkillType primarySkillType) { - if(mcMMO.p.getSkillTools().isChildSkill(primarySkillType)) { + if(SkillTools.isChildSkill(primarySkillType)) { return 1.0D; } @@ -569,7 +570,7 @@ public class McMMOPlayer implements Identified { public int getPowerLevel() { int powerLevel = 0; - for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { if (mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, primarySkillType)) { powerLevel += getSkillLevel(primarySkillType); } @@ -611,7 +612,7 @@ public class McMMOPlayer implements Identified { return; } - if (mcMMO.p.getSkillTools().isChildSkill(skill)) { + if (SkillTools.isChildSkill(skill)) { Set parentSkills = FamilyTree.getParents(skill); float splitXp = xp / parentSkills.size(); @@ -668,7 +669,7 @@ public class McMMOPlayer implements Identified { Bukkit.getPluginManager().callEvent(mcMMOPlayerPreXpGainEvent); xp = mcMMOPlayerPreXpGainEvent.getXpGained(); - if (mcMMO.p.getSkillTools().isChildSkill(primarySkillType)) { + if (SkillTools.isChildSkill(primarySkillType)) { Set parentSkills = FamilyTree.getParents(primarySkillType); for (PrimarySkillType parentSkill : parentSkills) { diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java index 3fc0d6d70..f2e4306fe 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.datatypes.player; import com.gmail.nossr50.config.experience.ExperienceConfig; -import com.gmail.nossr50.datatypes.MobHealthbarType; import com.gmail.nossr50.datatypes.experience.FormulaType; import com.gmail.nossr50.datatypes.experience.SkillXpGain; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; @@ -10,6 +9,7 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.runnables.player.PlayerProfileSaveTask; import com.gmail.nossr50.skills.child.FamilyTree; import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.skills.SkillTools; import com.google.common.collect.ImmutableMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,10 +27,11 @@ public class PlayerProfile { private volatile boolean changed; /* HUDs */ - private MobHealthbarType mobHealthbarType; private int scoreboardTipsShown; private int saveAttempts = 0; + private @Nullable Long lastLogin; + /* Skill Data */ private final Map skills = new EnumMap<>(PrimarySkillType.class); // Skill & Level private final Map skillsXp = new EnumMap<>(PrimarySkillType.class); // Skill & XP @@ -50,20 +51,22 @@ public class PlayerProfile { this.uuid = uuid; this.playerName = playerName; - mobHealthbarType = mcMMO.p.getGeneralConfig().getMobHealthbarDefault(); scoreboardTipsShown = 0; for (SuperAbilityType superAbilityType : SuperAbilityType.values()) { abilityDATS.put(superAbilityType, 0); } - for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { - skills.put(primarySkillType, mcMMO.p.getAdvancedConfig().getStartingLevel()); + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { + int startingLvl = mcMMO.p != null ? mcMMO.p.getAdvancedConfig().getStartingLevel() : 0; //TODO: Setup the mock since this was to avoid setting up a mock in a test + + skills.put(primarySkillType, startingLvl); skillsXp.put(primarySkillType, 0F); } //Misc Cooldowns uniquePlayerData.put(UniqueDataType.CHIMAERA_WING_DATS, 0); //Chimaera wing + lastLogin = System.currentTimeMillis(); } @Deprecated @@ -77,10 +80,9 @@ public class PlayerProfile { this.loaded = isLoaded; } - public PlayerProfile(@NotNull String playerName, UUID uuid, Map levelData, Map xpData, Map cooldownData, @Nullable MobHealthbarType mobHealthbarType, int scoreboardTipsShown, Map uniqueProfileData) { + public PlayerProfile(@NotNull String playerName, UUID uuid, Map levelData, Map xpData, Map cooldownData, int scoreboardTipsShown, Map uniqueProfileData, @Nullable Long lastLogin) { this.playerName = playerName; this.uuid = uuid; - mobHealthbarType = mcMMO.p.getGeneralConfig().getMobHealthbarDefault(); this.scoreboardTipsShown = scoreboardTipsShown; skills.putAll(levelData); @@ -89,6 +91,9 @@ public class PlayerProfile { uniquePlayerData.putAll(uniqueProfileData); loaded = true; + + if(lastLogin != null) + this.lastLogin = lastLogin; } public void scheduleAsyncSave() { @@ -115,7 +120,7 @@ public class PlayerProfile { } // TODO should this part be synchronized? - PlayerProfile profileCopy = new PlayerProfile(playerName, uuid, ImmutableMap.copyOf(skills), ImmutableMap.copyOf(skillsXp), ImmutableMap.copyOf(abilityDATS), mobHealthbarType, scoreboardTipsShown, ImmutableMap.copyOf(uniquePlayerData)); + PlayerProfile profileCopy = new PlayerProfile(playerName, uuid, ImmutableMap.copyOf(skills), ImmutableMap.copyOf(skillsXp), ImmutableMap.copyOf(abilityDATS), scoreboardTipsShown, ImmutableMap.copyOf(uniquePlayerData), lastLogin); changed = !mcMMO.getDatabaseManager().saveUser(profileCopy); if (changed) { @@ -149,6 +154,19 @@ public class PlayerProfile { } } + /** + * Get this users last login, will return current java.lang.System#currentTimeMillis() if it doesn't exist + * @return the last login + * @deprecated This is only function for FlatFileDB atm and its only here for unit testing right now + */ + @Deprecated + public @NotNull Long getLastLogin() { + if(lastLogin == null) + return System.currentTimeMillis(); + else + return lastLogin; + } + public String getPlayerName() { return playerName; } @@ -167,20 +185,6 @@ public class PlayerProfile { return loaded; } - /* - * Mob Healthbars - */ - - public MobHealthbarType getMobHealthbarType() { - return mobHealthbarType; - } - - public void setMobHealthbarType(MobHealthbarType mobHealthbarType) { - markProfileDirty(); - - this.mobHealthbarType = mobHealthbarType; - } - /** * Marks the profile as "dirty" which flags a profile to be saved in the next save operation */ @@ -256,7 +260,7 @@ public class PlayerProfile { */ public int getSkillLevel(PrimarySkillType skill) { - return mcMMO.p.getSkillTools().isChildSkill(skill) ? getChildSkillLevel(skill) : skills.get(skill); + return SkillTools.isChildSkill(skill) ? getChildSkillLevel(skill) : skills.get(skill); } public float getSkillXpLevelRaw(PrimarySkillType skill) { @@ -264,7 +268,7 @@ public class PlayerProfile { } public int getSkillXpLevel(PrimarySkillType skill) { - if(mcMMO.p.getSkillTools().isChildSkill(skill)) { + if(SkillTools.isChildSkill(skill)) { return 0; } @@ -272,7 +276,7 @@ public class PlayerProfile { } public void setSkillXpLevel(PrimarySkillType skill, float xpLevel) { - if (mcMMO.p.getSkillTools().isChildSkill(skill)) { + if (SkillTools.isChildSkill(skill)) { return; } @@ -299,7 +303,7 @@ public class PlayerProfile { * @param xp Amount of xp to remove */ public void removeXp(PrimarySkillType skill, int xp) { - if (mcMMO.p.getSkillTools().isChildSkill(skill)) { + if (SkillTools.isChildSkill(skill)) { return; } @@ -309,7 +313,7 @@ public class PlayerProfile { } public void removeXp(PrimarySkillType skill, float xp) { - if (mcMMO.p.getSkillTools().isChildSkill(skill)) { + if (SkillTools.isChildSkill(skill)) { return; } @@ -325,7 +329,7 @@ public class PlayerProfile { * @param level New level value for the skill */ public void modifySkill(PrimarySkillType skill, int level) { - if (mcMMO.p.getSkillTools().isChildSkill(skill)) { + if (SkillTools.isChildSkill(skill)) { return; } @@ -358,7 +362,7 @@ public class PlayerProfile { public void addXp(PrimarySkillType skill, float xp) { markProfileDirty(); - if (mcMMO.p.getSkillTools().isChildSkill(skill)) { + if (SkillTools.isChildSkill(skill)) { Set parentSkills = FamilyTree.getParents(skill); float dividedXP = (xp / parentSkills.size()); @@ -417,7 +421,7 @@ public class PlayerProfile { * @return the total amount of Xp until next level */ public int getXpToLevel(PrimarySkillType primarySkillType) { - if(mcMMO.p.getSkillTools().isChildSkill(primarySkillType)) { + if(SkillTools.isChildSkill(primarySkillType)) { return 0; } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java index f8abfa255..22ab7f4a6 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java @@ -191,7 +191,7 @@ public enum PrimarySkillType { */ @Deprecated public boolean isChildSkill() { - return mcMMO.p.getSkillTools().isChildSkill(this); + return SkillTools.isChildSkill(this); } /** diff --git a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java index 10da03550..2e21d3b72 100644 --- a/src/main/java/com/gmail/nossr50/listeners/SelfListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/SelfListener.java @@ -12,6 +12,7 @@ import com.gmail.nossr50.util.player.PlayerLevelUtils; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; import com.gmail.nossr50.util.skills.RankUtils; +import com.gmail.nossr50.util.skills.SkillTools; import com.gmail.nossr50.worldguard.WorldGuardManager; import com.gmail.nossr50.worldguard.WorldGuardUtils; import org.bukkit.entity.Player; @@ -132,7 +133,7 @@ public class SelfListener implements Listener { return; } - if (mcMMO.p.getSkillTools().isChildSkill(primarySkillType)) { + if (SkillTools.isChildSkill(primarySkillType)) { return; } diff --git a/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java b/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java index b589357c0..8b3c96dfe 100644 --- a/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java @@ -4,6 +4,7 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.scoreboards.ScoreboardManager; +import com.gmail.nossr50.util.skills.SkillTools; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; @@ -46,7 +47,7 @@ public class McrankCommandDisplayTask extends BukkitRunnable { sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Heading")); sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Player", playerName)); - for (PrimarySkillType skill : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + for (PrimarySkillType skill : SkillTools.NON_CHILD_SKILLS) { // if (!mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, skill)) { // continue; // } 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 056b17dea..dd061d8b6 100644 --- a/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/database/FormulaConversionTask.java @@ -10,6 +10,7 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.skills.SkillTools; import org.bukkit.command.CommandSender; import org.bukkit.scheduler.BukkitRunnable; @@ -58,7 +59,7 @@ public class FormulaConversionTask extends BukkitRunnable { private void editValues(PlayerProfile profile) { mcMMO.p.debug("========================================================================"); mcMMO.p.debug("Conversion report for " + profile.getPlayerName() + ":"); - for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { int oldLevel = profile.getSkillLevel(primarySkillType); int oldXPLevel = profile.getSkillXpLevel(primarySkillType); int totalOldXP = mcMMO.getFormulaManager().calculateTotalExperience(oldLevel, oldXPLevel); diff --git a/src/main/java/com/gmail/nossr50/skills/child/FamilyTree.java b/src/main/java/com/gmail/nossr50/skills/child/FamilyTree.java index 7a5639dc2..0be533600 100644 --- a/src/main/java/com/gmail/nossr50/skills/child/FamilyTree.java +++ b/src/main/java/com/gmail/nossr50/skills/child/FamilyTree.java @@ -1,7 +1,7 @@ package com.gmail.nossr50.skills.child; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; -import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.skills.SkillTools; import java.util.Collections; import java.util.EnumSet; @@ -41,13 +41,13 @@ public class FamilyTree { } protected static void enforceChildSkill(PrimarySkillType skill) { - if (!mcMMO.p.getSkillTools().isChildSkill(skill)) { + if (!SkillTools.isChildSkill(skill)) { throw new IllegalArgumentException(skill.name() + " is not a child skill!"); } } protected static void enforceNotChildSkill(PrimarySkillType skill) { - if (mcMMO.p.getSkillTools().isChildSkill(skill)) { + if (SkillTools.isChildSkill(skill)) { throw new IllegalArgumentException(skill.name() + " is a child skill!"); } } diff --git a/src/main/java/com/gmail/nossr50/util/EventUtils.java b/src/main/java/com/gmail/nossr50/util/EventUtils.java index e6d697852..828f43906 100644 --- a/src/main/java/com/gmail/nossr50/util/EventUtils.java +++ b/src/main/java/com/gmail/nossr50/util/EventUtils.java @@ -35,6 +35,7 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.CombatUtils; +import com.gmail.nossr50.util.skills.SkillTools; import org.bukkit.block.Block; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Entity; @@ -405,7 +406,7 @@ public final class EventUtils { experienceChanged = event.getExperienceChanged(); PlayerProfile playerProfile = UserManager.getPlayer(player).getProfile(); - for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { String skillName = primarySkillType.toString(); int playerSkillLevel = playerProfile.getSkillLevel(primarySkillType); int threshold = mcMMO.p.getGeneralConfig().getHardcoreDeathStatPenaltyLevelThreshold(); @@ -454,7 +455,7 @@ public final class EventUtils { PlayerProfile victimProfile = UserManager.getPlayer(victim).getProfile(); - for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { String skillName = primarySkillType.toString(); int victimSkillLevel = victimProfile.getSkillLevel(primarySkillType); diff --git a/src/main/java/com/gmail/nossr50/util/HardcoreManager.java b/src/main/java/com/gmail/nossr50/util/HardcoreManager.java index 3c2abfc38..491074a5e 100644 --- a/src/main/java/com/gmail/nossr50/util/HardcoreManager.java +++ b/src/main/java/com/gmail/nossr50/util/HardcoreManager.java @@ -6,6 +6,7 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.skills.SkillTools; import com.gmail.nossr50.worldguard.WorldGuardManager; import com.gmail.nossr50.worldguard.WorldGuardUtils; import org.bukkit.entity.Player; @@ -34,7 +35,7 @@ public final class HardcoreManager { HashMap levelChanged = new HashMap<>(); HashMap experienceChanged = new HashMap<>(); - for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { if (!mcMMO.p.getGeneralConfig().getHardcoreStatLossEnabled(primarySkillType)) { levelChanged.put(primarySkillType.toString(), 0); experienceChanged.put(primarySkillType.toString(), 0F); @@ -86,7 +87,7 @@ public final class HardcoreManager { HashMap levelChanged = new HashMap<>(); HashMap experienceChanged = new HashMap<>(); - for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { if (!mcMMO.p.getGeneralConfig().getHardcoreVampirismEnabled(primarySkillType)) { levelChanged.put(primarySkillType.toString(), 0); experienceChanged.put(primarySkillType.toString(), 0F); @@ -135,7 +136,7 @@ public final class HardcoreManager { public static boolean isStatLossEnabled() { boolean enabled = false; - for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { if (mcMMO.p.getGeneralConfig().getHardcoreStatLossEnabled(primarySkillType)) { enabled = true; break; @@ -153,7 +154,7 @@ public final class HardcoreManager { public static boolean isVampirismEnabled() { boolean enabled = false; - for (PrimarySkillType primarySkillType : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { if (mcMMO.p.getGeneralConfig().getHardcoreVampirismEnabled(primarySkillType)) { enabled = true; break; diff --git a/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java b/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java index adb2d4851..d40403ddd 100644 --- a/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java +++ b/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java @@ -7,6 +7,7 @@ import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.player.UserManager; +import com.gmail.nossr50.util.skills.SkillTools; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.text.StringUtils; import com.google.common.collect.ImmutableList; @@ -25,7 +26,7 @@ public final class CommandUtils { private CommandUtils() {} public static boolean isChildSkill(CommandSender sender, PrimarySkillType skill) { - if (skill == null || !mcMMO.p.getSkillTools().isChildSkill(skill)) { + if (skill == null || !SkillTools.isChildSkill(skill)) { return false; } @@ -205,7 +206,7 @@ public final class CommandUtils { } public static String displaySkill(PlayerProfile profile, PrimarySkillType skill) { - if (mcMMO.p.getSkillTools().isChildSkill(skill)) { + if (SkillTools.isChildSkill(skill)) { return LocaleLoader.getString("Skills.ChildStats", LocaleLoader.getString(StringUtils.getCapitalized(skill.toString()) + ".Listener") + " ", profile.getSkillLevel(skill)); } if (profile.getSkillLevel(skill) == mcMMO.p.getSkillTools().getLevelCap(skill)){ 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 9c23627da..be3e97cb4 100644 --- a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java +++ b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java @@ -16,6 +16,7 @@ import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.scoreboards.ScoreboardManager.SidebarType; +import com.gmail.nossr50.util.skills.SkillTools; import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -488,7 +489,7 @@ public class ScoreboardWrapper { case SKILL_BOARD: Validate.notNull(targetSkill); - if (!mcMMO.p.getSkillTools().isChildSkill(targetSkill)) { + if (!SkillTools.isChildSkill(targetSkill)) { int currentXP = mcMMOPlayer.getSkillXpLevel(targetSkill); sidebarObjective.getScore(ScoreboardManager.LABEL_CURRENT_XP).setScore(currentXP); @@ -573,7 +574,7 @@ public class ScoreboardWrapper { // Calculate power level here int powerLevel = 0; - for (PrimarySkillType skill : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { // Don't include child skills, makes the list too long + for (PrimarySkillType skill : SkillTools.NON_CHILD_SKILLS) { // Don't include child skills, makes the list too long int level = newProfile.getSkillLevel(skill); powerLevel += level; @@ -606,7 +607,7 @@ public class ScoreboardWrapper { Integer rank; Player player = mcMMO.p.getServer().getPlayerExact(playerName); - for (PrimarySkillType skill : mcMMO.p.getSkillTools().NON_CHILD_SKILLS) { + for (PrimarySkillType skill : SkillTools.NON_CHILD_SKILLS) { if (!mcMMO.p.getSkillTools().doesPlayerHaveSkillPermission(player, skill)) { continue; } diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java index ae33665aa..8d50873c5 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillTools.java @@ -29,7 +29,7 @@ public class SkillTools { public final @NotNull ImmutableList FORMATTED_SUBSKILL_NAMES; public final @NotNull ImmutableSet EXACT_SUBSKILL_NAMES; public final @NotNull ImmutableList CHILD_SKILLS; - public final @NotNull ImmutableList NON_CHILD_SKILLS; + public final static @NotNull ImmutableList NON_CHILD_SKILLS; public final @NotNull ImmutableList COMBAT_SKILLS; public final @NotNull ImmutableList GATHERING_SKILLS; public final @NotNull ImmutableList MISC_SKILLS; @@ -42,6 +42,16 @@ public class SkillTools { private final ImmutableMap mainActivatedAbilityChildMap; private final ImmutableMap primarySkillToolMap; + static { + ArrayList tempNonChildSkills = new ArrayList<>(); + for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { + if (primarySkillType != PrimarySkillType.SALVAGE && primarySkillType != PrimarySkillType.SMELTING) + tempNonChildSkills.add(primarySkillType); + } + + NON_CHILD_SKILLS = ImmutableList.copyOf(tempNonChildSkills); + } + public SkillTools(@NotNull mcMMO pluginRef) { this.pluginRef = pluginRef; @@ -130,18 +140,18 @@ public class SkillTools { */ List childSkills = new ArrayList<>(); - List nonChildSkills = new ArrayList<>(); +// List nonChildSkills = new ArrayList<>(); for (PrimarySkillType primarySkillType : PrimarySkillType.values()) { - if (isChildSkill(primarySkillType)) { + if (isChildSkill(primarySkillType)) childSkills.add(primarySkillType); - } else { - nonChildSkills.add(primarySkillType); - } +// } { +// nonChildSkills.add(primarySkillType); +// } } CHILD_SKILLS = ImmutableList.copyOf(childSkills); - NON_CHILD_SKILLS = ImmutableList.copyOf(nonChildSkills); +// NON_CHILD_SKILLS = ImmutableList.copyOf(nonChildSkills); /* * Build categorized skill lists @@ -318,7 +328,7 @@ public class SkillTools { } // TODO: This is a little "hacky", we probably need to add something to distinguish child skills in the enum, or to use another enum for them - public boolean isChildSkill(PrimarySkillType primarySkillType) { + public static boolean isChildSkill(PrimarySkillType primarySkillType) { switch (primarySkillType) { case SALVAGE: case SMELTING: diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index 5fdc3781f..30314b1fb 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -2,6 +2,11 @@ package com.gmail.nossr50.database; import com.gmail.nossr50.TestUtil; import com.gmail.nossr50.datatypes.database.DatabaseType; +import com.gmail.nossr50.datatypes.player.PlayerProfile; +import com.gmail.nossr50.datatypes.player.UniqueDataType; +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.datatypes.skills.SuperAbilityType; +import com.gmail.nossr50.util.skills.SkillTools; import com.google.common.io.Files; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -9,18 +14,14 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; import org.powermock.modules.junit4.PowerMockRunner; import java.io.*; import java.net.URI; import java.net.URISyntaxException; -import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; +import java.util.*; import java.util.logging.Logger; import static org.junit.Assert.*; @@ -30,17 +31,39 @@ import static org.junit.Assert.*; public class FlatFileDatabaseManagerTest { public static final @NotNull String TEST_FILE_NAME = "test.mcmmo.users"; - public static final int HEALTHY_RETURN_CODE = 0; - public static final String BAD_FILE_LINE_ONE = "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:"; - public static final String BAD_DATA_FILE_LINE_TWENTY_THREE = "nossr51:baddata:::baddata:baddata:640:baddata:1000:1000:1000:baddata:baddata:baddata:baddata:16:0:500:20273:0:0:0:0::1000:0:0:baddata:1593543012:0:0:0:0::1000:0:0:baddata:IGNORED:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1:0:"; + public static final @NotNull String BAD_FILE_LINE_ONE = "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:"; + public static final @NotNull String BAD_DATA_FILE_LINE_TWENTY_THREE = "nossr51:baddata:::baddata:baddata:640:baddata:1000:1000:1000:baddata:baddata:baddata:baddata:16:0:500:20273:0:0:0:0::1000:0:0:baddata:1593543012:0:0:0:0::1000:0:0:baddata:IGNORED:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1:0:"; + public static final @NotNull String DB_BADDATA = "baddatadb.users"; + public static final @NotNull String DB_HEALTHY = "healthydb.users"; + public static final @NotNull String HEALTHY_DB_LINE_1 = "nossr50:1:IGNORED:IGNORED:10:2:20:3:4:5:6:7:8:9:10:30:40:50:60:70:80:90:100:IGNORED:11:110:111:222:333:444:555:666:777:IGNORED:12:120:888:2020:HEARTS:13:130:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1111:999:"; + public static final @NotNull String HEALTHY_DB_LINE_ONE_UUID_STR = "588fe472-1c82-4c4e-9aa1-7eefccb277e3"; private static File tempDir; private final static @NotNull Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); private final long PURGE_TIME = 2630000000L; private static @Nullable FlatFileDatabaseManager db; + //Making them all unique makes it easier on us to edit this stuff later + int expectedLvlMining = 1, expectedLvlWoodcutting = 2, expectedLvlRepair = 3, + expectedLvlUnarmed = 4, expectedLvlHerbalism = 5, expectedLvlExcavation = 6, + expectedLvlArchery = 7, expectedLvlSwords = 8, expectedLvlAxes = 9, expectedLvlAcrobatics = 10, + expectedLvlTaming = 11, expectedLvlFishing = 12, expectedLvlAlchemy = 13; + + float expectedExpMining = 10, expectedExpWoodcutting = 20, expectedExpRepair = 30, + expectedExpUnarmed = 40, expectedExpHerbalism = 50, expectedExpExcavation = 60, + expectedExpArchery = 70, expectedExpSwords = 80, expectedExpAxes = 90, expectedExpAcrobatics = 100, + expectedExpTaming = 110, expectedExpFishing = 120, expectedExpAlchemy = 130; + + long expectedBerserkCd = 111, expectedGigaDrillBreakerCd = 222, expectedTreeFellerCd = 333, + expectedGreenTerraCd = 444, expectedSerratedStrikesCd = 555, expectedSkullSplitterCd = 666, + expectedSuperBreakerCd = 777, expectedBlastMiningCd = 888, expectedChimaeraWingCd = 999; + + int expectedScoreboardTips = 1111; + Long expectedLastLogin = 2020L; + @Before public void init() { assertNull(db); + //noinspection UnstableApiUsage tempDir = Files.createTempDir(); db = new FlatFileDatabaseManager(new File(tempDir.getPath() + File.separator + TEST_FILE_NAME), logger, PURGE_TIME, 0, true); } @@ -108,6 +131,249 @@ public class FlatFileDatabaseManagerTest { "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:badvalue:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:" }; + @Test + public void testSaveUser() { + //Make a Profile to save and check to see if it worked + UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); + String playerName = "nossr50"; + PlayerProfile testProfile = new PlayerProfile(playerName, uuid); + //The above profile should be "zero" initialized + + //Save the zero version and see if it looks correct + assertNotNull(db); + assertFalse(db.getUsersFile().exists()); + db.checkFileHealthAndStructure(); + assertTrue(db.getUsersFile().exists()); //Users file should have been created from the above com.gmail.nossr50.database.FlatFileDatabaseManager.checkFileHealthAndStructure + assertNotNull(db.getUsersFile()); + + //The DB is empty at this point, add our user + assertTrue(db.saveUser(testProfile)); //True means we saved the user + + //Check for the empty profile + PlayerProfile retrievedFromData = db.loadPlayerProfile(playerName); + assertTrue(retrievedFromData.isLoaded()); //PlayerProfile::isLoaded returns true if the data was created from the file, false if it wasn't found and a dummy profile was returned + assertEquals(uuid, retrievedFromData.getUniqueId()); + assertEquals(playerName, retrievedFromData.getPlayerName()); + } + + @Test + public void testLoadByName() { + + } + + @Test + public void testLoadByUUID() { + /* + * This test uses a file provided in test resources + */ + + ClassLoader classLoader = getClass().getClassLoader(); + URI resourceFileURI = null; + + try { + resourceFileURI = classLoader.getResource(DB_HEALTHY).toURI(); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + + assertNotNull(resourceFileURI); + File fromResourcesFile = new File(resourceFileURI); + assertNotNull(resourceFileURI); + File copyOfFile = new File(tempDir.getPath() + File.separator + DB_HEALTHY); + + if(copyOfFile.exists()) { + //noinspection ResultOfMethodCallIgnored + copyOfFile.delete(); + } + + assertTrue(fromResourcesFile.exists()); + + try { + //noinspection UnstableApiUsage + Files.copy(fromResourcesFile, copyOfFile); + } catch (IOException e) { + e.printStackTrace(); + } + + assertNotNull(copyOfFile); + + + + /* + * We have established the files are in good order, so now for the actual testing + */ + + //This makes sure our private method is working before the tests run afterwards + ArrayList dataFromFile = getSplitDataFromFile(copyOfFile); + System.out.println("File Path: "+copyOfFile.getAbsolutePath()); + assertArrayEquals(HEALTHY_DB_LINE_1.split(":"), dataFromFile.get(0)); + assertEquals(dataFromFile.get(0)[FlatFileDatabaseManager.UUID_INDEX], HEALTHY_DB_LINE_ONE_UUID_STR); + UUID healthDBEntryOneUUID = UUID.fromString(HEALTHY_DB_LINE_ONE_UUID_STR); + + FlatFileDatabaseManager db_a = new FlatFileDatabaseManager(copyOfFile, logger, PURGE_TIME, 0, true); + List flagsFound = db_a.checkFileHealthAndStructure(); + assertNull(flagsFound); //No flags should be found + + /* + * Once the DB looks fine load the profile + */ + + String playerName = "nossr50"; + UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); + + PlayerProfile profile = db_a.loadPlayerProfile(uuid, null); + testHealthyDataProfileValues(db_a, playerName, uuid, profile); + } + + private void testHealthyDataProfileValues(FlatFileDatabaseManager flatFileDatabaseManager, String playerName, UUID uuid, PlayerProfile playerProfile) { + PlayerProfile profile = flatFileDatabaseManager.loadPlayerProfile(uuid, null); + assertTrue(profile.isLoaded()); //PlayerProfile::isLoaded returns true if the data was created from the file, false if it wasn't found and a dummy profile was returned + assertEquals(uuid, profile.getUniqueId()); + assertEquals(playerName, profile.getPlayerName()); + + /* + * Player is a match and data is loaded, check values + */ + + for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { + if(SkillTools.isChildSkill(primarySkillType)) + continue; + +// System.out.println("Checking expected values for: "+primarySkillType); +// System.out.println("Profile Level Value: "+profile.getSkillLevel(primarySkillType)); +// System.out.println("Expected Lvl Value: "+getExpectedLevelHealthyDBEntryOne(primarySkillType)); +// System.out.println("Profile Exp Value: "+profile.getSkillXpLevelRaw(primarySkillType)); +// System.out.println("Expected Exp Value: "+getExpectedExperienceHealthyDBEntryOne(primarySkillType)); + + assertEquals(getExpectedLevelHealthyDBEntryOne(primarySkillType), profile.getSkillLevel(primarySkillType)); + assertEquals(getExpectedExperienceHealthyDBEntryOne(primarySkillType), profile.getSkillXpLevelRaw(primarySkillType), 0); + } + + //Check the other things + for(SuperAbilityType superAbilityType : SuperAbilityType.values()) { + assertEquals(getExpectedSuperAbilityDATS(superAbilityType), profile.getAbilityDATS(superAbilityType)); + } + + assertEquals(expectedChimaeraWingCd, profile.getUniqueData(UniqueDataType.CHIMAERA_WING_DATS)); + assertEquals(expectedScoreboardTips, profile.getScoreboardTipsShown()); + assertEquals(expectedLastLogin, profile.getLastLogin()); + } + + private long getExpectedSuperAbilityDATS(@NotNull SuperAbilityType superAbilityType) { + switch(superAbilityType) { + case BERSERK: + return expectedBerserkCd; + case SUPER_BREAKER: + return expectedSuperBreakerCd; + case GIGA_DRILL_BREAKER: + return expectedGigaDrillBreakerCd; + case GREEN_TERRA: + return expectedGreenTerraCd; + case SKULL_SPLITTER: + return expectedSkullSplitterCd; + case TREE_FELLER: + return expectedTreeFellerCd; + case SERRATED_STRIKES: + return expectedSerratedStrikesCd; + case BLAST_MINING: + return expectedBlastMiningCd; + } + + return -1; + } + + //TODO: Why is this stuff a float? + private float getExpectedExperienceHealthyDBEntryOne(@NotNull PrimarySkillType primarySkillType) { + switch(primarySkillType) { + case ACROBATICS: + return expectedExpAcrobatics; + case ALCHEMY: + return expectedExpAlchemy; + case ARCHERY: + return expectedExpArchery; + case AXES: + return expectedExpAxes; + case EXCAVATION: + return expectedExpExcavation; + case FISHING: + return expectedExpFishing; + case HERBALISM: + return expectedExpHerbalism; + case MINING: + return expectedExpMining; + case REPAIR: + return expectedExpRepair; + case SALVAGE: + case SMELTING: + return 0; + case SWORDS: + return expectedExpSwords; + case TAMING: + return expectedExpTaming; + case UNARMED: + return expectedExpUnarmed; + case WOODCUTTING: + return expectedExpWoodcutting; + } + + return -1; + } + + private int getExpectedLevelHealthyDBEntryOne(@NotNull PrimarySkillType primarySkillType) { + switch(primarySkillType) { + case ACROBATICS: + return expectedLvlAcrobatics; + case ALCHEMY: + return expectedLvlAlchemy; + case ARCHERY: + return expectedLvlArchery; + case AXES: + return expectedLvlAxes; + case EXCAVATION: + return expectedLvlExcavation; + case FISHING: + return expectedLvlFishing; + case HERBALISM: + return expectedLvlHerbalism; + case MINING: + return expectedLvlMining; + case REPAIR: + return expectedLvlRepair; + case SALVAGE: + case SMELTING: + return 0; + case SWORDS: + return expectedLvlSwords; + case TAMING: + return expectedLvlTaming; + case UNARMED: + return expectedLvlUnarmed; + case WOODCUTTING: + return expectedLvlWoodcutting; + } + + return -1; + } + + @Test + public void testOverwriteName() { + + } + + @Test + public void testDataNotFound() { + //Save the zero version and see if it looks correct + assertNotNull(db); + assertFalse(db.getUsersFile().exists()); + db.checkFileHealthAndStructure(); + assertTrue(db.getUsersFile().exists()); //Users file should have been created from the above com.gmail.nossr50.database.FlatFileDatabaseManager.checkFileHealthAndStructure + assertNotNull(db.getUsersFile()); + + //Check for the "unloaded" profile + PlayerProfile retrievedFromData = db.loadPlayerProfile("nossr50"); + assertFalse(retrievedFromData.isLoaded()); //PlayerProfile::isLoaded returns false if data doesn't exist for the user + } + @Test public void testPurgePowerlessUsers() { replaceDataInFile(db, normalDatabaseData); @@ -167,14 +433,11 @@ public class FlatFileDatabaseManagerTest { @Test public void testLoadFromFile() { - Path resourceDirectory = Paths.get("src","test","resources"); - String absolutePath = resourceDirectory.toFile().getAbsolutePath(); - ClassLoader classLoader = getClass().getClassLoader(); URI resourceFileURI = null; try { - resourceFileURI = classLoader.getResource("baddatadb.users").toURI(); + resourceFileURI = classLoader.getResource(DB_BADDATA).toURI(); } catch (URISyntaxException e) { e.printStackTrace(); } @@ -182,7 +445,7 @@ public class FlatFileDatabaseManagerTest { assertNotNull(resourceFileURI); File fromResourcesFile = new File(resourceFileURI); assertNotNull(resourceFileURI); - File copyOfFile = new File(tempDir.getPath() + File.separator + "baddatafile.users"); + File copyOfFile = new File(tempDir.getPath() + File.separator + DB_BADDATA); if(copyOfFile.exists()) { copyOfFile.delete(); @@ -282,7 +545,6 @@ public class FlatFileDatabaseManagerTest { } } } - } private void overwriteDataAndCheckForFlag(@NotNull FlatFileDatabaseManager targetDatabase, @NotNull String[] data, @NotNull FlatFileDataFlag flag) { diff --git a/src/test/resources/healthydb.users b/src/test/resources/healthydb.users new file mode 100644 index 000000000..38c671177 --- /dev/null +++ b/src/test/resources/healthydb.users @@ -0,0 +1,3 @@ +nossr50:1:IGNORED:IGNORED:10:2:20:3:4:5:6:7:8:9:10:30:40:50:60:70:80:90:100:IGNORED:11:110:111:222:333:444:555:666:777:IGNORED:12:120:888:2020:HEARTS:13:130:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1111:999: +mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906: +powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906: \ No newline at end of file From e6239936d2b1a41213d44d4e3d556c17e427b64e Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 13 Apr 2021 13:40:24 -0700 Subject: [PATCH 24/57] Add lastlogin tests --- .../gmail/nossr50/database/ExpectedType.java | 1 + .../nossr50/database/FlatFileDataFlag.java | 1 + .../database/FlatFileDataProcessor.java | 18 ++- .../database/FlatFileDatabaseManager.java | 19 ++- ...taProcessor.java => FlatFileDataUtil.java} | 7 +- .../datatypes/player/PlayerProfile.java | 2 +- .../database/FlatFileDatabaseManagerTest.java | 124 +++++++++++++----- ...sorTest.java => FlatFileDataUtilTest.java} | 4 +- src/test/resources/healthydb.users | 6 +- src/test/resources/missinglastlogin.users | 4 + 10 files changed, 130 insertions(+), 56 deletions(-) rename src/main/java/com/gmail/nossr50/database/flatfile/{FlatFileSaveDataProcessor.java => FlatFileDataUtil.java} (96%) rename src/test/java/com/gmail/nossr50/database/flatfile/{FlatFileSaveDataProcessorTest.java => FlatFileDataUtilTest.java} (83%) create mode 100644 src/test/resources/missinglastlogin.users diff --git a/src/main/java/com/gmail/nossr50/database/ExpectedType.java b/src/main/java/com/gmail/nossr50/database/ExpectedType.java index 57da078fb..ab3ad7c9c 100644 --- a/src/main/java/com/gmail/nossr50/database/ExpectedType.java +++ b/src/main/java/com/gmail/nossr50/database/ExpectedType.java @@ -3,6 +3,7 @@ package com.gmail.nossr50.database; public enum ExpectedType { STRING, INTEGER, + LONG, BOOLEAN, FLOAT, DOUBLE, diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java b/src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java index b67fe2806..b80c39e15 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDataFlag.java @@ -3,6 +3,7 @@ package com.gmail.nossr50.database; public enum FlatFileDataFlag { INCOMPLETE, BAD_VALUES, + LAST_LOGIN_SCHEMA_UPGRADE, MISSING_NAME, DUPLICATE_NAME, DUPLICATE_UUID, diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java index ddda18143..1b9651089 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java @@ -2,8 +2,9 @@ package com.gmail.nossr50.database; import com.gmail.nossr50.database.flatfile.FlatFileDataBuilder; import com.gmail.nossr50.database.flatfile.FlatFileDataContainer; -import com.gmail.nossr50.database.flatfile.FlatFileSaveDataProcessor; +import com.gmail.nossr50.database.flatfile.FlatFileDataUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.logging.Logger; @@ -134,16 +135,19 @@ public class FlatFileDataProcessor { //Check each data for bad values for(int i = 0; i < DATA_ENTRY_COUNT; i++) { if(shouldNotBeEmpty(splitDataLine[i], i)) { + + if(i == OVERHAUL_LAST_LOGIN) { + builder.appendFlag(FlatFileDataFlag.LAST_LOGIN_SCHEMA_UPGRADE); + } + badDataValues[i] = true; anyBadData = true; - reportBadDataLine("Data is empty when it should not be at index", "[index=" + i + "]", lineData); continue; } boolean isCorrectType = isOfExpectedType(splitDataLine[i], getExpectedValueType(i)); if(!isCorrectType) { - reportBadDataLine("Data is not of correct type", splitDataLine[i], lineData); anyBadData = true; badDataValues[i] = true; } @@ -177,7 +181,7 @@ public class FlatFileDataProcessor { } - public boolean shouldNotBeEmpty(String data, int index) { + public boolean shouldNotBeEmpty(@Nullable String data, int index) { if(getExpectedValueType(index) == ExpectedType.IGNORED) { return false; } else { @@ -255,6 +259,7 @@ public class FlatFileDataProcessor { case 23: //Assumption: Used to be used for something, no longer used case 33: //Assumption: Used to be used for something, no longer used case HEALTHBAR: + case LEGACY_LAST_LOGIN: return ExpectedType.IGNORED; case SKILLS_MINING: case SKILLS_REPAIR: @@ -269,7 +274,6 @@ public class FlatFileDataProcessor { case SKILLS_TAMING: case SKILLS_FISHING: case SKILLS_ALCHEMY: - case LAST_LOGIN: case COOLDOWN_BERSERK: case COOLDOWN_GIGA_DRILL_BREAKER: case COOLDOWN_TREE_FELLER: @@ -297,6 +301,8 @@ public class FlatFileDataProcessor { return ExpectedType.FLOAT; case UUID_INDEX: return ExpectedType.UUID; + case OVERHAUL_LAST_LOGIN: + return ExpectedType.LONG; } throw new IndexOutOfBoundsException(); @@ -320,7 +326,7 @@ public class FlatFileDataProcessor { //Fix our data if needed and prepare it to be saved for(FlatFileDataContainer dataContainer : flatFileDataContainers) { - String[] splitData = FlatFileSaveDataProcessor.getPreparedSaveDataLine(dataContainer); + String[] splitData = FlatFileDataUtil.getPreparedSaveDataLine(dataContainer); if(splitData == null) continue; diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index 42a65c868..97c77aeb5 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -70,15 +70,16 @@ public final class FlatFileDatabaseManager implements DatabaseManager { public static final int SKILLS_FISHING = 34; public static final int EXP_FISHING = 35; public static final int COOLDOWN_BLAST_MINING = 36; - public static final int LAST_LOGIN = 37; + public static final int LEGACY_LAST_LOGIN = 37; public static final int HEALTHBAR = 38; public static final int SKILLS_ALCHEMY = 39; public static final int EXP_ALCHEMY = 40; public static final int UUID_INDEX = 41; public static final int SCOREBOARD_TIPS = 42; public static final int COOLDOWN_CHIMAERA_WING = 43; + public static final int OVERHAUL_LAST_LOGIN = 44; - public static final int DATA_ENTRY_COUNT = COOLDOWN_CHIMAERA_WING + 1; //Update this everytime new data is added + public static final int DATA_ENTRY_COUNT = OVERHAUL_LAST_LOGIN + 1; //Update this everytime new data is added protected FlatFileDatabaseManager(@NotNull File usersFile, @NotNull Logger logger, long purgeTime, int startingLevel, boolean testing) { this.usersFile = usersFile; @@ -666,6 +667,10 @@ public final class FlatFileDatabaseManager implements DatabaseManager { String line; while ((line = in.readLine()) != null) { + if(line.startsWith("#")) { + continue; + } + // Find if the line contains the player we want. String[] rawSplitData = line.split(":"); @@ -718,6 +723,10 @@ public final class FlatFileDatabaseManager implements DatabaseManager { String line; while ((line = in.readLine()) != null) { + if(line.startsWith("#")) { + continue; + } + String[] character = line.split(":"); try { @@ -1071,7 +1080,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { fileWriter = new FileWriter(usersFilePath); //Write data to file if(dbCommentDate != null) - fileWriter.write(dbCommentDate); + fileWriter.write(dbCommentDate + "\r\n"); fileWriter.write(dataProcessor.processDataForSave().toString()); } @@ -1200,9 +1209,9 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } try { - lastLogin = Long.parseLong(character[LAST_LOGIN]); + lastLogin = Long.parseLong(character[OVERHAUL_LAST_LOGIN]); } catch (Exception e) { - lastLogin = System.currentTimeMillis(); + lastLogin = -1; } return new PlayerProfile(character[USERNAME_INDEX], uuid, skills, skillsXp, skillsDATS, scoreboardTipsShown, uniquePlayerDataMap, lastLogin); diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileSaveDataProcessor.java b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtil.java similarity index 96% rename from src/main/java/com/gmail/nossr50/database/flatfile/FlatFileSaveDataProcessor.java rename to src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtil.java index eb06d1dab..e4048cdf0 100644 --- a/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileSaveDataProcessor.java +++ b/src/main/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtil.java @@ -7,7 +7,7 @@ import org.jetbrains.annotations.Nullable; import static com.gmail.nossr50.database.FlatFileDatabaseManager.*; -public class FlatFileSaveDataProcessor { +public class FlatFileDataUtil { public static @Nullable String[] getPreparedSaveDataLine(@NotNull FlatFileDataContainer dataContainer) { if(dataContainer.getDataFlags() == null) { @@ -64,6 +64,7 @@ public class FlatFileSaveDataProcessor { case 3: //Assumption: Used to be for something, no longer used case 23: //Assumption: Used to be used for something, no longer used case 33: //Assumption: Used to be used for something, no longer used + case LEGACY_LAST_LOGIN: case HEALTHBAR: return "IGNORED"; case SKILLS_MINING: @@ -80,8 +81,8 @@ public class FlatFileSaveDataProcessor { case SKILLS_FISHING: case SKILLS_ALCHEMY: return String.valueOf(startingLevel); - case LAST_LOGIN: - return String.valueOf(System.currentTimeMillis() / 1000); //This is just to shorten the value + case OVERHAUL_LAST_LOGIN: + return String.valueOf(-1L); case COOLDOWN_BERSERK: case COOLDOWN_GIGA_DRILL_BREAKER: case COOLDOWN_TREE_FELLER: diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java index f2e4306fe..1295a6d05 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java @@ -162,7 +162,7 @@ public class PlayerProfile { @Deprecated public @NotNull Long getLastLogin() { if(lastLogin == null) - return System.currentTimeMillis(); + return -1L; else return lastLogin; } diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index 30314b1fb..48a1481b7 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -19,14 +19,13 @@ import org.powermock.modules.junit4.PowerMockRunner; import java.io.*; import java.net.URI; import java.net.URISyntaxException; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.*; import java.util.logging.Logger; import static org.junit.Assert.*; +//TODO: Test update leaderboards @RunWith(PowerMockRunner.class) public class FlatFileDatabaseManagerTest { @@ -35,8 +34,10 @@ public class FlatFileDatabaseManagerTest { public static final @NotNull String BAD_DATA_FILE_LINE_TWENTY_THREE = "nossr51:baddata:::baddata:baddata:640:baddata:1000:1000:1000:baddata:baddata:baddata:baddata:16:0:500:20273:0:0:0:0::1000:0:0:baddata:1593543012:0:0:0:0::1000:0:0:baddata:IGNORED:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1:0:"; public static final @NotNull String DB_BADDATA = "baddatadb.users"; public static final @NotNull String DB_HEALTHY = "healthydb.users"; - public static final @NotNull String HEALTHY_DB_LINE_1 = "nossr50:1:IGNORED:IGNORED:10:2:20:3:4:5:6:7:8:9:10:30:40:50:60:70:80:90:100:IGNORED:11:110:111:222:333:444:555:666:777:IGNORED:12:120:888:2020:HEARTS:13:130:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1111:999:"; + public static final @NotNull String HEALTHY_DB_LINE_1 = "nossr50:1:IGNORED:IGNORED:10:2:20:3:4:5:6:7:8:9:10:30:40:50:60:70:80:90:100:IGNORED:11:110:111:222:333:444:555:666:777:IGNORED:12:120:888:IGNORED:HEARTS:13:130:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1111:999:2020:"; public static final @NotNull String HEALTHY_DB_LINE_ONE_UUID_STR = "588fe472-1c82-4c4e-9aa1-7eefccb277e3"; + public static final String DB_MISSING_LAST_LOGIN = "missinglastlogin.users"; + public static final String LINE_TWO_FROM_MISSING_DB = "nossr50:1:IGNORED:IGNORED:10:2:20:3:4:5:6:7:8:9:10:30:40:50:60:70:80:90:100:IGNORED:11:110:111:222:333:444:555:666:777:IGNORED:12:120:888:0:HEARTS:13:130:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1111:999:"; private static File tempDir; private final static @NotNull Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); private final long PURGE_TIME = 2630000000L; @@ -157,21 +158,99 @@ public class FlatFileDatabaseManagerTest { } @Test - public void testLoadByName() { + public void testAddedMissingLastLoginValues() { + File dbFile = prepareDatabaseTestResource(DB_MISSING_LAST_LOGIN); + //This makes sure our private method is working before the tests run afterwards + ArrayList dataFromFile = getSplitDataFromFile(dbFile); + System.out.println("File Path: "+ dbFile.getAbsolutePath()); + assertArrayEquals(LINE_TWO_FROM_MISSING_DB.split(":"), dataFromFile.get(1)); + assertEquals(dataFromFile.get(1)[FlatFileDatabaseManager.UUID_INDEX], HEALTHY_DB_LINE_ONE_UUID_STR); + + db = new FlatFileDatabaseManager(dbFile, logger, PURGE_TIME, 0, true); + List flagsFound = db.checkFileHealthAndStructure(); + assertNotNull(flagsFound); + assertTrue(flagsFound.contains(FlatFileDataFlag.LAST_LOGIN_SCHEMA_UPGRADE)); + + //Check for the fixed value + PlayerProfile profile = db.loadPlayerProfile("nossr50"); + assertEquals(-1, (long) profile.getLastLogin()); + } + + + @Test + public void testLoadByName() { + File healthyDB = prepareDatabaseTestResource(DB_HEALTHY); + + /* + * We have established the files are in good order, so now for the actual testing + */ + + //This makes sure our private method is working before the tests run afterwards + ArrayList dataFromFile = getSplitDataFromFile(healthyDB); + System.out.println("File Path: "+healthyDB.getAbsolutePath()); + assertArrayEquals(HEALTHY_DB_LINE_1.split(":"), dataFromFile.get(0)); + assertEquals(dataFromFile.get(0)[FlatFileDatabaseManager.UUID_INDEX], HEALTHY_DB_LINE_ONE_UUID_STR); + UUID healthDBEntryOneUUID = UUID.fromString(HEALTHY_DB_LINE_ONE_UUID_STR); + + db = new FlatFileDatabaseManager(healthyDB, logger, PURGE_TIME, 0, true); + List flagsFound = db.checkFileHealthAndStructure(); + assertNull(flagsFound); //No flags should be found + + /* + * Once the DB looks fine load the profile + */ + + String playerName = "nossr50"; + UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); + + PlayerProfile profile = db.loadPlayerProfile(playerName); + testHealthyDataProfileValues(playerName, uuid, profile); } @Test public void testLoadByUUID() { + File dbFile = prepareDatabaseTestResource(DB_HEALTHY); + /* - * This test uses a file provided in test resources + * We have established the files are in good order, so now for the actual testing */ + //This makes sure our private method is working before the tests run afterwards + ArrayList dataFromFile = getSplitDataFromFile(dbFile); + System.out.println("File Path: " + dbFile.getAbsolutePath()); + assertArrayEquals(HEALTHY_DB_LINE_1.split(":"), dataFromFile.get(0)); + assertEquals(dataFromFile.get(0)[FlatFileDatabaseManager.UUID_INDEX], HEALTHY_DB_LINE_ONE_UUID_STR); + + db = new FlatFileDatabaseManager(dbFile, logger, PURGE_TIME, 0, true); + List flagsFound = db.checkFileHealthAndStructure(); + assertNull(flagsFound); //No flags should be found + + /* + * Once the DB looks fine load the profile + */ + + String playerName = "nossr50"; + UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); + + PlayerProfile profile1 = db.loadPlayerProfile(uuid, null); + PlayerProfile profile2 = db.loadPlayerProfile(uuid, playerName); + PlayerProfile profile3 = db.loadPlayerProfile(uuid, "incorrectName"); + PlayerProfile profile4 = db.loadPlayerProfile(new UUID(0, 1), "shouldBeUnloaded"); + assertFalse(profile4.isLoaded()); + + //Three possible ways to load the thing + testHealthyDataProfileValues(playerName, uuid, profile1); + testHealthyDataProfileValues(playerName, uuid, profile2); + testHealthyDataProfileValues(playerName, uuid, profile3); + } + + private File prepareDatabaseTestResource(@NotNull String dbFileName) { ClassLoader classLoader = getClass().getClassLoader(); URI resourceFileURI = null; try { - resourceFileURI = classLoader.getResource(DB_HEALTHY).toURI(); + resourceFileURI = classLoader.getResource(dbFileName).toURI(); } catch (URISyntaxException e) { e.printStackTrace(); } @@ -179,7 +258,7 @@ public class FlatFileDatabaseManagerTest { assertNotNull(resourceFileURI); File fromResourcesFile = new File(resourceFileURI); assertNotNull(resourceFileURI); - File copyOfFile = new File(tempDir.getPath() + File.separator + DB_HEALTHY); + File copyOfFile = new File(tempDir.getPath() + File.separator + dbFileName); if(copyOfFile.exists()) { //noinspection ResultOfMethodCallIgnored @@ -196,37 +275,10 @@ public class FlatFileDatabaseManagerTest { } assertNotNull(copyOfFile); - - - - /* - * We have established the files are in good order, so now for the actual testing - */ - - //This makes sure our private method is working before the tests run afterwards - ArrayList dataFromFile = getSplitDataFromFile(copyOfFile); - System.out.println("File Path: "+copyOfFile.getAbsolutePath()); - assertArrayEquals(HEALTHY_DB_LINE_1.split(":"), dataFromFile.get(0)); - assertEquals(dataFromFile.get(0)[FlatFileDatabaseManager.UUID_INDEX], HEALTHY_DB_LINE_ONE_UUID_STR); - UUID healthDBEntryOneUUID = UUID.fromString(HEALTHY_DB_LINE_ONE_UUID_STR); - - FlatFileDatabaseManager db_a = new FlatFileDatabaseManager(copyOfFile, logger, PURGE_TIME, 0, true); - List flagsFound = db_a.checkFileHealthAndStructure(); - assertNull(flagsFound); //No flags should be found - - /* - * Once the DB looks fine load the profile - */ - - String playerName = "nossr50"; - UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); - - PlayerProfile profile = db_a.loadPlayerProfile(uuid, null); - testHealthyDataProfileValues(db_a, playerName, uuid, profile); + return copyOfFile; } - private void testHealthyDataProfileValues(FlatFileDatabaseManager flatFileDatabaseManager, String playerName, UUID uuid, PlayerProfile playerProfile) { - PlayerProfile profile = flatFileDatabaseManager.loadPlayerProfile(uuid, null); + private void testHealthyDataProfileValues(@NotNull String playerName, @NotNull UUID uuid, @NotNull PlayerProfile profile) { assertTrue(profile.isLoaded()); //PlayerProfile::isLoaded returns true if the data was created from the file, false if it wasn't found and a dummy profile was returned assertEquals(uuid, profile.getUniqueId()); assertEquals(playerName, profile.getPlayerName()); diff --git a/src/test/java/com/gmail/nossr50/database/flatfile/FlatFileSaveDataProcessorTest.java b/src/test/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtilTest.java similarity index 83% rename from src/test/java/com/gmail/nossr50/database/flatfile/FlatFileSaveDataProcessorTest.java rename to src/test/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtilTest.java index 8b10772fa..ee6e71ffb 100644 --- a/src/test/java/com/gmail/nossr50/database/flatfile/FlatFileSaveDataProcessorTest.java +++ b/src/test/java/com/gmail/nossr50/database/flatfile/FlatFileDataUtilTest.java @@ -5,7 +5,7 @@ import org.junit.Test; import java.util.HashSet; -public class FlatFileSaveDataProcessorTest { +public class FlatFileDataUtilTest { @Test public void getPreparedSaveDataLine() { @@ -22,6 +22,6 @@ public class FlatFileSaveDataProcessorTest { @Test(expected = AssertionError.class) public void testTooManyDataEntriesSplitString() { FlatFileDataContainer dataContainer = new CategorizedFlatFileData(0, new HashSet<>(), new String[FlatFileDatabaseManager.DATA_ENTRY_COUNT + 1]); - FlatFileSaveDataProcessor.getPreparedSaveDataLine(dataContainer); + FlatFileDataUtil.getPreparedSaveDataLine(dataContainer); } } \ No newline at end of file diff --git a/src/test/resources/healthydb.users b/src/test/resources/healthydb.users index 38c671177..7ce5ccbad 100644 --- a/src/test/resources/healthydb.users +++ b/src/test/resources/healthydb.users @@ -1,3 +1,3 @@ -nossr50:1:IGNORED:IGNORED:10:2:20:3:4:5:6:7:8:9:10:30:40:50:60:70:80:90:100:IGNORED:11:110:111:222:333:444:555:666:777:IGNORED:12:120:888:2020:HEARTS:13:130:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1111:999: -mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906: -powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:0:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906: \ No newline at end of file +nossr50:1:IGNORED:IGNORED:10:2:20:3:4:5:6:7:8:9:10:30:40:50:60:70:80:90:100:IGNORED:11:110:111:222:333:444:555:666:777:IGNORED:12:120:888:IGNORED:HEARTS:13:130:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1111:999:2020: +mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:3030: +powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1337:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906:4040: \ No newline at end of file diff --git a/src/test/resources/missinglastlogin.users b/src/test/resources/missinglastlogin.users new file mode 100644 index 000000000..54378e194 --- /dev/null +++ b/src/test/resources/missinglastlogin.users @@ -0,0 +1,4 @@ +# A single comment line is sometimes at the top of the DB +nossr50:1:IGNORED:IGNORED:10:2:20:3:4:5:6:7:8:9:10:30:40:50:60:70:80:90:100:IGNORED:11:110:111:222:333:444:555:666:777:IGNORED:12:120:888:0:HEARTS:13:130:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1111:999: +mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906: +powerless:0:::0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0::0:0:0:0:0:0:0:0:0::0:0:0:1337:HEARTS:0:0:e0d07db8-f7e8-43c7-9ded-864dfc6f3b7c:5:1600906906: \ No newline at end of file From d9e195f63a9141bb3df20df7d34e81208fc773f0 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 13 Apr 2021 15:22:21 -0700 Subject: [PATCH 25/57] Add a newUser test --- Changelog.txt | 2 + pom.xml | 6 + .../nossr50/database/DatabaseManager.java | 10 +- .../database/FlatFileDatabaseManager.java | 202 +++++++----------- .../nossr50/database/SQLDatabaseManager.java | 27 ++- .../datatypes/player/PlayerProfile.java | 24 ++- src/main/java/com/gmail/nossr50/mcMMO.java | 9 + .../player/PlayerProfileLoadingTask.java | 2 + .../nossr50/util/commands/CommandUtils.java | 2 +- .../database/FlatFileDatabaseManagerTest.java | 61 +++++- 10 files changed, 191 insertions(+), 154 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index c11aa9f27..8a704c845 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -5,6 +5,8 @@ Version 2.1.189 Rewrote how FlatFileDatabase verifies data integrity (API) Added com.gmail.nossr50.database.DatabaseManager.loadPlayerProfile(org.bukkit.OfflinePlayer) (API) Deprecated com.gmail.nossr50.database.DatabaseManager.loadPlayerProfile(java.util.UUID, java.lang.String) + (API) Removed com.gmail.nossr50.database.DatabaseManager.newUser(java.lang.String, java.util.UUID) + (API) Added Added unit tests for FlatFileDatabaseManager (see notes) Fixed a bug where FlatFileDatabaseManager didn't properly upgrade older database entries to the newest schema The setting to disable the mcMMO user block tracker has been moved from our "hidden config" to persistent_data.yml diff --git a/pom.xml b/pom.xml index c39db8f41..231bd7f4b 100755 --- a/pom.xml +++ b/pom.xml @@ -220,6 +220,12 @@ + + com.github.seeseemelk + MockBukkit-v1.16 + 0.25.0 + test + co.aikar acf-bukkit diff --git a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java index 914a35aa2..3f9ac7a77 100644 --- a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java @@ -76,11 +76,11 @@ public interface DatabaseManager { /** * Add a new user to the database. - * - * @param playerName The name of the player to be added to the database + * @param playerName The name of the player to be added to the database * @param uuid The uuid of the player to be added to the database + * @return */ - void newUser(String playerName, UUID uuid); + @NotNull PlayerProfile newUser(String playerName, UUID uuid); @NotNull PlayerProfile newUser(@NotNull Player player); @@ -101,11 +101,13 @@ public interface DatabaseManager { * Load a player from the database. * @param uuid The uuid of the player to load from the database * @return The player's data, or an unloaded PlayerProfile if not found - * @deprecated Use {@link DatabaseManager#loadPlayerProfile(org.bukkit.OfflinePlayer)} if possible + * @deprecated Use {@link DatabaseManager#loadPlayerProfile(org.bukkit.OfflinePlayer)} or {@link DatabaseManager#loadPlayerProfile(java.util.UUID)} if possible */ @Deprecated @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid, @Nullable String playerName); + @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid); + /** * 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 97c77aeb5..8d4f8ea30 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -31,7 +31,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { private final @NotNull Logger logger; private final long purgeTime; private final int startingLevel; - private boolean testing; + private final boolean testing; private final long UPDATE_WAIT_TIME = 600000L; // 10 minutes private final @NotNull File usersFile; @@ -97,6 +97,8 @@ public final class FlatFileDatabaseManager implements DatabaseManager { logger.info("Detected "+flatFileDataFlags.size() + " data entries which need correction."); } } + + updateLeaderboards(); } } @@ -193,29 +195,31 @@ public final class FlatFileDatabaseManager implements DatabaseManager { String name = character[USERNAME_INDEX]; long lastPlayed = 0; boolean rewrite = false; + try { - lastPlayed = Long.parseLong(character[37]) * Misc.TIME_CONVERSION_FACTOR; - } - catch (NumberFormatException e) { + lastPlayed = Long.parseLong(character[OVERHAUL_LAST_LOGIN]); + } catch (NumberFormatException e) { e.printStackTrace(); } - if (lastPlayed == 0) { + + if (lastPlayed == -1) { OfflinePlayer player = mcMMO.p.getServer().getOfflinePlayer(name); - lastPlayed = player.getLastPlayed(); - rewrite = true; + + if(player.getLastPlayed() != 0) { + lastPlayed = player.getLastPlayed(); + rewrite = true; + } } if (currentTime - lastPlayed > purgeTime) { removedPlayers++; - } - else { + } else { if (rewrite) { // Rewrite their data with a valid time - character[37] = Long.toString(lastPlayed); + character[OVERHAUL_LAST_LOGIN] = Long.toString(lastPlayed); String newLine = org.apache.commons.lang.StringUtils.join(character, ":"); writer.append(newLine).append("\r\n"); - } - else { + } else { writer.append(line).append("\r\n"); } } @@ -421,51 +425,52 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - private void writeUserToLine(PlayerProfile profile, @NotNull String playerName, @Nullable UUID uuid, StringBuilder writer) { + public void writeUserToLine(@NotNull PlayerProfile profile, @NotNull String playerName, @Nullable UUID uuid, @NotNull Appendable writer) throws IOException { writer.append(playerName).append(":"); - writer.append(profile.getSkillLevel(PrimarySkillType.MINING)).append(":"); - writer.append(":"); - writer.append(":"); - writer.append(profile.getSkillXpLevel(PrimarySkillType.MINING)).append(":"); - writer.append(profile.getSkillLevel(PrimarySkillType.WOODCUTTING)).append(":"); - writer.append(profile.getSkillXpLevel(PrimarySkillType.WOODCUTTING)).append(":"); - writer.append(profile.getSkillLevel(PrimarySkillType.REPAIR)).append(":"); - writer.append(profile.getSkillLevel(PrimarySkillType.UNARMED)).append(":"); - writer.append(profile.getSkillLevel(PrimarySkillType.HERBALISM)).append(":"); - writer.append(profile.getSkillLevel(PrimarySkillType.EXCAVATION)).append(":"); - writer.append(profile.getSkillLevel(PrimarySkillType.ARCHERY)).append(":"); - writer.append(profile.getSkillLevel(PrimarySkillType.SWORDS)).append(":"); - writer.append(profile.getSkillLevel(PrimarySkillType.AXES)).append(":"); - writer.append(profile.getSkillLevel(PrimarySkillType.ACROBATICS)).append(":"); - writer.append(profile.getSkillXpLevel(PrimarySkillType.REPAIR)).append(":"); - writer.append(profile.getSkillXpLevel(PrimarySkillType.UNARMED)).append(":"); - writer.append(profile.getSkillXpLevel(PrimarySkillType.HERBALISM)).append(":"); - writer.append(profile.getSkillXpLevel(PrimarySkillType.EXCAVATION)).append(":"); - writer.append(profile.getSkillXpLevel(PrimarySkillType.ARCHERY)).append(":"); - writer.append(profile.getSkillXpLevel(PrimarySkillType.SWORDS)).append(":"); - writer.append(profile.getSkillXpLevel(PrimarySkillType.AXES)).append(":"); - writer.append(profile.getSkillXpLevel(PrimarySkillType.ACROBATICS)).append(":"); - writer.append(":"); - writer.append(profile.getSkillLevel(PrimarySkillType.TAMING)).append(":"); - writer.append(profile.getSkillXpLevel(PrimarySkillType.TAMING)).append(":"); - writer.append((int) profile.getAbilityDATS(SuperAbilityType.BERSERK)).append(":"); - writer.append((int) profile.getAbilityDATS(SuperAbilityType.GIGA_DRILL_BREAKER)).append(":"); - writer.append((int) profile.getAbilityDATS(SuperAbilityType.TREE_FELLER)).append(":"); - writer.append((int) profile.getAbilityDATS(SuperAbilityType.GREEN_TERRA)).append(":"); - writer.append((int) profile.getAbilityDATS(SuperAbilityType.SERRATED_STRIKES)).append(":"); - writer.append((int) profile.getAbilityDATS(SuperAbilityType.SKULL_SPLITTER)).append(":"); - writer.append((int) profile.getAbilityDATS(SuperAbilityType.SUPER_BREAKER)).append(":"); - writer.append(":"); - writer.append(profile.getSkillLevel(PrimarySkillType.FISHING)).append(":"); - writer.append(profile.getSkillXpLevel(PrimarySkillType.FISHING)).append(":"); - writer.append((int) profile.getAbilityDATS(SuperAbilityType.BLAST_MINING)).append(":"); - writer.append(System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR).append(":"); + writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.MINING))).append(":"); + writer.append(IGNORED).append(":"); + writer.append(IGNORED).append(":"); + writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.MINING))).append(":"); + writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.WOODCUTTING))).append(":"); + writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.WOODCUTTING))).append(":"); + writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.REPAIR))).append(":"); + writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.UNARMED))).append(":"); + writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.HERBALISM))).append(":"); + writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.EXCAVATION))).append(":"); + writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ARCHERY))).append(":"); + writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.SWORDS))).append(":"); + writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.AXES))).append(":"); + writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ACROBATICS))).append(":"); + writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.REPAIR))).append(":"); + writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.UNARMED))).append(":"); + writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.HERBALISM))).append(":"); + writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.EXCAVATION))).append(":"); + writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ARCHERY))).append(":"); + writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.SWORDS))).append(":"); + writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.AXES))).append(":"); + writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ACROBATICS))).append(":"); + writer.append(IGNORED).append(":"); + writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.TAMING))).append(":"); + writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.TAMING))).append(":"); + writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.BERSERK))).append(":"); + writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.GIGA_DRILL_BREAKER))).append(":"); + writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.TREE_FELLER))).append(":"); + writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.GREEN_TERRA))).append(":"); + writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SERRATED_STRIKES))).append(":"); + writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SKULL_SPLITTER))).append(":"); + writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SUPER_BREAKER))).append(":"); + writer.append(IGNORED).append(":"); + writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.FISHING))).append(":"); + writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.FISHING))).append(":"); + writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.BLAST_MINING))).append(":"); + writer.append(IGNORED).append(":"); //Legacy last login writer.append(IGNORED).append(":"); //mob health bar - writer.append(profile.getSkillLevel(PrimarySkillType.ALCHEMY)).append(":"); - writer.append(profile.getSkillXpLevel(PrimarySkillType.ALCHEMY)).append(":"); + writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ALCHEMY))).append(":"); + writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ALCHEMY))).append(":"); writer.append(uuid != null ? uuid.toString() : "NULL").append(":"); - writer.append(profile.getScoreboardTipsShown()).append(":"); - writer.append(profile.getUniqueData(UniqueDataType.CHIMAERA_WING_DATS)).append(":"); + writer.append(String.valueOf(profile.getScoreboardTipsShown())).append(":"); + writer.append(String.valueOf(profile.getUniqueData(UniqueDataType.CHIMAERA_WING_DATS))).append(":"); + writer.append(String.valueOf(profile.getLastLogin())).append(":"); //overhaul last login writer.append("\r\n"); } @@ -498,81 +503,21 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } public @NotNull PlayerProfile newUser(@NotNull Player player) { - newUser(player.getName(), player.getUniqueId()); - return new PlayerProfile(player.getName(), player.getUniqueId(), true); + return new PlayerProfile(player.getName(), player.getUniqueId(), true, startingLevel); } - public void newUser(String playerName, UUID uuid) { - BufferedWriter out = null; + public @NotNull PlayerProfile newUser(@NotNull String playerName, @NotNull UUID uuid) { + PlayerProfile playerProfile = new PlayerProfile(playerName, uuid, true, startingLevel); + synchronized (fileWritingLock) { - try { - // Open the file to write the player - out = new BufferedWriter(new FileWriter(usersFilePath, true)); - - String startingLevelStr = startingLevel + ":"; - - // Add the player to the end - out.append(playerName).append(":"); - out.append(startingLevelStr); // Mining - out.append(":"); - out.append(":"); - out.append("0:"); // Xp - out.append(startingLevelStr); // Woodcutting - out.append("0:"); // WoodCuttingXp - out.append(startingLevelStr); // Repair - out.append(startingLevelStr); // Unarmed - out.append(startingLevelStr); // Herbalism - out.append(startingLevelStr); // Excavation - out.append(startingLevelStr); // Archery - out.append(startingLevelStr); // Swords - out.append(startingLevelStr); // Axes - out.append(startingLevelStr); // Acrobatics - out.append("0:"); // RepairXp - out.append("0:"); // UnarmedXp - out.append("0:"); // HerbalismXp - out.append("0:"); // ExcavationXp - out.append("0:"); // ArcheryXp - out.append("0:"); // SwordsXp - out.append("0:"); // AxesXp - out.append("0:"); // AcrobaticsXp - out.append(":"); - out.append(startingLevelStr); // Taming - out.append("0:"); // TamingXp - out.append("0:"); // DATS - out.append("0:"); // DATS - out.append("0:"); // DATS - out.append("0:"); // DATS - out.append("0:"); // DATS - out.append("0:"); // DATS - out.append("0:"); // DATS - out.append(":"); - out.append(startingLevelStr); // Fishing - out.append("0:"); // FishingXp - out.append("0:"); // Blast Mining - out.append(String.valueOf(System.currentTimeMillis() / Misc.TIME_CONVERSION_FACTOR)).append(":"); // LastLogin - out.append(IGNORED).append(":"); // Mob Healthbar HUD - out.append(startingLevelStr); // Alchemy - out.append("0:"); // AlchemyXp - out.append(uuid != null ? uuid.toString() : "NULL").append(":"); // UUID - out.append("0:"); // Scoreboard tips shown - // Add more in the same format as the line above - - out.newLine(); - } - catch (Exception e) { + try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(usersFilePath, true))) { + writeUserToLine(playerProfile, playerName, uuid, bufferedWriter); + } catch (Exception e) { e.printStackTrace(); } - finally { - if (out != null) { - try { - out.close(); - } - catch (IOException e) { - // Ignore - } - } - } } + + return playerProfile; } public @NotNull PlayerProfile loadPlayerProfile(@NotNull OfflinePlayer offlinePlayer) { @@ -587,6 +532,10 @@ public final class FlatFileDatabaseManager implements DatabaseManager { return loadPlayerByUUID(uuid, playerName, false); } + public @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid) { + return loadPlayerByUUID(uuid, null, false); + } + private @NotNull PlayerProfile loadPlayerByUUID(@NotNull UUID uuid, @Nullable String playerName, boolean isOnline) { BufferedReader in = null; @@ -700,7 +649,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } //Return a new blank profile - return new PlayerProfile(playerName, null); + return new PlayerProfile(playerName, new UUID(0, 0), startingLevel); } private @NotNull PlayerProfile grabUnloadedProfile(@NotNull UUID uuid, @Nullable String playerName) { @@ -708,7 +657,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { playerName = ""; //No name for you boy! } - return new PlayerProfile(playerName, uuid); + return new PlayerProfile(playerName, uuid, 0); } public void convertUsers(DatabaseManager destination) { @@ -731,8 +680,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { try { destination.saveUser(loadFromLine(character)); - } - catch (Exception e) { + } catch (Exception e) { e.printStackTrace(); } convertedUsers++; diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index 6599e707c..01c14ed16 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -1,6 +1,7 @@ package com.gmail.nossr50.database; import com.gmail.nossr50.api.exceptions.InvalidSkillException; +import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.MobHealthbarType; import com.gmail.nossr50.datatypes.database.DatabaseType; import com.gmail.nossr50.datatypes.database.PlayerStat; @@ -491,19 +492,19 @@ public final class SQLDatabaseManager implements DatabaseManager { return skills; } - public void newUser(String playerName, UUID uuid) { + public @NotNull PlayerProfile newUser(String playerName, UUID uuid) { Connection connection = null; try { connection = getConnection(PoolIdentifier.MISC); newUser(connection, playerName, uuid); - } - catch (SQLException ex) { + } catch (SQLException ex) { printErrors(ex); - } - finally { + } finally { tryClose(connection); } + + return new PlayerProfile(playerName, uuid, true, mcMMO.p.getAdvancedConfig().getStartingLevel()); } @Override @@ -513,7 +514,7 @@ public final class SQLDatabaseManager implements DatabaseManager { int id = newUser(connection, player.getName(), player.getUniqueId()); if (id == -1) { - return new PlayerProfile(player.getName(), player.getUniqueId(), false); + return new PlayerProfile(player.getName(), player.getUniqueId(), false, mcMMO.p.getAdvancedConfig().getStartingLevel()); } else { return loadPlayerProfile(player.getUniqueId(), player.getName()); } @@ -521,7 +522,7 @@ public final class SQLDatabaseManager implements DatabaseManager { e.printStackTrace(); } - return new PlayerProfile(player.getName(), player.getUniqueId(), false); + return new PlayerProfile(player.getName(), player.getUniqueId(), false, mcMMO.p.getAdvancedConfig().getStartingLevel()); } private int newUser(Connection connection, String playerName, UUID uuid) { @@ -567,7 +568,7 @@ public final class SQLDatabaseManager implements DatabaseManager { return loadPlayerFromDB(null, playerName); } catch (RuntimeException e) { e.printStackTrace(); - return new PlayerProfile(playerName, false); + return new PlayerProfile(playerName, false, mcMMO.p.getAdvancedConfig().getStartingLevel()); } } @@ -575,6 +576,12 @@ public final class SQLDatabaseManager implements DatabaseManager { return loadPlayerFromDB(uuid, playerName); } + @Override + public @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid) { + return loadPlayerFromDB(uuid, null); + } + + private PlayerProfile loadPlayerFromDB(@Nullable UUID uuid, @Nullable String playerName) throws RuntimeException { if(uuid == null && playerName == null) { throw new RuntimeException("Error looking up player, both UUID and playerName are null and one must not be."); @@ -590,7 +597,7 @@ public final class SQLDatabaseManager implements DatabaseManager { if (id == -1) { // There is no such user - return new PlayerProfile(playerName, false); + return new PlayerProfile(playerName, mcMMO.p.getAdvancedConfig().getStartingLevel()); } // There is such a user writeMissingRows(connection, id); @@ -659,7 +666,7 @@ public final class SQLDatabaseManager implements DatabaseManager { } //Return empty profile - return new PlayerProfile(playerName, false); + return new PlayerProfile(playerName, mcMMO.p.getAdvancedConfig().getStartingLevel()); } public void convertUsers(DatabaseManager destination) { diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java index 1295a6d05..81d2d8417 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java @@ -43,11 +43,13 @@ public class PlayerProfile { private final Map rollingSkillsXp = new EnumMap(PrimarySkillType.class); @Deprecated - public PlayerProfile(String playerName) { - this(playerName, null); + //TODO: Add deprecated constructor w/o startinglevel + public PlayerProfile(String playerName, int startingLevel) { + this(playerName, null, startingLevel); } - public PlayerProfile(String playerName, UUID uuid) { + //TODO: Add deprecated constructor w/o startinglevel + public PlayerProfile(String playerName, UUID uuid, int startingLevel) { this.uuid = uuid; this.playerName = playerName; @@ -58,9 +60,7 @@ public class PlayerProfile { } for (PrimarySkillType primarySkillType : SkillTools.NON_CHILD_SKILLS) { - int startingLvl = mcMMO.p != null ? mcMMO.p.getAdvancedConfig().getStartingLevel() : 0; //TODO: Setup the mock since this was to avoid setting up a mock in a test - - skills.put(primarySkillType, startingLvl); + skills.put(primarySkillType, startingLevel); skillsXp.put(primarySkillType, 0F); } @@ -70,13 +70,13 @@ public class PlayerProfile { } @Deprecated - public PlayerProfile(@NotNull String playerName, boolean isLoaded) { - this(playerName); + public PlayerProfile(@NotNull String playerName, boolean isLoaded, int startingLvl) { + this(playerName, startingLvl); this.loaded = isLoaded; } - public PlayerProfile(@NotNull String playerName, UUID uuid, boolean isLoaded) { - this(playerName, uuid); + public PlayerProfile(@NotNull String playerName, UUID uuid, boolean isLoaded, int startingLvl) { + this(playerName, uuid, startingLvl); this.loaded = isLoaded; } @@ -167,6 +167,10 @@ public class PlayerProfile { return lastLogin; } + public void updateLastLogin() { + this.lastLogin = System.currentTimeMillis(); + } + public String getPlayerName() { return playerName; } diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index 69982d932..5e08bc34e 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -59,8 +59,10 @@ import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.plugin.java.JavaPluginLoader; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -168,6 +170,13 @@ public class mcMMO extends JavaPlugin { p = this; } + + protected mcMMO(JavaPluginLoader loader, PluginDescriptionFile description, File dataFolder, File file) + { + super(loader, description, dataFolder, file); + } + + /** * Things to be run when the plugin is enabled. */ 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 5dccb2cf1..95c0ddc71 100644 --- a/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java @@ -92,6 +92,8 @@ public class PlayerProfileLoadingTask extends BukkitRunnable { return; } + mcMMOPlayer.getProfile().updateLastLogin(); + mcMMOPlayer.setupPartyData(); UserManager.track(mcMMOPlayer); mcMMOPlayer.actualizeRespawnATS(); diff --git a/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java b/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java index d40403ddd..cda34dd8b 100644 --- a/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java +++ b/src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java @@ -86,7 +86,7 @@ public final class CommandUtils { return true; } - PlayerProfile profile = new PlayerProfile(playerName, false); + PlayerProfile profile = new PlayerProfile(playerName, false, 0); if (unloadedProfile(sender, profile)) { return false; diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index 48a1481b7..71f5de649 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -6,14 +6,20 @@ import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.player.UniqueDataType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask; import com.gmail.nossr50.util.skills.SkillTools; import com.google.common.io.Files; +import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; import org.powermock.modules.junit4.PowerMockRunner; import java.io.*; @@ -26,9 +32,10 @@ import static org.junit.Assert.*; //TODO: Test update leaderboards -@RunWith(PowerMockRunner.class) public class FlatFileDatabaseManagerTest { + public mcMMO plugin; + public static final @NotNull String TEST_FILE_NAME = "test.mcmmo.users"; public static final @NotNull String BAD_FILE_LINE_ONE = "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:"; public static final @NotNull String BAD_DATA_FILE_LINE_TWENTY_THREE = "nossr51:baddata:::baddata:baddata:640:baddata:1000:1000:1000:baddata:baddata:baddata:baddata:16:0:500:20273:0:0:0:0::1000:0:0:baddata:1593543012:0:0:0:0::1000:0:0:baddata:IGNORED:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1:0:"; @@ -137,7 +144,7 @@ public class FlatFileDatabaseManagerTest { //Make a Profile to save and check to see if it worked UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); String playerName = "nossr50"; - PlayerProfile testProfile = new PlayerProfile(playerName, uuid); + PlayerProfile testProfile = new PlayerProfile(playerName, uuid, 0); //The above profile should be "zero" initialized //Save the zero version and see if it looks correct @@ -208,6 +215,56 @@ public class FlatFileDatabaseManagerTest { testHealthyDataProfileValues(playerName, uuid, profile); } + @Test + public void testNewUser() { + //We will test that new user values line up with our expectations + UUID uuid = new UUID(0, 1); + String playerName = "nossr50"; + + int newUserTestStartingLvl = 1337; + db = new FlatFileDatabaseManager(new File(tempDir.getPath() + File.separator + TEST_FILE_NAME), logger, PURGE_TIME, newUserTestStartingLvl, true); + db.checkFileHealthAndStructure(); + + PlayerProfile playerProfile = db.newUser(playerName, uuid); + + assertTrue(playerProfile.isLoaded()); + assertEquals(playerName, playerProfile.getPlayerName()); + assertEquals(uuid, playerProfile.getUniqueId()); + + PlayerProfile retrievedFromDisk = db.loadPlayerProfile(uuid); + assertTrue(retrievedFromDisk.isLoaded()); + assertEquals(playerName, retrievedFromDisk.getPlayerName()); + assertEquals(uuid, retrievedFromDisk.getUniqueId()); + + //Checking a new user for being "zero" initialized + checkNewUserValues(playerProfile, newUserTestStartingLvl); + checkNewUserValues(retrievedFromDisk, newUserTestStartingLvl); + + //TODO: Should we do any dupe checking? Probably not needed as it would be caught on the next load + db.newUser("disco", new UUID(3, 3)); + db.newUser("dingus", new UUID(3, 4)); + db.newUser("duped_dingus", new UUID(3, 4)); + } + + private void checkNewUserValues(@NotNull PlayerProfile playerProfile, int startingLevel) { + //Checking a new user for being zero initialized + for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { + if(SkillTools.isChildSkill(primarySkillType)) + continue; + + assertEquals(startingLevel, playerProfile.getSkillLevel(primarySkillType)); + assertEquals(0, playerProfile.getSkillXpLevelRaw(primarySkillType), 0); + } + + for(SuperAbilityType superAbilityType : SuperAbilityType.values()) { + assertEquals(0, playerProfile.getAbilityDATS(superAbilityType)); + } + + assertTrue(playerProfile.getLastLogin() > 0); + assertEquals(playerProfile.getChimaerWingDATS(), 0); + assertEquals(playerProfile.getScoreboardTipsShown(), 0); + } + @Test public void testLoadByUUID() { File dbFile = prepareDatabaseTestResource(DB_HEALTHY); From 22b24b47741b53e6180673122d7aaa4328c7dcec Mon Sep 17 00:00:00 2001 From: nossr50 Date: Tue, 13 Apr 2021 17:25:56 -0700 Subject: [PATCH 26/57] JUnit 5 time --- pom.xml | 54 +++++-- .../database/FlatFileDataProcessor.java | 2 + .../database/FlatFileDatabaseManager.java | 134 +++++++++++------- .../nossr50/database/SQLDatabaseManager.java | 1 - .../database/FlatFileDatabaseManagerTest.java | 99 ++++++++++--- 5 files changed, 202 insertions(+), 88 deletions(-) diff --git a/pom.xml b/pom.xml index 231bd7f4b..38b04da11 100755 --- a/pom.xml +++ b/pom.xml @@ -11,6 +11,11 @@ scm:git:git@github.com:mcMMO-Dev/mcMMO.git HEAD + + + UTF-8 + + https://github.com/mcMMO-Dev/mcMMO/issues GitHub @@ -66,13 +71,12 @@ - org.apache.maven.plugins maven-surefire-plugin - 2.16 - - false - 1 - + 2.22.2 + + + maven-failsafe-plugin + 2.22.2 @@ -219,6 +223,17 @@ + + + + + + + + + + + com.github.seeseemelk @@ -271,6 +286,12 @@ net.kyori adventure-platform-common 4.0.0-SNAPSHOT + + + net.kyori + adventure-nbt + + org.apache.maven.scm @@ -314,9 +335,21 @@ - junit - junit-dep - 4.11 + org.junit.jupiter + junit-jupiter-api + 5.7.1 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.7.1 + test + + + org.junit.vintage + junit-vintage-engine + 5.6.2 test @@ -349,7 +382,4 @@ 19.0.0 - - UTF-8 - diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java index 1b9651089..a232d86cd 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDataProcessor.java @@ -119,6 +119,8 @@ public class FlatFileDataProcessor { if(names.contains(name)) { builder.appendFlag(FlatFileDataFlag.DUPLICATE_NAME); + anyBadData = true; + badDataValues[USERNAME_INDEX] = true; } if(!name.isEmpty()) diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index 8d4f8ea30..b47477651 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -174,6 +174,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { return purgedUsers; } + //TODO: Test this public void purgeOldUsers() { int removedPlayers = 0; long currentTime = System.currentTimeMillis(); @@ -211,7 +212,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - if (currentTime - lastPlayed > purgeTime) { + if (lastPlayed != -1 && lastPlayed != 0 && currentTime - lastPlayed > purgeTime) { removedPlayers++; } else { if (rewrite) { @@ -425,53 +426,53 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - public void writeUserToLine(@NotNull PlayerProfile profile, @NotNull String playerName, @Nullable UUID uuid, @NotNull Appendable writer) throws IOException { - writer.append(playerName).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.MINING))).append(":"); - writer.append(IGNORED).append(":"); - writer.append(IGNORED).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.MINING))).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.WOODCUTTING))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.WOODCUTTING))).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.REPAIR))).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.UNARMED))).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.HERBALISM))).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.EXCAVATION))).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ARCHERY))).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.SWORDS))).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.AXES))).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ACROBATICS))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.REPAIR))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.UNARMED))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.HERBALISM))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.EXCAVATION))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ARCHERY))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.SWORDS))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.AXES))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ACROBATICS))).append(":"); - writer.append(IGNORED).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.TAMING))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.TAMING))).append(":"); - writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.BERSERK))).append(":"); - writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.GIGA_DRILL_BREAKER))).append(":"); - writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.TREE_FELLER))).append(":"); - writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.GREEN_TERRA))).append(":"); - writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SERRATED_STRIKES))).append(":"); - writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SKULL_SPLITTER))).append(":"); - writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SUPER_BREAKER))).append(":"); - writer.append(IGNORED).append(":"); - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.FISHING))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.FISHING))).append(":"); - writer.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.BLAST_MINING))).append(":"); - writer.append(IGNORED).append(":"); //Legacy last login - writer.append(IGNORED).append(":"); //mob health bar - writer.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ALCHEMY))).append(":"); - writer.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ALCHEMY))).append(":"); - writer.append(uuid != null ? uuid.toString() : "NULL").append(":"); - writer.append(String.valueOf(profile.getScoreboardTipsShown())).append(":"); - writer.append(String.valueOf(profile.getUniqueData(UniqueDataType.CHIMAERA_WING_DATS))).append(":"); - writer.append(String.valueOf(profile.getLastLogin())).append(":"); //overhaul last login - writer.append("\r\n"); + public void writeUserToLine(@NotNull PlayerProfile profile, @NotNull String playerName, @Nullable UUID uuid, @NotNull Appendable appendable) throws IOException { + appendable.append(playerName).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.MINING))).append(":"); + appendable.append(IGNORED).append(":"); + appendable.append(IGNORED).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.MINING))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.WOODCUTTING))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.WOODCUTTING))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.REPAIR))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.UNARMED))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.HERBALISM))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.EXCAVATION))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ARCHERY))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.SWORDS))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.AXES))).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ACROBATICS))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.REPAIR))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.UNARMED))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.HERBALISM))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.EXCAVATION))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ARCHERY))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.SWORDS))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.AXES))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ACROBATICS))).append(":"); + appendable.append(IGNORED).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.TAMING))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.TAMING))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.BERSERK))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.GIGA_DRILL_BREAKER))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.TREE_FELLER))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.GREEN_TERRA))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SERRATED_STRIKES))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SKULL_SPLITTER))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.SUPER_BREAKER))).append(":"); + appendable.append(IGNORED).append(":"); + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.FISHING))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.FISHING))).append(":"); + appendable.append(String.valueOf(profile.getAbilityDATS(SuperAbilityType.BLAST_MINING))).append(":"); + appendable.append(IGNORED).append(":"); //Legacy last login + appendable.append(IGNORED).append(":"); //mob health bar + appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ALCHEMY))).append(":"); + appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ALCHEMY))).append(":"); + appendable.append(uuid != null ? uuid.toString() : "NULL").append(":"); + appendable.append(String.valueOf(profile.getScoreboardTipsShown())).append(":"); + appendable.append(String.valueOf(profile.getUniqueData(UniqueDataType.CHIMAERA_WING_DATS))).append(":"); + appendable.append(String.valueOf(profile.getLastLogin())).append(":"); //overhaul last login + appendable.append("\r\n"); } public @NotNull List readLeaderboard(@Nullable PrimarySkillType primarySkillType, int pageNumber, int statsPerPage) throws InvalidSkillException { @@ -510,9 +511,23 @@ public final class FlatFileDatabaseManager implements DatabaseManager { PlayerProfile playerProfile = new PlayerProfile(playerName, uuid, true, startingLevel); synchronized (fileWritingLock) { - try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(usersFilePath, true))) { - writeUserToLine(playerProfile, playerName, uuid, bufferedWriter); - } catch (Exception e) { + try(BufferedReader bufferedReader = new BufferedReader(new FileReader(usersFilePath))) { + StringBuilder stringBuilder = new StringBuilder(); + + String line; + + //Build up the file + while((line = bufferedReader.readLine()) != null) { + stringBuilder.append(line).append("\r\n"); + } + + try (FileWriter fileWriter = new FileWriter(usersFile)) { + writeUserToLine(playerProfile, playerName, uuid, stringBuilder); + fileWriter.write(stringBuilder.toString()); + } catch (Exception e) { + e.printStackTrace(); + } + } catch (IOException e) { e.printStackTrace(); } } @@ -536,7 +551,17 @@ public final class FlatFileDatabaseManager implements DatabaseManager { return loadPlayerByUUID(uuid, null, false); } - private @NotNull PlayerProfile loadPlayerByUUID(@NotNull UUID uuid, @Nullable String playerName, boolean isOnline) { + /** + * Find and load a player by UUID + * + * @param uuid target uuid + * @param playerName target player name + * @param replaceName name to replace if the found name differs + * @return a profile with the targets data or an unloaded profile if no data was found + * @deprecated only use this if you know what you are doing, replacing the name can cause havoc + */ + @Deprecated + public @NotNull PlayerProfile loadPlayerByUUID(@NotNull UUID uuid, @Nullable String playerName, boolean replaceName) { BufferedReader in = null; synchronized (fileWritingLock) { @@ -574,7 +599,8 @@ public final class FlatFileDatabaseManager implements DatabaseManager { /* Check for nickname changes and update since we are here anyways */ if(playerName != null) { - if(isOnline) { + if(replaceName) { + logger.info("A users name is being updated, this can happen from either a call to our API or they simply changed their name"); if (!rawSplitData[USERNAME_INDEX].equalsIgnoreCase(playerName)) { //logger.info("Name updated for player: " + rawSplitData[USERNAME_INDEX] + " => " + playerName); rawSplitData[USERNAME_INDEX] = playerName; @@ -1162,7 +1188,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { lastLogin = -1; } - return new PlayerProfile(character[USERNAME_INDEX], uuid, skills, skillsXp, skillsDATS, scoreboardTipsShown, uniquePlayerDataMap, lastLogin); + return new PlayerProfile(username, uuid, skills, skillsXp, skillsDATS, scoreboardTipsShown, uniquePlayerDataMap, lastLogin); } private void tryLoadSkillCooldownFromRawData(@NotNull Map cooldownMap, @NotNull String[] character, @NotNull SuperAbilityType superAbilityType, int cooldownSuperBreaker, @NotNull String userName) { diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index 01c14ed16..a937efb0b 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.database; import com.gmail.nossr50.api.exceptions.InvalidSkillException; -import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.datatypes.MobHealthbarType; import com.gmail.nossr50.datatypes.database.DatabaseType; import com.gmail.nossr50.datatypes.database.PlayerStat; diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index 71f5de649..d9cd5051d 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -6,36 +6,28 @@ import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.player.UniqueDataType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.runnables.player.PlayerProfileLoadingTask; import com.gmail.nossr50.util.skills.SkillTools; import com.google.common.io.Files; -import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor; -import org.powermock.modules.junit4.PowerMockRunner; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.*; import java.net.URI; import java.net.URISyntaxException; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; import java.util.logging.Logger; -import static org.junit.Assert.*; - +import static org.junit.jupiter.api.Assertions.*; //TODO: Test update leaderboards +//This class uses JUnit5/Jupiter public class FlatFileDatabaseManagerTest { - public mcMMO plugin; - public static final @NotNull String TEST_FILE_NAME = "test.mcmmo.users"; public static final @NotNull String BAD_FILE_LINE_ONE = "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:1138:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:"; public static final @NotNull String BAD_DATA_FILE_LINE_TWENTY_THREE = "nossr51:baddata:::baddata:baddata:640:baddata:1000:1000:1000:baddata:baddata:baddata:baddata:16:0:500:20273:0:0:0:0::1000:0:0:baddata:1593543012:0:0:0:0::1000:0:0:baddata:IGNORED:1000:0:588fe472-1c82-4c4e-9aa1-7eefccb277e3:1:0:"; @@ -68,7 +60,7 @@ public class FlatFileDatabaseManagerTest { int expectedScoreboardTips = 1111; Long expectedLastLogin = 2020L; - @Before + @BeforeEach public void init() { assertNull(db); //noinspection UnstableApiUsage @@ -76,7 +68,7 @@ public class FlatFileDatabaseManagerTest { db = new FlatFileDatabaseManager(new File(tempDir.getPath() + File.separator + TEST_FILE_NAME), logger, PURGE_TIME, 0, true); } - @After + @AfterEach public void tearDown() { TestUtil.recursiveDelete(tempDir); db = null; @@ -184,7 +176,6 @@ public class FlatFileDatabaseManagerTest { assertEquals(-1, (long) profile.getLastLogin()); } - @Test public void testLoadByName() { File healthyDB = prepareDatabaseTestResource(DB_HEALTHY); @@ -244,6 +235,47 @@ public class FlatFileDatabaseManagerTest { db.newUser("disco", new UUID(3, 3)); db.newUser("dingus", new UUID(3, 4)); db.newUser("duped_dingus", new UUID(3, 4)); + + assertEquals(5, getSplitDataFromFile(db.getUsersFile()).size()); + } + + @Test + public void testAddingUsersToEndOfExistingDB() { + //We will test that new user values line up with our expectations + UUID uuid = new UUID(0, 80); + String playerName = "the_kitty_man"; + + File file = prepareDatabaseTestResource(DB_HEALTHY); //Existing DB + + int newUserTestStartingLvl = 1337; + db = new FlatFileDatabaseManager(file, logger, PURGE_TIME, newUserTestStartingLvl, true); + db.checkFileHealthAndStructure(); + + PlayerProfile playerProfile = db.newUser(playerName, uuid); + + assertTrue(playerProfile.isLoaded()); + assertEquals(playerName, playerProfile.getPlayerName()); + assertEquals(uuid, playerProfile.getUniqueId()); + + PlayerProfile retrievedFromDisk = db.loadPlayerProfile(uuid, playerName); + assertTrue(retrievedFromDisk.isLoaded()); + assertEquals(playerName, retrievedFromDisk.getPlayerName()); + assertEquals(uuid, retrievedFromDisk.getUniqueId()); + + //Checking a new user for being "zero" initialized + checkNewUserValues(playerProfile, newUserTestStartingLvl); + checkNewUserValues(retrievedFromDisk, newUserTestStartingLvl); + + //TODO: Should we do any dupe checking? Probably not needed as it would be caught on the next load + db.newUser("bidoof", new UUID(3, 3)); + db.newUser("derp", new UUID(3, 4)); + db.newUser("pizza", new UUID(3, 4)); + + assertEquals(7, getSplitDataFromFile(db.getUsersFile()).size()); + + //Now we *fix* the DB and there should be one less + db.checkFileHealthAndStructure(); + assertEquals(6, getSplitDataFromFile(db.getUsersFile()).size()); } private void checkNewUserValues(@NotNull PlayerProfile playerProfile, int startingLevel) { @@ -466,7 +498,32 @@ public class FlatFileDatabaseManagerTest { @Test public void testOverwriteName() { + overwriteDataAndCheckForFlag(db, duplicateNameDatabaseData, FlatFileDataFlag.DUPLICATE_NAME); + ArrayList splitDataLines = getSplitDataFromFile(db.getUsersFile()); + assertNotEquals(splitDataLines.get(1)[0], splitDataLines.get(0)[0]); //Name comparison + } + @Test + public void testUpdateName() { + //TODO: The code in this test didn't actually trigger the save, so I'll have to do something else to test saving +// UUID uuid = UUID.fromString(HEALTHY_DB_LINE_ONE_UUID_STR); //Entrant "nossr50" +// String playerName = "the_new_name_man"; +// +// File file = prepareDatabaseTestResource(DB_HEALTHY); //Existing DB +// db = new FlatFileDatabaseManager(file, logger, PURGE_TIME, 0, true); +// db.checkFileHealthAndStructure(); +// ArrayList splitDataLines = getSplitDataFromFile(db.getUsersFile()); +// String oldName = "nossr50"; +// assertEquals(oldName, splitDataLines.get(0)[0]); //Name comparison +// assertEquals(uuid.toString(), splitDataLines.get(0)[FlatFileDatabaseManager.UUID_INDEX]); //UUID Comparison +// +// //Now we load the player and their name should get replaced +// PlayerProfile profile = db.loadPlayerByUUID(uuid, playerName, true); +// assertEquals(playerName, profile.getPlayerName()); +// +// splitDataLines = getSplitDataFromFile(db.getUsersFile()); //Load the file again +// assertNotEquals(oldName, splitDataLines.get(0)[0]); //Name comparison +// assertEquals(playerName, splitDataLines.get(0)[0]); //Name comparison } @Test @@ -573,9 +630,9 @@ public class FlatFileDatabaseManagerTest { //This makes sure our private method is working before the tests run afterwards ArrayList dataFromFile = getSplitDataFromFile(copyOfFile); System.out.println("File Path: "+copyOfFile.getAbsolutePath()); - assertEquals(BAD_FILE_LINE_ONE.split(":"), dataFromFile.get(0)); + assertArrayEquals(BAD_FILE_LINE_ONE.split(":"), dataFromFile.get(0)); assertEquals(dataFromFile.get(22)[0], "nossr51"); - assertEquals(BAD_DATA_FILE_LINE_TWENTY_THREE.split(":"), dataFromFile.get(22)); + assertArrayEquals(BAD_DATA_FILE_LINE_TWENTY_THREE.split(":"), dataFromFile.get(22)); FlatFileDatabaseManager db_a = new FlatFileDatabaseManager(copyOfFile, logger, PURGE_TIME, 0, true); List flagsFound = db_a.checkFileHealthAndStructure(); From 700a7f4d35869dd4fe29d236ae33c22aef9e8a97 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Wed, 14 Apr 2021 15:50:13 -0700 Subject: [PATCH 27/57] Fix ArrayIndexOutOfBounds for certain events due to spigot API bug Fixes #4488 --- Changelog.txt | 5 +- .../nossr50/listeners/BlockListener.java | 31 +- .../java/com/gmail/nossr50/util/Misc.java | 6 - .../util/blockmeta/BitSetChunkStore.java | 8 +- .../util/compat/CompatibilityLayer.java | 2 +- .../util/compat/CompatibilityManager.java | 39 ++ .../layers/world/WorldCompatibilityLayer.java | 11 + .../world/WorldCompatibilityLayer_1_16_4.java | 16 + .../util/blockmeta/ChunkStoreTest.java | 339 +++++++++++++++++- 9 files changed, 429 insertions(+), 28 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/util/compat/layers/world/WorldCompatibilityLayer.java create mode 100644 src/main/java/com/gmail/nossr50/util/compat/layers/world/WorldCompatibilityLayer_1_16_4.java diff --git a/Changelog.txt b/Changelog.txt index 8a704c845..d8c941814 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,5 +1,6 @@ Version 2.1.189 FlatFileDB now stores the last login of users again (was completely non functional for a while) + mcMMO will once again purge old users if the config option is on (see notes) Newly created flat file databases (mcmmo.users file) will have a comment line at the top noting the date the database was created Fixed a bug where FlatFileDatabase users could have their names saved as "null" (names will be fixed the next time the player logs in) Rewrote how FlatFileDatabase verifies data integrity @@ -24,7 +25,9 @@ Version 2.1.189 (API) Some members of PrimarySkillType were removed and not deprecated (such as the field constants) NOTES: - I spent over 20 hours refactoring FlatFileDB and writing unit tests for it, this will ensure that any changes in the code that could break the database are caught + Regarding purging old users on the FlatFileDB, since this wasn't functioning for a while, the last login of users has been reset and if mcMMO hasn't seen that user since this update, it won't purge them as it has no way to know if they are truly an old user + I'm likely going to add SQLite DB as an option in the future, I spent time to fix up the FlatFileDB as some Unit Testing practice. + I spent over 26 hours refactoring FlatFileDB and writing unit tests for it, this will ensure that any changes in the code that could break the database are caught Ultra Permissions is SAFE to use with mcMMO After getting in contact with the UltraPermissions devs and exhaustive testing, I have concluded that using UltraPermissions is completely safe with mcMMO. The users who had an issue with performance currently have an unknown cause, potentially it is from a plugin using the UltraPermissions API I really can't say without more data. My apologies to the UltraPermissions team for reporting an issue between our two plugins directly, as that is not the case. I would have tested it myself sooner but UltraPermissions was closed source and premium so I wasn't particularly motivated to do so, however I have been given access to the binaries so now I can do all the testing I want if future issues ever arise which I have zero expectations that they will. diff --git a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java index 4ac4cec47..06c3a7c2e 100644 --- a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java @@ -20,6 +20,7 @@ import com.gmail.nossr50.skills.repair.Repair; import com.gmail.nossr50.skills.salvage.Salvage; import com.gmail.nossr50.skills.woodcutting.WoodcuttingManager; import com.gmail.nossr50.util.*; +import com.gmail.nossr50.util.compat.layers.world.WorldCompatibilityLayer; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.SkillUtils; import com.gmail.nossr50.util.sounds.SoundManager; @@ -147,13 +148,21 @@ public class BlockListener implements Listener { // Get opposite direction so we get correct block BlockFace direction = event.getDirection(); Block movedBlock = event.getBlock().getRelative(direction); - if (movedBlock.getY() >= Misc.getWorldMinCompat(movedBlock.getWorld())) // Very weird that the event is giving us these, they shouldn't exist + + WorldCompatibilityLayer worldCompatibilityLayer = mcMMO.getCompatibilityManager().getWorldCompatibilityLayer(); + + World world = movedBlock.getWorld(); + + //Spigot makes bad things happen in its API + if(event.getBlock().getY() < worldCompatibilityLayer.getMaxWorldHeight(world) || event.getBlock().getY() >= worldCompatibilityLayer.getMinWorldHeight(world)) { mcMMO.getPlaceStore().setTrue(movedBlock); + } for (Block block : event.getBlocks()) { - movedBlock = block.getRelative(direction); - if (movedBlock.getY() < Misc.getWorldMinCompat(movedBlock.getWorld())) // Very weird that the event is giving us these, they shouldn't exist - continue; + if(block.getY() < worldCompatibilityLayer.getMaxWorldHeight(world) || block.getY() >= worldCompatibilityLayer.getMinWorldHeight(world)) { + mcMMO.getPlaceStore().setTrue(block.getRelative(direction)); + } + mcMMO.getPlaceStore().setTrue(movedBlock); } } @@ -185,13 +194,21 @@ public class BlockListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockFormEvent(BlockFormEvent event) { - /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) - return; + World world = event.getBlock().getWorld(); + /* WORLD BLACKLIST CHECK */ { + if(WorldBlacklist.isWorldBlacklisted(world)) + return; + } BlockState newState = event.getNewState(); if(ExperienceConfig.getInstance().preventStoneLavaFarming()) { + WorldCompatibilityLayer worldCompatibilityLayer = mcMMO.getCompatibilityManager().getWorldCompatibilityLayer(); + + if(event.getBlock().getY() > worldCompatibilityLayer.getMaxWorldHeight(world) || event.getBlock().getY() < worldCompatibilityLayer.getMinWorldHeight(world)) { + return; + } + if(newState.getType() != Material.OBSIDIAN && ExperienceConfig.getInstance().doesBlockGiveSkillXP(PrimarySkillType.MINING, newState.getBlockData())) { mcMMO.getPlaceStore().setTrue(newState); diff --git a/src/main/java/com/gmail/nossr50/util/Misc.java b/src/main/java/com/gmail/nossr50/util/Misc.java index 5f19031d6..bd5058856 100644 --- a/src/main/java/com/gmail/nossr50/util/Misc.java +++ b/src/main/java/com/gmail/nossr50/util/Misc.java @@ -260,12 +260,6 @@ public final class Misc { } } - public static int getWorldMinCompat(World world) - { - // TODO this method should access the world min variable in a version safe manner so that we don't restrict usage to new versions of spigot only - return 0; - } - public static void printProgress(int convertedUsers, int progressInterval, long startMillis) { if ((convertedUsers % progressInterval) == 0) { mcMMO.p.getLogger().info(String.format("Conversion progress: %d users at %.2f users/second", convertedUsers, convertedUsers / (double) ((System.currentTimeMillis() - startMillis) / TIME_CONVERSION_FACTOR))); diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/BitSetChunkStore.java b/src/main/java/com/gmail/nossr50/util/blockmeta/BitSetChunkStore.java index 4830c9045..ef5dc5459 100644 --- a/src/main/java/com/gmail/nossr50/util/blockmeta/BitSetChunkStore.java +++ b/src/main/java/com/gmail/nossr50/util/blockmeta/BitSetChunkStore.java @@ -1,5 +1,6 @@ package com.gmail.nossr50.util.blockmeta; +import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; import org.bukkit.Bukkit; import org.bukkit.World; @@ -25,7 +26,7 @@ public class BitSetChunkStore implements ChunkStore { private transient boolean dirty = false; public BitSetChunkStore(@NotNull World world, int cx, int cz) { - this(world.getUID(), Misc.getWorldMinCompat(world), world.getMaxHeight(), cx, cz); + this(world.getUID(), mcMMO.getCompatibilityManager().getWorldCompatibilityLayer().getMinWorldHeight(world), world.getMaxHeight(), cx, cz); } private BitSetChunkStore(@NotNull UUID worldUid, int worldMin, int worldMax, int cx, int cz) { @@ -109,15 +110,14 @@ public class BitSetChunkStore implements ChunkStore { return (z * 16 + x) + (256 * (y + yOffset)); } - private static int getWorldMin(@NotNull UUID worldUid, int storedWorldMin) - { + private static int getWorldMin(@NotNull UUID worldUid, int storedWorldMin) { World world = Bukkit.getWorld(worldUid); // Not sure how this case could come up, but might as well handle it gracefully. Loading a chunkstore for an unloaded world? if (world == null) return storedWorldMin; - return Misc.getWorldMinCompat(world); + return mcMMO.getCompatibilityManager().getWorldCompatibilityLayer().getMinWorldHeight(world); } private static int getWorldMax(@NotNull UUID worldUid, int storedWorldMax) diff --git a/src/main/java/com/gmail/nossr50/util/compat/CompatibilityLayer.java b/src/main/java/com/gmail/nossr50/util/compat/CompatibilityLayer.java index d09c52f99..51b240338 100644 --- a/src/main/java/com/gmail/nossr50/util/compat/CompatibilityLayer.java +++ b/src/main/java/com/gmail/nossr50/util/compat/CompatibilityLayer.java @@ -8,5 +8,5 @@ public interface CompatibilityLayer { * Whether or not this CompatibilityLayer successfully initialized and in theory should be functional * @return true if this CompatibilityLayer is functional */ - boolean noErrorsOnInitialize(); + default boolean noErrorsOnInitialize() { return true; }; } diff --git a/src/main/java/com/gmail/nossr50/util/compat/CompatibilityManager.java b/src/main/java/com/gmail/nossr50/util/compat/CompatibilityManager.java index 7a0a0e72a..6f34d3a89 100644 --- a/src/main/java/com/gmail/nossr50/util/compat/CompatibilityManager.java +++ b/src/main/java/com/gmail/nossr50/util/compat/CompatibilityManager.java @@ -10,9 +10,12 @@ import com.gmail.nossr50.util.compat.layers.persistentdata.SpigotPersistentDataL import com.gmail.nossr50.util.compat.layers.persistentdata.SpigotPersistentDataLayer_1_14; import com.gmail.nossr50.util.compat.layers.skills.AbstractMasterAnglerCompatibility; import com.gmail.nossr50.util.compat.layers.skills.MasterAnglerCompatibilityLayer; +import com.gmail.nossr50.util.compat.layers.world.WorldCompatibilityLayer; +import com.gmail.nossr50.util.compat.layers.world.WorldCompatibilityLayer_1_16_4; import com.gmail.nossr50.util.nms.NMSVersion; import com.gmail.nossr50.util.platform.MinecraftGameVersion; import com.gmail.nossr50.util.text.StringUtils; +import org.bukkit.World; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -37,6 +40,7 @@ public class CompatibilityManager { private AbstractPersistentDataLayer persistentDataLayer; private AbstractBungeeSerializerCompatibilityLayer bungeeSerializerCompatibilityLayer; private AbstractMasterAnglerCompatibility masterAnglerCompatibility; + private WorldCompatibilityLayer worldCompatibilityLayer; public CompatibilityManager(MinecraftGameVersion minecraftGameVersion) { mcMMO.p.getLogger().info("Loading compatibility layers..."); @@ -67,10 +71,31 @@ public class CompatibilityManager { initPersistentDataLayer(); initBungeeSerializerLayer(); initMasterAnglerLayer(); + initWorldCompatibilityLayer(); isFullyCompatibleServerSoftware = true; } + private void initWorldCompatibilityLayer() { + if(minecraftGameVersion.getMinorVersion().asInt() >= 16 && minecraftGameVersion.getPatchVersion().asInt() >= 4 || minecraftGameVersion.getMajorVersion().asInt() >= 2) { + if(hasNewWorldMinHeightAPI()) { + worldCompatibilityLayer = new WorldCompatibilityLayer_1_16_4(); + } + } else { + worldCompatibilityLayer = new WorldCompatibilityLayer() { + @Override + public int getMinWorldHeight(@NotNull World world) { + return WorldCompatibilityLayer.super.getMinWorldHeight(world); + } + + @Override + public int getMaxWorldHeight(@NotNull World world) { + return WorldCompatibilityLayer.super.getMaxWorldHeight(world); + } + }; + } + } + private void initMasterAnglerLayer() { if(minecraftGameVersion.getMinorVersion().asInt() >= 16 || minecraftGameVersion.getMajorVersion().asInt() >= 2) { if(hasNewFishingHookAPI()) { @@ -81,6 +106,16 @@ public class CompatibilityManager { } } + private boolean hasNewWorldMinHeightAPI() { + try { + Class checkForClass = Class.forName("org.bukkit.World"); + checkForClass.getMethod("getMinHeight"); + return true; + } catch (ClassNotFoundException | NoSuchMethodException e) { + return false; + } + } + private boolean hasNewFishingHookAPI() { try { Class checkForClass = Class.forName("org.bukkit.entity.FishHook"); @@ -182,4 +217,8 @@ public class CompatibilityManager { public @Nullable AbstractMasterAnglerCompatibility getMasterAnglerCompatibilityLayer() { return masterAnglerCompatibility; } + + public @NotNull WorldCompatibilityLayer getWorldCompatibilityLayer() { + return worldCompatibilityLayer; + } } diff --git a/src/main/java/com/gmail/nossr50/util/compat/layers/world/WorldCompatibilityLayer.java b/src/main/java/com/gmail/nossr50/util/compat/layers/world/WorldCompatibilityLayer.java new file mode 100644 index 000000000..a8f970987 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/compat/layers/world/WorldCompatibilityLayer.java @@ -0,0 +1,11 @@ +package com.gmail.nossr50.util.compat.layers.world; + +import com.gmail.nossr50.util.compat.CompatibilityLayer; +import org.bukkit.World; +import org.jetbrains.annotations.NotNull; + +public interface WorldCompatibilityLayer extends CompatibilityLayer { + default int getMinWorldHeight(@NotNull World world) { return 0; } + + default int getMaxWorldHeight(@NotNull World world) { return 255; } +} diff --git a/src/main/java/com/gmail/nossr50/util/compat/layers/world/WorldCompatibilityLayer_1_16_4.java b/src/main/java/com/gmail/nossr50/util/compat/layers/world/WorldCompatibilityLayer_1_16_4.java new file mode 100644 index 000000000..4e67aaf5c --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/compat/layers/world/WorldCompatibilityLayer_1_16_4.java @@ -0,0 +1,16 @@ +package com.gmail.nossr50.util.compat.layers.world; + +import org.bukkit.World; +import org.jetbrains.annotations.NotNull; + +public class WorldCompatibilityLayer_1_16_4 implements WorldCompatibilityLayer { + @Override + public int getMinWorldHeight(@NotNull World world) { + return world.getMinHeight(); + } + + @Override + public int getMaxWorldHeight(@NotNull World world) { + return world.getMaxHeight(); + } +} diff --git a/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java b/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java index 99e61dbe5..0812f9142 100644 --- a/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java +++ b/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java @@ -1,20 +1,34 @@ package com.gmail.nossr50.util.blockmeta; import com.gmail.nossr50.TestUtil; -import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.compat.CompatibilityManager; +import com.gmail.nossr50.util.compat.layers.world.WorldCompatibilityLayer; +import com.gmail.nossr50.util.platform.PlatformManager; import com.google.common.io.Files; -import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.block.Block; +import org.bukkit.*; +import org.bukkit.block.*; +import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Entity; +import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.MetadataValue; +import org.bukkit.plugin.Plugin; +import org.bukkit.util.BoundingBox; +import org.bukkit.util.RayTraceResult; +import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.junit.*; import org.junit.runner.RunWith; import org.mockito.Mockito; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; import java.io.*; +import java.util.Collection; +import java.util.List; import java.util.UUID; import static org.mockito.Mockito.mock; @@ -23,7 +37,7 @@ import static org.mockito.Mockito.mock; * Could be a lot better. But some tests are better than none! Tests the major things, still kinda unit-testy. Verifies that the serialization isn't completely broken. */ @RunWith(PowerMockRunner.class) -@PrepareForTest({ Bukkit.class, Misc.class }) +@PrepareForTest({ Bukkit.class, mcMMO.class}) public class ChunkStoreTest { private static File tempDir; @BeforeClass @@ -37,6 +51,10 @@ public class ChunkStoreTest { } private World mockWorld; + private CompatibilityManager compatibilityManager; + private WorldCompatibilityLayer worldCompatibilityLayer; + private PlatformManager platformManager; + @Before public void setUpMock(){ UUID worldUUID = UUID.randomUUID(); @@ -46,6 +64,39 @@ public class ChunkStoreTest { Mockito.when(mockWorld.getWorldFolder()).thenReturn(tempDir); PowerMockito.mockStatic(Bukkit.class); Mockito.when(Bukkit.getWorld(worldUUID)).thenReturn(mockWorld); + + platformManager = mock(PlatformManager.class); + compatibilityManager = mock(CompatibilityManager.class); + worldCompatibilityLayer = mock(WorldCompatibilityLayer.class); + + Whitebox.setInternalState(mcMMO.class, "platformManager", platformManager); + Mockito.when(mcMMO.getCompatibilityManager()).thenReturn(compatibilityManager); + + Assert.assertNotNull(mcMMO.getCompatibilityManager()); + Mockito.when(platformManager.getCompatibilityManager()).thenReturn(compatibilityManager); + Mockito.when(platformManager.getCompatibilityManager().getWorldCompatibilityLayer()).thenReturn(worldCompatibilityLayer); + Assert.assertNotNull(mcMMO.getCompatibilityManager().getWorldCompatibilityLayer()); + Mockito.when(worldCompatibilityLayer.getMinWorldHeight(mockWorld)).thenReturn(0); + Mockito.when(worldCompatibilityLayer.getMaxWorldHeight(mockWorld)).thenReturn(255); + } + + @Test + public void testSetTrue() { + Mockito.when(mcMMO.getCompatibilityManager().getWorldCompatibilityLayer().getMinWorldHeight(mockWorld)).thenReturn(-64); + HashChunkManager hashChunkManager = new HashChunkManager(); + int radius = 2; //Could be anything but drastically changes test time + + for(int x = -radius; x < radius; x++) { + for(int y = mockWorld.getMinHeight(); y < mockWorld.getMaxHeight(); y++) { + for(int z = -radius; z < radius; z++) { + TestBlock testBlock = new TestBlock(x, y, z, mockWorld); + hashChunkManager.setTrue(testBlock); + Assert.assertTrue(hashChunkManager.isTrue(testBlock)); + hashChunkManager.setFalse(testBlock); + Assert.assertFalse(hashChunkManager.isTrue(testBlock)); + } + } + } } @Test @@ -79,8 +130,7 @@ public class ChunkStoreTest { @Test public void testNegativeWorldMin() throws IOException { - PowerMockito.mockStatic(Misc.class); - Mockito.when(Misc.getWorldMinCompat(mockWorld)).thenReturn(-64); + Mockito.when(mcMMO.getCompatibilityManager().getWorldCompatibilityLayer().getMinWorldHeight(mockWorld)).thenReturn(-64); BitSetChunkStore original = new BitSetChunkStore(mockWorld, 1, 2); original.setTrue(14, -32, 12); @@ -99,8 +149,7 @@ public class ChunkStoreTest { original.setTrue(13, 3, 12); byte[] serializedBytes = serializeChunkstore(original); - PowerMockito.mockStatic(Misc.class); - Mockito.when(Misc.getWorldMinCompat(mockWorld)).thenReturn(-64); + Mockito.when(mcMMO.getCompatibilityManager().getWorldCompatibilityLayer().getMinWorldHeight(mockWorld)).thenReturn(-64); ChunkStore deserialized = BitSetChunkStore.Serialization.readChunkStore(new DataInputStream(new ByteArrayInputStream(serializedBytes))); assertEqualIgnoreMinMax(original, deserialized); } @@ -360,4 +409,276 @@ public class ChunkStoreTest { super.writeUTF(str); } } + + private class TestBlock implements Block { + + private final int x, y, z; + private final @NotNull World world; + + private TestBlock(int x, int y, int z, World world) { + this.x = x; + this.y = y; + this.z = z; + this.world = world; + } + + @Override + public byte getData() { + return 0; + } + + @NotNull + @Override + public BlockData getBlockData() { + return null; + } + + @NotNull + @Override + public Block getRelative(int modX, int modY, int modZ) { + return null; + } + + @NotNull + @Override + public Block getRelative(@NotNull BlockFace face) { + return null; + } + + @NotNull + @Override + public Block getRelative(@NotNull BlockFace face, int distance) { + return null; + } + + @NotNull + @Override + public Material getType() { + return null; + } + + @Override + public byte getLightLevel() { + return 0; + } + + @Override + public byte getLightFromSky() { + return 0; + } + + @Override + public byte getLightFromBlocks() { + return 0; + } + + @NotNull + @Override + public World getWorld() { + return world; + } + + @Override + public int getX() { + return x; + } + + @Override + public int getY() { + return y; + } + + @Override + public int getZ() { + return z; + } + + @NotNull + @Override + public Location getLocation() { + return null; + } + + @Nullable + @Override + public Location getLocation(@Nullable Location loc) { + return null; + } + + @NotNull + @Override + public Chunk getChunk() { + return null; + } + + @Override + public void setBlockData(@NotNull BlockData data) { + + } + + @Override + public void setBlockData(@NotNull BlockData data, boolean applyPhysics) { + + } + + @Override + public void setType(@NotNull Material type) { + + } + + @Override + public void setType(@NotNull Material type, boolean applyPhysics) { + + } + + @Nullable + @Override + public BlockFace getFace(@NotNull Block block) { + return null; + } + + @NotNull + @Override + public BlockState getState() { + return null; + } + + @NotNull + @Override + public Biome getBiome() { + return null; + } + + @Override + public void setBiome(@NotNull Biome bio) { + + } + + @Override + public boolean isBlockPowered() { + return false; + } + + @Override + public boolean isBlockIndirectlyPowered() { + return false; + } + + @Override + public boolean isBlockFacePowered(@NotNull BlockFace face) { + return false; + } + + @Override + public boolean isBlockFaceIndirectlyPowered(@NotNull BlockFace face) { + return false; + } + + @Override + public int getBlockPower(@NotNull BlockFace face) { + return 0; + } + + @Override + public int getBlockPower() { + return 0; + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public boolean isLiquid() { + return false; + } + + @Override + public double getTemperature() { + return 0; + } + + @Override + public double getHumidity() { + return 0; + } + + @NotNull + @Override + public PistonMoveReaction getPistonMoveReaction() { + return null; + } + + @Override + public boolean breakNaturally() { + return false; + } + + @Override + public boolean breakNaturally(@Nullable ItemStack tool) { + return false; + } + + @Override + public boolean applyBoneMeal(@NotNull BlockFace face) { + return false; + } + + @NotNull + @Override + public Collection getDrops() { + return null; + } + + @NotNull + @Override + public Collection getDrops(@Nullable ItemStack tool) { + return null; + } + + @NotNull + @Override + public Collection getDrops(@NotNull ItemStack tool, @Nullable Entity entity) { + return null; + } + + @Override + public boolean isPassable() { + return false; + } + + @Nullable + @Override + public RayTraceResult rayTrace(@NotNull Location start, @NotNull Vector direction, double maxDistance, @NotNull FluidCollisionMode fluidCollisionMode) { + return null; + } + + @NotNull + @Override + public BoundingBox getBoundingBox() { + return null; + } + + @Override + public void setMetadata(@NotNull String metadataKey, @NotNull MetadataValue newMetadataValue) { + + } + + @NotNull + @Override + public List getMetadata(@NotNull String metadataKey) { + return null; + } + + @Override + public boolean hasMetadata(@NotNull String metadataKey) { + return false; + } + + @Override + public void removeMetadata(@NotNull String metadataKey, @NotNull Plugin owningPlugin) { + + } + } } From bb57e6d464fe9ed11c07d178779ed379f42540d3 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Wed, 14 Apr 2021 16:38:19 -0700 Subject: [PATCH 28/57] actually a radius now.. although not really --- .../java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java b/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java index 0812f9142..bafb3f01b 100644 --- a/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java +++ b/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java @@ -86,9 +86,9 @@ public class ChunkStoreTest { HashChunkManager hashChunkManager = new HashChunkManager(); int radius = 2; //Could be anything but drastically changes test time - for(int x = -radius; x < radius; x++) { + for(int x = -radius; x <= radius; x++) { for(int y = mockWorld.getMinHeight(); y < mockWorld.getMaxHeight(); y++) { - for(int z = -radius; z < radius; z++) { + for(int z = -radius; z <= radius; z++) { TestBlock testBlock = new TestBlock(x, y, z, mockWorld); hashChunkManager.setTrue(testBlock); Assert.assertTrue(hashChunkManager.isTrue(testBlock)); From 729a91443aef9de6302067edf3aa8861650fa774 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Wed, 14 Apr 2021 16:48:48 -0700 Subject: [PATCH 29/57] 2.1.189 --- Changelog.txt | 25 ++++++++++++------------- pom.xml | 2 +- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index d8c941814..3fa51b47b 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,14 +1,18 @@ Version 2.1.189 - FlatFileDB now stores the last login of users again (was completely non functional for a while) - mcMMO will once again purge old users if the config option is on (see notes) - Newly created flat file databases (mcmmo.users file) will have a comment line at the top noting the date the database was created - Fixed a bug where FlatFileDatabase users could have their names saved as "null" (names will be fixed the next time the player logs in) Rewrote how FlatFileDatabase verifies data integrity + FlatFileDatabase has much better data validation and will repair broken/invalid data much better + Fixed a bug where FlatFileDatabase users could have their names saved as "null" (names will be fixed the next time the player logs in) + Added 20~ unit tests for FlatFileDatabaseManager (see notes) + FlatFileDB now stores the last login of users again (was completely non functional for a while) + Newly created flat file databases (mcmmo.users file) will have a comment line at the top noting the date the database was created + Minor performance optimizations to FlatFile database + mcMMO will once again purge old users if the config option is on (see notes) (API) Added com.gmail.nossr50.database.DatabaseManager.loadPlayerProfile(org.bukkit.OfflinePlayer) (API) Deprecated com.gmail.nossr50.database.DatabaseManager.loadPlayerProfile(java.util.UUID, java.lang.String) (API) Removed com.gmail.nossr50.database.DatabaseManager.newUser(java.lang.String, java.util.UUID) - (API) Added - Added unit tests for FlatFileDatabaseManager (see notes) + (API) PrimarySkillType will soon be just an enum with nothing special going on + (API) Deprecated the members of PrimarySkillType use mcMMO::getSkillTools instead, deprecated members will be removed in Tridents & Crossbows (due soon) + (API) Some members of PrimarySkillType were removed and not deprecated (such as the field constants) Fixed a bug where FlatFileDatabaseManager didn't properly upgrade older database entries to the newest schema The setting to disable the mcMMO user block tracker has been moved from our "hidden config" to persistent_data.yml Added 'mcMMO_Region_System.Enabled' to persistent_data.yml (don't touch this setting unless you know what you are doing) @@ -17,18 +21,13 @@ Version 2.1.189 Removed UltraPermissions warning Updated pl locale (Thanks Mich3l3k) Fixed an IllegalPluginAccessException error that could happen during server shutdown - Minor performance optimizations to FlatFile database Minor performance optimizations to misc parts of the codebase - Refactored a lot of code - (API) PrimarySkillType will soon be just an enum with nothing special going on - (API) Deprecated the members of PrimarySkillType use mcMMO::getSkillTools instead, deprecated members will be removed in Tridents & Crossbows (due soon) - (API) Some members of PrimarySkillType were removed and not deprecated (such as the field constants) NOTES: + I spent over 26 hours refactoring FlatFileDB and writing unit tests for it, this will ensure that any changes in the code that could break the database are caught at compile time (so long as we have enough tests, could probably use more) Regarding purging old users on the FlatFileDB, since this wasn't functioning for a while, the last login of users has been reset and if mcMMO hasn't seen that user since this update, it won't purge them as it has no way to know if they are truly an old user I'm likely going to add SQLite DB as an option in the future, I spent time to fix up the FlatFileDB as some Unit Testing practice. - I spent over 26 hours refactoring FlatFileDB and writing unit tests for it, this will ensure that any changes in the code that could break the database are caught - Ultra Permissions is SAFE to use with mcMMO + Ultra Permissions is SAFE to use with mcMMO, disregard previous messages stating otherwise After getting in contact with the UltraPermissions devs and exhaustive testing, I have concluded that using UltraPermissions is completely safe with mcMMO. The users who had an issue with performance currently have an unknown cause, potentially it is from a plugin using the UltraPermissions API I really can't say without more data. My apologies to the UltraPermissions team for reporting an issue between our two plugins directly, as that is not the case. I would have tested it myself sooner but UltraPermissions was closed source and premium so I wasn't particularly motivated to do so, however I have been given access to the binaries so now I can do all the testing I want if future issues ever arise which I have zero expectations that they will. Version 2.1.188 diff --git a/pom.xml b/pom.xml index 38b04da11..0b72bc524 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.189-SNAPSHOT + 2.1.189 mcMMO https://github.com/mcMMO-Dev/mcMMO From c9b03836008a84e73905ec9431506f1825706626 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Wed, 14 Apr 2021 18:14:50 -0700 Subject: [PATCH 30/57] Fix null error in BitSetChunkStore --- Changelog.txt | 20 ++++++++++--------- pom.xml | 2 +- .../util/compat/CompatibilityManager.java | 15 +++++++++++++- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 3fa51b47b..51aff52e3 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,4 +1,7 @@ +Version 2.1.190 + Fixed a null error in BitSetChunkStore Version 2.1.189 + Fixed a bug that would remove components from death messages when players were killed by mobs (thanks lexikiq) Rewrote how FlatFileDatabase verifies data integrity FlatFileDatabase has much better data validation and will repair broken/invalid data much better Fixed a bug where FlatFileDatabase users could have their names saved as "null" (names will be fixed the next time the player logs in) @@ -7,21 +10,20 @@ Version 2.1.189 Newly created flat file databases (mcmmo.users file) will have a comment line at the top noting the date the database was created Minor performance optimizations to FlatFile database mcMMO will once again purge old users if the config option is on (see notes) + Fixed a bug where FlatFileDatabaseManager didn't properly upgrade older database entries to the newest schema + The setting to disable the mcMMO user block tracker has been moved from our "hidden config" to persistent_data.yml + Added 'mcMMO_Region_System.Enabled' to persistent_data.yml (don't touch this setting unless you know what you are doing) + Removed MHD command (it didn't do anything for a while now) + Removed UltraPermissions warning + Updated pl locale (Thanks Mich3l3k) + Fixed an IllegalPluginAccessException error that could happen during server shutdown + Minor performance optimizations to misc parts of the codebase (API) Added com.gmail.nossr50.database.DatabaseManager.loadPlayerProfile(org.bukkit.OfflinePlayer) (API) Deprecated com.gmail.nossr50.database.DatabaseManager.loadPlayerProfile(java.util.UUID, java.lang.String) (API) Removed com.gmail.nossr50.database.DatabaseManager.newUser(java.lang.String, java.util.UUID) (API) PrimarySkillType will soon be just an enum with nothing special going on (API) Deprecated the members of PrimarySkillType use mcMMO::getSkillTools instead, deprecated members will be removed in Tridents & Crossbows (due soon) (API) Some members of PrimarySkillType were removed and not deprecated (such as the field constants) - Fixed a bug where FlatFileDatabaseManager didn't properly upgrade older database entries to the newest schema - The setting to disable the mcMMO user block tracker has been moved from our "hidden config" to persistent_data.yml - Added 'mcMMO_Region_System.Enabled' to persistent_data.yml (don't touch this setting unless you know what you are doing) - Fixed a bug that would remove components from death messages when players were killed by mobs (thanks lexikiq) - Removed MHD command (it didn't do anything for a while now) - Removed UltraPermissions warning - Updated pl locale (Thanks Mich3l3k) - Fixed an IllegalPluginAccessException error that could happen during server shutdown - Minor performance optimizations to misc parts of the codebase NOTES: I spent over 26 hours refactoring FlatFileDB and writing unit tests for it, this will ensure that any changes in the code that could break the database are caught at compile time (so long as we have enough tests, could probably use more) diff --git a/pom.xml b/pom.xml index 0b72bc524..fd3627104 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.189 + 2.1.190-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/util/compat/CompatibilityManager.java b/src/main/java/com/gmail/nossr50/util/compat/CompatibilityManager.java index 6f34d3a89..1b78a55df 100644 --- a/src/main/java/com/gmail/nossr50/util/compat/CompatibilityManager.java +++ b/src/main/java/com/gmail/nossr50/util/compat/CompatibilityManager.java @@ -77,9 +77,22 @@ public class CompatibilityManager { } private void initWorldCompatibilityLayer() { - if(minecraftGameVersion.getMinorVersion().asInt() >= 16 && minecraftGameVersion.getPatchVersion().asInt() >= 4 || minecraftGameVersion.getMajorVersion().asInt() >= 2) { + if((minecraftGameVersion.getMinorVersion().asInt() >= 16 && minecraftGameVersion.getPatchVersion().asInt() >= 4) + || minecraftGameVersion.getMajorVersion().asInt() >= 2) { if(hasNewWorldMinHeightAPI()) { worldCompatibilityLayer = new WorldCompatibilityLayer_1_16_4(); + } else { + worldCompatibilityLayer = new WorldCompatibilityLayer() { + @Override + public int getMinWorldHeight(@NotNull World world) { + return WorldCompatibilityLayer.super.getMinWorldHeight(world); + } + + @Override + public int getMaxWorldHeight(@NotNull World world) { + return WorldCompatibilityLayer.super.getMaxWorldHeight(world); + } + }; } } else { worldCompatibilityLayer = new WorldCompatibilityLayer() { From f2357a04ae4f2dbe851b8c2cf7bdedd33ecb16e3 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Wed, 14 Apr 2021 18:15:10 -0700 Subject: [PATCH 31/57] 2.1.190 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fd3627104..bb75b4ba3 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.190-SNAPSHOT + 2.1.190 mcMMO https://github.com/mcMMO-Dev/mcMMO From b9201b89b80fe69cf3dbdf4e6ad93ed3e350ecac Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 15 Apr 2021 09:38:30 -0700 Subject: [PATCH 32/57] Fix block tracking logic --- Changelog.txt | 3 + pom.xml | 2 +- .../nossr50/listeners/BlockListener.java | 80 +++++++++++-------- .../com/gmail/nossr50/util/BlockUtils.java | 10 +++ 4 files changed, 60 insertions(+), 35 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 51aff52e3..68e662288 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,6 @@ +Version 2.1.191 + Fixed a critical bug related to our BlockTracker + Some minor optimizations to our Block events Version 2.1.190 Fixed a null error in BitSetChunkStore Version 2.1.189 diff --git a/pom.xml b/pom.xml index bb75b4ba3..31d49fbbc 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.190 + 2.1.191-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java index 06c3a7c2e..658793842 100644 --- a/src/main/java/com/gmail/nossr50/listeners/BlockListener.java +++ b/src/main/java/com/gmail/nossr50/listeners/BlockListener.java @@ -123,10 +123,14 @@ public class BlockListener implements Listener { BlockFace direction = event.getDirection(); Block movedBlock; + WorldCompatibilityLayer worldCompatibilityLayer = mcMMO.getCompatibilityManager().getWorldCompatibilityLayer(); - for (Block b : event.getBlocks()) { - movedBlock = b.getRelative(direction); - mcMMO.getPlaceStore().setTrue(movedBlock); + for (Block block : event.getBlocks()) { + movedBlock = block.getRelative(direction); + + if(BlockUtils.isWithinWorldBounds(worldCompatibilityLayer, movedBlock)) { + mcMMO.getPlaceStore().setTrue(movedBlock); + } } } @@ -151,19 +155,15 @@ public class BlockListener implements Listener { WorldCompatibilityLayer worldCompatibilityLayer = mcMMO.getCompatibilityManager().getWorldCompatibilityLayer(); - World world = movedBlock.getWorld(); - //Spigot makes bad things happen in its API - if(event.getBlock().getY() < worldCompatibilityLayer.getMaxWorldHeight(world) || event.getBlock().getY() >= worldCompatibilityLayer.getMinWorldHeight(world)) { + if(BlockUtils.isWithinWorldBounds(worldCompatibilityLayer, movedBlock)) { mcMMO.getPlaceStore().setTrue(movedBlock); } for (Block block : event.getBlocks()) { - if(block.getY() < worldCompatibilityLayer.getMaxWorldHeight(world) || block.getY() >= worldCompatibilityLayer.getMinWorldHeight(world)) { + if(BlockUtils.isWithinWorldBounds(worldCompatibilityLayer, block)) { mcMMO.getPlaceStore().setTrue(block.getRelative(direction)); } - - mcMMO.getPlaceStore().setTrue(movedBlock); } } @@ -180,11 +180,16 @@ public class BlockListener implements Listener { if(WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) return; + BlockState blockState = event.getNewState(); - if(ExperienceConfig.getInstance().isSnowExploitPrevented() && BlockUtils.shouldBeWatched(blockState)) - { - mcMMO.getPlaceStore().setTrue(blockState.getBlock()); + if(ExperienceConfig.getInstance().isSnowExploitPrevented() && BlockUtils.shouldBeWatched(blockState)) { + WorldCompatibilityLayer worldCompatibilityLayer = mcMMO.getCompatibilityManager().getWorldCompatibilityLayer(); + Block block = blockState.getBlock(); + + if(BlockUtils.isWithinWorldBounds(worldCompatibilityLayer, block)) { + mcMMO.getPlaceStore().setTrue(block); + } } } @@ -195,23 +200,19 @@ public class BlockListener implements Listener { public void onBlockFormEvent(BlockFormEvent event) { World world = event.getBlock().getWorld(); - /* WORLD BLACKLIST CHECK */ { - if(WorldBlacklist.isWorldBlacklisted(world)) - return; - } - BlockState newState = event.getNewState(); + /* WORLD BLACKLIST CHECK */ + if(WorldBlacklist.isWorldBlacklisted(world)) + return; if(ExperienceConfig.getInstance().preventStoneLavaFarming()) { + BlockState newState = event.getNewState(); WorldCompatibilityLayer worldCompatibilityLayer = mcMMO.getCompatibilityManager().getWorldCompatibilityLayer(); - if(event.getBlock().getY() > worldCompatibilityLayer.getMaxWorldHeight(world) || event.getBlock().getY() < worldCompatibilityLayer.getMinWorldHeight(world)) { - return; - } - - if(newState.getType() != Material.OBSIDIAN - && ExperienceConfig.getInstance().doesBlockGiveSkillXP(PrimarySkillType.MINING, newState.getBlockData())) { - mcMMO.getPlaceStore().setTrue(newState); + if(newState.getType() != Material.OBSIDIAN && ExperienceConfig.getInstance().doesBlockGiveSkillXP(PrimarySkillType.MINING, newState.getBlockData())) { + if(BlockUtils.isWithinWorldBounds(worldCompatibilityLayer, newState.getBlock())) { + mcMMO.getPlaceStore().setTrue(newState); + } } } } @@ -224,16 +225,23 @@ public class BlockListener implements Listener { @EventHandler(priority = EventPriority.MONITOR) public void onBlockPlace(BlockPlaceEvent event) { BlockState blockState = event.getBlock().getState(); + Block block = blockState.getBlock(); /* Check if the blocks placed should be monitored so they do not give out XP in the future */ // if (!Tag.LOGS.isTagged(event.getBlockReplacedState().getType()) || !Tag.LOGS.isTagged(event.getBlockPlaced().getType())) - mcMMO.getPlaceStore().setTrue(blockState); /* WORLD BLACKLIST CHECK */ - if(WorldBlacklist.isWorldBlacklisted(event.getBlock().getWorld())) { + if(WorldBlacklist.isWorldBlacklisted(block.getWorld())) { return; } + WorldCompatibilityLayer worldCompatibilityLayer = mcMMO.getCompatibilityManager().getWorldCompatibilityLayer(); + + if(BlockUtils.isWithinWorldBounds(worldCompatibilityLayer, block)) { + mcMMO.getPlaceStore().setTrue(blockState); + } + + Player player = event.getPlayer(); if (!UserManager.hasPlayerDataKey(player)) { @@ -260,18 +268,21 @@ public class BlockListener implements Listener { */ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockMultiPlace(BlockMultiPlaceEvent event) { - for (BlockState replacedBlockState : event.getReplacedBlockStates()) - { + for (BlockState replacedBlockState : event.getReplacedBlockStates()) { BlockState blockState = replacedBlockState.getBlock().getState(); + Block block = blockState.getBlock(); + + WorldCompatibilityLayer worldCompatibilityLayer = mcMMO.getCompatibilityManager().getWorldCompatibilityLayer(); /* Check if the blocks placed should be monitored so they do not give out XP in the future */ - mcMMO.getPlaceStore().setTrue(blockState); + if(BlockUtils.isWithinWorldBounds(worldCompatibilityLayer, block)) { + mcMMO.getPlaceStore().setTrue(blockState); + } } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onBlockGrow(BlockGrowEvent event) - { + public void onBlockGrow(BlockGrowEvent event) { Block block = event.getBlock(); World world = block.getWorld(); @@ -280,10 +291,11 @@ public class BlockListener implements Listener { return; // Minecraft is dumb, the events still throw when a plant "grows" higher than the max block height. Even though no new block is created - if (block.getY() >= world.getMaxHeight()) - return; + WorldCompatibilityLayer worldCompatibilityLayer = mcMMO.getCompatibilityManager().getWorldCompatibilityLayer(); - mcMMO.getPlaceStore().setFalse(block); + if(BlockUtils.isWithinWorldBounds(worldCompatibilityLayer, block)) { + mcMMO.getPlaceStore().setFalse(block); + } } /** diff --git a/src/main/java/com/gmail/nossr50/util/BlockUtils.java b/src/main/java/com/gmail/nossr50/util/BlockUtils.java index e1944f738..b81a54631 100644 --- a/src/main/java/com/gmail/nossr50/util/BlockUtils.java +++ b/src/main/java/com/gmail/nossr50/util/BlockUtils.java @@ -7,14 +7,17 @@ import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.repair.Repair; import com.gmail.nossr50.skills.salvage.Salvage; +import com.gmail.nossr50.util.compat.layers.world.WorldCompatibilityLayer; import com.gmail.nossr50.util.random.RandomChanceSkill; import com.gmail.nossr50.util.random.RandomChanceUtil; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.data.Ageable; import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; import java.util.HashSet; @@ -285,4 +288,11 @@ public final class BlockUtils { public static boolean isPartOfTree(Block rayCast) { return hasWoodcuttingXP(rayCast.getState()) || isNonWoodPartOfTree(rayCast.getType()); } + + public static boolean isWithinWorldBounds(@NotNull WorldCompatibilityLayer worldCompatibilityLayer, @NotNull Block block) { + World world = block.getWorld(); + + return block.getY() > worldCompatibilityLayer.getMinWorldHeight(world) || block.getY() < worldCompatibilityLayer.getMaxWorldHeight(world); + } + } From 4f5f3aff8078cef9ad156065dab428278342a386 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 15 Apr 2021 10:43:48 -0700 Subject: [PATCH 33/57] Oops --- pom.xml | 8 ++++---- src/main/java/com/gmail/nossr50/util/BlockUtils.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 31d49fbbc..7de8380b8 100755 --- a/pom.xml +++ b/pom.xml @@ -212,15 +212,15 @@ sk89q-repo https://maven.sk89q.com/repo/ + + sonatype-oss + https://oss.sonatype.org/content/repositories/snapshots/ + aikar https://repo.aikar.co/content/groups/aikar/ - - sonatype-oss - https://oss.sonatype.org/content/repositories/snapshots/ - diff --git a/src/main/java/com/gmail/nossr50/util/BlockUtils.java b/src/main/java/com/gmail/nossr50/util/BlockUtils.java index b81a54631..d1cb63a2a 100644 --- a/src/main/java/com/gmail/nossr50/util/BlockUtils.java +++ b/src/main/java/com/gmail/nossr50/util/BlockUtils.java @@ -292,7 +292,7 @@ public final class BlockUtils { public static boolean isWithinWorldBounds(@NotNull WorldCompatibilityLayer worldCompatibilityLayer, @NotNull Block block) { World world = block.getWorld(); - return block.getY() > worldCompatibilityLayer.getMinWorldHeight(world) || block.getY() < worldCompatibilityLayer.getMaxWorldHeight(world); + return block.getY() > worldCompatibilityLayer.getMinWorldHeight(world) && block.getY() < worldCompatibilityLayer.getMaxWorldHeight(world); } } From e42eeb1dc42041c927756c6c6cc630bff6c71bbc Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 15 Apr 2021 11:53:23 -0700 Subject: [PATCH 34/57] Fix FlatFile leaderboards not working in certain situations + added leaderboards unit test --- Changelog.txt | 4 ++- .../database/FlatFileDatabaseManager.java | 24 ++++++++++++------ .../database/flatfile/LeaderboardStatus.java | 7 ++++++ .../java/com/gmail/nossr50/util/Misc.java | 1 - .../util/blockmeta/BitSetChunkStore.java | 1 - .../database/FlatFileDatabaseManagerTest.java | 25 +++++++++++++------ .../nossr50/util/text/TextUtilsTest.java | 7 +++--- 7 files changed, 47 insertions(+), 22 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/database/flatfile/LeaderboardStatus.java diff --git a/Changelog.txt b/Changelog.txt index 68e662288..96f6fbb21 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,6 +1,8 @@ Version 2.1.191 - Fixed a critical bug related to our BlockTracker + Fixed an exploit + Fixed a bug that prevented the leaderboards from working on FlatFile in some circumstances Some minor optimizations to our Block events + (Unit Tests) Added a test for initializing the leaderboard on FlatFile Version 2.1.190 Fixed a null error in BitSetChunkStore Version 2.1.189 diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index b47477651..dd85cccf5 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -1,6 +1,7 @@ package com.gmail.nossr50.database; import com.gmail.nossr50.api.exceptions.InvalidSkillException; +import com.gmail.nossr50.database.flatfile.LeaderboardStatus; import com.gmail.nossr50.datatypes.database.DatabaseType; import com.gmail.nossr50.datatypes.database.PlayerStat; import com.gmail.nossr50.datatypes.player.PlayerProfile; @@ -89,6 +90,10 @@ public final class FlatFileDatabaseManager implements DatabaseManager { this.startingLevel = startingLevel; this.testing = testing; + if(!usersFile.exists()) { + initEmptyDB(); + } + if(!testing) { List flatFileDataFlags = checkFileHealthAndStructure(); @@ -882,10 +887,10 @@ public final class FlatFileDatabaseManager implements DatabaseManager { /** * Update the leader boards. */ - public void updateLeaderboards() { + public @NotNull LeaderboardStatus updateLeaderboards() { // Only update FFS leaderboards every 10 minutes.. this puts a lot of strain on the server (depending on the size of the database) and should not be done frequently if (System.currentTimeMillis() < lastUpdate + UPDATE_WAIT_TIME) { - return; + return LeaderboardStatus.TOO_SOON_TO_UPDATE; } lastUpdate = System.currentTimeMillis(); // Log when the last update was run @@ -915,6 +920,10 @@ public final class FlatFileDatabaseManager implements DatabaseManager { String line; while ((line = in.readLine()) != null) { + + if(line.startsWith("#")) + continue; + String[] data = line.split(":"); playerName = data[USERNAME_INDEX]; int powerLevel = 0; @@ -940,8 +949,8 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } catch (Exception e) { logger.severe("Exception while reading " + usersFilePath + " during user " + playerName + " (Are you sure you formatted it correctly?) " + e); - } - finally { + return LeaderboardStatus.FAILED; + } finally { if (in != null) { try { in.close(); @@ -951,6 +960,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } } + } SkillComparator c = new SkillComparator(); @@ -983,6 +993,8 @@ public final class FlatFileDatabaseManager implements DatabaseManager { playerStatHash.put(PrimarySkillType.TAMING, taming); playerStatHash.put(PrimarySkillType.FISHING, fishing); playerStatHash.put(PrimarySkillType.ALCHEMY, alchemy); + + return LeaderboardStatus.UPDATED; } private void initEmptyDB() { @@ -1014,10 +1026,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager { logger.info("(" + usersFile.getPath() + ") Validating database file.."); FlatFileDataProcessor dataProcessor = null; - if(!usersFile.exists()) { - initEmptyDB(); - } - if (usersFile.exists()) { BufferedReader bufferedReader = null; FileWriter fileWriter = null; diff --git a/src/main/java/com/gmail/nossr50/database/flatfile/LeaderboardStatus.java b/src/main/java/com/gmail/nossr50/database/flatfile/LeaderboardStatus.java new file mode 100644 index 000000000..9b3313d99 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/flatfile/LeaderboardStatus.java @@ -0,0 +1,7 @@ +package com.gmail.nossr50.database.flatfile; + +public enum LeaderboardStatus { + TOO_SOON_TO_UPDATE, + UPDATED, + FAILED +} diff --git a/src/main/java/com/gmail/nossr50/util/Misc.java b/src/main/java/com/gmail/nossr50/util/Misc.java index bd5058856..9b74f110c 100644 --- a/src/main/java/com/gmail/nossr50/util/Misc.java +++ b/src/main/java/com/gmail/nossr50/util/Misc.java @@ -9,7 +9,6 @@ import com.gmail.nossr50.util.player.UserManager; import com.google.common.collect.ImmutableSet; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.World; import org.bukkit.block.BlockState; import org.bukkit.entity.*; import org.bukkit.inventory.ItemStack; diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/BitSetChunkStore.java b/src/main/java/com/gmail/nossr50/util/blockmeta/BitSetChunkStore.java index ef5dc5459..d850cec06 100644 --- a/src/main/java/com/gmail/nossr50/util/blockmeta/BitSetChunkStore.java +++ b/src/main/java/com/gmail/nossr50/util/blockmeta/BitSetChunkStore.java @@ -1,7 +1,6 @@ package com.gmail.nossr50.util.blockmeta; import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.Misc; import org.bukkit.Bukkit; import org.bukkit.World; import org.jetbrains.annotations.NotNull; diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index d9cd5051d..e00d3f3ae 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -1,6 +1,7 @@ package com.gmail.nossr50.database; import com.gmail.nossr50.TestUtil; +import com.gmail.nossr50.database.flatfile.LeaderboardStatus; import com.gmail.nossr50.datatypes.database.DatabaseType; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.player.UniqueDataType; @@ -24,7 +25,6 @@ import java.util.logging.Logger; import static org.junit.jupiter.api.Assertions.*; -//TODO: Test update leaderboards //This class uses JUnit5/Jupiter public class FlatFileDatabaseManagerTest { @@ -65,7 +65,11 @@ public class FlatFileDatabaseManagerTest { assertNull(db); //noinspection UnstableApiUsage tempDir = Files.createTempDir(); - db = new FlatFileDatabaseManager(new File(tempDir.getPath() + File.separator + TEST_FILE_NAME), logger, PURGE_TIME, 0, true); + db = new FlatFileDatabaseManager(new File(getTemporaryUserFilePath()), logger, PURGE_TIME, 0, true); + } + + private @NotNull String getTemporaryUserFilePath() { + return tempDir.getPath() + File.separator + TEST_FILE_NAME; } @AfterEach @@ -131,6 +135,17 @@ public class FlatFileDatabaseManagerTest { "mrfloris:2420:::0:2452:0:1983:1937:1790:3042:badvalue:3102:2408:3411:0:0:0:0:0:0:0:0::642:0:1617583171:0:1617165043:0:1617583004:1617563189:1616785408::2184:0:0:1617852413:HEARTS:415:0:631e3896-da2a-4077-974b-d047859d76bc:5:1600906906:" }; + @Test + public void testDefaultInit() { + db = new FlatFileDatabaseManager(getTemporaryUserFilePath(), logger, PURGE_TIME, 0); + } + + @Test + public void testUpdateLeaderboards() { + assertNotNull(db); + assertEquals(LeaderboardStatus.UPDATED, db.updateLeaderboards()); + } + @Test public void testSaveUser() { //Make a Profile to save and check to see if it worked @@ -141,8 +156,6 @@ public class FlatFileDatabaseManagerTest { //Save the zero version and see if it looks correct assertNotNull(db); - assertFalse(db.getUsersFile().exists()); - db.checkFileHealthAndStructure(); assertTrue(db.getUsersFile().exists()); //Users file should have been created from the above com.gmail.nossr50.database.FlatFileDatabaseManager.checkFileHealthAndStructure assertNotNull(db.getUsersFile()); @@ -530,9 +543,7 @@ public class FlatFileDatabaseManagerTest { public void testDataNotFound() { //Save the zero version and see if it looks correct assertNotNull(db); - assertFalse(db.getUsersFile().exists()); - db.checkFileHealthAndStructure(); - assertTrue(db.getUsersFile().exists()); //Users file should have been created from the above com.gmail.nossr50.database.FlatFileDatabaseManager.checkFileHealthAndStructure + assertTrue(db.getUsersFile().exists()); assertNotNull(db.getUsersFile()); //Check for the "unloaded" profile diff --git a/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java b/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java index fee41b9b3..da1e021db 100644 --- a/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java +++ b/src/test/java/com/gmail/nossr50/util/text/TextUtilsTest.java @@ -2,8 +2,8 @@ package com.gmail.nossr50.util.text; import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.format.NamedTextColor; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; /** * This Unit Test checks if Adventure was set up correctly and works as expected. @@ -26,7 +26,6 @@ public class TextUtilsTest { */ TextComponent component = TextUtils.colorizeText(inputText); - Assert.assertEquals("Looks like Adventure is not working correctly.", - NamedTextColor.DARK_RED, component.color()); + Assertions.assertEquals(NamedTextColor.DARK_RED, component.color(), "Looks like Adventure is not working correctly."); } } From 522f40f0feb8f07324588c7352909e8c4301c179 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 15 Apr 2021 11:54:05 -0700 Subject: [PATCH 35/57] 2.1.191 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7de8380b8..930916e1b 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.191-SNAPSHOT + 2.1.191 mcMMO https://github.com/mcMMO-Dev/mcMMO From 1269652e94a614ac76fdbd18df2b39a9efbc2707 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 15 Apr 2021 11:59:27 -0700 Subject: [PATCH 36/57] Dev mode --- Changelog.txt | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 96f6fbb21..4ec46bbba 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,5 +1,5 @@ Version 2.1.191 - Fixed an exploit + Fixed a bug related to our blocktracker Fixed a bug that prevented the leaderboards from working on FlatFile in some circumstances Some minor optimizations to our Block events (Unit Tests) Added a test for initializing the leaderboard on FlatFile diff --git a/pom.xml b/pom.xml index 930916e1b..0b364e33f 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.191 + 2.1.192-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO From 48de5057a4bd7a3e65abc7be778c0e38bcda9279 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 15 Apr 2021 14:43:37 -0700 Subject: [PATCH 37/57] Fix another bug where usernames can be saved as null for FlatFileDB --- Changelog.txt | 16 + .../com/gmail/nossr50/api/DatabaseAPI.java | 32 +- .../com/gmail/nossr50/api/ExperienceAPI.java | 110 ++++++- .../database/ConvertDatabaseCommand.java | 2 +- .../experience/ExperienceCommand.java | 5 +- .../experience/SkillresetCommand.java | 7 +- .../nossr50/database/DatabaseManager.java | 14 +- .../database/FlatFileDatabaseManager.java | 267 ++++++++++------- .../nossr50/database/SQLDatabaseManager.java | 10 +- .../com/gmail/nossr50/database/UserQuery.java | 7 + .../gmail/nossr50/database/UserQueryFull.java | 31 ++ .../gmail/nossr50/database/UserQueryName.java | 7 + .../nossr50/database/UserQueryNameImpl.java | 20 ++ .../gmail/nossr50/database/UserQueryType.java | 7 + .../gmail/nossr50/database/UserQueryUUID.java | 11 + .../nossr50/database/UserQueryUUIDImpl.java | 23 ++ .../datatypes/player/PlayerProfile.java | 13 +- .../player/PlayerProfileLoadingTask.java | 2 +- .../database/FlatFileDatabaseManagerTest.java | 280 ++++++++++++++++-- 19 files changed, 686 insertions(+), 178 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/database/UserQuery.java create mode 100644 src/main/java/com/gmail/nossr50/database/UserQueryFull.java create mode 100644 src/main/java/com/gmail/nossr50/database/UserQueryName.java create mode 100644 src/main/java/com/gmail/nossr50/database/UserQueryNameImpl.java create mode 100644 src/main/java/com/gmail/nossr50/database/UserQueryType.java create mode 100644 src/main/java/com/gmail/nossr50/database/UserQueryUUID.java create mode 100644 src/main/java/com/gmail/nossr50/database/UserQueryUUIDImpl.java diff --git a/Changelog.txt b/Changelog.txt index 4ec46bbba..3361322de 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,19 @@ +Version 2.1.192 + Removed some debug messages from FlatFileDatabaseManager + Fixed another bug where player names could be saved as null for FlatFileDB (they will update on the players next login at the next save interval) + (API) Removed deprecation from com.gmail.nossr50.api.ExperienceAPI.getOfflineProfile(java.lang.String) + (API) Added com.gmail.nossr50.api.DatabaseAPI.doesPlayerExistInDB(org.bukkit.OfflinePlayer) + (API) Added com.gmail.nossr50.api.ExperienceAPI.getOfflineProfile(org.bukkit.OfflinePlayer) + (API) Added com.gmail.nossr50.api.ExperienceAPI.getOfflineXP(org.bukkit.OfflinePlayer, java.lang.String) + (API) Added com.gmail.nossr50.api.ExperienceAPI.getOfflineXPRaw(org.bukkit.OfflinePlayer, com.gmail.nossr50.datatypes.skills.PrimarySkillType) + (API) Added com.gmail.nossr50.api.ExperienceAPI.getOfflineXPRaw(org.bukkit.OfflinePlayer, java.lang.String) + (API) Added com.gmail.nossr50.api.ExperienceAPI.getOfflineXPToNextLevel(org.bukkit.OfflinePlayer, java.lang.String) + (API) Added com.gmail.nossr50.api.DatabaseAPI.doesPlayerExistInDB(java.lang.String) + (Unit Tests) Added some more unit tests to FlatFileDB + + NOTES: + I removed a lot of API that should honestly never have been added, this will break some plugins, those plugins will have to update. + Version 2.1.191 Fixed a bug related to our blocktracker Fixed a bug that prevented the leaderboards from working on FlatFile in some circumstances diff --git a/src/main/java/com/gmail/nossr50/api/DatabaseAPI.java b/src/main/java/com/gmail/nossr50/api/DatabaseAPI.java index 8f2879549..55f682377 100644 --- a/src/main/java/com/gmail/nossr50/api/DatabaseAPI.java +++ b/src/main/java/com/gmail/nossr50/api/DatabaseAPI.java @@ -2,6 +2,8 @@ package com.gmail.nossr50.api; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.mcMMO; +import org.bukkit.OfflinePlayer; +import org.jetbrains.annotations.NotNull; import java.util.UUID; @@ -9,20 +11,38 @@ public class DatabaseAPI { /** * Checks if a player exists in the mcMMO Database - * @param uuid player UUID + * @param offlinePlayer target player * @return true if the player exists in the DB, false if they do not */ - public boolean doesPlayerExistInDB(String uuid) { - return doesPlayerExistInDB(UUID.fromString(uuid)); + public boolean doesPlayerExistInDB(@NotNull OfflinePlayer offlinePlayer) { + PlayerProfile playerProfile = mcMMO.getDatabaseManager().loadPlayerProfile(offlinePlayer); + + return playerProfile.isLoaded(); } /** * Checks if a player exists in the mcMMO Database - * @param uuid player UUID + * @param uuid target player * @return true if the player exists in the DB, false if they do not */ - public boolean doesPlayerExistInDB(UUID uuid) { - PlayerProfile playerProfile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid, null); + public boolean doesPlayerExistInDB(@NotNull UUID uuid) { + PlayerProfile playerProfile = null; + try { + playerProfile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid); + } catch (Exception e) { + return false; + } + + return playerProfile.isLoaded(); + } + + /** + * Checks if a player exists in the mcMMO Database + * @param playerName target player + * @return true if the player exists in the DB, false if they do not + */ + public boolean doesPlayerExistInDB(@NotNull String playerName) { + PlayerProfile playerProfile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName); return playerProfile.isLoaded(); } diff --git a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java index a7055bbb5..678f1346b 100644 --- a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java +++ b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java @@ -13,11 +13,11 @@ import com.gmail.nossr50.skills.child.FamilyTree; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.CombatUtils; import com.gmail.nossr50.util.skills.SkillTools; -import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.block.BlockState; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Set; @@ -432,6 +432,23 @@ public final class ExperienceAPI { return getOfflineProfile(uuid).getSkillXpLevel(getNonChildSkillType(skillType)); } + /** + * Get the amount of XP an offline player has in a specific skill. + *
+ * This function is designed for API usage. + * + * @param offlinePlayer The player to get XP for + * @param skillType The skill to get XP for + * @return the amount of XP in a given skill + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + * @throws UnsupportedOperationException if the given skill is a child skill + */ + public static int getOfflineXP(@NotNull OfflinePlayer offlinePlayer, @NotNull String skillType) throws InvalidPlayerException { + return getOfflineProfile(offlinePlayer).getSkillXpLevel(getNonChildSkillType(skillType)); + } + /** * Get the raw amount of XP a player has in a specific skill. *
@@ -483,6 +500,30 @@ public final class ExperienceAPI { return getOfflineProfile(uuid).getSkillXpLevelRaw(getNonChildSkillType(skillType)); } + /** + * Get the raw amount of XP an offline player has in a specific skill. + *
+ * This function is designed for API usage. + * + * @param offlinePlayer The player to get XP for + * @param skillType The skill to get XP for + * @return the amount of XP in a given skill + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + * @throws UnsupportedOperationException if the given skill is a child skill + */ + public static float getOfflineXPRaw(@NotNull OfflinePlayer offlinePlayer, @NotNull String skillType) throws InvalidPlayerException, UnsupportedOperationException, InvalidSkillException { + return getOfflineProfile(offlinePlayer).getSkillXpLevelRaw(getNonChildSkillType(skillType)); + } + + public static float getOfflineXPRaw(@NotNull OfflinePlayer offlinePlayer, @NotNull PrimarySkillType skillType) throws InvalidPlayerException, UnsupportedOperationException { + if(SkillTools.isChildSkill(skillType)) + throw new UnsupportedOperationException(); + + return getOfflineProfile(offlinePlayer).getSkillXpLevelRaw(skillType); + } + /** * Get the total amount of XP needed to reach the next level. *
@@ -530,10 +571,27 @@ public final class ExperienceAPI { * @throws InvalidPlayerException if the given player does not exist in the database * @throws UnsupportedOperationException if the given skill is a child skill */ - public static int getOfflineXPToNextLevel(UUID uuid, String skillType) { + public static int getOfflineXPToNextLevel(@NotNull UUID uuid, @NotNull String skillType) { return getOfflineProfile(uuid).getXpToLevel(getNonChildSkillType(skillType)); } + /** + * Get the total amount of XP an offline player needs to reach the next level. + *
+ * This function is designed for API usage. + * + * @param offlinePlayer The player to get XP for + * @param skillType The skill to get XP for + * @return the total amount of XP needed to reach the next level + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + * @throws UnsupportedOperationException if the given skill is a child skill + */ + public static int getOfflineXPToNextLevel(@NotNull OfflinePlayer offlinePlayer, @NotNull String skillType) throws UnsupportedOperationException, InvalidSkillException, InvalidPlayerException { + return getOfflineProfile(offlinePlayer).getXpToLevel(getNonChildSkillType(skillType)); + } + /** * Get the amount of XP remaining until the next level. *
@@ -595,6 +653,26 @@ public final class ExperienceAPI { return profile.getXpToLevel(skill) - profile.getSkillXpLevelRaw(skill); } + /** + * Get the amount of XP an offline player has left before leveling up. + *
+ * This function is designed for API usage. + * + * @param offlinePlayer The player to get XP for + * @param skillType The skill to get XP for + * @return the amount of XP needed to reach the next level + * + * @throws InvalidSkillException if the given skill is not valid + * @throws InvalidPlayerException if the given player does not exist in the database + * @throws UnsupportedOperationException if the given skill is a child skill + */ + public static float getOfflineXPRemaining(OfflinePlayer offlinePlayer, String skillType) throws InvalidSkillException, InvalidPlayerException, UnsupportedOperationException { + PrimarySkillType skill = getNonChildSkillType(skillType); + PlayerProfile profile = getOfflineProfile(offlinePlayer); + + return profile.getXpToLevel(skill) - profile.getSkillXpLevelRaw(skill); + } + /** * Add levels to a skill. *
@@ -1129,25 +1207,22 @@ public final class ExperienceAPI { } // Utility methods follow. - private static void addOfflineXP(UUID playerUniqueId, PrimarySkillType skill, int XP) { + private static void addOfflineXP(@NotNull UUID playerUniqueId, @NotNull PrimarySkillType skill, int XP) { PlayerProfile profile = getOfflineProfile(playerUniqueId); profile.addXp(skill, XP); profile.save(true); } - @Deprecated - private static void addOfflineXP(String playerName, PrimarySkillType skill, int XP) { + private static void addOfflineXP(@NotNull String playerName, @NotNull PrimarySkillType skill, int XP) { PlayerProfile profile = getOfflineProfile(playerName); profile.addXp(skill, XP); profile.scheduleAsyncSave(); } - private static PlayerProfile getOfflineProfile(UUID uuid) throws InvalidPlayerException { - OfflinePlayer offlinePlayer = Bukkit.getServer().getOfflinePlayer(uuid); - String playerName = offlinePlayer.getName(); - PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid, playerName); + private static @NotNull PlayerProfile getOfflineProfile(@NotNull UUID uuid) throws InvalidPlayerException { + PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid); if (!profile.isLoaded()) { throw new InvalidPlayerException(); @@ -1156,11 +1231,18 @@ public final class ExperienceAPI { return profile; } - @Deprecated - private static PlayerProfile getOfflineProfile(String playerName) throws InvalidPlayerException { - OfflinePlayer offlinePlayer = Bukkit.getServer().getOfflinePlayer(playerName); - UUID uuid = offlinePlayer.getUniqueId(); - PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid, playerName); + private static @NotNull PlayerProfile getOfflineProfile(@NotNull OfflinePlayer offlinePlayer) throws InvalidPlayerException { + PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(offlinePlayer); + + if (!profile.isLoaded()) { + throw new InvalidPlayerException(); + } + + return profile; + } + + private static @NotNull PlayerProfile getOfflineProfile(@NotNull String playerName) throws InvalidPlayerException { + PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName); if (!profile.isLoaded()) { throw new InvalidPlayerException(); 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 1667e9111..8642bc922 100644 --- a/src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/database/ConvertDatabaseCommand.java @@ -58,7 +58,7 @@ public class ConvertDatabaseCommand implements CommandExecutor { UserManager.clearAll(); for (Player player : mcMMO.p.getServer().getOnlinePlayers()) { - PlayerProfile profile = oldDatabase.loadPlayerProfile(player.getUniqueId(), null); + PlayerProfile profile = oldDatabase.loadPlayerProfile(player); if (profile.isLoaded()) { mcMMO.getDatabaseManager().saveUser(profile); 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 4e84f8bff..5f310828e 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java @@ -97,12 +97,9 @@ public abstract class ExperienceCommand implements TabExecutor { // If the mcMMOPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process. if (mcMMOPlayer == null) { - UUID uuid = null; - OfflinePlayer offlinePlayer = mcMMO.p.getServer().getOfflinePlayer(playerName); PlayerProfile profile; - uuid = offlinePlayer.getUniqueId(); - profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid, null); + profile = mcMMO.getDatabaseManager().loadPlayerProfile(playerName); //Check loading by UUID if (CommandUtils.unloadedProfile(sender, profile)) { 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 4b558d422..d4353224e 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java @@ -79,11 +79,8 @@ public class SkillresetCommand implements TabExecutor { // If the mcMMOPlayer doesn't exist, create a temporary profile and check if it's present in the database. If it's not, abort the process. if (mcMMOPlayer == null) { - UUID uuid = null; - OfflinePlayer player = mcMMO.p.getServer().getOfflinePlayer(playerName); - uuid = player.getUniqueId(); - - PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(uuid, playerName); + OfflinePlayer offlinePlayer = mcMMO.p.getServer().getOfflinePlayer(playerName); + PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(offlinePlayer); //Check loading by UUID if (CommandUtils.unloadedProfile(sender, profile)) { diff --git a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java index 3f9ac7a77..c377bbbfe 100644 --- a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java @@ -1,5 +1,6 @@ package com.gmail.nossr50.database; +import com.gmail.nossr50.api.exceptions.InvalidPlayerException; import com.gmail.nossr50.api.exceptions.InvalidSkillException; import com.gmail.nossr50.datatypes.database.DatabaseType; import com.gmail.nossr50.datatypes.database.PlayerStat; @@ -93,18 +94,7 @@ public interface DatabaseManager { */ @NotNull PlayerProfile loadPlayerProfile(@NotNull String playerName); - default @NotNull PlayerProfile loadPlayerProfile(@NotNull OfflinePlayer offlinePlayer) { - return loadPlayerProfile(offlinePlayer.getUniqueId(), offlinePlayer.getName()); - } - - /** - * Load a player from the database. - * @param uuid The uuid of the player to load from the database - * @return The player's data, or an unloaded PlayerProfile if not found - * @deprecated Use {@link DatabaseManager#loadPlayerProfile(org.bukkit.OfflinePlayer)} or {@link DatabaseManager#loadPlayerProfile(java.util.UUID)} if possible - */ - @Deprecated - @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid, @Nullable String playerName); + @NotNull PlayerProfile loadPlayerProfile(@NotNull OfflinePlayer offlinePlayer); @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid); diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index dd85cccf5..f301777b1 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -17,6 +17,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.*; +import java.security.InvalidParameterException; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; @@ -341,14 +342,8 @@ public final class FlatFileDatabaseManager implements DatabaseManager { String line; boolean wroteUser = false; - if(testing) { - System.out.println("-- saveUser bufferedreader feed --"); - } // While not at the end of the file while ((line = in.readLine()) != null) { - if(testing) { - System.out.println(line); - } if(line.startsWith("#")) { writer.append(line).append("\r\n"); continue; @@ -384,7 +379,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { 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); + writeUserToLine(profile, writer); wroteUser = true; } } @@ -393,12 +388,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { * If we couldn't find the user in the DB we need to add him */ if(!wroteUser) { - writeUserToLine(profile, playerName, uuid, writer); - } - - if(testing) { - System.out.println("-- saveUser (FileWriter contents before save) --"); - System.out.println(writer.toString()); + writeUserToLine(profile, writer); } // Write the new file @@ -431,8 +421,8 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } - public void writeUserToLine(@NotNull PlayerProfile profile, @NotNull String playerName, @Nullable UUID uuid, @NotNull Appendable appendable) throws IOException { - appendable.append(playerName).append(":"); + public void writeUserToLine(@NotNull PlayerProfile profile, @NotNull Appendable appendable) throws IOException { + appendable.append(profile.getPlayerName()).append(":"); appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.MINING))).append(":"); appendable.append(IGNORED).append(":"); appendable.append(IGNORED).append(":"); @@ -473,7 +463,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { appendable.append(IGNORED).append(":"); //mob health bar appendable.append(String.valueOf(profile.getSkillLevel(PrimarySkillType.ALCHEMY))).append(":"); appendable.append(String.valueOf(profile.getSkillXpLevel(PrimarySkillType.ALCHEMY))).append(":"); - appendable.append(uuid != null ? uuid.toString() : "NULL").append(":"); + appendable.append(profile.getUniqueId() != null ? profile.getUniqueId().toString() : "NULL").append(":"); appendable.append(String.valueOf(profile.getScoreboardTipsShown())).append(":"); appendable.append(String.valueOf(profile.getUniqueData(UniqueDataType.CHIMAERA_WING_DATS))).append(":"); appendable.append(String.valueOf(profile.getLastLogin())).append(":"); //overhaul last login @@ -527,7 +517,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } try (FileWriter fileWriter = new FileWriter(usersFile)) { - writeUserToLine(playerProfile, playerName, uuid, stringBuilder); + writeUserToLine(playerProfile, stringBuilder); fileWriter.write(stringBuilder.toString()); } catch (Exception e) { e.printStackTrace(); @@ -541,103 +531,53 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } public @NotNull PlayerProfile loadPlayerProfile(@NotNull OfflinePlayer offlinePlayer) { - return loadPlayerByUUID(offlinePlayer.getUniqueId(), offlinePlayer.getName(), offlinePlayer.isOnline()); + return processUserQuery(getUserQuery(offlinePlayer.getUniqueId(), offlinePlayer.getName())); } public @NotNull PlayerProfile loadPlayerProfile(@NotNull String playerName) { - return loadPlayerByName(playerName); - } - - public @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid, @Nullable String playerName) { - return loadPlayerByUUID(uuid, playerName, false); + return processUserQuery(getUserQuery(null, playerName)); } public @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid) { - return loadPlayerByUUID(uuid, null, false); + return processUserQuery(getUserQuery(uuid, null)); + } + + private @NotNull UserQuery getUserQuery(@Nullable UUID uuid, @Nullable String playerName) throws NullPointerException { + boolean hasName = playerName != null && !playerName.equalsIgnoreCase("null"); + + if(hasName && uuid != null) { + return new UserQueryFull(playerName, uuid); + } else if (uuid != null) { + return new UserQueryUUIDImpl(uuid); + } else if(hasName) { + return new UserQueryNameImpl(playerName); + } else { + throw new NullPointerException("Both name and UUID cannot be null, at least one must be non-null!"); + } } /** - * Find and load a player by UUID + * Find and load a player by UUID/Name + * If the name isn't null and doesn't match the name in the DB, the players name is then replaced/updated * - * @param uuid target uuid - * @param playerName target player name - * @param replaceName name to replace if the found name differs + * @param userQuery the query * @return a profile with the targets data or an unloaded profile if no data was found - * @deprecated only use this if you know what you are doing, replacing the name can cause havoc */ - @Deprecated - public @NotNull PlayerProfile loadPlayerByUUID(@NotNull UUID uuid, @Nullable String playerName, boolean replaceName) { - BufferedReader in = null; - - 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 < (UUID_INDEX + 1)) { - continue; - } - - /* 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(playerName != null) { - if(replaceName) { - logger.info("A users name is being updated, this can happen from either a call to our API or they simply changed their name"); - if (!rawSplitData[USERNAME_INDEX].equalsIgnoreCase(playerName)) { - //logger.info("Name updated for player: " + rawSplitData[USERNAME_INDEX] + " => " + playerName); - rawSplitData[USERNAME_INDEX] = playerName; - } - } - } - - 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 - } - } - } + private @NotNull PlayerProfile processUserQuery(@NotNull UserQuery userQuery) throws RuntimeException { + switch(userQuery.getType()) { + case UUID_AND_NAME: + return queryByUUIDAndName((UserQueryFull) userQuery); + case UUID: + return queryByUUID((UserQueryUUID) userQuery); + case NAME: + return queryByName((UserQueryNameImpl) userQuery); + default: + throw new RuntimeException("No case for this UserQueryType!"); } - - /* - * 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) { + private @NotNull PlayerProfile queryByName(@NotNull UserQueryName userQuery) { + String playerName = userQuery.getName(); BufferedReader in = null; synchronized (fileWritingLock) { @@ -646,19 +586,23 @@ public final class FlatFileDatabaseManager implements DatabaseManager { in = new BufferedReader(new FileReader(usersFilePath)); String line; + while ((line = in.readLine()) != null) { if(line.startsWith("#")) { continue; } + // Find if the line contains the player we want. String[] rawSplitData = line.split(":"); + /* Don't read corrupt data */ if(rawSplitData.length < (USERNAME_INDEX + 1)) { continue; } + //If we couldn't find anyone if(playerName.equalsIgnoreCase(rawSplitData[USERNAME_INDEX])) { return loadFromLine(rawSplitData); @@ -679,10 +623,135 @@ public final class FlatFileDatabaseManager implements DatabaseManager { } } + //Return a new blank profile return new PlayerProfile(playerName, new UUID(0, 0), startingLevel); } + private @NotNull PlayerProfile queryByUUID(@NotNull UserQueryUUID userQuery) { + BufferedReader in = null; + UUID uuid = userQuery.getUUID(); + + synchronized (fileWritingLock) { + try { + // Open the user file + in = new BufferedReader(new FileReader(usersFilePath)); + String line; + + while ((line = in.readLine()) != null) { + if(line.startsWith("#")) { + continue; + } + // Find if the line contains the player we want. + String[] rawSplitData = line.split(":"); + + /* Don't read corrupt data */ + if(rawSplitData.length < (UUID_INDEX + 1)) { + continue; + } + + try { + UUID fromDataUUID = UUID.fromString(rawSplitData[UUID_INDEX]); + if(fromDataUUID.equals(uuid)) { + return loadFromLine(rawSplitData); + } + } catch (Exception e) { + if(testing) { + e.printStackTrace(); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + // I have no idea why it's necessary to inline tryClose() here, but it removes + // a resource leak warning, and I'm trusting the compiler on this one. + if (in != null) { + try { + in.close(); + } catch (IOException e) { + // Ignore + } + } + } + } + + /* + * No match was found in the file + */ + + return grabUnloadedProfile(uuid, "Player-Not-Found="+uuid.toString()); + } + + private @NotNull PlayerProfile queryByUUIDAndName(@NotNull UserQueryFull userQuery) { + BufferedReader in = null; + String playerName = userQuery.getName(); + UUID uuid = userQuery.getUUID(); + + synchronized (fileWritingLock) { + try { + // Open the user file + in = new BufferedReader(new FileReader(usersFilePath)); + String line; + + while ((line = in.readLine()) != null) { + if(line.startsWith("#")) { + continue; + } + // Find if the line contains the player we want. + String[] rawSplitData = line.split(":"); + + /* Don't read corrupt data */ + if(rawSplitData.length < (UUID_INDEX + 1)) { + continue; + } + + try { + UUID fromDataUUID = UUID.fromString(rawSplitData[UUID_INDEX]); + if(fromDataUUID.equals(uuid)) { + //Matched UUID, now check if name matches + String dbPlayerName = rawSplitData[USERNAME_INDEX]; + + boolean matchingName = dbPlayerName.equalsIgnoreCase(playerName); + + if (!matchingName) { + logger.info("When loading user: "+playerName +" with UUID of (" + uuid.toString() + +") we found a mismatched name, the name in the DB will be replaced (DB name: "+dbPlayerName+")"); + //logger.info("Name updated for player: " + rawSplitData[USERNAME_INDEX] + " => " + playerName); + rawSplitData[USERNAME_INDEX] = playerName; + } + + //TODO: Logic to replace name here + return loadFromLine(rawSplitData); + } + } catch (Exception e) { + if(testing) { + e.printStackTrace(); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + // I have no idea why it's necessary to inline tryClose() here, but it removes + // a resource leak warning, and I'm trusting the compiler on this one. + if (in != null) { + try { + in.close(); + } catch (IOException e) { + // Ignore + } + } + } + } + + /* + * No match was found in the file + */ + + return grabUnloadedProfile(uuid, playerName); //Create an empty new profile and return + } + private @NotNull PlayerProfile grabUnloadedProfile(@NotNull UUID uuid, @Nullable String playerName) { if(playerName == null) { playerName = ""; //No name for you boy! diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index a937efb0b..566a2e4f5 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -15,6 +15,7 @@ import com.gmail.nossr50.util.Misc; import com.gmail.nossr50.util.skills.SkillTools; import org.apache.tomcat.jdbc.pool.DataSource; import org.apache.tomcat.jdbc.pool.PoolProperties; +import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; import org.jetbrains.annotations.NotNull; @@ -515,7 +516,7 @@ public final class SQLDatabaseManager implements DatabaseManager { if (id == -1) { return new PlayerProfile(player.getName(), player.getUniqueId(), false, mcMMO.p.getAdvancedConfig().getStartingLevel()); } else { - return loadPlayerProfile(player.getUniqueId(), player.getName()); + return loadPlayerProfile(player); } } catch (SQLException e) { e.printStackTrace(); @@ -571,7 +572,12 @@ public final class SQLDatabaseManager implements DatabaseManager { } } - public @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid, @Nullable String playerName) { + @Override + public @NotNull PlayerProfile loadPlayerProfile(@NotNull OfflinePlayer offlinePlayer) { + return loadPlayerFromDB(offlinePlayer.getUniqueId(), offlinePlayer.getName()); + } + + public @NotNull PlayerProfile loadPlayerProfile(@NotNull UUID uuid, @Nullable String playerName) { return loadPlayerFromDB(uuid, playerName); } diff --git a/src/main/java/com/gmail/nossr50/database/UserQuery.java b/src/main/java/com/gmail/nossr50/database/UserQuery.java new file mode 100644 index 000000000..4c6b5e730 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/UserQuery.java @@ -0,0 +1,7 @@ +package com.gmail.nossr50.database; + +import org.jetbrains.annotations.NotNull; + +public interface UserQuery { + @NotNull UserQueryType getType(); +} diff --git a/src/main/java/com/gmail/nossr50/database/UserQueryFull.java b/src/main/java/com/gmail/nossr50/database/UserQueryFull.java new file mode 100644 index 000000000..47a3e965a --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/UserQueryFull.java @@ -0,0 +1,31 @@ +package com.gmail.nossr50.database; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public class UserQueryFull implements UserQueryUUID, UserQueryName { + + private final @NotNull String name; + private final @NotNull UUID uuid; + + public UserQueryFull(@NotNull String name, @NotNull UUID uuid) { + this.name = name; + this.uuid = uuid; + } + + @Override + public @NotNull UserQueryType getType() { + return UserQueryType.UUID_AND_NAME; + } + + @Override + public @NotNull String getName() { + return name; + } + + @Override + public @NotNull UUID getUUID() { + return uuid; + } +} diff --git a/src/main/java/com/gmail/nossr50/database/UserQueryName.java b/src/main/java/com/gmail/nossr50/database/UserQueryName.java new file mode 100644 index 000000000..60604101c --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/UserQueryName.java @@ -0,0 +1,7 @@ +package com.gmail.nossr50.database; + +import org.jetbrains.annotations.NotNull; + +public interface UserQueryName extends UserQuery { + @NotNull String getName(); +} diff --git a/src/main/java/com/gmail/nossr50/database/UserQueryNameImpl.java b/src/main/java/com/gmail/nossr50/database/UserQueryNameImpl.java new file mode 100644 index 000000000..fe7abf910 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/UserQueryNameImpl.java @@ -0,0 +1,20 @@ +package com.gmail.nossr50.database; + +import org.jetbrains.annotations.NotNull; + +public class UserQueryNameImpl implements UserQueryName { + private final @NotNull String name; + + public UserQueryNameImpl(@NotNull String name) { + this.name = name; + } + + @Override + public @NotNull UserQueryType getType() { + return UserQueryType.NAME; + } + + public @NotNull String getName() { + return name; + } +} diff --git a/src/main/java/com/gmail/nossr50/database/UserQueryType.java b/src/main/java/com/gmail/nossr50/database/UserQueryType.java new file mode 100644 index 000000000..588dd76b0 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/UserQueryType.java @@ -0,0 +1,7 @@ +package com.gmail.nossr50.database; + +public enum UserQueryType { + UUID_AND_NAME, + UUID, + NAME +} diff --git a/src/main/java/com/gmail/nossr50/database/UserQueryUUID.java b/src/main/java/com/gmail/nossr50/database/UserQueryUUID.java new file mode 100644 index 000000000..192997f90 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/UserQueryUUID.java @@ -0,0 +1,11 @@ +package com.gmail.nossr50.database; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public interface UserQueryUUID extends UserQuery { + + @NotNull UUID getUUID(); + +} diff --git a/src/main/java/com/gmail/nossr50/database/UserQueryUUIDImpl.java b/src/main/java/com/gmail/nossr50/database/UserQueryUUIDImpl.java new file mode 100644 index 000000000..49ad038f5 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/database/UserQueryUUIDImpl.java @@ -0,0 +1,23 @@ +package com.gmail.nossr50.database; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public class UserQueryUUIDImpl implements UserQueryUUID { + private final @NotNull UUID uuid; + + public UserQueryUUIDImpl(@NotNull UUID uuid) { + this.uuid = uuid; + } + + @Override + public @NotNull UserQueryType getType() { + return UserQueryType.UUID; + } + + @Override + public @NotNull UUID getUUID() { + return uuid; + } +} diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java index 81d2d8417..ff9ebbb70 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java @@ -22,7 +22,7 @@ import java.util.concurrent.DelayQueue; public class PlayerProfile { private final String playerName; - private UUID uuid; + private @Nullable UUID uuid; private boolean loaded; private volatile boolean changed; @@ -49,7 +49,7 @@ public class PlayerProfile { } //TODO: Add deprecated constructor w/o startinglevel - public PlayerProfile(String playerName, UUID uuid, int startingLevel) { + public PlayerProfile(String playerName, @Nullable UUID uuid, int startingLevel) { this.uuid = uuid; this.playerName = playerName; @@ -100,10 +100,6 @@ public class PlayerProfile { new PlayerProfileSaveTask(this, false).runTaskAsynchronously(mcMMO.p); } - public void scheduleSyncSave() { - new PlayerProfileSaveTask(this, true).runTask(mcMMO.p); - } - public void scheduleAsyncSaveDelay() { new PlayerProfileSaveTask(this, false).runTaskLaterAsynchronously(mcMMO.p, 20); } @@ -126,8 +122,7 @@ public class PlayerProfile { if (changed) { mcMMO.p.getLogger().severe("PlayerProfile saving failed for player: " + playerName + " " + uuid); - if(saveAttempts > 0) - { + if(saveAttempts > 0) { mcMMO.p.getLogger().severe("Attempted to save profile for player "+getPlayerName() + " resulted in failure. "+saveAttempts+" have been made so far."); } @@ -138,7 +133,7 @@ public class PlayerProfile { //Back out of async saving if we detect a server shutdown, this is not always going to be caught if(mcMMO.isServerShutdownExecuted() || useSync) - scheduleSyncSave(); //Execute sync saves immediately + new PlayerProfileSaveTask(this, true).runTask(mcMMO.p); else scheduleAsyncSave(); 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 95c0ddc71..5a82b43da 100644 --- a/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/player/PlayerProfileLoadingTask.java @@ -41,7 +41,7 @@ public class PlayerProfileLoadingTask extends BukkitRunnable { return; } - PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(player.getUniqueId(), player.getName()); + PlayerProfile profile = mcMMO.getDatabaseManager().loadPlayerProfile(player); if(!profile.isLoaded()) { mcMMO.p.getLogger().info("Creating new data for player: "+player.getName()); diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index e00d3f3ae..e6001626a 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -9,18 +9,25 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.util.skills.SkillTools; import com.google.common.io.Files; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.Statistic; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.*; import java.io.*; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.UUID; +import java.util.logging.Filter; +import java.util.logging.LogRecord; import java.util.logging.Logger; import static org.junit.jupiter.api.Assertions.*; @@ -60,6 +67,11 @@ public class FlatFileDatabaseManagerTest { int expectedScoreboardTips = 1111; Long expectedLastLogin = 2020L; + @BeforeAll + static void initBeforeAll() { + logger.setFilter(new DebugFilter()); + } + @BeforeEach public void init() { assertNull(db); @@ -175,7 +187,7 @@ public class FlatFileDatabaseManagerTest { //This makes sure our private method is working before the tests run afterwards ArrayList dataFromFile = getSplitDataFromFile(dbFile); - System.out.println("File Path: "+ dbFile.getAbsolutePath()); + logger.info("File Path: "+ dbFile.getAbsolutePath()); assertArrayEquals(LINE_TWO_FROM_MISSING_DB.split(":"), dataFromFile.get(1)); assertEquals(dataFromFile.get(1)[FlatFileDatabaseManager.UUID_INDEX], HEALTHY_DB_LINE_ONE_UUID_STR); @@ -199,7 +211,7 @@ public class FlatFileDatabaseManagerTest { //This makes sure our private method is working before the tests run afterwards ArrayList dataFromFile = getSplitDataFromFile(healthyDB); - System.out.println("File Path: "+healthyDB.getAbsolutePath()); + logger.info("File Path: "+healthyDB.getAbsolutePath()); assertArrayEquals(HEALTHY_DB_LINE_1.split(":"), dataFromFile.get(0)); assertEquals(dataFromFile.get(0)[FlatFileDatabaseManager.UUID_INDEX], HEALTHY_DB_LINE_ONE_UUID_STR); UUID healthDBEntryOneUUID = UUID.fromString(HEALTHY_DB_LINE_ONE_UUID_STR); @@ -270,7 +282,7 @@ public class FlatFileDatabaseManagerTest { assertEquals(playerName, playerProfile.getPlayerName()); assertEquals(uuid, playerProfile.getUniqueId()); - PlayerProfile retrievedFromDisk = db.loadPlayerProfile(uuid, playerName); + PlayerProfile retrievedFromDisk = db.loadPlayerProfile(uuid); assertTrue(retrievedFromDisk.isLoaded()); assertEquals(playerName, retrievedFromDisk.getPlayerName()); assertEquals(uuid, retrievedFromDisk.getUniqueId()); @@ -320,7 +332,7 @@ public class FlatFileDatabaseManagerTest { //This makes sure our private method is working before the tests run afterwards ArrayList dataFromFile = getSplitDataFromFile(dbFile); - System.out.println("File Path: " + dbFile.getAbsolutePath()); + logger.info("File Path: " + dbFile.getAbsolutePath()); assertArrayEquals(HEALTHY_DB_LINE_1.split(":"), dataFromFile.get(0)); assertEquals(dataFromFile.get(0)[FlatFileDatabaseManager.UUID_INDEX], HEALTHY_DB_LINE_ONE_UUID_STR); @@ -335,16 +347,50 @@ public class FlatFileDatabaseManagerTest { String playerName = "nossr50"; UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); - PlayerProfile profile1 = db.loadPlayerProfile(uuid, null); - PlayerProfile profile2 = db.loadPlayerProfile(uuid, playerName); - PlayerProfile profile3 = db.loadPlayerProfile(uuid, "incorrectName"); - PlayerProfile profile4 = db.loadPlayerProfile(new UUID(0, 1), "shouldBeUnloaded"); - assertFalse(profile4.isLoaded()); - - //Three possible ways to load the thing + PlayerProfile profile1 = db.loadPlayerProfile(uuid); testHealthyDataProfileValues(playerName, uuid, profile1); - testHealthyDataProfileValues(playerName, uuid, profile2); - testHealthyDataProfileValues(playerName, uuid, profile3); + + + assertFalse(db.loadPlayerProfile(new UUID(0, 1)).isLoaded()); //This profile should not exist and therefor will return unloaded + } + + @Test + public void testLoadByUUIDAndName() { + File dbFile = prepareDatabaseTestResource(DB_HEALTHY); + + /* + * We have established the files are in good order, so now for the actual testing + */ + + //This makes sure our private method is working before the tests run afterwards + ArrayList dataFromFile = getSplitDataFromFile(dbFile); + logger.info("File Path: " + dbFile.getAbsolutePath()); + assertArrayEquals(HEALTHY_DB_LINE_1.split(":"), dataFromFile.get(0)); + assertEquals(dataFromFile.get(0)[FlatFileDatabaseManager.UUID_INDEX], HEALTHY_DB_LINE_ONE_UUID_STR); + + db = new FlatFileDatabaseManager(dbFile, logger, PURGE_TIME, 0, true); + List flagsFound = db.checkFileHealthAndStructure(); + assertNull(flagsFound); //No flags should be found + + /* + * Once the DB looks fine load the profile + */ + + String playerName = "nossr50"; + UUID uuid = UUID.fromString("588fe472-1c82-4c4e-9aa1-7eefccb277e3"); + + TestOfflinePlayer player = new TestOfflinePlayer(playerName, uuid); + PlayerProfile profile1 = db.loadPlayerProfile(player); + testHealthyDataProfileValues(playerName, uuid, profile1); + + String updatedName = "updatedName"; + TestOfflinePlayer updatedNamePlayer = new TestOfflinePlayer(updatedName, uuid); + PlayerProfile updatedNameProfile = db.loadPlayerProfile(updatedNamePlayer); + testHealthyDataProfileValues(updatedName, uuid, updatedNameProfile); + + TestOfflinePlayer shouldNotExist = new TestOfflinePlayer("doesntexist", new UUID(0, 1)); + PlayerProfile profile3 = db.loadPlayerProfile(shouldNotExist); + assertFalse(profile3.isLoaded()); } private File prepareDatabaseTestResource(@NotNull String dbFileName) { @@ -393,11 +439,11 @@ public class FlatFileDatabaseManagerTest { if(SkillTools.isChildSkill(primarySkillType)) continue; -// System.out.println("Checking expected values for: "+primarySkillType); -// System.out.println("Profile Level Value: "+profile.getSkillLevel(primarySkillType)); -// System.out.println("Expected Lvl Value: "+getExpectedLevelHealthyDBEntryOne(primarySkillType)); -// System.out.println("Profile Exp Value: "+profile.getSkillXpLevelRaw(primarySkillType)); -// System.out.println("Expected Exp Value: "+getExpectedExperienceHealthyDBEntryOne(primarySkillType)); +// logger.info("Checking expected values for: "+primarySkillType); +// logger.info("Profile Level Value: "+profile.getSkillLevel(primarySkillType)); +// logger.info("Expected Lvl Value: "+getExpectedLevelHealthyDBEntryOne(primarySkillType)); +// logger.info("Profile Exp Value: "+profile.getSkillXpLevelRaw(primarySkillType)); +// logger.info("Expected Exp Value: "+getExpectedExperienceHealthyDBEntryOne(primarySkillType)); assertEquals(getExpectedLevelHealthyDBEntryOne(primarySkillType), profile.getSkillLevel(primarySkillType)); assertEquals(getExpectedExperienceHealthyDBEntryOne(primarySkillType), profile.getSkillXpLevelRaw(primarySkillType), 0); @@ -640,7 +686,7 @@ public class FlatFileDatabaseManagerTest { //This makes sure our private method is working before the tests run afterwards ArrayList dataFromFile = getSplitDataFromFile(copyOfFile); - System.out.println("File Path: "+copyOfFile.getAbsolutePath()); + logger.info("File Path: "+copyOfFile.getAbsolutePath()); assertArrayEquals(BAD_FILE_LINE_ONE.split(":"), dataFromFile.get(0)); assertEquals(dataFromFile.get(22)[0], "nossr51"); assertArrayEquals(BAD_DATA_FILE_LINE_TWENTY_THREE.split(":"), dataFromFile.get(22)); @@ -688,7 +734,7 @@ public class FlatFileDatabaseManagerTest { out.write(writer.toString()); } catch (FileNotFoundException e) { e.printStackTrace(); - System.out.println("File not found"); + logger.info("File not found"); } catch (IOException e) { e.printStackTrace(); } finally { @@ -703,12 +749,12 @@ public class FlatFileDatabaseManagerTest { } try { - System.out.println("Added the following lines to the FlatFileDatabase for the purposes of the test..."); + logger.info("Added the following lines to the FlatFileDatabase for the purposes of the test..."); // Open the file in = new BufferedReader(new FileReader(filePath)); String line; while ((line = in.readLine()) != null) { - System.out.println(line); + logger.info(line); } } catch (IOException e) { e.printStackTrace(); @@ -731,4 +777,188 @@ public class FlatFileDatabaseManagerTest { assertNotNull(dataFlags); assertTrue(dataFlags.contains(flag)); } + + private class TestOfflinePlayer implements OfflinePlayer { + + private final @NotNull String name; + private final @NotNull UUID uuid; + + private TestOfflinePlayer(@NotNull String name, @NotNull UUID uuid) { + this.name = name; + this.uuid = uuid; + } + + @Override + public boolean isOnline() { + return false; + } + + @Nullable + @Override + public String getName() { + return name; + } + + @NotNull + @Override + public UUID getUniqueId() { + return uuid; + } + + @Override + public boolean isBanned() { + return false; + } + + @Override + public boolean isWhitelisted() { + return false; + } + + @Override + public void setWhitelisted(boolean value) { + + } + + @Nullable + @Override + public Player getPlayer() { + return null; + } + + @Override + public long getFirstPlayed() { + return 0; + } + + @Override + public long getLastPlayed() { + return 0; + } + + @Override + public boolean hasPlayedBefore() { + return false; + } + + @Nullable + @Override + public Location getBedSpawnLocation() { + return null; + } + + @Override + public void incrementStatistic(@NotNull Statistic statistic) throws IllegalArgumentException { + + } + + @Override + public void decrementStatistic(@NotNull Statistic statistic) throws IllegalArgumentException { + + } + + @Override + public void incrementStatistic(@NotNull Statistic statistic, int amount) throws IllegalArgumentException { + + } + + @Override + public void decrementStatistic(@NotNull Statistic statistic, int amount) throws IllegalArgumentException { + + } + + @Override + public void setStatistic(@NotNull Statistic statistic, int newValue) throws IllegalArgumentException { + + } + + @Override + public int getStatistic(@NotNull Statistic statistic) throws IllegalArgumentException { + return 0; + } + + @Override + public void incrementStatistic(@NotNull Statistic statistic, @NotNull Material material) throws IllegalArgumentException { + + } + + @Override + public void decrementStatistic(@NotNull Statistic statistic, @NotNull Material material) throws IllegalArgumentException { + + } + + @Override + public int getStatistic(@NotNull Statistic statistic, @NotNull Material material) throws IllegalArgumentException { + return 0; + } + + @Override + public void incrementStatistic(@NotNull Statistic statistic, @NotNull Material material, int amount) throws IllegalArgumentException { + + } + + @Override + public void decrementStatistic(@NotNull Statistic statistic, @NotNull Material material, int amount) throws IllegalArgumentException { + + } + + @Override + public void setStatistic(@NotNull Statistic statistic, @NotNull Material material, int newValue) throws IllegalArgumentException { + + } + + @Override + public void incrementStatistic(@NotNull Statistic statistic, @NotNull EntityType entityType) throws IllegalArgumentException { + + } + + @Override + public void decrementStatistic(@NotNull Statistic statistic, @NotNull EntityType entityType) throws IllegalArgumentException { + + } + + @Override + public int getStatistic(@NotNull Statistic statistic, @NotNull EntityType entityType) throws IllegalArgumentException { + return 0; + } + + @Override + public void incrementStatistic(@NotNull Statistic statistic, @NotNull EntityType entityType, int amount) throws IllegalArgumentException { + + } + + @Override + public void decrementStatistic(@NotNull Statistic statistic, @NotNull EntityType entityType, int amount) { + + } + + @Override + public void setStatistic(@NotNull Statistic statistic, @NotNull EntityType entityType, int newValue) { + + } + + @NotNull + @Override + public Map serialize() { + return null; + } + + @Override + public boolean isOp() { + return false; + } + + @Override + public void setOp(boolean value) { + + } + } + + private static class DebugFilter implements Filter { + + @Override + public boolean isLoggable(LogRecord record) { + return false; + } + } } \ No newline at end of file From 8fdc611fb0e083963c02dbf9e15b4e7b1fc4b1a6 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 15 Apr 2021 14:48:24 -0700 Subject: [PATCH 38/57] Add some code to a test to check for user names being updated --- .../database/FlatFileDatabaseManagerTest.java | 38 +++++++------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index e6001626a..bfc3c01f5 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -175,10 +175,23 @@ public class FlatFileDatabaseManagerTest { assertTrue(db.saveUser(testProfile)); //True means we saved the user //Check for the empty profile - PlayerProfile retrievedFromData = db.loadPlayerProfile(playerName); + PlayerProfile retrievedFromData = db.loadPlayerProfile(uuid); assertTrue(retrievedFromData.isLoaded()); //PlayerProfile::isLoaded returns true if the data was created from the file, false if it wasn't found and a dummy profile was returned assertEquals(uuid, retrievedFromData.getUniqueId()); assertEquals(playerName, retrievedFromData.getPlayerName()); + + /* + * Test overwriting names with new names + */ + + String alteredName = "changedmyname"; + PlayerProfile changedNameProfile = new PlayerProfile(alteredName, uuid, 0); + assertTrue(db.saveUser(changedNameProfile)); //True means we saved the user + + retrievedFromData = db.loadPlayerProfile(uuid); + assertTrue(retrievedFromData.isLoaded()); //PlayerProfile::isLoaded returns true if the data was created from the file, false if it wasn't found and a dummy profile was returned + assertEquals(uuid, retrievedFromData.getUniqueId()); + assertEquals(alteredName, retrievedFromData.getPlayerName()); } @Test @@ -562,29 +575,6 @@ public class FlatFileDatabaseManagerTest { assertNotEquals(splitDataLines.get(1)[0], splitDataLines.get(0)[0]); //Name comparison } - @Test - public void testUpdateName() { - //TODO: The code in this test didn't actually trigger the save, so I'll have to do something else to test saving -// UUID uuid = UUID.fromString(HEALTHY_DB_LINE_ONE_UUID_STR); //Entrant "nossr50" -// String playerName = "the_new_name_man"; -// -// File file = prepareDatabaseTestResource(DB_HEALTHY); //Existing DB -// db = new FlatFileDatabaseManager(file, logger, PURGE_TIME, 0, true); -// db.checkFileHealthAndStructure(); -// ArrayList splitDataLines = getSplitDataFromFile(db.getUsersFile()); -// String oldName = "nossr50"; -// assertEquals(oldName, splitDataLines.get(0)[0]); //Name comparison -// assertEquals(uuid.toString(), splitDataLines.get(0)[FlatFileDatabaseManager.UUID_INDEX]); //UUID Comparison -// -// //Now we load the player and their name should get replaced -// PlayerProfile profile = db.loadPlayerByUUID(uuid, playerName, true); -// assertEquals(playerName, profile.getPlayerName()); -// -// splitDataLines = getSplitDataFromFile(db.getUsersFile()); //Load the file again -// assertNotEquals(oldName, splitDataLines.get(0)[0]); //Name comparison -// assertEquals(playerName, splitDataLines.get(0)[0]); //Name comparison - } - @Test public void testDataNotFound() { //Save the zero version and see if it looks correct From 8027b4741e85af4ebbddeac2981461336399a6cf Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 15 Apr 2021 14:48:54 -0700 Subject: [PATCH 39/57] 2.1.192 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0b364e33f..320b75d5d 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.192-SNAPSHOT + 2.1.192 mcMMO https://github.com/mcMMO-Dev/mcMMO From 04459f1ea712c8ae4ca85516bcb47ca40c9fa60b Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 16 Apr 2021 09:55:44 -0700 Subject: [PATCH 40/57] Fix leaderboards & fix override locale bug Fixes #4493 Fixes #4492 --- Changelog.txt | 7 ++- pom.xml | 2 +- .../database/FlatFileDatabaseManager.java | 6 +- src/main/java/com/gmail/nossr50/mcMMO.java | 2 + .../database/FlatFileDatabaseManagerTest.java | 62 +++++++++++++++++++ 5 files changed, 73 insertions(+), 6 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 3361322de..179f32012 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,7 @@ +Version 2.1.193 + Fixed another bug where mcrank/mctop/leaderboards weren't loading + Fixed a bug where override locales weren't being loaded (but worked after a reloadlocale command) + (Unit Tests) Added a test to make sure leaderboards were working Version 2.1.192 Removed some debug messages from FlatFileDatabaseManager Fixed another bug where player names could be saved as null for FlatFileDB (they will update on the players next login at the next save interval) @@ -11,9 +15,6 @@ Version 2.1.192 (API) Added com.gmail.nossr50.api.DatabaseAPI.doesPlayerExistInDB(java.lang.String) (Unit Tests) Added some more unit tests to FlatFileDB - NOTES: - I removed a lot of API that should honestly never have been added, this will break some plugins, those plugins will have to update. - Version 2.1.191 Fixed a bug related to our blocktracker Fixed a bug that prevented the leaderboards from working on FlatFile in some circumstances diff --git a/pom.xml b/pom.xml index 320b75d5d..3a19d20e1 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.192 + 2.1.193-SNAPSHOT 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 f301777b1..32f327614 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -10,6 +10,7 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.blockmeta.HashChunkManager; import com.gmail.nossr50.util.skills.SkillTools; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; @@ -484,15 +485,16 @@ public final class FlatFileDatabaseManager implements DatabaseManager { return statsList.subList(Math.min(fromIndex, statsList.size()), Math.min(fromIndex + statsPerPage, statsList.size())); } - public Map readRank(String playerName) { + public @NotNull HashMap readRank(String playerName) { updateLeaderboards(); - Map skills = new EnumMap(PrimarySkillType.class); + HashMap skills = new HashMap<>(); for (PrimarySkillType skill : SkillTools.NON_CHILD_SKILLS) { skills.put(skill, getPlayerRank(playerName, playerStatHash.get(skill))); } + //TODO: Gross skills.put(null, getPlayerRank(playerName, powerLevels)); return skills; diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index 5e08bc34e..a0b7ebf43 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -18,6 +18,7 @@ import com.gmail.nossr50.database.DatabaseManagerFactory; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.subskills.acrobatics.Roll; import com.gmail.nossr50.listeners.*; +import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.runnables.SaveTimerTask; import com.gmail.nossr50.runnables.backups.CleanBackupsTask; @@ -337,6 +338,7 @@ public class mcMMO extends JavaPlugin { transientEntityTracker = new TransientEntityTracker(); setServerShutdown(false); //Reset flag, used to make decisions about async saves + LocaleLoader.reloadLocale(); //Apply override locale } public static PlayerLevelUtils getPlayerLevelUtils() { diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index bfc3c01f5..feb796e9f 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -644,6 +644,36 @@ public class FlatFileDatabaseManagerTest { assertEquals(db.getDatabaseType(), DatabaseType.FLATFILE); } + @Test + public void testReadRank() { + //This is an empty DB + assertNotNull(db); + String rankBoyName = "rankBoy"; + UUID rankBoyUUID = new UUID(1337, 1337); + String rankGirlName = "rankGirl"; + UUID rankGirlUUID = new UUID(7331, 7331); + + PlayerProfile rankGirlProfile = addPlayerProfileWithLevelsAndSave(rankGirlName, rankGirlUUID, 100); //Rank 1 + PlayerProfile rankBoyProfile = addPlayerProfileWithLevelsAndSave(rankBoyName, rankBoyUUID, 10); //Rank 2 + + assertEquals(LeaderboardStatus.UPDATED, db.updateLeaderboards()); + Map rankGirlPositions = db.readRank(rankGirlName); + Map rankBoyPositions = db.readRank(rankBoyName); + + for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { + if(primarySkillType.isChildSkill()) { + assertNull(rankBoyPositions.get(primarySkillType)); + assertNull(rankGirlPositions.get(primarySkillType)); + } else { + assertEquals(1, rankGirlPositions.get(primarySkillType)); + assertEquals(2, rankBoyPositions.get(primarySkillType)); + } + } + + assertEquals(1, db.readRank(rankGirlName).get(null)); //Girl should be position 1 + assertEquals(2, db.readRank(rankBoyName).get(null)); //Boy should be position 2 + } + @Test public void testLoadFromFile() { ClassLoader classLoader = getClass().getClassLoader(); @@ -708,6 +738,38 @@ public class FlatFileDatabaseManagerTest { return splitDataList; } + private @NotNull PlayerProfile addPlayerProfileWithLevelsAndSave(String playerName, UUID uuid, int levels) { + assertNotNull(db); + assertFalse(db.loadPlayerProfile(uuid).isLoaded()); + + db.newUser(playerName, uuid); + PlayerProfile leveledProfile = db.loadPlayerProfile(uuid); + + assertTrue(leveledProfile.isLoaded()); + assertEquals(playerName, leveledProfile.getPlayerName()); + assertEquals(uuid, leveledProfile.getUniqueId()); + + for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { + if(SkillTools.isChildSkill(primarySkillType)) + continue; + + leveledProfile.modifySkill(primarySkillType, levels); //TODO: This method also resets XP, not cool + } + + db.saveUser(leveledProfile); + leveledProfile = db.loadPlayerProfile(uuid); + + for(PrimarySkillType primarySkillType : PrimarySkillType.values()) { + if(SkillTools.isChildSkill(primarySkillType)) { + continue; + } + + assertEquals(levels, leveledProfile.getSkillLevel(primarySkillType)); + } + + return leveledProfile; + } + private void replaceDataInFile(@NotNull FlatFileDatabaseManager flatFileDatabaseManager, @NotNull String[] dataEntries) { String filePath = flatFileDatabaseManager.getUsersFile().getAbsolutePath(); BufferedReader in = null; From 739342160737dfafc61a5c23fd2e08fd2592f484 Mon Sep 17 00:00:00 2001 From: Warrior <50800980+Warriorrrr@users.noreply.github.com> Date: Fri, 16 Apr 2021 19:03:57 +0200 Subject: [PATCH 41/57] Some patches (#4494) Fixed blocks being dropped from blast mining even if yield was set to 0. Tree feller not working entirely if one fake block break event is cancelled. (Fixes #4189) Fixes no woodcutting xp being rewarded if a tree is too big while using tree feller. --- .../com/gmail/nossr50/datatypes/player/McMMOPlayer.java | 4 ++++ .../com/gmail/nossr50/skills/mining/MiningManager.java | 4 +++- .../nossr50/skills/woodcutting/WoodcuttingManager.java | 7 ++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index e6c3a22d9..c68521e10 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -941,6 +941,10 @@ public class McMMOPlayer implements Identified { //Sounds SoundManager.worldSendSound(player.getWorld(), player.getLocation(), SoundType.ABILITY_ACTIVATED_GENERIC); + //If the current item is still buffed somehow, remove it to prevent enchantments from stacking. + if (superAbilityType == SuperAbilityType.SUPER_BREAKER || superAbilityType == SuperAbilityType.GIGA_DRILL_BREAKER) + SkillUtils.removeAbilityBuff(player.getInventory().getItemInMainHand()); + // Enable the ability profile.setAbilityDATS(superAbilityType, System.currentTimeMillis() + (ticks * Misc.TIME_CONVERSION_FACTOR)); setAbilityMode(superAbilityType, true); diff --git a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java index 9cad29d7b..4ab9f6a17 100644 --- a/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java +++ b/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java @@ -157,8 +157,10 @@ public class MiningManager extends SkillManager { //TODO: Rewrite this garbage //TODO: Rewrite this garbage public void blastMiningDropProcessing(float yield, EntityExplodeEvent event) { - //Strip out only stuff that gives mining XP + if (yield == 0) + return; + //Strip out only stuff that gives mining XP List ores = new ArrayList<>(); List notOres = new ArrayList<>(); diff --git a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java index 49fa5bd20..3fd8f2ab9 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java @@ -107,6 +107,11 @@ public class WoodcuttingManager extends SkillManager { treeFellerReachedThreshold = false; NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Woodcutting.Skills.TreeFeller.Threshold"); + + //Tree feller won't be activated for this block, award normal xp. + processWoodcuttingBlockXP(blockState); + processHarvestLumber(blockState); + return; } @@ -282,7 +287,7 @@ public class WoodcuttingManager extends SkillManager { Block block = blockState.getBlock(); if (!EventUtils.simulateBlockBreak(block, player, true)) { - break; // TODO: Shouldn't we use continue instead? + continue; } /* From 76ebd85afaac46d511107bab134e1dbef558964b Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 16 Apr 2021 10:05:21 -0700 Subject: [PATCH 42/57] Update changelog --- Changelog.txt | 4 ++++ src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 179f32012..c44ad03f2 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -2,6 +2,10 @@ Version 2.1.193 Fixed another bug where mcrank/mctop/leaderboards weren't loading Fixed a bug where override locales weren't being loaded (but worked after a reloadlocale command) (Unit Tests) Added a test to make sure leaderboards were working + Fixed blocks being dropped from blast mining even if yield was set to 0 (thanks Warriorrrr) + Fixed Tree feller not working entirely if one fake block break event is cancelled. (thanks Warriorrrr) + Fixes no woodcutting xp being rewarded if a tree is too big while using tree feller. (thanks Warriorrrr) + Version 2.1.192 Removed some debug messages from FlatFileDatabaseManager Fixed another bug where player names could be saved as null for FlatFileDB (they will update on the players next login at the next save interval) diff --git a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java index 938ca2343..cdff05e8f 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/SkillUtils.java @@ -158,8 +158,7 @@ public final class SkillUtils { //1.13.2+ will have persistent metadata for this item AbstractPersistentDataLayer compatLayer = mcMMO.getCompatibilityManager().getPersistentDataLayer(); compatLayer.setSuperAbilityBoostedItem(heldItem, originalDigSpeed); - } - else { + } else { int duration = 0; int amplifier = 0; From fee2b93b4bb1fbb946ad5687576d31e2cccc1136 Mon Sep 17 00:00:00 2001 From: Mich3l3k <47540709+Mich3l3k@users.noreply.github.com> Date: Fri, 16 Apr 2021 19:06:30 +0200 Subject: [PATCH 43/57] Update locale_pl.properties (#4486) * Update locale_pl.properties Lots of minor bugs fixed and the woodcut has a better translated name (as well as the ability to woodcut etc.) And all guides have been translated :D * Update locale_pl.properties Guides.Salvage.* translated Fixed few mistakes And added support to the latest version of plugin (like swords update) --- .../resources/locale/locale_pl.properties | 190 +++++++++--------- 1 file changed, 96 insertions(+), 94 deletions(-) diff --git a/src/main/resources/locale/locale_pl.properties b/src/main/resources/locale/locale_pl.properties index 4cbc5109c..96bc89e2e 100644 --- a/src/main/resources/locale/locale_pl.properties +++ b/src/main/resources/locale/locale_pl.properties @@ -21,7 +21,7 @@ JSON.Alchemy=Alchemia JSON.Archery=\u0141ucznictwo JSON.Axes=Siekiery JSON.Excavation=Wykopalisko -JSON.Fishing=Rybarz +JSON.Fishing=Rybak JSON.Herbalism=Zielarstwo JSON.Mining=G\u00f3rnictwo JSON.Repair=Naprawiacz @@ -29,7 +29,7 @@ JSON.Salvage=Odzyskiwacz JSON.Swords=Miecze JSON.Taming=Tresowanie JSON.Unarmed=Niezr\u0119czno\u015b\u0107 -JSON.Woodcutting=\u015acinacz Drzew +JSON.Woodcutting=Drwal JSON.URL.Website=Oficjalna strona mcMMO! JSON.URL.Discord=Oficjalny discord mcMMO! JSON.URL.Patreon=Wesprzyj nossr50 i jego projekt mcMMO na Patreon! @@ -88,7 +88,7 @@ Overhaul.Name.Alchemy=Alchemia Overhaul.Name.Archery=\u0141ucznictwo Overhaul.Name.Axes=Siekiery Overhaul.Name.Excavation=Wykopalisko -Overhaul.Name.Fishing=Rybarz +Overhaul.Name.Fishing=Rybak Overhaul.Name.Herbalism=Zielarstwo Overhaul.Name.Mining=G\u00f3rnictwo Overhaul.Name.Repair=Naprawiacz @@ -97,7 +97,7 @@ Overhaul.Name.Smelting=Przepalanie Overhaul.Name.Swords=Miecze Overhaul.Name.Taming=Tresowanie Overhaul.Name.Unarmed=Niezr\u0119czno\u015b\u0107 -Overhaul.Name.Woodcutting=\u015acinacz Drzew +Overhaul.Name.Woodcutting=Drwal # /mcMMO Command Style Stuff Commands.mcc.Header=&c---[]&amcMMO Komendy&c[]--- Commands.Other=&c---[]&aSPECJALNE KOMENDY&c[]--- @@ -112,7 +112,7 @@ XPBar.Alchemy=Alchemia Lv.&6{0} XPBar.Archery=\u0141ucznictwo Lv.&6{0} XPBar.Axes=Siekiery Lv.&6{0} XPBar.Excavation=Wykopalisko Lv.&6{0} -XPBar.Fishing=Rybarz Lv.&6{0} +XPBar.Fishing=Rybak Lv.&6{0} XPBar.Herbalism=Zielarstwo Lv.&6{0} XPBar.Mining=G\u00f3rnictwo Lv.&6{0} XPBar.Repair=Naprawiacz Lv.&6{0} @@ -121,7 +121,7 @@ XPBar.Smelting=Przepalanie Lv.&6{0} XPBar.Swords=Miecze Lv.&6{0} XPBar.Taming=Tresowanie Lv.&6{0} XPBar.Unarmed=Niezr\u0119czno\u015b\u0107 Lv.&6{0} -XPBar.Woodcutting=\u015acinacz Drzew Lv.&6{0} +XPBar.Woodcutting=Drwal Lv.&6{0} #This is just a preset template that gets used if the 'ExtraDetails' setting is turned on in experience.yml (off by default), you can ignore this template and just edit the strings above XPBar.Complex.Template={0} &3 {4}&f% &3(&f{1}&3/&f{2}&3) # XP BAR Allows for the following variables -- {0} = Skill Level, {1} Current XP, {2} XP Needed for next level, {3} Power Level, {4} Percentage of Level @@ -132,7 +132,7 @@ XPBar.Complex.Template={0} &3 {4}&f% &3(&f{1}&3/&f{2}&3) Acrobatics.Ability.Proc=&a**\u0141askawe L\u0105dowanie** Acrobatics.Combat.Proc=&a**Unik** Acrobatics.SubSkill.Roll.Stats=&6Szansa na &e{0}%&6 Szansa na \u0142\u0105ske&e {1}% -Acrobatics.SubSkill.Roll.Stat=Szansa na +Acrobatics.SubSkill.Roll.Stat=Szansa na Przewr\u00f3t Acrobatics.SubSkill.Roll.Stat.Extra=Szansa na \u0141agodny Przewr\u00f3t Acrobatics.SubSkill.Roll.Name=Przewr\u00f3t Acrobatics.SubSkill.Roll.Description=Wyl\u0105duj strategicznie, aby unikn\u0105\u0107 uszkodze\u0144. @@ -143,7 +143,7 @@ Acrobatics.SubSkill.GracefulRoll.Name=\u0141agodny przewr\u00f3t Acrobatics.SubSkill.GracefulRoll.Description=Podwaja efekt normalnego przewrotu. Acrobatics.SubSkill.Dodge.Name=Unik Acrobatics.SubSkill.Dodge.Description=Redukuje obra\u017cenia od ataku o po\u0142ow\u0119 -Acrobatics.SubSkill.Dodge.Stat=Szansa na unik +Acrobatics.SubSkill.Dodge.Stat=Szansa na Unik Acrobatics.Listener=Akrobatyka: Acrobatics.Roll.Text=&o**Przewr\u00f3t** Acrobatics.SkillName=AKROBATYKA @@ -267,7 +267,7 @@ Fishing.SkillName=W\u0118DKARSTWO #HERBALISM Herbalism.Ability.GTe.NeedMore=Potrzebujesz wi\u0119cej nasion, aby rozprzestrzeni\u0107 Zielona Tera. Herbalism.Ability.GTh.Fail=**ZIELONA TERA ZAWODZI** -Herbalism.Ability.GTh=&a**GREEN THUMB** +Herbalism.Ability.GTh=&a**ZIELONY L\u0104D** Herbalism.Ability.Lower=&7Opuszczasz swoj\u0105 motyk\u0119. Herbalism.Ability.Ready=&6Przygotowujesz&3 swoj\u0105 motyk\u0119. Herbalism.Ability.ShroomThumb.Fail=**HALUCYNKI ZAWODZ\u0104** @@ -304,22 +304,22 @@ Mining.Ability.Locked.0=ZABLOKOWANE DO {0}+ UMIEJ\u0118TNO\u015a\u0106 (PODMUCH Mining.Ability.Locked.1=ZABLOKOWANE DO {0}+ UMIEJ\u0118TNO\u015a\u0106 (WI\u0118KSZE BOMBY) Mining.Ability.Locked.2=ZABLOKOWANE DO {0}+ UMIEJ\u0118TNO\u015a\u0106 (EKSPERTYZY ROZBI\u00d3RKI) Mining.Ability.Lower=&7Opuszczasz sw\u00f3j kilof. -Mining.Ability.Ready=&3You &6ready&3 Tw\u00f3j kilof. +Mining.Ability.Ready=&6Przygotowujesz&3 sw\u00f3j kilof. Mining.SubSkill.SuperBreaker.Name=Super Niszczyciel Mining.SubSkill.SuperBreaker.Description=Pr\u0119dko\u015b\u0107+, Szansa na potr\u00f3jny \u0142up Mining.SubSkill.SuperBreaker.Stat=Trwanie: Super Niszczyciel Mining.SubSkill.DoubleDrops.Name=Podw\u00f3jny drop Mining.SubSkill.DoubleDrops.Description=Podwaja normalny \u0142up -Mining.SubSkill.DoubleDrops.Stat=Podw\u00f3jna szansa na upuszczenie +Mining.SubSkill.DoubleDrops.Stat=Podw\u00f3jna szansa na upuszczenie \u0142upu Mining.SubSkill.BlastMining.Name=Podmuch G\u00f3rnictwa Mining.SubSkill.BlastMining.Description=Premie do wydobywania z TNT -Mining.SubSkill.BlastMining.Stat=Blast Mining:&a Rank {0}/{1} &7({2}) -Mining.SubSkill.BlastMining.Stat.Extra=Blast Radius Increase: &a+{0} +Mining.SubSkill.BlastMining.Stat=Ranga Podmuchu G\u00f3rnictwa:&a {0}/{1} &7({2}) +Mining.SubSkill.BlastMining.Stat.Extra=Dodatkowy Zasi\u0119g Podmuchu G\u00f3rnictwa: &a+{0} Mining.SubSkill.BiggerBombs.Name=Wi\u0119ksze bomby Mining.SubSkill.BiggerBombs.Description=Zwi\u0119ksza promie\u0144 wybuchu -Mining.SubSkill.DemolitionsExpertise.Name=Ekspertyzy Rozbi\u00f3rki +Mining.SubSkill.DemolitionsExpertise.Name=Ekspertyza Rozbi\u00f3rki Mining.SubSkill.DemolitionsExpertise.Description=Zmniejsza obra\u017cenia zadawane TNT -Mining.SubSkill.DemolitionsExpertise.Stat=Zmniejszenie obra\u017ce\u0144 od eksperta od wyburze\u0144 +Mining.SubSkill.DemolitionsExpertise.Stat=Zmniejszenie obra\u017ce\u0144 od Eksperyza Rozbi\u00f3rki Mining.Listener=G\u00f3rnictwo: Mining.SkillName=G\u00d3RNICTWO Mining.Skills.SuperBreaker.Off=**Super Niszczyciel wy\u0142\u0105czy\u0142 si\u0119** @@ -405,7 +405,7 @@ Anvil.Unbreakable=Ten przedmiot jest niezniszczalny! #SWORDS Swords.Ability.Lower=&7Opuszczasz sw\u00f3j miecz. Swords.Ability.Ready=&6Przygotowujesz&3 sw\u00f3j miecz. -Swords.Combat.Rupture.Note=&7NOTATKA: &e1 P\u0119kni\u0119cie zdarza si\u0119 co 0,5 sekundy! +Swords.Combat.Rupture.Note=&7NOTATKA: &eP\u0119kni\u0119cie to okresowe obra\u017cenia, kt\u00f3re s\u0105 zadawane 2 razy na sekunde oraz omijaj\u0105 one zbroj\u0119! Swords.Combat.Bleeding.Started=&4 Krwawisz! Swords.Combat.Bleeding.Stopped=&7Krwawienie ju\u017c si\u0119 zatrzyma\u0142o&7! Swords.Combat.Bleeding=&a**PRZECIWNIK KRWAWI** @@ -427,7 +427,9 @@ Swords.SubSkill.SwordsLimitBreak.Name=Prze\u0142amywanie limit\u00f3w miecza Swords.SubSkill.SwordsLimitBreak.Description=Prze\u0142amywanie limit\u00f3w. Zwi\u0119kszone obra\u017cenia zadawane trudnym przeciwnikom. Przeznaczony dla PVP, zale\u017cnie od ustawie\u0144 serwera, czy zwi\u0119kszy obra\u017cenia w PVE, czy nie. Swords.SubSkill.SwordsLimitBreak.Stat=Prze\u0142amywanie limit\u00f3w max obra\u017ce\u0144 Swords.SubSkill.Rupture.Stat=Szansa na Rozerwanie -Swords.SubSkill.Rupture.Stat.Extra=Rozerwanie: &a{0} ticks [{1} DMG vs Gracz] [{2} DMG vs Moby] +Swords.SubSkill.Rupture.Stat.Extra=[[DARK_AQUA]]Czas Rozerwania: &a{0}s przeciwko Graczom, {1}s przeciwko Mobom. +Swords.SubSkill.Rupture.Stat.TickDamage=[[DARK_AQUA]]Obra\u017cenia Rozerwania na tik: &e{0}&a przeciwko Graczom, &e{1}&a przeciwko Mobom. +Swords.SubSkill.Rupture.Stat.ExplosionDamage=[[DARK_AQUA]]Obra\u017cenia eksplozji Rozerwania: &e{0}&a przeciwko Graczom, &e{1}&a przeciwko Mobom. Swords.Effect.4=Krwawienie+ z\u0105bkowane uderzenia Swords.Effect.5={0} Tick Rupture Swords.Listener=Miecze: @@ -547,8 +549,8 @@ Woodcutting.SubSkill.BarkSurgeon.Name=Chirurg Kory Woodcutting.SubSkill.BarkSurgeon.Description=Wydobywaj przydatne materia\u0142y podczas \u015bcinania drzew. Woodcutting.SubSkill.NaturesBounty.Name=Nagroda natury Woodcutting.SubSkill.NaturesBounty.Description=Zbieraj do\u015bwiadczenie z natury. -Woodcutting.Listener=\u015acinacz Drzew: -Woodcutting.SkillName=\u015aCINACZ DRZEW +Woodcutting.Listener=Drwal: +Woodcutting.SkillName=DRWAL Woodcutting.Skills.TreeFeller.Off=**\u015acinacz Drzew przesta\u0142 dzia\u0142a\u0107** Woodcutting.Skills.TreeFeller.On=&a**\u015aCINACZ DRZEW AKTYWOWANY** Woodcutting.Skills.TreeFeller.Refresh=&aTwoja umiej\u0119tno\u015b\u015b &e\u015acinacz Drzew &azosta\u0142a od\u015bwie\u017cona! @@ -822,7 +824,7 @@ Party.ItemShare.Category.Herbalism=Tresowanie Party.ItemShare.Category.Woodcutting=\u015acinanie Drzew Party.ItemShare.Category.Misc=R\u00f3\u017cne ##xp -Commands.XPGain.Acrobatics=Spadanie +Commands.XPGain.Acrobatics=Spadanie z wysoko\u015bci Commands.XPGain.Alchemy=Warzenie Mikstur Commands.XPGain.Archery=Atakowanie potwor\u00f3w Commands.XPGain.Axes=Atakowanie potwor\u00f3w @@ -831,7 +833,7 @@ Commands.XPGain.Excavation=Kopanie i znajdowanie skarb\u00f3w Commands.XPGain.Fishing=\u0141owienie Commands.XPGain.Herbalism=Zbieranie zi\u00f3\u0142 Commands.XPGain.Mining=Kopanie kamienia & rud -Commands.XPGain.Repair=Naprawa +Commands.XPGain.Repair=Naprawa u\u017cywaj\u0105c specjalnego kowad\u0142a Commands.XPGain.Swords=Atakowanie potwor\u00f3w Commands.XPGain.Taming=Rozmna\u017canie zwierz\u0105t, albo walka w/ z twoimi psami Commands.XPGain.Unarmed=Atakowanie potwor\u00f3w @@ -872,88 +874,88 @@ Guides.Page.OutOfRange=Ta strona nie istnieje, jest/s\u0105 tylko {0} stron/a/y. Guides.Usage= Prawod\u0142owe u\u017cycie to /{0} ? [strona] ##Acrobatics Guides.Acrobatics.Section.0=&3O Akrobatyce:\n&eakrobatyka to sztuka poruszania si\u0119 z wdzi\u0119kiem w mcMMO.\n&eZapewnia premie bojowe i premie do obra\u017ce\u0144 otoczenia.\n\n&3ZDOBYWANIE XP:\n&eAby zdoby\u0107 PD w tej umiej\u0119tno\u015bci, musisz wykona\u0107 unik\n&ew walce lub przetrwa\u0107 upadki z wysoko\u015bci, kt\u00f3re ci\u0119 rani\u0105. -Guides.Acrobatics.Section.1=&3How does Rolling work?\n&eYou have a passive chance when you take fall damage\n&eto negate the damage done. You can hold the sneak button to\n&edouble your chances during the fall.\n&eThis triggers a Graceful Roll instead of a standard one.\n&eGraceful Rolls are like regular rolls but are twice as likely to\n&eoccur and provide more damage safety than regular rolls.\n&eRolling chance is tied to your skill level -Guides.Acrobatics.Section.2=&3How does Dodge work?\n&eDodge is a passive chance when you are\n&einjured in combat to halve the damage taken.\n&eIt is tied to your skill level. +Guides.Acrobatics.Section.1=&3Jak dzia\u0142a Przewr\u00f3t??\n&eMasz pasywn\u0105 szans\u0119, gdy odniesiesz obra\u017cenia od upadku, aby zneutralizowa\u0107 zadane obra\u017cenia. Mo\u017cesz przytrzyma\u0107 przycisk skradania si\u0119, aby podwoi\u0107 swoje szanse podczas upadku. To wyzwala \u014agodny Przwr\u00f3t zamiast standardowego. \u0141agodne Przewroty s\u0105 jak zwyk\u0142e, ale prawdopodobie\u0144stwo wyst\u0105pienia Przewrotu jest dwukrotnie wi\u0119ksze i zapewnia wi\u0119ksze bezpiecze\u0144stwo obra\u017ce\u0144 ni\u017c zwyk\u0142e Przewroty.\n&eSzansa na przewr\u00f3t zale\u017cy od poziomu Twojej umiej\u0119tno\u015bci. +Guides.Acrobatics.Section.2=&3Jak dzia\u0142a unik?\n&eUnik to pasywna szansa na zmniejszenie o po\u0142ow\u0119 otrzymywanych obra\u017ce\u0144, gdy odniesiesz obra\u017cenia w walce. Jest to powi\u0105zane z Twoim poziomem umiej\u0119tno\u015bci. ##Alchemy Guides.Alchemy.Section.0=&3O Alchemi:\n&eAlchemia polega na warzeniu mikstur.\n&eZapewnia przyspieszenie czasu warzenia mikstury,\n&ea tak\u017ce dodanie nowych (wcze\u015bniej) nieosi\u0105galnych mikstur. \n\n\n&3ZDOBYWANIE XP:\n&eAby zdoby\u0107 XP tej umiej\u0119tno\u015bci, musisz warzy\u0107 mikstury. -Guides.Alchemy.Section.1=&3How does Catalysis work?\n&eCatalysis speeds of the brewing process, with a\n&emax speed of 4x at level 1000.\n&eThis ability is unlocked at level 100 by default. -Guides.Alchemy.Section.2=&3How does Concoctions work?\n&eConcoctions allows brewing of more potions with custom ingredients.\n&eWhich special ingredients are unlocked is determined\n&eby your Rank. There are 8 ranks to unlock. -Guides.Alchemy.Section.3=&3Concoctions tier 1 ingredients:\n&eBlaze Powder, Fermented Spider Eye, Ghast Tear, Redstone,\n&eGlowstone Dust, Sugar, Glistering Melon, Golden Carrot,\n&eMagma Cream, Nether Wart, Spider Eye, Suplhur, Water Lily,\n&ePufferfish\n&e(Vanilla Potions) -Guides.Alchemy.Section.4=&3Concoctions tier 2 ingredients:\n&eCarrot (Potion of Haste)\n&eSlimeball (Potion of Dullness)\n\n&3Concoctions tier 3 ingredients:\n&eQuartz (Potion of Absorption)\n&eRed Mushroom (Potion of Leaping) -Guides.Alchemy.Section.5=&3Concoctions tier 4 ingredients:\n&eApple (Potion of Health Boost)\n&eRotten Flesh (Potion of Hunger)\n\n&3Concoctions tier 5 ingredients:\n&eBrown Mushroom (Potion of Nausea)\n&eInk Sack (Potion of Blindness) -Guides.Alchemy.Section.6=&3Concoctions tier 6 ingredients:\n&eFern (Potion of Saturation)\n\n&3Concoctions tier 7 ingredients:\n&ePoisonous Potato (Potion of Decay)\n\n&3Concoctions tier 8 ingredients:\n&eRegular Golden Apple (Potion of Resistance) +Guides.Alchemy.Section.1=&3Jak dzia\u0142a Kataliza?\n&eSzybko\u015b\u0107 katalizy procesu warzenia, z maksymaln\u0105 pr\u0119dko\u015bci\u0105 4x na poziomie 1000. Ta umiej\u0119tno\u015b\u0107 jest domy\u015blnie odblokowywana na poziomie 100. +Guides.Alchemy.Section.2=&3Jak dzia\u0142aj\u0105 Mikstury?\n&eMikstury pozwalaj\u0105 na warzenie wi\u0119kszej liczby mikstur z niestandardowych sk\u0142adnik\u00f3w. To, kt\u00f3re specjalne sk\u0142adniki zostan\u0105 odblokowane, zale\u017cy od Twojej rangi. Do odblokowania jest 8 stopni. +Guides.Alchemy.Section.3=&3Sk\u0142adniki mikstur tieru 1:\n&eP\u0142omienny Proszek, Fermentowane Oko Paj\u0105ka, \u0141za Ghasta, Redstone,\n&eJasnopy\u0142, Cukier, Poz\u0142acany Arbuz, Z\u0142ota Marchewka,\n&eMagmowy Krem, Brodawka, Oko Paj\u0105ka, Proch, Lilia Wodna,\n&eRozdymka\n&e(Mikstury Wanilla) +Guides.Alchemy.Section.4=&3Sk\u0142adniki mikstur tieru 2:\n&eMarchwka (Miktura Szybko\u015bci)\n&eKulka Szlamu (Miktura Ot\u0119pienia)\n\n&3Sk\u0142adniki mikstur tieru 3:\n&eKwarc (Miksutra Absorpcji)\n&eMuchomor (Mikstura Skoku) +Guides.Alchemy.Section.5=&3Sk\u0142adniki mikstur tieru 4:\n&eJab\u0142ko (Mikstura boostu zdrowia)\n&eZgni\u0142e Mi\u0119so (PMiksutra G\u0142odu)\n\n&3Sk\u0142adniki mikstur tieru 5:\n&eBr\u0105zowy Grzyb (Mikstura Md\u0142o\u015bci)\n&eAtrament (Mikstura O\u015blepienia) +Guides.Alchemy.Section.6=&3Sk\u0142adniki mikstur tieru 6:\n&ePapro\u0107 (Mikstura Nasycenia)\n\n&3Sk\u0142adniki mikstur tieru 7:\n&eZatruty Ziemniak (Mikstura Rozk\u0142adu)\n\n&3Sk\u0142adniki mikstur tieru 8:\n&eZ\u0142ote Jab\u0142ko (Mikstura Odporno\u015bci) ##Archery Guides.Archery.Section.0=&3O \u0141ucznictwie:\n&e\u0141ucznictwo polega na strzelaniu z \u0142uku strza\u0142.\n&eZapewnia r\u00f3\u017cne bonusy bojowe, takie jak zwi\u0119kszenie obra\u017ce\u0144,\n&ekt\u00f3re skaluje si\u0119 z twoim poziomem i daje mo\u017cliwo\u015b\u0107 oszo\u0142omienia\n&eprzeciwnik\u00f3w w PvP. W dodatku mo\u017cesz odzyska\u0107\n&ecz\u0119\u015b\u0107 strza\u0142 z martwych wrog\u00f3w.\n\n\n&3ZDOBYWANIE XP:\n&eAby zdoby\u0107 XP w tej umiej\u0119tno\u015bci, musisz strzela\u0107 do mob\u00f3w lub\n&edo innych graczy. -Guides.Archery.Section.1=&3How does Skill Shot work?\n&eSkill Shot provides additional damage to your shots.\n&eThe bonus damage from Skill Shot increases as you\n&elevel in Archery.\n&eWith the default settings, your archery damage increases 10%\n&eevery 50 levels, to a maximum of 200% bonus damage. -Guides.Archery.Section.2=&3How does Daze work?\n&eYou have a passive chance to daze other players when\n&eyou shoot them. When Daze triggers it forces your opponents\n&eto look straight up for a short duration.\n&eA Daze shot also deals an additional 4 damage (2 hearts). -Guides.Archery.Section.3=&3How does Arrow Retrieval work?\n&eYou have a passive chance to retrieve some of your arrows\n&ewhen you kill a mob with your bow.\n&eThis chance increases as you level in Archery.\n&eBy default, this ability increases by 0.1% per level, up to 100%\n&eat level 1000. +Guides.Archery.Section.1=&3Jak dzia\u0142a Umiej\u0119tne Strzelanie??\n&eUmiej\u0119tne strzelanie zapewnia dodatkowe obra\u017cenia strza\u0142om.\n&eDodatkowe obra\u017cenia rosn\u0105 wraz z poziomem \u0141ucznictwa.\n&ePrzy domy\u015blnych ustawieniach twoje obra\u017cenia zwi\u0119kszaj\u0105 si\u0119 o 10% co 50 poziom\u00f3w, do maksymalnie 200% dodatkowych obra\u017ce\u0144. +Guides.Archery.Section.2=&3Jak dzia\u0142a Oszo\u0142omienie?\n&eMasz pasywn\u0105 szans\u0119 oszo\u0142omienia innych graczy, gdy do nich strzelasz. Aktywacja Oszo\u0142omienia zmusza przeciwnik\u00f3w do patrzenia prosto w g\u00f3r\u0119 przez kr\u00f3tki czas. Strza\u0142a oszo\u0142omiaj\u0105ca zadaje dodatkowe 4 obra\u017cenia (2 serca). +Guides.Archery.Section.3=&3Jak dzia\u0142a Odzyskiwanie Strza\u0142?\n&eMasz pasywn\u0105 szans\u0119 na odzyskanie niekt\u00f3rych strza\u0142, gdy zabijesz \u0142ukiem. Ta szansa ro\u015bnie wraz ze zdobywaniem kolejnych poziom\u00f3w w \u0141ucznictwie. Domy\u015blnie zdolno\u015b\u0107 ta ro\u015bnie o 0,1% na poziom, do 100% na poziomie 1000. ##Axes -Guides.Axes.Section.0=&3About Axes:\n&eZ umiej\u0119tno\u015bci\u0105 Topory mo\u017cesz zrobi\u0107 co\u015b wi\u0119cej\n&eni\u017c niszczy\u0107 lasy! Mo\u017cesz hakowa\u0107 i sieka\u0107 moby\n&ei graczy, aby zdobywa\u0107 XP, musisz atakowa\u0107 moby siekier\u0105 z efektem\n&eodrzucenie i zada\u0107 \u015bmiertelny cios.\n&eTw\u00f3j top\u00f3r r\u00f3wnie\u017c staje si\u0119 r\u0119cznym r\u0119bakiem,\n&eponiewa\u017c bardzo obni\u017casz poziom zbroi\n&przeciwnika wraz z poziomiem umiej\u0119tno\u015bci.\n&3ZDOBYWANIE XP:\n&eAby zdobywa\u0107 XP musisz atakowa\u0107 moby\n&elub graczy siekier\u0105. -Guides.Axes.Section.1=&3How does Skull Splitter work?\n&eThis ability allows you to deal an AoE (Area of Effect) hit.\n&eThis AoE hit will deal half as much damage as you did to the\n&emain target, so it's great for clearing out large piles of mobs. -Guides.Axes.Section.2=&3How does Critical Strikes work?\n&eCritical Strikes is a passive ability which gives players a\n&echance to deal additional damage.\n&eWith the default settings, every 2 skill levels in Axes awards a\n&e0.1% chance to deal a Critical Strike, causing 2.0 times damage\n&eto mobs or 1.5 times damage against other players. -Guides.Axes.Section.3=&3How does Axe Mastery work?\n&eAxe Mastery is a passive ability that will add additional damage\n&eto your hits when using Axes.\n&eBy default, the bonus damage increases by 1 every 50 levels,\n&eup to a cap of 4 extra damage at level 200. -Guides.Axes.Section.4=&3How does Armor Impact work?\n&eStrike with enough force to shatter armor!\n&eArmor Impact has a passive chance to damage your\n&eopponent's armor. This damage increases as you level in Axes. -Guides.Axes.Section.5=&3How does Greater Impact work?\n&eYou have a passive chance to achieve a greater impact when\n&ehitting mobs or players with your axe.\n&eBy default this chance is 25%. This passive ability has an\n&eextreme knockback effect, similar to the Knockback II\n&eenchantment. In addition, it deals bonus damage to the target. +Guides.Axes.Section.0=&3O Siekierach:\n&eZ umiej\u0119tno\u015bci\u0105 Topory mo\u017cesz zrobi\u0107 co\u015b wi\u0119cej\n&eni\u017c niszczy\u0107 lasy! Mo\u017cesz hakowa\u0107 i sieka\u0107 moby\n&ei graczy, aby zdobywa\u0107 XP, musisz atakowa\u0107 moby siekier\u0105 z efektem\n&eodrzucenie i zada\u0107 \u015bmiertelny cios.\n&eTw\u00f3j top\u00f3r r\u00f3wnie\u017c staje si\u0119 r\u0119cznym r\u0119bakiem,\n&eponiewa\u017c bardzo obni\u017casz poziom zbroi\n&eprzeciwnikom wraz z poziomiem umiej\u0119tno\u015bci.\n&3ZDOBYWANIE XP:\n&eAby zdobywa\u0107 XP musisz atakowa\u0107 moby\n&elub graczy siekier\u0105. +Guides.Axes.Section.1=&3Jak dzia\u0142a Przecinacz Czaszek?\n&eTa umiej\u0119tno\u015b\u0107 pozwala Ci zada\u0107 obra\u017cenia AoE (Obszarowe). Obra\u017cenia obszarowe zadaj\u0105 po\u0142ow\u0119 Twoich obra\u017ce\u0144, co czyni je dobrym sposobem do zabijania grup mob\u00f3w. +Guides.Axes.Section.2=&3Jak dzia\u0142a Trafienie Krytyczne?\n&eTrafienia krytyczne jest to pasywna umiej\u0119tno\u015b\u0107, kt\u00f3ra daje Ci mo\u017cliwo\u015b\u0107 zadania dodatkowych obra\u017ce\u0144. Przy domy\u015blnych ustawieniach co 2 poziom umiej\u0119tno\u015bci daje Ci 0.1% szansy na trafienie krytyczne, kt\u00f3re zadaje 2x mobom lub 1.5x przeciwko graczom. +Guides.Axes.Section.3=&3Jak dzia\u0142a Mistrz Siekier?\n&eJest to umiej\u0119tno\u015b\u0107 pasywna, kt\u00f3ra daje Ci mo\u017cliwo\u015b\u0107 zadania dodatkowych obra\u017ce\u0144 przy u\u017cyciu toporka. Obra\u017cenia zwi\u0119kszaj\u0105 si\u0119 o 1 co 50 poziom\u00f3w, do maksymalnie 4 obra\u017ce\u0144 na poziomie 200. +Guides.Axes.Section.4=&3Jak dzia\u0142a Uderzenie Pancerza?\n&eUderz z wystarczaj\u0105c\u0105 si\u0142\u0105, aby rozbi\u0107 zbroj\u0119! Uderzenie Pancerza posiada pasywn\u0105 umiej\u0119tno\u015b\u0107, kt\u00f3ra mo\u017ce uszkodzi\u0107 pancerz Twojego przeciwnika. Obra\u017cenia te s\u0105 zwi\u0119kszanie wraz z poziomem Siekiery. +Guides.Axes.Section.5=&3Jak dzia\u0142a Wi\u0119kszy Wp\u0142yw?\n&eZ ka\u017cdym uderzeniem masz coraz wi\u0119ksz\u0105 szanse na aktywacje Wi\u0119kszy Wp\u0142yw, gdy uderzasz gracza lub moba skiekier\u0105. Domy\u015blna szansa wynosi 25%. Pasywna umiej\u0119tno\u015b\u0107 posiada extremalny efekt odrzutu, podobny do Odrzutu II, jednak\u017ce zadaje ona wi\u0119cej obra\u017ce\u0144\n&eenchantment. Ponadto zadaje dodatkowe obra\u017cenia celowi. ##Excavation -Guides.Excavation.Section.0=&3About Excavation:\n&eExcavation is the act of digging up dirt to find treasures.\n&eBy excavating the land you will find treasures.\n&eThe more you do this the more treasures you can find.\n\n&3XP GAIN:\n&eTo gain XP in this skill you must dig with a shovel in hand.\n&eOnly certain materials can be dug up for treasures and XP. -Guides.Excavation.Section.1=&3Compatible Materials:\n&eGrass, Dirt, Sand, Clay, Gravel, Mycelium, Soul Sand, Snow -Guides.Excavation.Section.2=&3How to use Giga Drill Breaker:\n&eWith a shovel in hand right click to ready your tool.\n&eOnce in this state you have about 4 seconds to make\n&econtact with Excavation compatible materials this will\n&eactivate Giga Drill Breaker. -Guides.Excavation.Section.3=&3What is Giga Drill Breaker?\n&eGiga Drill Breaker is an ability with a cooldown\n&etied to Excavation skill. It triples your chance\n&eof finding treasures and enables instant break\n&eon Excavation materials. -Guides.Excavation.Section.4=&3How does Archaeology work?\n&eEvery possible treasure for Excavation has its own\n&eskill level requirement for it to drop, as a result it's\n&edifficult to say how much it is helping you.\n&eJust keep in mind that the higher your Excavation skill\n&eis, the more treasures that can be found.\n&eAnd also keep in mind that each type of Excavation\n&ecompatible material has its own unique list of treasures.\n&eIn other words you will find different treasures in Dirt\nðan you would in Gravel. -Guides.Excavation.Section.5=&3Notes about Excavation:\n&eExcavation drops are completely customizeable\n&eSo results vary server to server. +Guides.Excavation.Section.0=&3O Wykopalisku:\n&eWykopaliska to czynno\u015b\u0107 polegaj\u0105ca na wykopywaniu ziemi w celu znalezienia skarb\u00f3w..\n&eIm wi\u0119cej b\u0119dziesz kopa\u0107, tym wi\u0119cej znajdziesz skarb\u00f3w.\n\n&3ZDOBYWANIE XP:\n&eAby zdoby\u0107 XP w tej umiej\u0119tno\u015bci nale\u017cy kopa\u0107 \u0142opat\u0105. Tylko niekt\u00f3re rzeczy mo\u017cna wykopa\u0107, aby zdoby\u0107 skarby i EXP. Aby przygotowa\u0107 narz\u0119dzie wci\u015bnij prawy przycisk myszy z \u0142opat\u0105 w d\u0142oni. +Guides.Excavation.Section.1=&3Kompatybilne Materia\u0142y:\n&eTrawa, Ziemia, Piasek, Glina, \u017bwir, Mycelinium, Piasek Dusz, \u015anieg +Guides.Excavation.Section.2=&3Jak u\u017cy\u0107 Giga Wiert\u0142o:\n&eKliknij prawy przycisk z \u0142opat\u0105 w r\u0119ce, aby aktywowa\u0107 Giga Wiert\u0142o.\n&eGdy znajdziesz si\u0119 w tym stanie, masz oko\u0142o 4 sekund na kontakt z materia\u0142ami kompatybilnymi z Wykopalisko, aktywuje to Giga Wiert\u0142o. +Guides.Excavation.Section.3=&3Co to Giga Wiert\u0142o?\n&eGiga Wiert\u0142o to umiej\u0119tno\u015b\u0107 posiadaj\u0105ca czas odnowienia. Daje Ci potr\u00f3jn\u0105 szans\u0119 na znalezienie skarb\u00f3w oraz umo\u017cliwia natychmiastowe kopanie. +Guides.Excavation.Section.4=&3Jak dzia\u0142a Archeologia?\n&eKa\u017cdy skarb posiada sw\u00f3j wymagany poziom, dlatego otrzymujesz skarb w zale\u017clo\u015bci od Twojego poziomu umiej\u0119tno\u015bci. Pami\u0119taj im wy\u017cszy jest Tw\u00f3j poziom umiej\u0119tno\u015bci, tym wi\u0119cej skarb\u00f3w mo\u017cesz znale\u017a\u0107. Ka\u017cdy skarb, wykopywany z r\u00f3\u017cnych materia\u0142\u00f3w posiada swoj\u0105 unikalna list\u0119 przedmiot\u00f3w, kt\u00f3re si\u0119 w nim znajduj\u0105. Inny skarb otrzymasz z bruku, a zupe\u0142nie inny ze \u017cwiru. +Guides.Excavation.Section.5=&3Notatki o Wykopaliskach:\n&ePrzedmioty z wykopalisk s\u0105 w pe\u0142ni konfigurowalne, tak wi\u0119c wyniki r\u00f3\u017cni\u0105 si\u0119 mi\u0119dzy serwerami. ##Fishing -Guides.Fishing.Section.0=&3About Fishing:\n&eWith the Fishing skill, Fishing is exciting again!\n&eFind hidden treasures, and shake items off mobs.\n\n&3XP GAIN:\n&eCatch fish. -Guides.Fishing.Section.1=&3How does Treasure Hunter work?\n&eThis ability allows you to find treasure from fishing \n&ewith a small chance of the items being enchanted.\n&eEvery possible treasure for Fishing has a chance\n&eto drop on any level. It depends however\n&ewhat the rarity of the item is how often it will drop.\n&eThe higher your Fishing skill is, the better\n&eyour chances are to find better treasures. -Guides.Fishing.Section.2=&3How does Ice Fishing work?\n&eThis passive skill allows you to fish in ice lakes!\n&eCast your fishing rod in an ice lake and the ability will\n&ecreate a small hole in the ice to fish in. -Guides.Fishing.Section.3=&3How does Master Angler work?\n&eThis passive skill increases the bite chance while fishing.\n&eWhen you've unlocked this ability, fishing while in\n&ea boat improves odds of catching a fish. -Guides.Fishing.Section.4=&3How does Shake work?\n&eThis active ability allows you to shake items loose from mobs\n&eby hooking them with the fishing rod. \n&eMobs will drop items they would normally drop on death.\n&eIt is also possible to acquire mob skulls, which are normally \n&eunobtainable in survival mode. -Guides.Fishing.Section.5=&3How does Fisherman's Diet work?\n&eThis passive skill increases the amount of hunger restored \n&efrom eating fish. -Guides.Fishing.Section.6=&3Notes about Fishing:\n&eFishing drops are completely customizable,\n&eso results vary server to server. +Guides.Fishing.Section.0=&3O W\u0119dkarstwie:\n&eDzi\u0119ki umiej\u0119tno\u015bci W\u0119dkarstwo, w\u0119dkarstwo zn\u00f3w jest ekscytuj\u0105ce! Znajd\u017a ukryte skarby i strz\u0105\u015bnij przedmioty z mob\u00f3w.\n\n&3ZDOBYWANIE XP:\n&e\u0141owienie ryb. +Guides.Fishing.Section.1=&3Jak dzia\u0142a \u0141owca Skarb\u00f3w?\n&eTa umiej\u0119tno\u015b\u0107 pozwala ci znale\u017a\u0107 skarb z \u0142owienia z niewielk\u0105 szans\u0105 na zakl\u0119cie przedmiot\u00f3w. Ka\u017cdy mo\u017cliwy skarb dla w\u0119dkarzy ma szans\u0119 spa\u015b\u0107 na dowolnym poziomie. Zale\u017cy to jednak od rzadko\u015bci przedmiotu, jak cz\u0119sto b\u0119dzie on wypada\u0142. Im wy\u017cszy poziom umiej\u0119tno\u015bci \u0141owienie ryb, tym wi\u0119ksze masz szanse na znalezienie lepszych skarb\u00f3w. +Guides.Fishing.Section.2=&3Jak dzia\u0142aj\u0105 Mro\u017ane Po\u0142owy?\n&eTa umiej\u0119tno\u015b\u0107 pasywna pozwala \u0142owi\u0107 ryby w lodowych jeziorach! Wrzu\u0107 w\u0119dk\u0119 do lodowego jeziora, a stworzysz w lodzie ma\u0142\u0105 dziur\u0119 do \u0142owienia. +Guides.Fishing.Section.3=&3Jak dzia\u0142a Mistrz W\u0119dkarstwa?\n&eTa umiej\u0119tno\u015b\u0107 pasywna zwi\u0119ksza szans\u0119 brania podczas \u0142owienia. Po odblokowaniu tej umiej\u0119tno\u015bci \u0142owienie na \u0142odzi zwi\u0119ksza szanse na z\u0142owienie ryby. +Guides.Fishing.Section.4=&3Jak dzia\u0142a Potrz\u0105sanie?\n&eTa aktywna umiej\u0119tno\u015b\u0107 pozwala strz\u0105sa\u0107 przedmioty z mob\u00f3w poprzez zaczepienie ich w\u0119dk\u0105. Moby upuszczaj\u0105 przedmioty, kt\u00f3re normalnie upuszczaj\u0105 po \u015bmierci. Mo\u017cliwe jest r\u00f3wnie\u017c zdobycie czaszek mob\u00f3w, kt\u00f3re normalnie s\u0105 nieosi\u0105galne w trybie przetrwania. +Guides.Fishing.Section.5=&3Jak dzia\u0142a Dieta Rybaka?\n&eTa umiej\u0119tno\u015b\u0107 pasywna zwi\u0119ksza ilo\u015b\u0107 przywracanego g\u0142odu po jedzeniu ryby. +Guides.Fishing.Section.6=&3Notatki o W\u0119dkarstwie:\n&ePrzedmioty z \u0142owienia s\u0105 w pe\u0142ni konfigurowalne, tak wi\u0119c wyniki r\u00f3\u017cni\u0105 si\u0119 mi\u0119dzy serwerami. ##Herbalism -Guides.Herbalism.Section.0=&3About Herbalism:\n&eHerbalism is about collecting herbs and plants.\n\n\n&3XP GAIN:\n&eCollect plants and herbs. -Guides.Herbalism.Section.1=&3Compatible Blocks\n&eWheat, Potatoes, Carrots, Melons, \n&ePumpkins, Sugar Canes, Cocoa Beans, Flowers, Cacti, Mushrooms,\n&eNether Wart, Lily Pads, and Vines. -Guides.Herbalism.Section.2=&3How does Green Terra work?\n&eGreen Terra is an active ability, you can right-click\n&ewhile holding a hoe to activate Green Terra.\n&eGreen Terra grants players a chance to get 3x drops from\n&eharvesting plants. It also gives players the ability to\n&espread life into blocks and transform them using seeds\n&efrom your inventory. -Guides.Herbalism.Section.3=&3How does Green Thumb (Crops) work?\n&eThis passive ability will automatically replant crops when\n&eharvesting.\n&eYour chance of success depends on your Herbalism skill. -Guides.Herbalism.Section.4=&3How does Green Thumb (Cobble/Stone Brick/Dirt) work?\n&eThis active ability allows you to turn blocks into their\n&e"plant-related" counterparts. You can do this by right-clicking\n&ea block, while holding seeds. This will consume 1 seed. -Guides.Herbalism.Section.5=&3How does Farmer's Diet work?\n&eThis passive skill increases the amount of hunger restored \n&ewhen eating Bread, Cookies, Melons, Mushroom Soup, Carrots,\n&eand Potatoes. -Guides.Herbalism.Section.6=&3How does Hylian Luck work?\n&eThis passive ability gives you a chance to find rare items\n&ewhen certain blocks are broken with a sword. -Guides.Herbalism.Section.7=&3How do Double Drops work?\n&eThis passive ability gives players more yield from their\n&eharvests. +Guides.Herbalism.Section.0=&3O Zielarstwie:\n&eZielarstwo polega na zbieraniu zi\u00f3\u0142 i ro\u015blin.\n\n\n&3ZDOBYWANIE XP:\n&eZbieraj ro\u015bliny i zio\u0142a. +Guides.Herbalism.Section.1=&3Kompatybilne ro\u015bliny:\n&eSiano, Ziemniaki, Marchewki, Arbuzy, \n&eDynie, Trzcina Cukrowa, Kakao, Kwiaty, Kaktusy, Grzyby,\n&eBrodawka, Lilie Wodne, i Liany. +Guides.Herbalism.Section.2=&3Jak dzia\u0142a Zielona Terra?\n&eZielona Terra to umiej\u0119tno\u015b\u0107 aktywna, mo\u017cesz przytrzyma\u0107 motyk\u0119 prawym przyciskiem myszy, aby aktywowa\u0107 Zielon\u0105 Terr\u0119. Zielona Terra daje graczom szans\u0119 na zdobycie 3x przedmiot\u00f3w ze zbioru ro\u015blin. Daje tak\u017ce graczom mo\u017cliwo\u015b\u0107 dzielenia \u017cycia na bloki i przekszta\u0142cania ich za pomoc\u0105 nasion z ekwipunku. +Guides.Herbalism.Section.3=&3Jak dzia\u0142a Zielona R\u0105czka (Nasiona)?\n&eTa pasywna umiej\u0119tno\u015b\u0107 automatycznie przesadza plony podczas zbioru. Twoja szansa na sukces zale\u017cy od umiej\u0119tno\u015bci zielarstwa. +Guides.Herbalism.Section.4=&3Jak dzia\u0142a Zielona R\u0105czka (Bruk/Kamienne Ceg\u0142y/Ziemia)?\n&eTa aktywna zdolno\u015b\u0107 pozwala zamieni\u0107 bloki w ich odpowiedniki „zwi\u0105zane z ro\u015blinami”. Mo\u017cesz to zrobi\u0107, klikaj\u0105c prawym przyciskiem myszy blok, trzymaj\u0105c jednocze\u015bnie nasiona. To poch\u0142onie 1 ziarno. +Guides.Herbalism.Section.5=&3Jak dzia\u0142a Dieta Farmera?\n&eTa umiej\u0119tno\u015b\u0107 pasywna zwi\u0119ksza ilo\u015b\u0107 przywracanego g\u0142odu podczas jedzenia chleba, ciastek, arbuz\u00f3w, zupy grzybowej, marchwi i ziemniak\u00f3w. +Guides.Herbalism.Section.6=&3Jak dzia\u0142a Wielkie Szcz\u0119\u015bcie?\n&eTa pasywna umiej\u0119tno\u015b\u0107 daje ci szans\u0119 na znalezienie rzadkich przedmiot\u00f3w, gdy niekt\u00f3re bloki zostan\u0105 rozbite mieczem. +Guides.Herbalism.Section.7=&3Jak dzia\u0142a Podw\u00f3jny \u0141up?\n&eTa pasywna umiej\u0119tno\u015b\u0107 zapewnia graczom wi\u0119ksze plony. ##Mining -Guides.Mining.Section.0=&3About Mining:\n&eMining consists of mining stone and ores. It provides bonuses\n&eto the amount of materials dropped while mining.\n\n&3XP GAIN:\n&eTo gain XP in this skill, you must mine with a pickaxe in hand.\n&eOnly certain blocks award XP. -Guides.Mining.Section.1=&3Compatible Materials:\n&eStone, Coal Ore, Iron Ore, Gold Ore, Diamond Ore, Redstone Ore,\n&eLapis Ore, Obsidian, Mossy Cobblestone, Ender Stone,\n&eGlowstone, and Netherrack. -Guides.Mining.Section.2=&3How to use Super Breaker:\n&eWith a pickaxe in your hand, right click to ready your tool.\n&eOnce in this state, you have about 4 seconds to make contact\n&ewith Mining compatible materials, which will activate Super\n&eBreaker. -Guides.Mining.Section.3=&3What is Super Breaker?\n&eSuper Breaker is an ability with a cooldown tied to the Mining\n&eskill. It triples your chance of extra items dropping and\n&eenables instant break on Mining materials. -Guides.Mining.Section.4=&3How to use Blast Mining:\n&eWith a pickaxe in hand,\n&ecrouch and right-click on TNT from a distance. This will cause the TNT\n&eto instantly explode. -Guides.Mining.Section.5=&3How does Blast Mining work?\n&eBlast Mining is an ability with a cooldown tied to the Mining\n&eskill. It gives bonuses when mining with TNT and allows you\n&eto remote detonate TNT. There are three parts to Blast Mining.\n&eThe first part is Bigger Bombs, which increases blast radius.\n&eThe second is Demolitions Expert, which decreases damage\n&efrom TNT explosions. The third part simply increases the\n&eamount of ores dropped from TNT and decreases the\n&edebris dropped. +Guides.Mining.Section.0=&3O G\u00f3rnictwie:\n&eG\u00f3rnictwo obejmuje wydobywanie kamienia i rud. Zapewnia bonusy do ilo\u015bci upuszczanych materia\u0142\u00f3w podczas wydobywania.\n\n&3ZDOBYWANIE XP:\n&eAby zdoby\u0107 XP w tej umiej\u0119tno\u015bci, musisz kopa\u0107 z kilofem w d\u0142oni. Tylko niekt\u00f3re bloki zapewniaj\u0105 XP . +Guides.Mining.Section.1=&3Kompatybilne Minera\u0142y:\n&eKamie\u0144, Ruda W\u0119gla, Ruda \u017belaza, Ruda Z\u0142ota, Ruda Diamentu, Ruda Redstone,\n&eRuda Lapisu, Obsydian, Zamszony Bruk, Kamie\u0144 Endu,\n&eJasnog\u0142az, i Netherrack. +Guides.Mining.Section.2=&3Jak u\u017cy\u0107 Super Niszczyciela:\n&eKliknij prawy przycisk z kilofem w r\u0119ce, aby aktywowa\u0107 Super Niszczyciel.\n&eGdy znajdziesz si\u0119 w tym stanie, masz oko\u0142o 4 sekund na kontakt z materia\u0142ami kompatybilnymi z Wykopalisko, aktywuje to Super Niszczyciel. +Guides.Mining.Section.3=&3Co to Super Niszczyciel?\n&eSuper Niszczyciel to umiej\u0119tno\u015b\u0107, kt\u00f3rej czas odnowienia jest powi\u0105zany z umiej\u0119tno\u015bci\u0105 G\u00f3rnictwo. Potroi szans\u0119 na upuszczenie dodatkowych przedmiot\u00f3w i umo\u017cliwia natychmiastowe niszczenie przy wydobywaniu materia\u0142\u00f3w. +Guides.Mining.Section.4=&3Jak u\u017cy\u0107 Podm\u00f3ch G\u00f3rnictwa:\n&eZ kilofem w d\u0142oni kucnij i kliknij prawym przyciskiem myszy na TNT z daleka. Spowoduje to natychmiastow\u0105 eksplozj\u0119 TNT. +Guides.Mining.Section.5=&3Jak dzia\u0142\u0105 Podm\u00f3ch G\u00f3rnictwa?\n&ePodm\u00f3ch G\u00f3rnictwa to umiej\u0119tno\u015b\u0107, kt\u00f3rej czas odnowienia jest powi\u0105zany z umiej\u0119tno\u015bci\u0105 G\u00f3rnictwo. Daje bonusy podczas wydobywania z TNT i pozwala zdalnie zdetonowa\u0107 TNT. Podm\u00f3ch G\u00f3rnictwa sk\u0142ada si\u0119 z trzech cz\u0119\u015bci. Pierwsza cz\u0119\u015b\u0107 to Wi\u0119ksze Bomby, kt\u00f3ra zwi\u0119ksza zasi\u0119g ra\u017cenia. Druga to Eksportyza Rozbi\u00f3rki, kt\u00f3ra zmniejsza obra\u017cenia od wybuch\u00f3w TNT. Trzecia cz\u0119\u015b\u0107 po prostu zwi\u0119ksza ilo\u015b\u0107 rud zrzucanych z trotylu i zmniejsza ilo\u015b\u0107 upuszczanych gruzu. ##Repair -Guides.Repair.Section.0=&3About Repair:\n&eRepair allows you to use an iron block to repair armor and\n&etools.\n\n&3XP GAIN:\n&eRepair tools or armor using the mcMMO Anvil. This is an\n&eiron block by default and should not be confused with\nðe Vanilla Minecraft Anvil. -Guides.Repair.Section.1=&3How can I use Repair?\n&ePlace down a mcMMO Anvil and right-click to repair the item \n&eyou're currently holding. This consumes 1 item on every use. -Guides.Repair.Section.2=&3How does Repair Mastery work?\n&eRepair Mastery increases the repair amount. The extra amount\n&erepaired is influenced by your Repair skill level. -Guides.Repair.Section.3=&3How does Super Repair work?\n&eSuper Repair is a passive ability. When repairing an item,\n&eit grants players a chance to repair an item with\n&edouble effectiveness. -Guides.Repair.Section.4=&3How does Arcane Forging work?\n&eThis passive ability allows you to repair items with a certain\n&echance of maintaining its enchantments. The enchants may be\n&ekept at their existing levels, downgraded to a lower level,\n&eor lost entirely. +Guides.Repair.Section.0=&3O Naprawianiu:\n&eNaprawa umo\u017cliwia u\u017cycie \u017celaznego bloku do naprawy zbroi i narz\u0119dzi .\n\n&3ZDOBYWANIE XP:\n&eNapraw narz\u0119dzia lub zbroj\u0119 za pomoc\u0105 kowad\u0142a mcMMO. Jest to domy\u015blnie \u017celazny blok i nie nale\u017cy go myli\u0107 z kowad\u0142em Vanilla. +Guides.Repair.Section.1=&3Jak naprawia\u0107 w mcMMO?\n&ePo\u0142\u00f3\u017c kowad\u0142o mcMMO i kliknij prawym przyciskiem myszy, aby naprawi\u0107 przedmiot, kt\u00f3ry aktualnie trzymasz. Przy ka\u017cdym u\u017cyciu zu\u017cywa 1 przedmiot (Na przyk\u0142ad przy \u017celaznych narz\u0119dziach zu\u017cyje jedno \u017celazo). +Guides.Repair.Section.2=&3Jak dzia\u0142a Mistrz Napraw?\n&ePoziom Mistrza Napraw zwi\u0119ksza si\u0119 wraz z naprawianymi przedmiotami. Dodatkow\u0105 przywr\u00f3con\u0105 wytrzyma\u0142o\u015b\u0107 zale\u017cy od poziomu Naprawianie. +Guides.Repair.Section.3=&3Jak dzia\u0142a Super Naprawa?\n&eSuper Naprawa to umiej\u0119tno\u015b\u0107 pasywna. Podczas naprawy przedmiotu daje graczom szans\u0119 na naprawienie przedmiotu z podw\u00f3jn\u0105 skuteczno\u015bci\u0105. +Guides.Repair.Section.4=&3Jak dzia\u0142a Tajemne Fa\u0142szowanie?\n&eTa pasywna umiej\u0119tno\u015b\u0107 pozwala naprawia\u0107 przedmioty z pewn\u0105 szans\u0105 na utrzymanie zakl\u0119\u0107. Zakl\u0119cia mog\u0105 pozosta\u0107 na dotychczasowych poziomach, zdegradowane do ni\u017cszych lub ca\u0142kowicie utracone. ##Salvage -Guides.Salvage.Section.0=&3About Salvage:\n&eSalvage allows you to use a gold block to salvage armor and\n&etools.\n\n&3XP GAIN:\n&eSalvage is a child skill of Repair and Fishing, your Salvage\n&eskill level is based on your Fishing and Repair skill levels. -Guides.Salvage.Section.1=&3How can I use Salvage?\n&ePlace down a mcMMO Salvage Anvil and right-click to salvage\nðe item you're currently holding. This will break apart the item,\n&eand give back materials used to craft the item.\n\n&eFor example, salvaging an iron pickaxe will give you iron bars. -Guides.Salvage.Section.2=&3How does Advanced Salvage work?\n&eWhen unlocked, this ability allows you to salvage damaged items.\n&eThe yield percentage increases as you level up. A higher yield\n&emeans that you can get more materials back.\n&eWith advanced salvage you will always get 1 material back,\n&eunless the item is too damaged. So you don't have to worry\n&eabout destroying items without getting anything in return. -Guides.Salvage.Section.3=&3To illustrate how this works, here's an example:\n&eLet's say we salvage a gold pickaxe which is damaged for 20%,\nðis means that the maximum amount you could get is only 2\n&e(because the pick is crafted with 3 ingots - each worth\n&e33,33% durability) which is equal to 66%. If your yield\n&epercentage is below 66% you are not able to get 2 ingots.\n&eIf it is above this value you are able to gain the "full amount",\n&ewhich means that you will get 2 ingots. -Guides.Salvage.Section.4=&3How does Arcane Salvage work?\n&eThis ability allows you to get enchanted books when salvaging\n&eenchanted items. Depending on your level the chance of\n&esuccessfully extracting a full or partial enchantment varies.\n\n&eWhen an enchantment is partially extracted, the enchantment\n&ebook will have a lower level enchantment compared to what\n&eit was on the item. +Guides.Salvage.Section.0=&3O odzyskiwaniu:\n&eUmie\u015bci\u0142e\u015b odzyskiwanie pozwala ci u\u017cy\u015b z\u0142otego bloku do odzyskania zbroi i narz\u0119dzi..\n\n&3ZDOBYWANIE XP:\n&eOdzyskiwanie to umiej\u0119tno\u015b\u0107 podrz\u0119dna Naprawy i W\u0119dkarstwa, wi\u0119c Tw\u00f3j poziom umiej\u0119tno\u015bci Odzyskiwania jest oparty na twoich poziomach umiej\u0119tno\u015bci W\u0119dkarstwa i Naprawy. +Guides.Salvage.Section.1=&3Jak u\u017cwa\u0107 Odzyskiwanie?\n&ePo\u0142\u00f3\u017c kowad\u0142o mcMMO (tj. z\u0142oty blok) i kliknij prawym przyciskiem myszy, aby odzyska\u0107 przedmioty z narz\u0119dzia, kt\u00f3ry aktualnie trzymasz. Spowoduje to zniszczenie przedmiotu i zwr\u00f3cenie materia\u0142\u00f3w u\u017cytych do wytworzenia przedmiotu. +Guides.Salvage.Section.2=&3Jak dzia\u0142a Zaawansowane Odzyskiwanie?\n&ePo odblokowaniu umiej\u0119tno\u015b\u0107 ta pozwala na odzyskanie uszkodzonych przedmiot\u00f3w. Procent zysku ro\u015bnie wraz ze wzrostem poziomu. Wy\u017csza wydajno\u015b\u0107 oznacza, \u017ce mo\u017cna odzyska\u0107 wi\u0119cej materia\u0142\u00f3w. Dzi\u0119ki zaawansowanemu odzyskowi zawsze otrzymasz 1 materia\u0142 z powrotem, chyba \u017ce przedmiot jest zbyt uszkodzony. Nie musisz wi\u0119c martwi\u0107 si\u0119 o niszczenie przedmiot\u00f3w, nie otrzymuj\u0105c niczego w zamian. +Guides.Salvage.Section.3=&3Aby pokaza\u0107 przyk\u0142ad, tutaj go opisujemy:\n&ePowiedzmy, \u017ce odzyskujemy z\u0142oty kilof, kt\u00f3ry jest uszkodzony o 20%, co oznacza, \u017ce maksymalna kwota, jak\u0105 mo\u017cesz zdoby\u0107, to tylko 2 (poniewa\u017c kilof jest tworzony z 3 sztabek - ka\u017cdy wart 33,33% wytrzyma\u0142o\u015bci), co jest r\u00f3wne 66% . Je\u015bli Tw\u00f3j procent wytrzyma\u0142o\u015bci jest ni\u017cszy ni\u017c 66%, nie jeste\u015b w stanie uzyska\u0107 2 sztabek. Je\u015bli jest powy\u017cej tej warto\u015bci, mo\u017cesz uzyska\u0107 „pe\u0142n\u0105 kwot\u0119”, co oznacza, \u017ce otrzymasz 2 sztabki. +Guides.Salvage.Section.4=&3Jak dzia\u0142a Tajemne Odzyskiwanie?\n&eTa umiej\u0119tno\u015b\u0107 pozwala zdoby\u0107 zakl\u0119te ksi\u0105\u017cki podczas odzyskiwania zakl\u0119tych przedmiot\u00f3w. W zale\u017cno\u015bci od twojego poziomu, szansa na pomy\u015blne wyodr\u0119bnienie pe\u0142nego lub cz\u0119\u015bciowego zakl\u0119cia jest r\u00f3\u017cna.\n\n&eKiedy zakl\u0119cie zostanie cz\u0119\u015bciowo wydobyte, ksi\u0119ga zakl\u0119\u0107 b\u0119dzie mia\u0142a ni\u017cszy poziom zakl\u0119cia w por\u00f3wnaniu z tym, co znajdowa\u0142o si\u0119 na przedmiocie. ##Smelting -Guides.Smelting.Section.0=Coming soon... +Guides.Smelting.Section.0=Wkr\u00f3tce... ##Swords -Guides.Swords.Section.0=&3About Swords:\n&eThis skill awards combat bonuses to anyone fighting with a\n&esword.\n\n&3XP GAIN:\n&eXP is gained based on the amount of damage dealt to mobs or \n&eother players when wielding a sword. -Guides.Swords.Section.1=&3How does Serrated Strikes work?\n&eSerrated Strikes is an active ability, you can activate it by\n&eright-clicking with a sword. This ability allows you to deal \n&ean AoE (Area of Effect) hit. This AoE will do a bonus 25%\n&edamage and will inflict a bleed effect that lasts for 5 ticks. -Guides.Swords.Section.2=&3How does Counter Attack work?\n&eCounter Attack is an active ability. When blocking and taking\n&ehits from mobs, you will have a chance to reflect 50% of \nðe damage that was taken. -Guides.Swords.Section.3=&3How does Rupture work?\n&eRupture causes enemies to take damage every two seconds. The \n&etarget will bleed until the effect wears off, or death, \n&ewhichever comes first.\n&eThe duration of the bleed is increased by your sword skill. +Guides.Swords.Section.0=&3O Mieczach:\n&eTa umiej\u0119tno\u015b\u0107 zapewnia premie bojowe ka\u017cdemu, kto walczy mieczem..\n\n&3ZDOBYWANIE XP:\n&eXP jest zdobywane w oparciu o ilo\u015b\u0107 obra\u017ce\u0144 zadanych mobom lub innym graczom, gdy dzier\u017cysz miecz. . +Guides.Swords.Section.1=&3Jak dzia\u0142aj\u0105 Z\u0105bkowane Uderzenia?\n&eZ\u0105bkowane Uderzenia to umiej\u0119tno\u015b\u0107 aktywna, kt\u00f3r\u0105 mo\u017cna aktywowa\u0107, klikaj\u0105c prawym przyciskiem myszy mieczem. Ta umiej\u0119tno\u015b\u0107 pozwala na zadanie trafienia obszarowego. Ten obszar dzia\u0142ania zadaje dodatkowe 25% obra\u017ce\u0144 i wywo\u0142a efekt krwawienia trwaj\u0105cy 5 tik\u00f3w. +Guides.Swords.Section.2=&3Jak dzia\u0142a Kontraatak?\n&eKontratak to aktywna umiej\u0119tno\u015b\u0107. Podczas blokowania i przyjmowania trafie\u0144 od mob\u00f3w, b\u0119dziesz mia\u0142 szans\u0119 odbi\u0107 50% otrzymanych obra\u017ce\u0144. +Guides.Swords.Section.3=&3Jak dzia\u0142a Rozerwanie?\n&eRozerwanie powoduje, \u017ce wrogowie otrzymuj\u0105 obra\u017cenia co dwie sekundy. Cel b\u0119dzie krwawi\u0142 do momentu ust\u0105pienia efektu lub \u015bmierci, w zale\u017cno\u015bci od tego, co nast\u0105pi wcze\u015bniej. Poziom umiej\u0119tno\u015bci Miecze zwi\u0119ksza czas trwania krwawienia. ##Taming -Guides.Taming.Section.0=&3About Taming:\n&eTaming will give players various combat bonuses when using\n&etamed wolves.\n\n&3XP GAIN:\n&eTo gain XP in this skill, you need to tame wolves/ocelots or\n&eget into combat with your wolves. -Guides.Taming.Section.1=&3How does Call of the Wild work?\n&eCall of the Wild is an active ability that will allow you to summon\n&ea wolf or an ocelot by your side. You can do this by\n&esneaking + left-clicking while holding bones or fish. -Guides.Taming.Section.2=&3How does Beast Lore work?\n&eBeast Lore allows players to inspect pets and to check the\n&estats of wolves and ocelots. Left-click a wolf or ocelot to use\n&eBeast Lore. -Guides.Taming.Section.3=&3How does Gore work?\n&eGore is a passive ability that has a chance of inflicting a\n&ebleeding effect on your wolves' targets. -Guides.Taming.Section.4=&3How does Sharpened Claws work?\n&eSharpened Claws provides a damage bonus to damage dealt\n&eby wolves. The damage bonus depends on your Taming level. -Guides.Taming.Section.5=&3How does Environmentally Aware work?\n&eThis passive ability will allow wolves to teleport to you when\nðey get near hazards, such as Cacti/Lava. It will also give\n&ewolves fall damage immunity. -Guides.Taming.Section.6=&3How does Thick Fur work?\n&eThis passive ability will reduce damage and make wolves\n&efire resistant. -Guides.Taming.Section.7=&3How does Shock Proof work?\n&eThis passive ability reduces damage done to wolves\n&efrom explosions. -Guides.Taming.Section.8=&3How does Fast Food Service work?\n&eThis passive ability gives wolves a chance to heal whenever\nðey perform an attack. +Guides.Taming.Section.0=&3O Oswajaniu:\n&eOswajanie zapewni graczom r\u00f3\u017cne bonusy bojowe podczas u\u017cywania oswojonych wilk\u00f3w.\n\n&3ZDOBYWANIE XP:\n&eAby zdoby\u0107 XP w tej umiej\u0119tno\u015bci, musisz oswoi\u0107 wilki lub oceloty i wyruszy\u0107 do walki ze swoimi sprzymierze\u0144cami. +Guides.Taming.Section.1=&3Jak dzia\u0142a Zew Natury?\n&eZew Natury to aktywna umiej\u0119tno\u015b\u0107, kt\u00f3ra pozwoli ci przywo\u0142a\u0107 wilka lub ocelota do swojego boku. Mo\u017cesz to zrobi\u0107 kucaj\u0105c (shift) + klikni\u0119cie lewym przyciskiem myszy, trzymaj\u0105c ko\u015bci lub ryb\u0119. +Guides.Taming.Section.2=&3Jak dzia\u0142a Wiedza Bestii?\n&eWiedza Bestii pozwala graczom na zbadanie zwierzak\u00f3w i sprawdzanie stanu wilk\u00f3w i ocelot\u00f3w. Kliknij lewym przyciskiem myszy na wilka lub ocelota, aby u\u017cy\u0107 Wiedzy Bestii. +Guides.Taming.Section.3=&3How does Gore work?\n&eKrwawienie to pasywna umiej\u0119tno\u015b\u0107, kt\u00f3ra ma szans\u0119 wywo\u0142a\u0107 efekt krwawienia na celach przez Twoich wilk\u00f3w. +Guides.Taming.Section.4=&3Jak dzia\u0142aj\u0105 Zaostrzone Pazury?\n&eZaostrzone Pazury zapewnia premi\u0119 do obra\u017ce\u0144 zadawanych przez wilki. Premia do obra\u017ce\u0144 zale\u017cy od Twojego poziomu Oswajania. +Guides.Taming.Section.5=&3Jak dzia\u0142a Sprzymierzeniec Natury?\n&eTa pasywna umiej\u0119tno\u015b\u0107 pozwoli wilkom teleportowa\u0107 si\u0119 do ciebie, gdy zbli\u017c\u0105 si\u0119 do niebezpiecze\u0144stw, takich jak kaktusy czy lawa. Zapewni tak\u017ce wilkom odporno\u015b\u0107 na obra\u017cenia od upadku. +Guides.Taming.Section.6=&3Jak dzia\u0142a grube futro??\n&eTa pasywna umiej\u0119tno\u015b\u0107 zmniejszy obra\u017cenia i sprawi, \u017ce wilki b\u0119d\u0105 odporne na ogie\u0144. +Guides.Taming.Section.7=&3Jak dzia\u0142a odporno\u015b\u0107 na wstrz\u0105sy?\n&eTa umiej\u0119tno\u015b\u0107 pasywna zmniejsza obra\u017cenia zadawane wilkom od eksplozji. +Guides.Taming.Section.8=&3Jak dzia\u0142a serwis Fast Food??\n&eTa pasywna umiej\u0119tno\u015b\u0107 daje wilkom szans\u0119 na uleczenie si\u0119, gdy wykonaj\u0105 atak. ##Unarmed Guides.Unarmed.Section.0=&3About Unarmed:\n&eUnarmed will give players various combat bonuses when using\n&eyour fists as a weapon. \n\n&3XP GAIN:\n&eXP is gained based on the amount of damage dealt to mobs \n&eor other players when unarmed. Guides.Unarmed.Section.1=&3How does Berserk work?\n&eBeserk is an active ability that is activated by\n&eright-clicking. While in Beserk mode, you deal 50% more\n&edamage and you can break weak materials instantly, such as\n&eDirt and Grass. @@ -962,10 +964,10 @@ Guides.Unarmed.Section.3=&3How does Arrow Deflect work?\n&eArrow Deflect is a pa Guides.Unarmed.Section.4=&3How does Iron Grip work?\n&eIron Grip is a passive ability that counters disarm. As your\n&eunarmed level increases, the chance of preventing a disarm increases. Guides.Unarmed.Section.5=&3How does Disarm work?\n&eThis passive ability allows players to disarm other players,\n&ecausing the target's equipped item to fall to the ground. ##Woodcutting -Guides.Woodcutting.Section.0=&3About Woodcutting:\n&eWoodcutting is all about chopping down trees.\n\n&3XP GAIN:\n&eXP is gained whenever you break log blocks. -Guides.Woodcutting.Section.1=&3How does Tree Feller work?\n&eTree Feller is an active ability, you can right-click\n&ewhile holding an ax to activate Tree Feller. This will\n&ecause the entire tree to break instantly, dropping all\n&eof its logs at once. -Guides.Woodcutting.Section.2=&3How does Leaf Blower work?\n&eLeaf Blower is a passive ability that will cause leaf\n&eblocks to break instantly when hit with an axe. By default,\nðis ability unlocks at level 100. -Guides.Woodcutting.Section.3=&3How do Double Drops work?\n&eThis passive ability gives you a chance to obtain an extra\n&eblock for every log you chop. +Guides.Woodcutting.Section.0=&3O Drwalu:\n&eDrwal polega na wycinaniu drzew.\n\n&3ZDOBYWANIE XP:\n&eXP jest zdobywany za ka\u017cdym razem, gdy niszczysz bloki k\u0142\u00f3d. +Guides.Woodcutting.Section.1=&3Jak dzia\u0142a \u015acinacz Drzew?\n&e\u015cinacz Drzew to aktywna umiej\u0119tno\u015b\u0107, mo\u0107na klikn\u0105\u0107 prawym przyciskiem trzymaj\u0105c siekier\u0119, aby aktywowa\u0107 \u015cinacz Drzew. Spowoduje to natychmiastowe zniszczenie ca\u0142ego drzewa, zrzucaj\u0105c jednocze\u015bnie wszystkie k\u0142ody. +Guides.Woodcutting.Section.2=&3Jak dzia\u0142a Dmuchawa Do Li\u015bci?\n&eDmuchawa do li\u015bci to umiej\u0119tno\u015b\u0107 pasywna, kt\u00f3ra powoduje, \u017ce bloki li\u015bci natychmiast si\u0119 niszcz\u0105 po uderzeniu siekier\u0105. Umiej\u0119tno\u015b\u0107 ta domy\u015blnie odblokowuje si\u0119 na poziomie 100. +Guides.Woodcutting.Section.3=&3Jak dzia\u0142a Podw\u00f3jny \u0141up?\n&eTa pasywna umiej\u0119tno\u015b\u0107 daje ci szans\u0119 na uzyskanie dodatkowego bloku za ka\u017cd\u0105 posiekan\u0105 k\u0142od\u0119. #INSPECT Inspect.Offline= &cNie masz uprawnie\u0144 do sprawdzania graczy offline! Inspect.OfflineStats=Statystyki mcMMO dla gracza off-line &e{0} @@ -982,7 +984,7 @@ Item.Generic.Wait=Musisz odczeka\u0107 zanim ponownie to u\u017cyjesz! &e({0}s) Item.Injured.Wait=Niedawno by\u0142e\u015b kontuzjowany i musisz poczeka\u0107, zanim to wykorzystasz. &e({0}s) Item.FluxPickaxe.Name=Topi\u0105cy Kilof Item.FluxPickaxe.Lore.1=&7Ma szanse na natychmiastowe przepalenie rudy. -Item.FluxPickaxe.Lore.2=&7Wymaga poziomu &6Przepalanie: &7{0}+ +Item.FluxPickaxe.Lore.2=&7Wymaga poziomu &6Przepalania: &7{0}+ #TELEPORTATION Teleport.Commencing=&7Rozpoczynanie teleportacji… Przez &6({0}) &7sekund, nie ruszaj si\u0119... Teleport.Cancelled=&4Teleportacja anulowana! From cfe1fd2b26b86cfb4f7cc5ee4ffd74f2531c7f9e Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 16 Apr 2021 10:07:02 -0700 Subject: [PATCH 44/57] Update changelog --- Changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.txt b/Changelog.txt index c44ad03f2..116167bbf 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -5,6 +5,7 @@ Version 2.1.193 Fixed blocks being dropped from blast mining even if yield was set to 0 (thanks Warriorrrr) Fixed Tree feller not working entirely if one fake block break event is cancelled. (thanks Warriorrrr) Fixes no woodcutting xp being rewarded if a tree is too big while using tree feller. (thanks Warriorrrr) + Updated pl locale (thanks Mich3l3k) Version 2.1.192 Removed some debug messages from FlatFileDatabaseManager From 81a3441d623a7bdf1f509214de0bd616769956f4 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 16 Apr 2021 10:07:36 -0700 Subject: [PATCH 45/57] 2.1.193 --- Changelog.txt | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 116167bbf..9ce8d58c1 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,7 +1,7 @@ Version 2.1.193 Fixed another bug where mcrank/mctop/leaderboards weren't loading Fixed a bug where override locales weren't being loaded (but worked after a reloadlocale command) - (Unit Tests) Added a test to make sure leaderboards were working + (Unit Tests) Added a test to make sure leaderboards for FlatFile were working Fixed blocks being dropped from blast mining even if yield was set to 0 (thanks Warriorrrr) Fixed Tree feller not working entirely if one fake block break event is cancelled. (thanks Warriorrrr) Fixes no woodcutting xp being rewarded if a tree is too big while using tree feller. (thanks Warriorrrr) diff --git a/pom.xml b/pom.xml index 3a19d20e1..97c687111 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.193-SNAPSHOT + 2.1.193 mcMMO https://github.com/mcMMO-Dev/mcMMO From c29f311f1e5b370a5ce8f1e323d5d231abb75ab9 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 16 Apr 2021 12:24:02 -0700 Subject: [PATCH 46/57] More proper fix --- Changelog.txt | 3 +++ pom.xml | 2 +- src/main/java/com/gmail/nossr50/locale/LocaleLoader.java | 1 + src/main/java/com/gmail/nossr50/mcMMO.java | 3 +-- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 9ce8d58c1..7227a5083 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,6 @@ +Version 2.1.194 + Fixed a bug where mcMMO didn't properly setup file paths for locale override + Version 2.1.193 Fixed another bug where mcrank/mctop/leaderboards weren't loading Fixed a bug where override locales weren't being loaded (but worked after a reloadlocale command) diff --git a/pom.xml b/pom.xml index 97c687111..6cc309b22 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.193 + 2.1.194-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java b/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java index 2cfcc4052..cf8d5bfb0 100644 --- a/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java +++ b/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java @@ -152,6 +152,7 @@ public final class LocaleLoader { mcMMO.p.getLogger().log(Level.WARNING, "Failed to load locale from " + localePath, e); } } + bundle = ResourceBundle.getBundle(BUNDLE_ROOT, locale); enBundle = ResourceBundle.getBundle(BUNDLE_ROOT, Locale.US); } diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index a0b7ebf43..7b34c18e1 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -184,6 +184,7 @@ public class mcMMO extends JavaPlugin { @Override public void onEnable() { try { + setupFilePaths(); generalConfig = new GeneralConfig(getDataFolder()); //Load before skillTools skillTools = new SkillTools(this); //Load after general config @@ -207,7 +208,6 @@ public class mcMMO extends JavaPlugin { upgradeManager = new UpgradeManager(); - setupFilePaths(); modManager = new ModManager(); @@ -338,7 +338,6 @@ public class mcMMO extends JavaPlugin { transientEntityTracker = new TransientEntityTracker(); setServerShutdown(false); //Reset flag, used to make decisions about async saves - LocaleLoader.reloadLocale(); //Apply override locale } public static PlayerLevelUtils getPlayerLevelUtils() { From 16f79b9fbc7206303390516db1c0fb9ff6f3e8af Mon Sep 17 00:00:00 2001 From: nossr50 Date: Fri, 16 Apr 2021 13:50:41 -0700 Subject: [PATCH 47/57] Locale override now uses a specific file instead of weird name matching --- Changelog.txt | 8 +- .../experience/ExperienceCommand.java | 2 - .../experience/SkillresetCommand.java | 1 - .../nossr50/database/DatabaseManager.java | 1 - .../database/FlatFileDatabaseManager.java | 4 +- .../gmail/nossr50/locale/LocaleLoader.java | 169 ++++++++++++++++-- src/main/java/com/gmail/nossr50/mcMMO.java | 1 - .../database/FlatFileDatabaseManagerTest.java | 5 +- 8 files changed, 167 insertions(+), 24 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 7227a5083..0c88afb19 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,5 +1,11 @@ Version 2.1.194 - Fixed a bug where mcMMO didn't properly setup file paths for locale override + Locale override files are now named locale_override.properties (converted automatically/generated automatically) + Existing in use locale override files will be renamed to locale_override.properties and have some useful text put in them + mcMMO will now generate a locale override file with some detailed instructions if one doesn't exist (will be found in /plugins/mcMMO/locales/locale_override.properties) + + NOTES: + If you were overriding locale before this update mcMMO will just rename the existing override file to locale_override.properties add some useful text and then load it + Remember you can use /mcreloadlocale to swap the edits in without restarting the server Version 2.1.193 Fixed another bug where mcrank/mctop/leaderboards weren't loading 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 5f310828e..4bd6b4eeb 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java @@ -9,7 +9,6 @@ import com.gmail.nossr50.util.commands.CommandUtils; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.SkillTools; import com.google.common.collect.ImmutableList; -import org.bukkit.OfflinePlayer; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; @@ -19,7 +18,6 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; -import java.util.UUID; public abstract class ExperienceCommand implements TabExecutor { @Override 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 d4353224e..edc99e2ad 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java @@ -22,7 +22,6 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; -import java.util.UUID; /** * This class mirrors the structure of ExperienceCommand, except the diff --git a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java index c377bbbfe..586c8c0b6 100644 --- a/src/main/java/com/gmail/nossr50/database/DatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/DatabaseManager.java @@ -1,6 +1,5 @@ package com.gmail.nossr50.database; -import com.gmail.nossr50.api.exceptions.InvalidPlayerException; import com.gmail.nossr50.api.exceptions.InvalidSkillException; import com.gmail.nossr50.datatypes.database.DatabaseType; import com.gmail.nossr50.datatypes.database.PlayerStat; diff --git a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java index 32f327614..dc1b40855 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java @@ -10,7 +10,6 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.Misc; -import com.gmail.nossr50.util.blockmeta.HashChunkManager; import com.gmail.nossr50.util.skills.SkillTools; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; @@ -18,7 +17,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.*; -import java.security.InvalidParameterException; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; @@ -1074,7 +1072,7 @@ public final class FlatFileDatabaseManager implements DatabaseManager { try { // Open the file to write the player bufferedWriter = new BufferedWriter(new FileWriter(usersFilePath, true)); - DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"); + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm"); LocalDateTime localDateTime = LocalDateTime.now(); bufferedWriter.append("# mcMMO Database created on ").append(localDateTime.format(dateTimeFormatter)).append("\r\n"); //Empty file } catch (Exception e) { diff --git a/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java b/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java index cf8d5bfb0..0fed62f4f 100644 --- a/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java +++ b/src/main/java/com/gmail/nossr50/locale/LocaleLoader.java @@ -4,18 +4,21 @@ import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.util.text.TextUtils; import net.kyori.adventure.text.TextComponent; import org.bukkit.ChatColor; +import org.jetbrains.annotations.NotNull; -import java.io.IOException; -import java.io.Reader; +import java.io.*; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.text.MessageFormat; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.*; import java.util.logging.Level; public final class LocaleLoader { private static final String BUNDLE_ROOT = "com.gmail.nossr50.locale.locale"; + private static final String OVERRIDE_FILE_NAME = "locale_override.properties"; private static Map bundleCache = new HashMap<>(); private static ResourceBundle bundle = null; private static ResourceBundle filesystemBundle = null; @@ -30,8 +33,9 @@ public final class LocaleLoader { /** * Gets the appropriate string from the Locale files. * - * @param key The key to look up the string with + * @param key The key to look up the string with * @param messageArguments Any arguments to be added to the string + * * @return The properly formatted locale string */ public static String getString(String key, Object... messageArguments) { @@ -44,11 +48,13 @@ public final class LocaleLoader { } //TODO: Remove this hacky crap with something better later + /** * Gets the appropriate TextComponent representation of a formatted string from the Locale files. * - * @param key The key to look up the string with + * @param key The key to look up the string with * @param messageArguments Any arguments to be added to the text component + * * @return The properly formatted text component */ public static TextComponent getTextComponent(String key, Object... messageArguments) { @@ -75,19 +81,18 @@ public final class LocaleLoader { if (filesystemBundle != null) { try { return filesystemBundle.getString(key); + } catch (MissingResourceException ignored) { } - catch (MissingResourceException ignored) {} } try { return bundle.getString(key); + } catch (MissingResourceException ignored) { } - catch (MissingResourceException ignored) {} try { return enBundle.getString(key); - } - catch (MissingResourceException ignored) { + } catch (MissingResourceException ignored) { if (!key.contains("Guides")) { mcMMO.p.getLogger().warning("Could not find locale string: " + key); } @@ -134,8 +139,7 @@ public final class LocaleLoader { if (myLocale.length == 1) { locale = new Locale(myLocale[0]); - } - else if (myLocale.length >= 2) { + } else if (myLocale.length >= 2) { locale = new Locale(myLocale[0], myLocale[1]); } @@ -144,18 +148,155 @@ public final class LocaleLoader { } Path localePath = Paths.get(mcMMO.getLocalesDirectory() + "locale_" + locale.toString() + ".properties"); + Path overridePath = Paths.get(mcMMO.getLocalesDirectory() + OVERRIDE_FILE_NAME); + File overrideFile = overridePath.toFile(); + if (Files.exists(localePath) && Files.isRegularFile(localePath)) { - try (Reader localeReader = Files.newBufferedReader(localePath)) { - mcMMO.p.getLogger().log(Level.INFO, "Loading locale from {0}", localePath); + + File oldOverrideFile = localePath.toFile(); + + try { + //Copy the file + com.google.common.io.Files.copy(oldOverrideFile, overrideFile); + //Remove the old file now + oldOverrideFile.delete(); + + //Insert our helpful text + StringBuilder stringBuilder = new StringBuilder(); + + try(BufferedReader bufferedReader = new BufferedReader(new FileReader(overrideFile.getPath()))) { + // Open the file + String line; + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm"); + LocalDateTime localDateTime = LocalDateTime.now(); + stringBuilder.append("# mcMMO Locale Override File created on ").append(localDateTime.format(dateTimeFormatter)).append("\r\n"); //Empty file + stringBuilder.append(getLocaleHelpTextWithoutExamples()); //Add our helpful text + while ((line = bufferedReader.readLine()) != null) { + stringBuilder.append(line).append("\r\n"); + } + } catch (IOException e) { + e.printStackTrace(); + } + + try(FileWriter fileWriter = new FileWriter(overrideFile.getPath())) { + fileWriter.write(stringBuilder.toString()); + } catch (IOException e) { + e.printStackTrace(); + } + + } catch (IOException e) { + e.printStackTrace(); + } + } + + //Use the new locale file + if (Files.exists(overridePath) && Files.isRegularFile(overridePath)) { + try (Reader localeReader = Files.newBufferedReader(overridePath)) { + mcMMO.p.getLogger().log(Level.INFO, "Loading locale from {0}", overridePath); filesystemBundle = new PropertyResourceBundle(localeReader); } catch (IOException e) { - mcMMO.p.getLogger().log(Level.WARNING, "Failed to load locale from " + localePath, e); + mcMMO.p.getLogger().log(Level.WARNING, "Failed to load locale from " + overridePath, e); + } + } else { + //Create a blank file and fill it in with some helpful text + try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(overrideFile, true))) { + // Open the file to write the player + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm"); + LocalDateTime localDateTime = LocalDateTime.now(); + bufferedWriter.append("# mcMMO Locale Override File created on ").append(localDateTime.format(dateTimeFormatter)).append("\r\n"); //Empty file + String localeExplanation = getLocaleHelpText(); + bufferedWriter.append(localeExplanation); + } catch (Exception e) { + e.printStackTrace(); } } bundle = ResourceBundle.getBundle(BUNDLE_ROOT, locale); - enBundle = ResourceBundle.getBundle(BUNDLE_ROOT, Locale.US); } + + enBundle = ResourceBundle.getBundle(BUNDLE_ROOT, Locale.US); + } + + @NotNull + private static String getLocaleHelpText() { + String localeExplanation = + "# -- Are you looking to change the language of mcMMO but without editing it yourself? --\n" + + "\n" + + "# mcMMO has quite a few built in translations, you can choose which translation by editing config.yml with the appropriate locale code. The setting is `General.Locale` in config.yml\n" + + "# Odds are, if you speak a popular language on earth we already have a translation for it.\n" + + "# However our translations are done by the community, and update infrequently. (Please help us out <3)\n" + + "# We would love more people to help update our locales, submit any updated translation file to our GitHub or email it to me at business@neetgames.com\n" + + "# For a list of built in translations, view this link: https://github.com/mcMMO-Dev/mcMMO/tree/master/src/main/resources/locale\n" + + "\n" + + "\n" + + "# -- Using a built in translation -- \n" + + "# Assuming you read the above section, edit config.yml's General.Locale from en_US to the locale code that we support (see the above link), then reboot your server\n" + + "\n" + + "\n" + + "# -- Do you want to change the text in mcMMO? Including adding colors? ( Locale Override ) -- \n" + + "# First, a brief explanation.\n" + + "# Locales are the language files used by mcMMO, they also contain color codes and most of the styling used by mcMMO.\n" + + "# You can customize a locale outside of the JAR in version 2.1.51 and up.\n" + + "#\n" + + "# Locales can be overridden by editing this file\n" + + "# You can find the up to date current locale files here https://github.com/mcMMO-Dev/mcMMO/tree/master/src/main/resources/locale\n" + + "# The master file is en_US, if a translation is missing entries (as they often are) it will pull from the en_US file https://github.com/mcMMO-Dev/mcMMO/blob/master/src/main/resources/locale/locale_en_US.properties\n" + + "#\n" + + "# To override a locale, add entries to this file and copy ** only ** the strings you want to replace, otherwise you will not see any updated strings when mcMMO updates and will have to manually change them and read patch notes carefully.\n" + + "# If you wish to replace every line in some way, feel free to copy the entire contents of this file, just be advised that you will need to be on top of locale updates in mcMMO and follow our changelog closely.\n" + + "\n" + + "\n" + + "# WARNING: Locales only support ASCII and UTF16 characters at the moment, so you'll need to run special characters through a UTF16 converter (google it) to get them to work. This will be fixed in the future!\n" + + "# FIND KEYS HERE: On our github repo (en_US is our master file and has ALL the keys) -> https://github.com/mcMMO-Dev/mcMMO/tree/master/src/main/resources/locale\n" + + "# WARNING: Some keys in our master file are unused, make gratuitous use of Ctrl+F\n" + + "# HOW TO APPLY: You can either restart the server for these changes to take effect or run /mcreloadlocale.\n" + + "# -- Add Keys Below --\n" + + getExamples(); + return localeExplanation; + } + + @NotNull + private static String getExamples() { + return "This.Is.An.Example.Put.Locale.Keys.Here.One=&aExample text using hex color codes\n" + + "This.Is.An.Example.Put.Locale.Keys.Here.Two=[[DARK_AQUA]]Example text using our own color codes\n" + + "This.Is.An.Example.Put.Locale.Keys.Here.Three=Example text with no colors\n"; + } + + @NotNull + private static String getLocaleHelpTextWithoutExamples() { + String localeExplanation = + "# -- Are you looking to change the language of mcMMO but without editing it yourself? --\n" + + "\n" + + "# mcMMO has quite a few built in translations, you can choose which translation by editing config.yml with the appropriate locale code. The setting is `General.Locale` in config.yml\n" + + "# Odds are, if you speak a popular language on earth we already have a translation for it.\n" + + "# However our translations are done by the community, and update infrequently. (Please help us out <3)\n" + + "# We would love more people to help update our locales, submit any updated translation file to our GitHub or email it to me at business@neetgames.com\n" + + "# For a list of built in translations, view this link: https://github.com/mcMMO-Dev/mcMMO/tree/master/src/main/resources/locale\n" + + "\n" + + "\n" + + "# -- Using a built in translation -- \n" + + "# Assuming you read the above section, edit config.yml's General.Locale from en_US to the locale code that we support (see the above link), then reboot your server\n" + + "\n" + + "\n" + + "# -- Do you want to change the text in mcMMO? Including adding colors? ( Locale Override ) -- \n" + + "# First, a brief explanation.\n" + + "# Locales are the language files used by mcMMO, they also contain color codes and most of the styling used by mcMMO.\n" + + "# You can customize a locale outside of the JAR in version 2.1.51 and up.\n" + + "#\n" + + "# Locales can be overridden by editing this file\n" + + "# You can find the up to date current locale files here https://github.com/mcMMO-Dev/mcMMO/tree/master/src/main/resources/locale\n" + + "# The master file is en_US, if a translation is missing entries (as they often are) it will pull from the en_US file https://github.com/mcMMO-Dev/mcMMO/blob/master/src/main/resources/locale/locale_en_US.properties\n" + + "#\n" + + "# To override a locale, add entries to this file and copy ** only ** the strings you want to replace, otherwise you will not see any updated strings when mcMMO updates and will have to manually change them and read patch notes carefully.\n" + + "# If you wish to replace every line in some way, feel free to copy the entire contents of this file, just be advised that you will need to be on top of locale updates in mcMMO and follow our changelog closely.\n" + + "\n" + + "\n" + + "# WARNING: Locales only support ASCII and UTF16 characters at the moment, so you'll need to run special characters through a UTF16 converter (google it) to get them to work. This will be fixed in the future!\n" + + "# FIND KEYS HERE: On our github repo (en_US is our master file and has ALL the keys) -> https://github.com/mcMMO-Dev/mcMMO/tree/master/src/main/resources/locale\n" + + "# WARNING: Some keys in our master file are unused, make gratuitous use of Ctrl+F\n" + + "# HOW TO APPLY: You can either restart the server for these changes to take effect or run /mcreloadlocale.\n" + + "# -- Add Keys Below --\n"; + return localeExplanation; } public static String addColors(String input) { diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index 7b34c18e1..d182ecc02 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -18,7 +18,6 @@ import com.gmail.nossr50.database.DatabaseManagerFactory; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.subskills.acrobatics.Roll; import com.gmail.nossr50.listeners.*; -import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.party.PartyManager; import com.gmail.nossr50.runnables.SaveTimerTask; import com.gmail.nossr50.runnables.backups.CleanBackupsTask; diff --git a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java index feb796e9f..62d13f69a 100644 --- a/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java +++ b/src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java @@ -17,7 +17,10 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.junit.jupiter.api.*; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.*; import java.net.URI; From 2c44590c526c30b865bb79f3b0a6a60d5be95e4f Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 18 Apr 2021 17:21:37 -0700 Subject: [PATCH 48/57] world bounds tweak --- .../java/com/gmail/nossr50/util/BlockUtils.java | 3 ++- .../layers/world/WorldCompatibilityLayer.java | 2 +- .../nossr50/util/blockmeta/ChunkStoreTest.java | 17 +++++++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/util/BlockUtils.java b/src/main/java/com/gmail/nossr50/util/BlockUtils.java index d1cb63a2a..135025952 100644 --- a/src/main/java/com/gmail/nossr50/util/BlockUtils.java +++ b/src/main/java/com/gmail/nossr50/util/BlockUtils.java @@ -292,7 +292,8 @@ public final class BlockUtils { public static boolean isWithinWorldBounds(@NotNull WorldCompatibilityLayer worldCompatibilityLayer, @NotNull Block block) { World world = block.getWorld(); - return block.getY() > worldCompatibilityLayer.getMinWorldHeight(world) && block.getY() < worldCompatibilityLayer.getMaxWorldHeight(world); + //pretty sure both height and min height are able to have blocks placed on them + return block.getY() >= worldCompatibilityLayer.getMinWorldHeight(world) && block.getY() <= worldCompatibilityLayer.getMaxWorldHeight(world); } } diff --git a/src/main/java/com/gmail/nossr50/util/compat/layers/world/WorldCompatibilityLayer.java b/src/main/java/com/gmail/nossr50/util/compat/layers/world/WorldCompatibilityLayer.java index a8f970987..115aeb7fb 100644 --- a/src/main/java/com/gmail/nossr50/util/compat/layers/world/WorldCompatibilityLayer.java +++ b/src/main/java/com/gmail/nossr50/util/compat/layers/world/WorldCompatibilityLayer.java @@ -7,5 +7,5 @@ import org.jetbrains.annotations.NotNull; public interface WorldCompatibilityLayer extends CompatibilityLayer { default int getMinWorldHeight(@NotNull World world) { return 0; } - default int getMaxWorldHeight(@NotNull World world) { return 255; } + default int getMaxWorldHeight(@NotNull World world) { return 256; } } diff --git a/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java b/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java index bafb3f01b..b8e93d9cc 100644 --- a/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java +++ b/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java @@ -2,6 +2,7 @@ package com.gmail.nossr50.util.blockmeta; import com.gmail.nossr50.TestUtil; import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.BlockUtils; import com.gmail.nossr50.util.compat.CompatibilityManager; import com.gmail.nossr50.util.compat.layers.world.WorldCompatibilityLayer; import com.gmail.nossr50.util.platform.PlatformManager; @@ -97,6 +98,22 @@ public class ChunkStoreTest { } } } + + //Bot Block + TestBlock bottomBlock = new TestBlock(1337, 0, -1337, mockWorld); + Assert.assertFalse(hashChunkManager.isTrue(bottomBlock)); + + Assert.assertTrue(BlockUtils.isWithinWorldBounds(worldCompatibilityLayer, bottomBlock)); + hashChunkManager.setTrue(bottomBlock); + Assert.assertTrue(hashChunkManager.isTrue(bottomBlock)); + + //Top Block + TestBlock topBlock = new TestBlock(1337, 256, -1337, mockWorld); + Assert.assertFalse(hashChunkManager.isTrue(topBlock)); + + Assert.assertTrue(BlockUtils.isWithinWorldBounds(worldCompatibilityLayer, topBlock)); + hashChunkManager.setTrue(topBlock); + Assert.assertTrue(hashChunkManager.isTrue(topBlock)); } @Test From a844f2709386d01c3289c669678d91a4f428025e Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 18 Apr 2021 17:28:27 -0700 Subject: [PATCH 49/57] Fix mistakes --- .../com/gmail/nossr50/util/BlockUtils.java | 2 +- .../util/blockmeta/ChunkStoreTest.java | 20 ++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/util/BlockUtils.java b/src/main/java/com/gmail/nossr50/util/BlockUtils.java index 135025952..984ccbdaf 100644 --- a/src/main/java/com/gmail/nossr50/util/BlockUtils.java +++ b/src/main/java/com/gmail/nossr50/util/BlockUtils.java @@ -293,7 +293,7 @@ public final class BlockUtils { World world = block.getWorld(); //pretty sure both height and min height are able to have blocks placed on them - return block.getY() >= worldCompatibilityLayer.getMinWorldHeight(world) && block.getY() <= worldCompatibilityLayer.getMaxWorldHeight(world); + return block.getY() >= worldCompatibilityLayer.getMinWorldHeight(world) && block.getY() < worldCompatibilityLayer.getMaxWorldHeight(world); } } diff --git a/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java b/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java index b8e93d9cc..8876c99d6 100644 --- a/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java +++ b/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java @@ -40,6 +40,8 @@ import static org.mockito.Mockito.mock; @RunWith(PowerMockRunner.class) @PrepareForTest({ Bukkit.class, mcMMO.class}) public class ChunkStoreTest { + public static final int LEGACY_WORLD_HEIGHT_MAX = 256; + public static final int LEGACY_WORLD_HEIGHT_MIN = 0; private static File tempDir; @BeforeClass public static void setUpClass() { @@ -77,8 +79,20 @@ public class ChunkStoreTest { Mockito.when(platformManager.getCompatibilityManager()).thenReturn(compatibilityManager); Mockito.when(platformManager.getCompatibilityManager().getWorldCompatibilityLayer()).thenReturn(worldCompatibilityLayer); Assert.assertNotNull(mcMMO.getCompatibilityManager().getWorldCompatibilityLayer()); - Mockito.when(worldCompatibilityLayer.getMinWorldHeight(mockWorld)).thenReturn(0); - Mockito.when(worldCompatibilityLayer.getMaxWorldHeight(mockWorld)).thenReturn(255); + Mockito.when(worldCompatibilityLayer.getMinWorldHeight(mockWorld)).thenReturn(LEGACY_WORLD_HEIGHT_MIN); + Mockito.when(worldCompatibilityLayer.getMaxWorldHeight(mockWorld)).thenReturn(LEGACY_WORLD_HEIGHT_MAX); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testIndexOutOfBounds() { + Mockito.when(mcMMO.getCompatibilityManager().getWorldCompatibilityLayer().getMinWorldHeight(mockWorld)).thenReturn(-64); + HashChunkManager hashChunkManager = new HashChunkManager(); + + + //Top Block + TestBlock illegalHeightBlock = new TestBlock(1337, 256, -1337, mockWorld); + Assert.assertFalse(hashChunkManager.isTrue(illegalHeightBlock)); + hashChunkManager.setTrue(illegalHeightBlock); } @Test @@ -108,7 +122,7 @@ public class ChunkStoreTest { Assert.assertTrue(hashChunkManager.isTrue(bottomBlock)); //Top Block - TestBlock topBlock = new TestBlock(1337, 256, -1337, mockWorld); + TestBlock topBlock = new TestBlock(1337, 255, -1337, mockWorld); Assert.assertFalse(hashChunkManager.isTrue(topBlock)); Assert.assertTrue(BlockUtils.isWithinWorldBounds(worldCompatibilityLayer, topBlock)); From 317f966f73c2b2218bdc846ed6186475ac098e02 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 18 Apr 2021 17:31:20 -0700 Subject: [PATCH 50/57] Fix comment Fixes #4496 --- src/main/java/com/gmail/nossr50/util/BlockUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/gmail/nossr50/util/BlockUtils.java b/src/main/java/com/gmail/nossr50/util/BlockUtils.java index 984ccbdaf..dada7a1bf 100644 --- a/src/main/java/com/gmail/nossr50/util/BlockUtils.java +++ b/src/main/java/com/gmail/nossr50/util/BlockUtils.java @@ -292,7 +292,7 @@ public final class BlockUtils { public static boolean isWithinWorldBounds(@NotNull WorldCompatibilityLayer worldCompatibilityLayer, @NotNull Block block) { World world = block.getWorld(); - //pretty sure both height and min height are able to have blocks placed on them + //World min height = inclusive | World max height = exclusive return block.getY() >= worldCompatibilityLayer.getMinWorldHeight(world) && block.getY() < worldCompatibilityLayer.getMaxWorldHeight(world); } From aa562a4710bce1671804b3ecbd9e7bb55a3bf250 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 18 Apr 2021 17:52:45 -0700 Subject: [PATCH 51/57] 2.1.194 --- Changelog.txt | 3 +++ pom.xml | 2 +- .../nossr50/database/SQLDatabaseManager.java | 24 ++++++++++++------- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 0c88afb19..c1130eedf 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,4 +1,7 @@ Version 2.1.194 + Fixed an XP exploit + Updated SQL to not throw errors if upgrades.yml was reset for any reason + Updated SQL to use the newest driver path (and fall back to the old one if the new one doesn't exist on the server) Locale override files are now named locale_override.properties (converted automatically/generated automatically) Existing in use locale override files will be renamed to locale_override.properties and have some useful text put in them mcMMO will now generate a locale override file with some detailed instructions if one doesn't exist (will be found in /plugins/mcMMO/locales/locale_override.properties) diff --git a/pom.xml b/pom.xml index 6cc309b22..95e3d1652 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.194-SNAPSHOT + 2.1.194 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 566a2e4f5..bdbed4983 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -31,6 +31,7 @@ public final class SQLDatabaseManager implements DatabaseManager { public static final String UUID_VARCHAR = "VARCHAR(36)"; public static final String USER_VARCHAR = "VARCHAR(40)"; public static final int CHILD_SKILLS_SIZE = 2; + public static final String LEGACY_DRIVER_PATH = "com.mysql.jdbc.Driver"; private final String tablePrefix = mcMMO.p.getGeneralConfig().getMySQLTablePrefix(); private final Map cachedUserIDs = new HashMap<>(); @@ -44,6 +45,7 @@ public final class SQLDatabaseManager implements DatabaseManager { private final ReentrantLock massUpdateLock = new ReentrantLock(); private final String CHARSET_SQL = "utf8mb4"; //This is compliant with UTF-8 while "utf8" is not, confusing but this is how it is. + private String driverPath = "com.mysql.cj.jdbc.Driver"; //modern driver protected SQLDatabaseManager() { String connectionString = "jdbc:mysql://" + mcMMO.p.getGeneralConfig().getMySQLServerName() @@ -60,10 +62,16 @@ public final class SQLDatabaseManager implements DatabaseManager { try { // Force driver to load if not yet loaded - Class.forName("com.mysql.jdbc.Driver"); - } - catch (ClassNotFoundException e) { - e.printStackTrace(); + Class.forName(driverPath); + } catch (ClassNotFoundException e) { + try { + driverPath = LEGACY_DRIVER_PATH; //fall on deprecated path if new path isn't found + Class.forName(driverPath); + } catch (ClassNotFoundException ex) { + e.printStackTrace(); + ex.printStackTrace(); + mcMMO.p.getLogger().severe("Neither driver found"); + } return; //throw e; // aborts onEnable() Riking if you want to do this, fully implement it. } @@ -71,7 +79,7 @@ public final class SQLDatabaseManager implements DatabaseManager { debug = mcMMO.p.getGeneralConfig().getMySQLDebug(); PoolProperties poolProperties = new PoolProperties(); - poolProperties.setDriverClassName("com.mysql.jdbc.Driver"); + poolProperties.setDriverClassName(driverPath); poolProperties.setUrl(connectionString); poolProperties.setUsername(mcMMO.p.getGeneralConfig().getMySQLUserName()); poolProperties.setPassword(mcMMO.p.getGeneralConfig().getMySQLUserPassword()); @@ -86,7 +94,7 @@ public final class SQLDatabaseManager implements DatabaseManager { poolProperties.setValidationInterval(30000); miscPool = new DataSource(poolProperties); poolProperties = new PoolProperties(); - poolProperties.setDriverClassName("com.mysql.jdbc.Driver"); + poolProperties.setDriverClassName(driverPath); poolProperties.setUrl(connectionString); poolProperties.setUsername(mcMMO.p.getGeneralConfig().getMySQLUserName()); poolProperties.setPassword(mcMMO.p.getGeneralConfig().getMySQLUserPassword()); @@ -101,7 +109,7 @@ public final class SQLDatabaseManager implements DatabaseManager { poolProperties.setValidationInterval(30000); savePool = new DataSource(poolProperties); poolProperties = new PoolProperties(); - poolProperties.setDriverClassName("com.mysql.jdbc.Driver"); + poolProperties.setDriverClassName(driverPath); poolProperties.setUrl(connectionString); poolProperties.setUsername(mcMMO.p.getGeneralConfig().getMySQLUserName()); poolProperties.setPassword(mcMMO.p.getGeneralConfig().getMySQLUserPassword()); @@ -1018,7 +1026,7 @@ public final class SQLDatabaseManager implements DatabaseManager { break; case ADD_SQL_INDEXES: - checkUpgradeAddSQLIndexes(statement); +// checkUpgradeAddSQLIndexes(statement); break; case ADD_MOB_HEALTHBARS: From 77a7b9865966bdc7d46278cff8610909799994ad Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 19 Apr 2021 12:15:00 -0700 Subject: [PATCH 52/57] Dev mode --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 95e3d1652..9958e7d4c 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.194 + 2.1.195-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO From c8b1a171941fb1132164269849c2a7fc86edd6bc Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 19 Apr 2021 12:20:15 -0700 Subject: [PATCH 53/57] this should fix null connection error with MySQL Fixes #4497 --- .../java/com/gmail/nossr50/database/SQLDatabaseManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java index bdbed4983..dfa33b83f 100644 --- a/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java +++ b/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java @@ -71,8 +71,8 @@ public final class SQLDatabaseManager implements DatabaseManager { e.printStackTrace(); ex.printStackTrace(); mcMMO.p.getLogger().severe("Neither driver found"); + return; } - return; //throw e; // aborts onEnable() Riking if you want to do this, fully implement it. } From 71edf0e9f4bcb6343eff91019fd17d0b1269c19e Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 19 Apr 2021 12:22:25 -0700 Subject: [PATCH 54/57] Update changelog --- Changelog.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog.txt b/Changelog.txt index c1130eedf..2386f4465 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,6 @@ +Version 2.1.195 + Fixed a null connection error which affected some SQL users + Version 2.1.194 Fixed an XP exploit Updated SQL to not throw errors if upgrades.yml was reset for any reason From 9a4ec456adaefb92460dd1bd04f89f651b9aa4e0 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 19 Apr 2021 12:26:15 -0700 Subject: [PATCH 55/57] 2.1.195 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9958e7d4c..401beec99 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.195-SNAPSHOT + 2.1.195 mcMMO https://github.com/mcMMO-Dev/mcMMO From 5416d1b36e2323117ad22d822b6d511fc649e0e4 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 19 Apr 2021 12:43:21 -0700 Subject: [PATCH 56/57] Add crossbows to enchantable items list --- Changelog.txt | 3 +++ pom.xml | 2 +- src/main/java/com/gmail/nossr50/util/MaterialMapStore.java | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Changelog.txt b/Changelog.txt index 2386f4465..c5ecccd36 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,6 @@ +Version 2.1.196 + Crossbows can now be fished up with enchantments + Version 2.1.195 Fixed a null connection error which affected some SQL users diff --git a/pom.xml b/pom.xml index 401beec99..1c31c575e 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.195 + 2.1.196-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO diff --git a/src/main/java/com/gmail/nossr50/util/MaterialMapStore.java b/src/main/java/com/gmail/nossr50/util/MaterialMapStore.java index 04564574b..8395711a7 100644 --- a/src/main/java/com/gmail/nossr50/util/MaterialMapStore.java +++ b/src/main/java/com/gmail/nossr50/util/MaterialMapStore.java @@ -424,6 +424,7 @@ public class MaterialMapStore { enchantables.addAll(pickAxes); enchantables.addAll(tridents); enchantables.addAll(bows); + enchantables.addAll(crossbows); enchantables.add("shears"); enchantables.add("fishing_rod"); From 394e9e511013d7e73eb1737aaec1aff313b77ff1 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Mon, 19 Apr 2021 12:45:51 -0700 Subject: [PATCH 57/57] Update changelog --- Changelog.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog.txt b/Changelog.txt index c5ecccd36..ffced64ac 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,6 +1,9 @@ Version 2.1.196 Crossbows can now be fished up with enchantments + NOTES: + Crossbows is not in the default fishing loot list, you'd have to add it yourself. + Version 2.1.195 Fixed a null connection error which affected some SQL users