2
0
Эх сурвалжийг харах

Huge changes to how config files are loaded/updated, fixes many issues
Fixes #4715

nossr50 3 жил өмнө
parent
commit
c21a040ddb
34 өөрчлөгдсөн 1650 нэмэгдсэн , 742 устгасан
  1. 9 1
      Changelog.txt
  2. 270 95
      src/main/java/com/gmail/nossr50/config/AdvancedConfig.java
  3. 7 10
      src/main/java/com/gmail/nossr50/config/AutoUpdateConfigLoader.java
  4. 192 0
      src/main/java/com/gmail/nossr50/config/BukkitConfig.java
  5. 3 1
      src/main/java/com/gmail/nossr50/config/ChatConfig.java
  6. 8 12
      src/main/java/com/gmail/nossr50/config/ConfigLoader.java
  7. 16 16
      src/main/java/com/gmail/nossr50/config/CoreSkillsConfig.java
  8. 686 196
      src/main/java/com/gmail/nossr50/config/GeneralConfig.java
  9. 1 1
      src/main/java/com/gmail/nossr50/config/PersistentDataConfig.java
  10. 39 42
      src/main/java/com/gmail/nossr50/config/RankConfig.java
  11. 23 30
      src/main/java/com/gmail/nossr50/config/SoundConfig.java
  12. 18 23
      src/main/java/com/gmail/nossr50/config/WorldBlacklist.java
  13. 204 87
      src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java
  14. 4 6
      src/main/java/com/gmail/nossr50/config/mods/CustomArmorConfig.java
  15. 10 14
      src/main/java/com/gmail/nossr50/config/mods/CustomBlockConfig.java
  16. 2 3
      src/main/java/com/gmail/nossr50/config/mods/CustomEntityConfig.java
  17. 6 9
      src/main/java/com/gmail/nossr50/config/mods/CustomToolConfig.java
  18. 4 3
      src/main/java/com/gmail/nossr50/config/party/ItemWeightConfig.java
  19. 14 19
      src/main/java/com/gmail/nossr50/config/skills/alchemy/PotionConfig.java
  20. 17 28
      src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfig.java
  21. 10 17
      src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfigManager.java
  22. 21 32
      src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfig.java
  23. 9 16
      src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfigManager.java
  24. 45 39
      src/main/java/com/gmail/nossr50/config/treasure/FishingTreasureConfig.java
  25. 22 26
      src/main/java/com/gmail/nossr50/config/treasure/TreasureConfig.java
  26. 0 1
      src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java
  27. 1 1
      src/main/java/com/gmail/nossr50/mcMMO.java
  28. 2 2
      src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java
  29. 0 2
      src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java
  30. 1 1
      src/main/java/com/gmail/nossr50/util/experience/ExperienceBarWrapper.java
  31. 2 2
      src/main/java/com/gmail/nossr50/util/upgrade/UpgradeManager.java
  32. 4 4
      src/main/resources/coreskills.yml
  33. 0 1
      src/main/resources/repair.vanilla.yml
  34. 0 2
      src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java

+ 9 - 1
Changelog.txt

@@ -1,6 +1,14 @@
 Version 2.1.208
+    Significantly rewrote to how mcMMO loads/updates config files
+    Fixed a bug where huge config files caused the server to take forever to start/shutdown
+    Fixed config files duplicating comments and updated their code to use Spigot API (thanks the456gamer)
+    mcMMO now repairs config files (removing duplicate comments, see notes)
     Updated lithuanian locale (thanks dexasz)
-    
+
+    NOTES:
+    Due to a change in Spigot mcMMO started growing config files at an alarming rate until they became so big they wouldn't load, and well before they got to that stage they slowed down loading the server
+    mcMMO now uses the Spigot API in a smarter way for config files
+
 Version 2.1.207
     Fixed an IndexOutOfBounds exception with our BlockTracker
     Fixed a bug where leveling up a party at level cap would spam the chat with messages

+ 270 - 95
src/main/java/com/gmail/nossr50/config/AdvancedConfig.java

@@ -10,13 +10,18 @@ import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 
-public class AdvancedConfig extends AutoUpdateConfigLoader {
+public class AdvancedConfig extends BukkitConfig {
 
     public AdvancedConfig(File dataFolder) {
         super("advanced.yml", dataFolder);
         validate();
     }
 
+    @Override
+    public void initDefaults() {
+        config.addDefault("Skills.General.StartingLevel", 0);
+    }
+
     @Override
     protected boolean validateKeys() {
         // Validate all the settings!
@@ -99,8 +104,7 @@ public class AdvancedConfig extends AutoUpdateConfigLoader {
         }
 
         /* AXES */
-        if(getAxeMasteryRankDamageMultiplier() < 0)
-        {
+        if (getAxeMasteryRankDamageMultiplier() < 0) {
             reason.add("Skills.Axes.AxeMastery.RankDamageMultiplier should be at least 0!");
         }
 
@@ -404,12 +408,18 @@ public class AdvancedConfig extends AutoUpdateConfigLoader {
     }
 
     @Override
-    protected void loadKeys() {}
+    protected void loadKeys() {
+    }
 
     /* GENERAL */
 
-    public boolean canApplyLimitBreakPVE() { return config.getBoolean("Skills.General.LimitBreak.AllowPVE", false); }
-    public int getStartingLevel() { return config.getInt("Skills.General.StartingLevel", 1); }
+    public boolean canApplyLimitBreakPVE() {
+        return config.getBoolean("Skills.General.LimitBreak.AllowPVE", false);
+    }
+
+    public int getStartingLevel() {
+        return config.getInt("Skills.General.StartingLevel", 1);
+    }
 
     public boolean allowPlayerTips() {
         return config.getBoolean("Feedback.PlayerTips", true);
@@ -418,10 +428,11 @@ public class AdvancedConfig extends AutoUpdateConfigLoader {
     /**
      * This returns the maximum level at which superabilities will stop lengthening from scaling alongside skill level.
      * It returns a different value depending on whether or not the server is in retro mode
+     *
      * @return the level at which abilities stop increasing in length
      */
     public int getAbilityLengthCap() {
-        if(!mcMMO.isRetroModeEnabled())
+        if (!mcMMO.isRetroModeEnabled())
             return config.getInt("Skills.General.Ability.Length.Standard.CapLevel", 50);
         else
             return config.getInt("Skills.General.Ability.Length.RetroMode.CapLevel", 500);
@@ -430,27 +441,32 @@ public class AdvancedConfig extends AutoUpdateConfigLoader {
     /**
      * This returns the frequency at which abilities will increase in length
      * It returns a different value depending on whether or not the server is in retro mode
+     *
      * @return the number of levels required per ability length increase
      */
     public int getAbilityLength() {
-        if(!mcMMO.isRetroModeEnabled())
+        if (!mcMMO.isRetroModeEnabled())
             return config.getInt("Skills.General.Ability.Length.Standard.IncreaseLevel", 5);
         else
             return config.getInt("Skills.General.Ability.Length.RetroMode.IncreaseLevel", 50);
     }
 
-    public int getEnchantBuff() { return config.getInt("Skills.General.Ability.EnchantBuff", 5); }
+    public int getEnchantBuff() {
+        return config.getInt("Skills.General.Ability.EnchantBuff", 5);
+    }
 
     /**
      * Grabs the max bonus level for a skill used in RNG calculations
      * All max level values in the config are multiplied by 10 if the server is in retro mode as the values in the config are based around the new 1-100 skill system scaling
      * A value of 10 in the file will be returned as 100 for retro mode servers to accommodate the change in scaling
+     *
      * @param subSkillType target subskill
+     *
      * @return the level at which this skills max benefits will be reached on the curve
      */
     public int getMaxBonusLevel(SubSkillType subSkillType) {
         String keyPath = subSkillType.getAdvConfigAddress() + ".MaxBonusLevel.";
-        return mcMMO.isRetroModeEnabled() ? config.getInt(keyPath+"RetroMode", 1000) : config.getInt(keyPath+"Standard", 100);
+        return mcMMO.isRetroModeEnabled() ? config.getInt(keyPath + "RetroMode", 1000) : config.getInt(keyPath + "Standard", 100);
     }
 
     public int getMaxBonusLevel(AbstractSubSkill abstractSubSkill) {
@@ -462,35 +478,29 @@ public class AdvancedConfig extends AutoUpdateConfigLoader {
         return config.getDouble(subSkillType.getAdvConfigAddress() + ".ChanceMax", 100.0D);
     }
 
-    public double getMaximumProbability(AbstractSubSkill abstractSubSkill)
-    {
+    public double getMaximumProbability(AbstractSubSkill abstractSubSkill) {
         return getMaximumProbability(abstractSubSkill.getSubSkillType());
     }
 
     /* Notification Settings */
 
-    public boolean doesSkillCommandSendBlankLines()
-    {
+    public boolean doesSkillCommandSendBlankLines() {
         return config.getBoolean("Feedback.SkillCommand.BlankLinesAboveHeader", true);
     }
 
-    public boolean doesNotificationUseActionBar(NotificationType notificationType)
-    {
-        return config.getBoolean("Feedback.ActionBarNotifications."+notificationType.toString()+".Enabled", true);
+    public boolean doesNotificationUseActionBar(NotificationType notificationType) {
+        return config.getBoolean("Feedback.ActionBarNotifications." + notificationType.toString() + ".Enabled", true);
     }
 
-    public boolean doesNotificationSendCopyToChat(NotificationType notificationType)
-    {
-        return config.getBoolean("Feedback.ActionBarNotifications."+notificationType.toString()+".SendCopyOfMessageToChat", false);
+    public boolean doesNotificationSendCopyToChat(NotificationType notificationType) {
+        return config.getBoolean("Feedback.ActionBarNotifications." + notificationType.toString() + ".SendCopyOfMessageToChat", false);
     }
 
-    public boolean useTitlesForXPEvent()
-    {
+    public boolean useTitlesForXPEvent() {
         return config.getBoolean("Feedback.Events.XP.SendTitles", true);
     }
 
-    public boolean sendAbilityNotificationToOtherPlayers()
-    {
+    public boolean sendAbilityNotificationToOtherPlayers() {
         return config.getBoolean("Feedback.Events.AbilityActivation.SendNotificationToOtherPlayers", true);
     }
 
@@ -509,6 +519,7 @@ public class AdvancedConfig extends AutoUpdateConfigLoader {
 
     /**
      * Used to color our details header in our JSON Hover Object tooltips
+     *
      * @return the ChatColor for this element
      */
     /*public ChatColor getJSONStatHoverDetailsColor()
@@ -557,7 +568,6 @@ public class AdvancedConfig extends AutoUpdateConfigLoader {
     {
         return getChatColor(config.getString("Style.JSON.Notification."+notificationType.toString()+".Color"));
     }*/
-
     private ChatColor getChatColorFromKey(String keyLocation) {
         String colorName = config.getString(keyLocation);
 
@@ -598,111 +608,243 @@ public class AdvancedConfig extends AutoUpdateConfigLoader {
 
     /**
      * Some SubSkills have the ability to retain classic functionality
+     *
      * @param subSkillType SubSkillType with classic functionality
+     *
      * @return true if the subskill is in classic mode
      */
-    public boolean isSubSkillClassic(SubSkillType subSkillType)
-    {
-        return config.getBoolean(subSkillType.getAdvConfigAddress()+".Classic");
+    public boolean isSubSkillClassic(SubSkillType subSkillType) {
+        return config.getBoolean(subSkillType.getAdvConfigAddress() + ".Classic");
     }
 
     /* ACROBATICS */
-    public double getDodgeDamageModifier() { return config.getDouble("Skills.Acrobatics.Dodge.DamageModifier", 2.0D); }
+    public double getDodgeDamageModifier() {
+        return config.getDouble("Skills.Acrobatics.Dodge.DamageModifier", 2.0D);
+    }
 
-    public double getRollDamageThreshold() { return config.getDouble("Skills.Acrobatics.Roll.DamageThreshold", 7.0D); }
+    public double getRollDamageThreshold() {
+        return config.getDouble("Skills.Acrobatics.Roll.DamageThreshold", 7.0D);
+    }
 
-    public double getGracefulRollDamageThreshold() { return config.getDouble("Skills.Acrobatics.GracefulRoll.DamageThreshold", 14.0D); }
+    public double getGracefulRollDamageThreshold() {
+        return config.getDouble("Skills.Acrobatics.GracefulRoll.DamageThreshold", 14.0D);
+    }
 
     /* ALCHEMY */
-    public int getCatalysisMaxBonusLevel() { return config.getInt("Skills.Alchemy.Catalysis.MaxBonusLevel", 1000); }
+    public int getCatalysisMaxBonusLevel() {
+        return config.getInt("Skills.Alchemy.Catalysis.MaxBonusLevel", 1000);
+    }
+
+    public double getCatalysisMinSpeed() {
+        return config.getDouble("Skills.Alchemy.Catalysis.MinSpeed", 1.0D);
+    }
 
-    public double getCatalysisMinSpeed() { return config.getDouble("Skills.Alchemy.Catalysis.MinSpeed", 1.0D); }
-    public double getCatalysisMaxSpeed() { return config.getDouble("Skills.Alchemy.Catalysis.MaxSpeed", 4.0D); }
+    public double getCatalysisMaxSpeed() {
+        return config.getDouble("Skills.Alchemy.Catalysis.MaxSpeed", 4.0D);
+    }
 
 
     /* ARCHERY */
-    public double getSkillShotRankDamageMultiplier() { return config.getDouble("Skills.Archery.SkillShot.RankDamageMultiplier", 10.0D); }
-    public double getSkillShotDamageMax() { return config.getDouble("Skills.Archery.SkillShot.MaxDamage", 9.0D); }
+    public double getSkillShotRankDamageMultiplier() {
+        return config.getDouble("Skills.Archery.SkillShot.RankDamageMultiplier", 10.0D);
+    }
 
-    public double getDazeBonusDamage() { return config.getDouble("Skills.Archery.Daze.BonusDamage", 4.0D); }
+    public double getSkillShotDamageMax() {
+        return config.getDouble("Skills.Archery.SkillShot.MaxDamage", 9.0D);
+    }
 
-    public double getForceMultiplier() { return config.getDouble("Skills.Archery.ForceMultiplier", 2.0D); }
+    public double getDazeBonusDamage() {
+        return config.getDouble("Skills.Archery.Daze.BonusDamage", 4.0D);
+    }
+
+    public double getForceMultiplier() {
+        return config.getDouble("Skills.Archery.ForceMultiplier", 2.0D);
+    }
 
     /* AXES */
-    public double getAxeMasteryRankDamageMultiplier() { return config.getDouble("Skills.Axes.AxeMastery.RankDamageMultiplier", 1.0D); }
+    public double getAxeMasteryRankDamageMultiplier() {
+        return config.getDouble("Skills.Axes.AxeMastery.RankDamageMultiplier", 1.0D);
+    }
 
-    public double getCriticalStrikesPVPModifier() { return config.getDouble("Skills.Axes.CriticalStrikes.PVP_Modifier", 1.5D); }
-    public double getCriticalStrikesPVEModifier() { return config.getDouble("Skills.Axes.CriticalStrikes.PVE_Modifier", 2.0D); }
+    public double getCriticalStrikesPVPModifier() {
+        return config.getDouble("Skills.Axes.CriticalStrikes.PVP_Modifier", 1.5D);
+    }
+
+    public double getCriticalStrikesPVEModifier() {
+        return config.getDouble("Skills.Axes.CriticalStrikes.PVE_Modifier", 2.0D);
+    }
+
+    public double getGreaterImpactChance() {
+        return config.getDouble("Skills.Axes.GreaterImpact.Chance", 25.0D);
+    }
+
+    public double getGreaterImpactModifier() {
+        return config.getDouble("Skills.Axes.GreaterImpact.KnockbackModifier", 1.5D);
+    }
 
-    public double getGreaterImpactChance() { return config.getDouble("Skills.Axes.GreaterImpact.Chance", 25.0D); }
-    public double getGreaterImpactModifier() { return config.getDouble("Skills.Axes.GreaterImpact.KnockbackModifier", 1.5D); }
-    public double getGreaterImpactBonusDamage() { return config.getDouble("Skills.Axes.GreaterImpact.BonusDamage", 2.0D); }
+    public double getGreaterImpactBonusDamage() {
+        return config.getDouble("Skills.Axes.GreaterImpact.BonusDamage", 2.0D);
+    }
 
-    public double getImpactChance() { return config.getDouble("Skills.Axes.ArmorImpact.Chance", 25.0D); }
-    public double getImpactDurabilityDamageMultiplier() { return config.getDouble("Skills.Axes.ArmorImpact.DamagePerRank", 6.5D); }
+    public double getImpactChance() {
+        return config.getDouble("Skills.Axes.ArmorImpact.Chance", 25.0D);
+    }
 
-    public double getSkullSplitterModifier() { return config.getDouble("Skills.Axes.SkullSplitter.DamageModifier", 2.0D); }
+    public double getImpactDurabilityDamageMultiplier() {
+        return config.getDouble("Skills.Axes.ArmorImpact.DamagePerRank", 6.5D);
+    }
+
+    public double getSkullSplitterModifier() {
+        return config.getDouble("Skills.Axes.SkullSplitter.DamageModifier", 2.0D);
+    }
 
     /* EXCAVATION */
     //Nothing to configure, everything is already configurable in config.yml
 
     /* FISHING */
-    public double getShakeChance(int rank) { return config.getDouble("Skills.Fishing.ShakeChance.Rank_" + rank); }
-    public int getFishingVanillaXPModifier(int rank) { return config.getInt("Skills.Fishing.VanillaXPMultiplier.Rank_" + rank); }
+    public double getShakeChance(int rank) {
+        return config.getDouble("Skills.Fishing.ShakeChance.Rank_" + rank);
+    }
+
+    public int getFishingVanillaXPModifier(int rank) {
+        return config.getInt("Skills.Fishing.VanillaXPMultiplier.Rank_" + rank);
+    }
+
+    public int getFishingReductionMinWaitTicks() {
+        return config.getInt("Skills.Fishing.MasterAngler.Tick_Reduction_Per_Rank.Min_Wait", 10);
+    }
+
+    public int getFishingReductionMaxWaitTicks() {
+        return config.getInt("Skills.Fishing.MasterAngler.Tick_Reduction_Per_Rank.Max_Wait", 30);
+    }
+
+    public int getFishingBoatReductionMinWaitTicks() {
+        return config.getInt("Skills.Fishing.MasterAngler.Boat_Tick_Reduction.Min_Wait", 10);
+    }
+
+    public int getFishingBoatReductionMaxWaitTicks() {
+        return config.getInt("Skills.Fishing.MasterAngler.Boat_Tick_Reduction.Max_Wait", 30);
+    }
+
+    public int getFishingReductionMinWaitCap() {
+        return config.getInt("Skills.Fishing.MasterAngler.Tick_Reduction_Caps.Min_Wait", 40);
+    }
+
+    public int getFishingReductionMaxWaitCap() {
+        return config.getInt("Skills.Fishing.MasterAngler.Tick_Reduction_Caps.Max_Wait", 100);
+    }
+
+    public int getFishermanDietRankChange() {
+        return config.getInt("Skills.Fishing.FishermansDiet.RankChange", 200);
+    }
 
-    public int getFishingReductionMinWaitTicks() { return config.getInt("Skills.Fishing.MasterAngler.Tick_Reduction_Per_Rank.Min_Wait", 10);}
-    public int getFishingReductionMaxWaitTicks() { return config.getInt("Skills.Fishing.MasterAngler.Tick_Reduction_Per_Rank.Max_Wait", 30);}
-    public int getFishingBoatReductionMinWaitTicks() { return config.getInt("Skills.Fishing.MasterAngler.Boat_Tick_Reduction.Min_Wait", 10);}
-    public int getFishingBoatReductionMaxWaitTicks() { return config.getInt("Skills.Fishing.MasterAngler.Boat_Tick_Reduction.Max_Wait", 30);}
-    public int getFishingReductionMinWaitCap() { return config.getInt("Skills.Fishing.MasterAngler.Tick_Reduction_Caps.Min_Wait", 40);}
-    public int getFishingReductionMaxWaitCap() { return config.getInt("Skills.Fishing.MasterAngler.Tick_Reduction_Caps.Max_Wait", 100);}
-    public int getFishermanDietRankChange() { return config.getInt("Skills.Fishing.FishermansDiet.RankChange", 200); }
 
+    public double getMasterAnglerBoatModifier() {
+        return config.getDouble("Skills.Fishing.MasterAngler.BoatModifier", 2.0);
+    }
 
-    public double getMasterAnglerBoatModifier() {return config.getDouble("Skills.Fishing.MasterAngler.BoatModifier", 2.0); }
-    public double getMasterAnglerBiomeModifier() {return config.getDouble("Skills.Fishing.MasterAngler.BiomeModifier", 2.0); }
+    public double getMasterAnglerBiomeModifier() {
+        return config.getDouble("Skills.Fishing.MasterAngler.BiomeModifier", 2.0);
+    }
 
     /* HERBALISM */
-    public int getFarmerDietRankChange() { return config.getInt("Skills.Herbalism.FarmersDiet.RankChange", 200); }
+    public int getFarmerDietRankChange() {
+        return config.getInt("Skills.Herbalism.FarmersDiet.RankChange", 200);
+    }
 
-    public int getGreenThumbStageChange() { return config.getInt("Skills.Herbalism.GreenThumb.StageChange", 200); }
+    public int getGreenThumbStageChange() {
+        return config.getInt("Skills.Herbalism.GreenThumb.StageChange", 200);
+    }
 
     /* MINING */
-    public boolean getDoubleDropSilkTouchEnabled() { return config.getBoolean("Skills.Mining.DoubleDrops.SilkTouch", true); }
-    public boolean getAllowMiningTripleDrops() { return config.getBoolean("Skills.Mining.SuperBreaker.AllowTripleDrops", true); }
-    public int getBlastMiningRankLevel(int rank) { return config.getInt("Skills.Mining.BlastMining.Rank_Levels.Rank_" + rank); }
-    public double getBlastDamageDecrease(int rank) { return config.getDouble("Skills.Mining.BlastMining.BlastDamageDecrease.Rank_" + rank); }
-    public double getOreBonus(int rank) { return config.getDouble("Skills.Mining.BlastMining.OreBonus.Rank_" + rank); }
-    public double getDebrisReduction(int rank) { return config.getDouble("Skills.Mining.BlastMining.DebrisReduction.Rank_" + rank); }
-    public int getDropMultiplier(int rank) { return config.getInt("Skills.Mining.BlastMining.DropMultiplier.Rank_" + rank); }
-    public double getBlastRadiusModifier(int rank) { return config.getDouble("Skills.Mining.BlastMining.BlastRadiusModifier.Rank_" + rank); }
+    public boolean getDoubleDropSilkTouchEnabled() {
+        return config.getBoolean("Skills.Mining.DoubleDrops.SilkTouch", true);
+    }
+
+    public boolean getAllowMiningTripleDrops() {
+        return config.getBoolean("Skills.Mining.SuperBreaker.AllowTripleDrops", true);
+    }
+
+    public int getBlastMiningRankLevel(int rank) {
+        return config.getInt("Skills.Mining.BlastMining.Rank_Levels.Rank_" + rank);
+    }
+
+    public double getBlastDamageDecrease(int rank) {
+        return config.getDouble("Skills.Mining.BlastMining.BlastDamageDecrease.Rank_" + rank);
+    }
+
+    public double getOreBonus(int rank) {
+        return config.getDouble("Skills.Mining.BlastMining.OreBonus.Rank_" + rank);
+    }
+
+    public double getDebrisReduction(int rank) {
+        return config.getDouble("Skills.Mining.BlastMining.DebrisReduction.Rank_" + rank);
+    }
+
+    public int getDropMultiplier(int rank) {
+        return config.getInt("Skills.Mining.BlastMining.DropMultiplier.Rank_" + rank);
+    }
+
+    public double getBlastRadiusModifier(int rank) {
+        return config.getDouble("Skills.Mining.BlastMining.BlastRadiusModifier.Rank_" + rank);
+    }
 
     /* REPAIR */
-    public double getRepairMasteryMaxBonus() { return config.getDouble("Skills.Repair.RepairMastery.MaxBonusPercentage", 200.0D); }
-    public int getRepairMasteryMaxLevel() { return config.getInt("Skills.Repair.RepairMastery.MaxBonusLevel", 100); }
-    public boolean getAllowEnchantedRepairMaterials() { return config.getBoolean("Skills.Repair.Use_Enchanted_Materials", false); }
+    public double getRepairMasteryMaxBonus() {
+        return config.getDouble("Skills.Repair.RepairMastery.MaxBonusPercentage", 200.0D);
+    }
+
+    public int getRepairMasteryMaxLevel() {
+        return config.getInt("Skills.Repair.RepairMastery.MaxBonusLevel", 100);
+    }
 
-    public boolean getArcaneForgingEnchantLossEnabled() { return config.getBoolean("Skills.Repair.ArcaneForging.May_Lose_Enchants", true); }
-    public double getArcaneForgingKeepEnchantsChance(int rank) { return config.getDouble("Skills.Repair.ArcaneForging.Keep_Enchants_Chance.Rank_" + rank); }
+    public boolean getAllowEnchantedRepairMaterials() {
+        return config.getBoolean("Skills.Repair.Use_Enchanted_Materials", false);
+    }
 
-    public boolean getArcaneForgingDowngradeEnabled() { return config.getBoolean("Skills.Repair.ArcaneForging.Downgrades_Enabled", true); }
-    public double getArcaneForgingDowngradeChance(int rank) { return config.getDouble("Skills.Repair.ArcaneForging.Downgrades_Chance.Rank_" + rank); }
+    public boolean getArcaneForgingEnchantLossEnabled() {
+        return config.getBoolean("Skills.Repair.ArcaneForging.May_Lose_Enchants", true);
+    }
 
-    public boolean getArcaneSalvageEnchantDowngradeEnabled() { return config.getBoolean("Skills.Salvage.ArcaneSalvage.EnchantDowngradeEnabled", true); }
-    public boolean getArcaneSalvageEnchantLossEnabled() { return config.getBoolean("Skills.Salvage.ArcaneSalvage.EnchantLossEnabled", true); }
+    public double getArcaneForgingKeepEnchantsChance(int rank) {
+        return config.getDouble("Skills.Repair.ArcaneForging.Keep_Enchants_Chance.Rank_" + rank);
+    }
 
-    public double getArcaneSalvageExtractFullEnchantsChance(int rank) { return config.getDouble("Skills.Salvage.ArcaneSalvage.ExtractFullEnchant.Rank_" + rank); }
-    public double getArcaneSalvageExtractPartialEnchantsChance(int rank) { return config.getDouble("Skills.Salvage.ArcaneSalvage.ExtractPartialEnchant.Rank_" + rank); }
+    public boolean getArcaneForgingDowngradeEnabled() {
+        return config.getBoolean("Skills.Repair.ArcaneForging.Downgrades_Enabled", true);
+    }
+
+    public double getArcaneForgingDowngradeChance(int rank) {
+        return config.getDouble("Skills.Repair.ArcaneForging.Downgrades_Chance.Rank_" + rank);
+    }
+
+    public boolean getArcaneSalvageEnchantDowngradeEnabled() {
+        return config.getBoolean("Skills.Salvage.ArcaneSalvage.EnchantDowngradeEnabled", true);
+    }
+
+    public boolean getArcaneSalvageEnchantLossEnabled() {
+        return config.getBoolean("Skills.Salvage.ArcaneSalvage.EnchantLossEnabled", true);
+    }
+
+    public double getArcaneSalvageExtractFullEnchantsChance(int rank) {
+        return config.getDouble("Skills.Salvage.ArcaneSalvage.ExtractFullEnchant.Rank_" + rank);
+    }
+
+    public double getArcaneSalvageExtractPartialEnchantsChance(int rank) {
+        return config.getDouble("Skills.Salvage.ArcaneSalvage.ExtractPartialEnchant.Rank_" + rank);
+    }
 
     /* SMELTING */
     public int getBurnModifierMaxLevel() {
-        if(mcMMO.isRetroModeEnabled())
+        if (mcMMO.isRetroModeEnabled())
             return config.getInt("Skills.Smelting.FuelEfficiency.RetroMode.MaxBonusLevel", 1000);
         else
             return config.getInt("Skills.Smelting.FuelEfficiency.Standard.MaxBonusLevel", 100);
     }
 
-    public double getFluxMiningChance() { return config.getDouble("Skills.Smelting.FluxMining.Chance", 33.0D); }
+    public double getFluxMiningChance() {
+        return config.getDouble("Skills.Smelting.FluxMining.Chance", 33.0D);
+    }
 
     /* SWORDS */
     public double getRuptureTickDamage(boolean isTargetPlayer, int rank) {
@@ -732,35 +874,68 @@ public class AdvancedConfig extends AutoUpdateConfigLoader {
         return config.getDouble(root + rank, 33);
     }
 
-    public double getCounterModifier() { return config.getDouble("Skills.Swords.CounterAttack.DamageModifier", 2.0D); }
+    public double getCounterModifier() {
+        return config.getDouble("Skills.Swords.CounterAttack.DamageModifier", 2.0D);
+    }
 
-    public double getSerratedStrikesModifier() { return config.getDouble("Skills.Swords.SerratedStrikes.DamageModifier", 4.0D); }
-    public int getSerratedStrikesTicks() { return config.getInt("Skills.Swords.SerratedStrikes.RuptureTicks", 5); }
+    public double getSerratedStrikesModifier() {
+        return config.getDouble("Skills.Swords.SerratedStrikes.DamageModifier", 4.0D);
+    }
+
+    public int getSerratedStrikesTicks() {
+        return config.getInt("Skills.Swords.SerratedStrikes.RuptureTicks", 5);
+    }
 
     /* TAMING */
-    public double getGoreModifier() { return config.getDouble("Skills.Taming.Gore.Modifier", 2.0D); }
+    public double getGoreModifier() {
+        return config.getDouble("Skills.Taming.Gore.Modifier", 2.0D);
+    }
 
-    public double getFastFoodChance() { return config.getDouble("Skills.Taming.FastFoodService.Chance", 50.0D); }
-    public double getPummelChance() { return config.getDouble("Skills.Taming.Pummel.Chance", 10.0D); }
+    public double getFastFoodChance() {
+        return config.getDouble("Skills.Taming.FastFoodService.Chance", 50.0D);
+    }
+
+    public double getPummelChance() {
+        return config.getDouble("Skills.Taming.Pummel.Chance", 10.0D);
+    }
 
-    public double getThickFurModifier() { return config.getDouble("Skills.Taming.ThickFur.Modifier", 2.0D); }
+    public double getThickFurModifier() {
+        return config.getDouble("Skills.Taming.ThickFur.Modifier", 2.0D);
+    }
 
-    public double getShockProofModifier() { return config.getDouble("Skills.Taming.ShockProof.Modifier", 6.0D); }
+    public double getShockProofModifier() {
+        return config.getDouble("Skills.Taming.ShockProof.Modifier", 6.0D);
+    }
+
+    public double getSharpenedClawsBonus() {
+        return config.getDouble("Skills.Taming.SharpenedClaws.Bonus", 2.0D);
+    }
 
-    public double getSharpenedClawsBonus() { return config.getDouble("Skills.Taming.SharpenedClaws.Bonus", 2.0D); }
+    public double getMinHorseJumpStrength() {
+        return config.getDouble("Skills.Taming.CallOfTheWild.MinHorseJumpStrength", 0.7D);
+    }
 
-    public double getMinHorseJumpStrength() { return config.getDouble("Skills.Taming.CallOfTheWild.MinHorseJumpStrength", 0.7D); }
-    public double getMaxHorseJumpStrength() { return config.getDouble("Skills.Taming.CallOfTheWild.MaxHorseJumpStrength", 2.0D); }
+    public double getMaxHorseJumpStrength() {
+        return config.getDouble("Skills.Taming.CallOfTheWild.MaxHorseJumpStrength", 2.0D);
+    }
 
     /* UNARMED */
 
-    public boolean isSteelArmDamageCustom() { return config.getBoolean("Skills.Unarmed.SteelArmStyle.Damage_Override", false); }
+    public boolean isSteelArmDamageCustom() {
+        return config.getBoolean("Skills.Unarmed.SteelArmStyle.Damage_Override", false);
+    }
+
     public double getSteelArmOverride(int rank, double def) {
         String key = "Rank_" + rank;
         return config.getDouble("Skills.Unarmed.SteelArmStyle.Override." + key, def);
     }
-    public boolean getDisarmProtected() { return config.getBoolean("Skills.Unarmed.Disarm.AntiTheft", false); }
+
+    public boolean getDisarmProtected() {
+        return config.getBoolean("Skills.Unarmed.Disarm.AntiTheft", false);
+    }
 
     /* WOODCUTTING */
-    public boolean isKnockOnWoodXPOrbEnabled() { return config.getBoolean("Skills.Woodcutting.TreeFeller.Knock_On_Wood.Add_XP_Orbs_To_Drops", true); }
+    public boolean isKnockOnWoodXPOrbEnabled() {
+        return config.getBoolean("Skills.Woodcutting.TreeFeller.Knock_On_Wood.Add_XP_Orbs_To_Drops", true);
+    }
 }

+ 7 - 10
src/main/java/com/gmail/nossr50/config/AutoUpdateConfigLoader.java

@@ -31,10 +31,9 @@ public abstract class AutoUpdateConfigLoader extends ConfigLoader {
 
     protected void saveConfig() {
         try {
-            mcMMO.p.getLogger().info("Saving changes to config file - "+fileName);
-            YamlConfiguration yamlConfiguration = (YamlConfiguration) config;
-            yamlConfiguration.options().indent(4);
-            yamlConfiguration.save(configFile);
+            mcMMO.p.getLogger().info("Saving changes to config file - " + fileName);
+            config.options().indent(2);
+            config.save(configFile);
         } catch (IOException e) {
             e.printStackTrace();
         }
@@ -59,13 +58,12 @@ public abstract class AutoUpdateConfigLoader extends ConfigLoader {
         oldKeys.removeAll(internalConfigKeys);
 
         if (!oldKeys.isEmpty()) {
-            mcMMO.p.debug("old key(s) in \"" +fileName+"\"");
+            mcMMO.p.debug("old key(s) in \"" + fileName + "\"");
             for (String key : oldKeys) {
                 mcMMO.p.debug("  old-key:" + key);
             }
         }
 
-
         // keys present in template that are not in current file
         Set<String> newKeys = new HashSet<>(internalConfigKeys);
         newKeys.removeAll(configKeys);
@@ -82,7 +80,7 @@ public abstract class AutoUpdateConfigLoader extends ConfigLoader {
         if (needSave) {
             // Save it
 
-            if(dataFolder == null) {
+            if (dataFolder == null) {
                 mcMMO.p.getLogger().severe("Data folder should never be null!");
                 return;
             }
@@ -95,12 +93,11 @@ public abstract class AutoUpdateConfigLoader extends ConfigLoader {
                 }
 
                 File newSaveFile = new File(dataFolder, saveName);
-                YamlConfiguration yamlConfiguration = (YamlConfiguration) config;
+                YamlConfiguration yamlConfiguration = config;
                 yamlConfiguration.options().indent(4);
                 yamlConfiguration.save(newSaveFile);
 
-            }
-            catch (Exception e) {
+            } catch (Exception e) {
                 e.printStackTrace();
             }
         }

+ 192 - 0
src/main/java/com/gmail/nossr50/config/BukkitConfig.java

@@ -0,0 +1,192 @@
+package com.gmail.nossr50.config;
+
+import com.gmail.nossr50.mcMMO;
+import org.bukkit.configuration.InvalidConfigurationException;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.*;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public abstract class BukkitConfig {
+    public static final String CURRENT_CONFIG_PATCH_VER = "ConfigPatchVersion: 1";
+    protected final String fileName;
+    protected final File configFile;
+    protected YamlConfiguration config;
+    protected @NotNull
+    final File dataFolder;
+
+    public BukkitConfig(@NotNull String fileName, @NotNull File dataFolder) {
+        mcMMO.p.getLogger().info("[config] Initializing config: " + fileName);
+        this.fileName = fileName;
+        this.dataFolder = dataFolder;
+        configFile = new File(dataFolder, fileName);
+        purgeComments(true);
+        this.config = initConfig();
+        initDefaults();
+        updateFile();
+        mcMMO.p.getLogger().info("[config] Config initialized: " + fileName);
+    }
+
+    @Deprecated
+    public BukkitConfig(@NotNull String fileName) {
+        this(fileName, mcMMO.p.getDataFolder());
+    }
+
+    /**
+     * Initialize default values for the config
+     */
+    public void initDefaults() {}
+
+    /**
+     * Update the file on the disk by copying out any new and missing defaults
+     */
+    public void updateFile() {
+        try {
+            config.save(configFile);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private YamlConfiguration initConfig() {
+        if (!configFile.exists()) {
+            mcMMO.p.getLogger().info("[config] User config file not found, copying a default config to disk: " + fileName);
+            mcMMO.p.saveResource(fileName, false);
+        }
+
+        mcMMO.p.getLogger().info("[config] Loading config from disk: " + fileName);
+        YamlConfiguration config = new YamlConfiguration();
+        config.options().indent(4);
+        config.options().parseComments(true);
+        config.options().copyDefaults(true);
+
+        try {
+            config.load(configFile);
+        } catch (IOException | InvalidConfigurationException e) {
+            e.printStackTrace();
+        }
+
+        return config;
+    }
+
+    protected abstract void loadKeys();
+
+    protected boolean validateKeys() {
+        return true;
+    }
+
+    protected boolean noErrorsInConfig(List<String> issues) {
+        for (String issue : issues) {
+            mcMMO.p.getLogger().warning(issue);
+        }
+
+        return issues.isEmpty();
+    }
+
+    protected void validate() {
+        if (validateKeys()) {
+            mcMMO.p.debug("No errors found in " + fileName + "!");
+        } else {
+            mcMMO.p.getLogger().warning("Errors were found in " + fileName + "! mcMMO was disabled!");
+            mcMMO.p.getServer().getPluginManager().disablePlugin(mcMMO.p);
+            mcMMO.p.noErrorsInConfigFiles = false;
+        }
+    }
+
+    public void backup() {
+        mcMMO.p.getLogger().severe("You are using an old version of the " + fileName + " file.");
+        mcMMO.p.getLogger().severe("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 (mcMMO.p.getResource(fileName) != null) {
+            mcMMO.p.saveResource(fileName, true);
+        }
+
+        mcMMO.p.getLogger().warning("Reloading " + fileName + " with new values...");
+        initConfig();
+        loadKeys();
+    }
+
+    public File getFile() {
+        return configFile;
+    }
+
+    /**
+     * Somewhere between December 2021-January 2022 Spigot updated their
+     * SnakeYAML dependency/API and due to our own crappy legacy code
+     * this introduced a very problematic bug where comments got duplicated
+     * <p>
+     * This method hotfixes the problem by just deleting any existing comments
+     * it's ugly, but it gets the job done
+     *
+     * @param silentFail when true mcMMO will report errors during the patch process or debug information
+     *                   the option to have it fail silently is because mcMMO wants to check files before they are parsed as a file with a zillion comments will fail to even load
+     */
+    private void purgeComments(boolean silentFail) {
+        if(!configFile.exists())
+            return;
+
+        int dupedLines = 0, lineCount = 0, lineCountAfter = 0;
+        try (FileReader fileReader = new FileReader(configFile);
+             BufferedReader bufferedReader = new BufferedReader(fileReader)) {
+            StringBuilder stringBuilder = new StringBuilder();
+            String line;
+            Set<String> seenBefore = new HashSet<>();
+
+            stringBuilder.append(CURRENT_CONFIG_PATCH_VER).append(System.lineSeparator());
+            boolean noPatchNeeded = false;
+
+            // While not at the end of the file
+            while ((line = bufferedReader.readLine()) != null) {
+                lineCount++;
+
+                if(line.startsWith(CURRENT_CONFIG_PATCH_VER)) {
+                    noPatchNeeded = true;
+                    break;
+                }
+
+                if (line.startsWith("#")) {
+                    if(seenBefore.contains(line))
+                        dupedLines++;
+                    else
+                        seenBefore.add(line);
+
+                    continue; //Delete the line by not appending it
+                }
+
+                stringBuilder
+                        .append(line) //Convert existing files into two-spaced format
+                        .append(System.lineSeparator());
+                lineCountAfter++;
+            }
+
+            if(noPatchNeeded)
+                return;
+
+            if(lineCount == 0 && !silentFail) {
+                mcMMO.p.getLogger().info("[config patcher] Config line count: " + lineCount);
+                throw new InvalidConfigurationException("[config patcher] Patching of config file resulted in an empty file, this will not be saved. Contact the mcMMO devs!");
+            }
+
+            if(dupedLines > 0 && !silentFail) {
+                mcMMO.p.getLogger().info("[config patcher] Found "+dupedLines+" duplicate comments in config file: " + configFile.getName());
+                mcMMO.p.getLogger().info("[config patcher] Purging the duplicate comments... (Nothing is broken, this is just info used for debugging)");
+                mcMMO.p.getLogger().info("[config patcher] Line count before: "+lineCount);
+                mcMMO.p.getLogger().info("[config patcher] Line count after: "+lineCountAfter);
+            }
+
+            // Write out the *patched* file
+            // AKA the file without any comments
+            try (FileWriter fileWriter = new FileWriter(configFile)) {
+                fileWriter.write(stringBuilder.toString());
+            }
+        } catch (IOException | InvalidConfigurationException ex) {
+            mcMMO.p.getLogger().severe("Failed to patch config file: " + configFile.getName());
+            ex.printStackTrace();
+        }
+    }
+}

+ 3 - 1
src/main/java/com/gmail/nossr50/config/ChatConfig.java

@@ -4,7 +4,7 @@ import com.gmail.nossr50.datatypes.chat.ChatChannel;
 import com.gmail.nossr50.util.text.StringUtils;
 import org.jetbrains.annotations.NotNull;
 
-public class ChatConfig extends AutoUpdateConfigLoader {
+public class ChatConfig extends BukkitConfig {
     private static ChatConfig instance;
 
     private ChatConfig() {
@@ -41,7 +41,9 @@ public class ChatConfig extends AutoUpdateConfigLoader {
 
     /**
      * Whether or not to use display names for players in target {@link ChatChannel}
+     *
      * @param chatChannel target chat channel
+     *
      * @return true if display names should be used
      */
     public boolean useDisplayNames(@NotNull ChatChannel chatChannel) {

+ 8 - 12
src/main/java/com/gmail/nossr50/config/ConfigLoader.java

@@ -1,7 +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;
 
@@ -9,10 +8,10 @@ import java.io.File;
 import java.util.List;
 
 public abstract class ConfigLoader {
-    protected String fileName;
     protected final File configFile;
-    protected FileConfiguration config;
-    protected @NotNull final File dataFolder;
+    protected final @NotNull File dataFolder;
+    protected String fileName;
+    protected YamlConfiguration config;
 
     public ConfigLoader(String relativePath, String fileName, @NotNull File dataFolder) {
         this.fileName = fileName;
@@ -46,17 +45,15 @@ public abstract class ConfigLoader {
 
     protected void loadFile() {
         if (!configFile.exists()) {
-            mcMMO.p.debug("Creating mcMMO " + fileName + " File...");
+            mcMMO.p.getLogger().info("Creating mcMMO " + fileName + " File...");
 
             try {
                 mcMMO.p.saveResource(fileName, false); // Normal files
-            }
-            catch (IllegalArgumentException ex) {
+            } catch (IllegalArgumentException ex) {
                 mcMMO.p.saveResource(configFile.getParentFile().getName() + File.separator + fileName, false); // Mod files
             }
-        }
-        else {
-            mcMMO.p.debug("Loading mcMMO " + fileName + " File...");
+        } else {
+            mcMMO.p.getLogger().info("Loading mcMMO " + fileName + " File...");
         }
 
         config = YamlConfiguration.loadConfiguration(configFile);
@@ -79,8 +76,7 @@ public abstract class ConfigLoader {
     protected void validate() {
         if (validateKeys()) {
             mcMMO.p.debug("No errors found in " + fileName + "!");
-        }
-        else {
+        } else {
             mcMMO.p.getLogger().warning("Errors were found in " + fileName + "! mcMMO was disabled!");
             mcMMO.p.getServer().getPluginManager().disablePlugin(mcMMO.p);
             mcMMO.p.noErrorsInConfigFiles = false;

+ 16 - 16
src/main/java/com/gmail/nossr50/config/CoreSkillsConfig.java

@@ -4,26 +4,24 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill;
 import com.gmail.nossr50.util.text.StringUtils;
 
-public class CoreSkillsConfig extends AutoUpdateConfigLoader {
+public class CoreSkillsConfig extends BukkitConfig {
     private static CoreSkillsConfig instance;
 
-    public CoreSkillsConfig()
-    {
+    public CoreSkillsConfig() {
         super("coreskills.yml");
         validate();
     }
 
-    @Override
-    protected void loadKeys() {
+    public static CoreSkillsConfig getInstance() {
+        if (instance == null)
+            instance = new CoreSkillsConfig();
 
+        return instance;
     }
 
-    public static CoreSkillsConfig getInstance()
-    {
-        if(instance == null)
-            return new CoreSkillsConfig();
+    @Override
+    protected void loadKeys() {
 
-        return instance;
     }
 
     @Override
@@ -39,21 +37,23 @@ public class CoreSkillsConfig extends AutoUpdateConfigLoader {
     /**
      * Whether or not a skill is enabled
      * Defaults true
+     *
      * @param abstractSubSkill SubSkill definition to check
+     *
      * @return true if subskill is enabled
      */
-    public boolean isSkillEnabled(AbstractSubSkill abstractSubSkill)
-    {
-        return config.getBoolean(StringUtils.getCapitalized(abstractSubSkill.getPrimarySkill().toString())+"."+ abstractSubSkill.getConfigKeyName()+".Enabled", true);
+    public boolean isSkillEnabled(AbstractSubSkill abstractSubSkill) {
+        return config.getBoolean(StringUtils.getCapitalized(abstractSubSkill.getPrimarySkill().toString()) + "." + abstractSubSkill.getConfigKeyName() + ".Enabled", true);
     }
 
     /**
      * Whether or not this primary skill is enabled
+     *
      * @param primarySkillType target primary skill
+     *
      * @return true if enabled
      */
-    public boolean isPrimarySkillEnabled(PrimarySkillType primarySkillType)
-    {
-        return config.getBoolean(StringUtils.getCapitalized(primarySkillType.toString())+".Enabled", true);
+    public boolean isPrimarySkillEnabled(PrimarySkillType primarySkillType) {
+        return config.getBoolean(StringUtils.getCapitalized(primarySkillType.toString()) + ".Enabled", true);
     }
 }

+ 686 - 196
src/main/java/com/gmail/nossr50/config/GeneralConfig.java

@@ -18,7 +18,7 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Set;
 
-public class GeneralConfig extends AutoUpdateConfigLoader {
+public class GeneralConfig extends BukkitConfig {
 
     public GeneralConfig(@NotNull File dataFolder) {
         super("config.yml", dataFolder);
@@ -159,99 +159,264 @@ public class GeneralConfig extends AutoUpdateConfigLoader {
      */
 
     /* General Settings */
-    public boolean getIsMetricsEnabled() { return config.getBoolean("Metrics.bstats", true); }
+    public boolean getIsMetricsEnabled() {
+        return config.getBoolean("Metrics.bstats", true);
+    }
 
     //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 boolean getIsRetroMode() {
+        return config.getBoolean("General.RetroMode.Enabled", true);
+    }
+
+    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);
+    }
+
+    public int getSaveInterval() {
+        return config.getInt("General.Save_Interval", 10);
+    }
+
+    public boolean getStatsTrackingEnabled() {
+        return config.getBoolean("General.Stats_Tracking", true);
+    }
+
+    public boolean getUpdateCheckEnabled() {
+        return config.getBoolean("General.Update_Check", true);
+    }
+
+    public boolean getPreferBeta() {
+        return config.getBoolean("General.Prefer_Beta", false);
+    }
+
+    public boolean getVerboseLoggingEnabled() {
+        return config.getBoolean("General.Verbose_Logging", false);
+    }
 
-    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); }
-    public int getSaveInterval() { return config.getInt("General.Save_Interval", 10); }
-    public boolean getStatsTrackingEnabled() { return config.getBoolean("General.Stats_Tracking", true); }
-    public boolean getUpdateCheckEnabled() { return config.getBoolean("General.Update_Check", true); }
-    public boolean getPreferBeta() { return config.getBoolean("General.Prefer_Beta", false); }
-    public boolean getVerboseLoggingEnabled() { return config.getBoolean("General.Verbose_Logging", false); }
 
+    public boolean getMatchOfflinePlayers() {
+        return config.getBoolean("Commands.Generic.Match_OfflinePlayers", false);
+    }
 
-    public boolean getMatchOfflinePlayers() { return config.getBoolean("Commands.Generic.Match_OfflinePlayers", false); }
-    public long getDatabasePlayerCooldown() { return config.getLong("Commands.Database.Player_Cooldown", 1750); }
+    public long getDatabasePlayerCooldown() {
+        return config.getLong("Commands.Database.Player_Cooldown", 1750);
+    }
 
-    public boolean getLevelUpSoundsEnabled() { return config.getBoolean("General.LevelUp_Sounds", true); }
-    public boolean getRefreshChunksEnabled() { return config.getBoolean("General.Refresh_Chunks", false); }
+    public boolean getLevelUpSoundsEnabled() {
+        return config.getBoolean("General.LevelUp_Sounds", true);
+    }
+
+    public boolean getRefreshChunksEnabled() {
+        return config.getBoolean("General.Refresh_Chunks", false);
+    }
 
-    public boolean getMobHealthbarEnabled() { return config.getBoolean("Mob_Healthbar.Enabled", true); }
+    public boolean getMobHealthbarEnabled() {
+        return config.getBoolean("Mob_Healthbar.Enabled", true);
+    }
 
     /* Mob Healthbar */
     public MobHealthbarType getMobHealthbarDefault() {
         try {
             return MobHealthbarType.valueOf(config.getString("Mob_Healthbar.Display_Type", "HEARTS").toUpperCase(Locale.ENGLISH).trim());
-        }
-        catch (IllegalArgumentException ex) {
+        } catch (IllegalArgumentException ex) {
             return MobHealthbarType.HEARTS;
         }
     }
 
-    public int getMobHealthbarTime() { return Math.max(1, config.getInt("Mob_Healthbar.Display_Time", 3)); }
+    public int getMobHealthbarTime() {
+        return Math.max(1, config.getInt("Mob_Healthbar.Display_Time", 3));
+    }
 
     /* Scoreboards */
-    public boolean getScoreboardsEnabled() { return config.getBoolean("Scoreboard.UseScoreboards", true); }
-    public boolean getPowerLevelTagsEnabled() { return config.getBoolean("Scoreboard.Power_Level_Tags", false); }
-    public boolean getAllowKeepBoard() { return config.getBoolean("Scoreboard.Allow_Keep", true); }
-    public int getTipsAmount() { return config.getInt("Scoreboard.Tips_Amount", 5); }
-    public boolean getShowStatsAfterLogin() { return config.getBoolean("Scoreboard.Show_Stats_After_Login", false); }
-    public boolean getScoreboardRainbows() { return config.getBoolean("Scoreboard.Rainbows", false); }
-    public boolean getShowAbilityNames() { return config.getBoolean("Scoreboard.Ability_Names", true); }
-
-    public boolean getRankUseChat() { return config.getBoolean("Scoreboard.Types.Rank.Print", false); }
-    public boolean getRankUseBoard() { return config.getBoolean("Scoreboard.Types.Rank.Board", true); }
-    public int getRankScoreboardTime() { return config.getInt("Scoreboard.Types.Rank.Display_Time", 10); }
-
-    public boolean getTopUseChat() { return config.getBoolean("Scoreboard.Types.Top.Print", true); }
-    public boolean getTopUseBoard() { return config.getBoolean("Scoreboard.Types.Top.Board", true); }
-    public int getTopScoreboardTime() { return config.getInt("Scoreboard.Types.Top.Display_Time", 15); }
-
-    public boolean getStatsUseChat() { return config.getBoolean("Scoreboard.Types.Stats.Print", true); }
-    public boolean getStatsUseBoard() { return config.getBoolean("Scoreboard.Types.Stats.Board", true); }
-    public int getStatsScoreboardTime() { return config.getInt("Scoreboard.Types.Stats.Display_Time", 10); }
-
-    public boolean getInspectUseChat() { return config.getBoolean("Scoreboard.Types.Inspect.Print", true); }
-    public boolean getInspectUseBoard() { return config.getBoolean("Scoreboard.Types.Inspect.Board", true); }
-    public int getInspectScoreboardTime() { return config.getInt("Scoreboard.Types.Inspect.Display_Time", 25); }
-
-    public boolean getCooldownUseChat() { return config.getBoolean("Scoreboard.Types.Cooldown.Print", false); }
-    public boolean getCooldownUseBoard() { return config.getBoolean("Scoreboard.Types.Cooldown.Board", true); }
-    public int getCooldownScoreboardTime() { return config.getInt("Scoreboard.Types.Cooldown.Display_Time", 41); }
-
-    public boolean getSkillUseBoard() { return config.getBoolean("Scoreboard.Types.Skill.Board", true); }
-    public int getSkillScoreboardTime() { return config.getInt("Scoreboard.Types.Skill.Display_Time", 30); }
-    public boolean getSkillLevelUpBoard() { return config.getBoolean("Scoreboard.Types.Skill.LevelUp_Board", true); }
-    public int getSkillLevelUpTime() { return config.getInt("Scoreboard.Types.Skill.LevelUp_Time", 5); }
+    public boolean getScoreboardsEnabled() {
+        return config.getBoolean("Scoreboard.UseScoreboards", true);
+    }
+
+    public boolean getPowerLevelTagsEnabled() {
+        return config.getBoolean("Scoreboard.Power_Level_Tags", false);
+    }
+
+    public boolean getAllowKeepBoard() {
+        return config.getBoolean("Scoreboard.Allow_Keep", true);
+    }
+
+    public int getTipsAmount() {
+        return config.getInt("Scoreboard.Tips_Amount", 5);
+    }
+
+    public boolean getShowStatsAfterLogin() {
+        return config.getBoolean("Scoreboard.Show_Stats_After_Login", false);
+    }
+
+    public boolean getScoreboardRainbows() {
+        return config.getBoolean("Scoreboard.Rainbows", false);
+    }
+
+    public boolean getShowAbilityNames() {
+        return config.getBoolean("Scoreboard.Ability_Names", true);
+    }
+
+    public boolean getRankUseChat() {
+        return config.getBoolean("Scoreboard.Types.Rank.Print", false);
+    }
+
+    public boolean getRankUseBoard() {
+        return config.getBoolean("Scoreboard.Types.Rank.Board", true);
+    }
+
+    public int getRankScoreboardTime() {
+        return config.getInt("Scoreboard.Types.Rank.Display_Time", 10);
+    }
+
+    public boolean getTopUseChat() {
+        return config.getBoolean("Scoreboard.Types.Top.Print", true);
+    }
+
+    public boolean getTopUseBoard() {
+        return config.getBoolean("Scoreboard.Types.Top.Board", true);
+    }
+
+    public int getTopScoreboardTime() {
+        return config.getInt("Scoreboard.Types.Top.Display_Time", 15);
+    }
+
+    public boolean getStatsUseChat() {
+        return config.getBoolean("Scoreboard.Types.Stats.Print", true);
+    }
+
+    public boolean getStatsUseBoard() {
+        return config.getBoolean("Scoreboard.Types.Stats.Board", true);
+    }
+
+    public int getStatsScoreboardTime() {
+        return config.getInt("Scoreboard.Types.Stats.Display_Time", 10);
+    }
+
+    public boolean getInspectUseChat() {
+        return config.getBoolean("Scoreboard.Types.Inspect.Print", true);
+    }
+
+    public boolean getInspectUseBoard() {
+        return config.getBoolean("Scoreboard.Types.Inspect.Board", true);
+    }
+
+    public int getInspectScoreboardTime() {
+        return config.getInt("Scoreboard.Types.Inspect.Display_Time", 25);
+    }
+
+    public boolean getCooldownUseChat() {
+        return config.getBoolean("Scoreboard.Types.Cooldown.Print", false);
+    }
+
+    public boolean getCooldownUseBoard() {
+        return config.getBoolean("Scoreboard.Types.Cooldown.Board", true);
+    }
+
+    public int getCooldownScoreboardTime() {
+        return config.getInt("Scoreboard.Types.Cooldown.Display_Time", 41);
+    }
+
+    public boolean getSkillUseBoard() {
+        return config.getBoolean("Scoreboard.Types.Skill.Board", true);
+    }
+
+    public int getSkillScoreboardTime() {
+        return config.getInt("Scoreboard.Types.Skill.Display_Time", 30);
+    }
+
+    public boolean getSkillLevelUpBoard() {
+        return config.getBoolean("Scoreboard.Types.Skill.LevelUp_Board", true);
+    }
+
+    public int getSkillLevelUpTime() {
+        return config.getInt("Scoreboard.Types.Skill.LevelUp_Time", 5);
+    }
 
     /* Database Purging */
-    public int getPurgeInterval() { return config.getInt("Database_Purging.Purge_Interval", -1); }
-    public int getOldUsersCutoff() { return config.getInt("Database_Purging.Old_User_Cutoff", 6); }
+    public int getPurgeInterval() {
+        return config.getInt("Database_Purging.Purge_Interval", -1);
+    }
+
+    public int getOldUsersCutoff() {
+        return config.getInt("Database_Purging.Old_User_Cutoff", 6);
+    }
 
     /* Backups */
-    public boolean getBackupsEnabled() { return config.getBoolean("Backups.Enabled", true); }
-    public boolean getKeepLast24Hours() { return config.getBoolean("Backups.Keep.Last_24_Hours", true); }
-    public boolean getKeepDailyLastWeek() { return config.getBoolean("Backups.Keep.Daily_Last_Week", true); }
-    public boolean getKeepWeeklyPastMonth() { return config.getBoolean("Backups.Keep.Weekly_Past_Months", true); }
+    public boolean getBackupsEnabled() {
+        return config.getBoolean("Backups.Enabled", true);
+    }
+
+    public boolean getKeepLast24Hours() {
+        return config.getBoolean("Backups.Keep.Last_24_Hours", true);
+    }
+
+    public boolean getKeepDailyLastWeek() {
+        return config.getBoolean("Backups.Keep.Daily_Last_Week", true);
+    }
+
+    public boolean getKeepWeeklyPastMonth() {
+        return config.getBoolean("Backups.Keep.Weekly_Past_Months", true);
+    }
 
     /* mySQL */
-    public boolean getUseMySQL() { return config.getBoolean("MySQL.Enabled", false); }
-    public String getMySQLTablePrefix() { return config.getString("MySQL.Database.TablePrefix", "mcmmo_"); }
-    public String getMySQLDatabaseName() { return getStringIncludingInts("MySQL.Database.Name"); }
-    public String getMySQLUserName() { return getStringIncludingInts("MySQL.Database.User_Name"); }
-    public int getMySQLServerPort() { return config.getInt("MySQL.Server.Port", 3306); }
-    public String getMySQLServerName() { return config.getString("MySQL.Server.Address", "localhost"); }
-    public String getMySQLUserPassword() { return getStringIncludingInts("MySQL.Database.User_Password"); }
-    public int getMySQLMaxConnections(PoolIdentifier identifier) { return config.getInt("MySQL.Database.MaxConnections." + StringUtils.getCapitalized(identifier.toString()), 30); }
-    public int getMySQLMaxPoolSize(PoolIdentifier identifier) { return config.getInt("MySQL.Database.MaxPoolSize." + StringUtils.getCapitalized(identifier.toString()), 10); }
-    public boolean getMySQLSSL() { return config.getBoolean("MySQL.Server.SSL", true); }
-    public boolean getMySQLDebug() { return config.getBoolean("MySQL.Debug", false); }
-    public boolean getMySQLPublicKeyRetrieval() { return config.getBoolean("MySQL.Server.allowPublicKeyRetrieval", true); }
+    public boolean getUseMySQL() {
+        return config.getBoolean("MySQL.Enabled", false);
+    }
+
+    public String getMySQLTablePrefix() {
+        return config.getString("MySQL.Database.TablePrefix", "mcmmo_");
+    }
+
+    public String getMySQLDatabaseName() {
+        return getStringIncludingInts("MySQL.Database.Name");
+    }
+
+    public String getMySQLUserName() {
+        return getStringIncludingInts("MySQL.Database.User_Name");
+    }
+
+    public int getMySQLServerPort() {
+        return config.getInt("MySQL.Server.Port", 3306);
+    }
+
+    public String getMySQLServerName() {
+        return config.getString("MySQL.Server.Address", "localhost");
+    }
+
+    public String getMySQLUserPassword() {
+        return getStringIncludingInts("MySQL.Database.User_Password");
+    }
+
+    public int getMySQLMaxConnections(PoolIdentifier identifier) {
+        return config.getInt("MySQL.Database.MaxConnections." + StringUtils.getCapitalized(identifier.toString()), 30);
+    }
+
+    public int getMySQLMaxPoolSize(PoolIdentifier identifier) {
+        return config.getInt("MySQL.Database.MaxPoolSize." + StringUtils.getCapitalized(identifier.toString()), 10);
+    }
+
+    public boolean getMySQLSSL() {
+        return config.getBoolean("MySQL.Server.SSL", true);
+    }
+
+    public boolean getMySQLDebug() {
+        return config.getBoolean("MySQL.Debug", false);
+    }
+
+    public boolean getMySQLPublicKeyRetrieval() {
+        return config.getBoolean("MySQL.Server.allowPublicKeyRetrieval", true);
+    }
 
     private String getStringIncludingInts(String key) {
         String str = config.getString(key);
@@ -267,113 +432,279 @@ public class GeneralConfig extends AutoUpdateConfigLoader {
     }
 
     /* Hardcore Mode */
-    public boolean getHardcoreStatLossEnabled(PrimarySkillType primarySkillType) { return config.getBoolean("Hardcore.Death_Stat_Loss.Enabled." + StringUtils.getCapitalized(primarySkillType.toString()), false); }
-    public void setHardcoreStatLossEnabled(PrimarySkillType primarySkillType, boolean enabled) { config.set("Hardcore.Death_Stat_Loss.Enabled." + StringUtils.getCapitalized(primarySkillType.toString()), enabled); }
+    public boolean getHardcoreStatLossEnabled(PrimarySkillType primarySkillType) {
+        return config.getBoolean("Hardcore.Death_Stat_Loss.Enabled." + StringUtils.getCapitalized(primarySkillType.toString()), false);
+    }
+
+    public void setHardcoreStatLossEnabled(PrimarySkillType primarySkillType, boolean enabled) {
+        config.set("Hardcore.Death_Stat_Loss.Enabled." + StringUtils.getCapitalized(primarySkillType.toString()), enabled);
+    }
+
+    public double getHardcoreDeathStatPenaltyPercentage() {
+        return config.getDouble("Hardcore.Death_Stat_Loss.Penalty_Percentage", 75.0D);
+    }
+
+    public void setHardcoreDeathStatPenaltyPercentage(double value) {
+        config.set("Hardcore.Death_Stat_Loss.Penalty_Percentage", value);
+    }
+
+    public int getHardcoreDeathStatPenaltyLevelThreshold() {
+        return config.getInt("Hardcore.Death_Stat_Loss.Level_Threshold", 0);
+    }
 
-    public double getHardcoreDeathStatPenaltyPercentage() { return config.getDouble("Hardcore.Death_Stat_Loss.Penalty_Percentage", 75.0D); }
-    public void setHardcoreDeathStatPenaltyPercentage(double value) { config.set("Hardcore.Death_Stat_Loss.Penalty_Percentage", value); }
+    public boolean getHardcoreVampirismEnabled(PrimarySkillType primarySkillType) {
+        return config.getBoolean("Hardcore.Vampirism.Enabled." + StringUtils.getCapitalized(primarySkillType.toString()), false);
+    }
 
-    public int getHardcoreDeathStatPenaltyLevelThreshold() { return config.getInt("Hardcore.Death_Stat_Loss.Level_Threshold", 0); }
+    public void setHardcoreVampirismEnabled(PrimarySkillType primarySkillType, boolean enabled) {
+        config.set("Hardcore.Vampirism.Enabled." + StringUtils.getCapitalized(primarySkillType.toString()), enabled);
+    }
 
-    public boolean getHardcoreVampirismEnabled(PrimarySkillType primarySkillType) { return config.getBoolean("Hardcore.Vampirism.Enabled." + StringUtils.getCapitalized(primarySkillType.toString()), false); }
-    public void setHardcoreVampirismEnabled(PrimarySkillType primarySkillType, boolean enabled) { config.set("Hardcore.Vampirism.Enabled." + StringUtils.getCapitalized(primarySkillType.toString()), enabled); }
+    public double getHardcoreVampirismStatLeechPercentage() {
+        return config.getDouble("Hardcore.Vampirism.Leech_Percentage", 5.0D);
+    }
 
-    public double getHardcoreVampirismStatLeechPercentage() { return config.getDouble("Hardcore.Vampirism.Leech_Percentage", 5.0D); }
-    public void setHardcoreVampirismStatLeechPercentage(double value) { config.set("Hardcore.Vampirism.Leech_Percentage", value); }
+    public void setHardcoreVampirismStatLeechPercentage(double value) {
+        config.set("Hardcore.Vampirism.Leech_Percentage", value);
+    }
 
-    public int getHardcoreVampirismLevelThreshold() { return config.getInt("Hardcore.Vampirism.Level_Threshold", 0); }
+    public int getHardcoreVampirismLevelThreshold() {
+        return config.getInt("Hardcore.Vampirism.Level_Threshold", 0);
+    }
 
     /* SMP Mods */
-    public boolean getToolModsEnabled() { return config.getBoolean("Mods.Tool_Mods_Enabled", false); }
-    public boolean getArmorModsEnabled() { return config.getBoolean("Mods.Armor_Mods_Enabled", false); }
-    public boolean getBlockModsEnabled() { return config.getBoolean("Mods.Block_Mods_Enabled", false); }
-    public boolean getEntityModsEnabled() { return config.getBoolean("Mods.Entity_Mods_Enabled", false); }
+    public boolean getToolModsEnabled() {
+        return config.getBoolean("Mods.Tool_Mods_Enabled", false);
+    }
+
+    public boolean getArmorModsEnabled() {
+        return config.getBoolean("Mods.Armor_Mods_Enabled", false);
+    }
+
+    public boolean getBlockModsEnabled() {
+        return config.getBoolean("Mods.Block_Mods_Enabled", false);
+    }
+
+    public boolean getEntityModsEnabled() {
+        return config.getBoolean("Mods.Entity_Mods_Enabled", false);
+    }
 
     /* Items */
-    public int getChimaeraUseCost() { return config.getInt("Items.Chimaera_Wing.Use_Cost", 1); }
-    public int getChimaeraRecipeCost() { return config.getInt("Items.Chimaera_Wing.Recipe_Cost", 5); }
-    public Material getChimaeraItem() { return Material.matchMaterial(config.getString("Items.Chimaera_Wing.Item_Name", "Feather")); }
-    public boolean getChimaeraEnabled() { return config.getBoolean("Items.Chimaera_Wing.Enabled", true); }
-    public boolean getChimaeraPreventUseUnderground() { return config.getBoolean("Items.Chimaera_Wing.Prevent_Use_Underground", true); }
-    public boolean getChimaeraUseBedSpawn() { return config.getBoolean("Items.Chimaera_Wing.Use_Bed_Spawn", true); }
-    public int getChimaeraCooldown() { return config.getInt("Items.Chimaera_Wing.Cooldown", 240); }
-    public int getChimaeraWarmup() { return config.getInt("Items.Chimaera_Wing.Warmup", 5); }
-    public int getChimaeraRecentlyHurtCooldown() { return config.getInt("Items.Chimaera_Wing.RecentlyHurt_Cooldown", 60); }
-    public boolean getChimaeraSoundEnabled() { return config.getBoolean("Items.Chimaera_Wing.Sound_Enabled", true); }
-
-    public boolean getFluxPickaxeSoundEnabled() { return config.getBoolean("Items.Flux_Pickaxe.Sound_Enabled", true); }
+    public int getChimaeraUseCost() {
+        return config.getInt("Items.Chimaera_Wing.Use_Cost", 1);
+    }
+
+    public int getChimaeraRecipeCost() {
+        return config.getInt("Items.Chimaera_Wing.Recipe_Cost", 5);
+    }
+
+    public Material getChimaeraItem() {
+        return Material.matchMaterial(config.getString("Items.Chimaera_Wing.Item_Name", "Feather"));
+    }
+
+    public boolean getChimaeraEnabled() {
+        return config.getBoolean("Items.Chimaera_Wing.Enabled", true);
+    }
+
+    public boolean getChimaeraPreventUseUnderground() {
+        return config.getBoolean("Items.Chimaera_Wing.Prevent_Use_Underground", true);
+    }
+
+    public boolean getChimaeraUseBedSpawn() {
+        return config.getBoolean("Items.Chimaera_Wing.Use_Bed_Spawn", true);
+    }
+
+    public int getChimaeraCooldown() {
+        return config.getInt("Items.Chimaera_Wing.Cooldown", 240);
+    }
+
+    public int getChimaeraWarmup() {
+        return config.getInt("Items.Chimaera_Wing.Warmup", 5);
+    }
+
+    public int getChimaeraRecentlyHurtCooldown() {
+        return config.getInt("Items.Chimaera_Wing.RecentlyHurt_Cooldown", 60);
+    }
+
+    public boolean getChimaeraSoundEnabled() {
+        return config.getBoolean("Items.Chimaera_Wing.Sound_Enabled", true);
+    }
+
+    public boolean getFluxPickaxeSoundEnabled() {
+        return config.getBoolean("Items.Flux_Pickaxe.Sound_Enabled", true);
+    }
 
     /* Particles */
-    public boolean getAbilityActivationEffectEnabled() { return config.getBoolean("Particles.Ability_Activation", true); }
-    public boolean getAbilityDeactivationEffectEnabled() { return config.getBoolean("Particles.Ability_Deactivation", true); }
-    public boolean getBleedEffectEnabled() { return config.getBoolean("Particles.Bleed", true); }
-    public boolean getDodgeEffectEnabled() { return config.getBoolean("Particles.Dodge", true); }
-    public boolean getFluxEffectEnabled() { return config.getBoolean("Particles.Flux", true); }
-    public boolean getGreaterImpactEffectEnabled() { return config.getBoolean("Particles.Greater_Impact", true); }
-    public boolean getCallOfTheWildEffectEnabled() { return config.getBoolean("Particles.Call_of_the_Wild", true); }
-    public boolean getLevelUpEffectsEnabled() { return config.getBoolean("Particles.LevelUp_Enabled", true); }
-    public int getLevelUpEffectsTier() { return config.getInt("Particles.LevelUp_Tier", 100); }
+    public boolean getAbilityActivationEffectEnabled() {
+        return config.getBoolean("Particles.Ability_Activation", true);
+    }
+
+    public boolean getAbilityDeactivationEffectEnabled() {
+        return config.getBoolean("Particles.Ability_Deactivation", true);
+    }
+
+    public boolean getBleedEffectEnabled() {
+        return config.getBoolean("Particles.Bleed", true);
+    }
+
+    public boolean getDodgeEffectEnabled() {
+        return config.getBoolean("Particles.Dodge", true);
+    }
+
+    public boolean getFluxEffectEnabled() {
+        return config.getBoolean("Particles.Flux", true);
+    }
+
+    public boolean getGreaterImpactEffectEnabled() {
+        return config.getBoolean("Particles.Greater_Impact", true);
+    }
+
+    public boolean getCallOfTheWildEffectEnabled() {
+        return config.getBoolean("Particles.Call_of_the_Wild", true);
+    }
+
+    public boolean getLevelUpEffectsEnabled() {
+        return config.getBoolean("Particles.LevelUp_Enabled", true);
+    }
+
+    public int getLevelUpEffectsTier() {
+        return config.getInt("Particles.LevelUp_Tier", 100);
+    }
 //    public boolean getLargeFireworks() { return config.getBoolean("Particles.LargeFireworks", true); }
 
     /* PARTY SETTINGS */
-    public boolean getPartyFriendlyFire() { return config.getBoolean("Party.FriendlyFire", false);}
-    public int getPartyMaxSize() {return config.getInt("Party.MaxSize", -1); }
-    public int getAutoPartyKickInterval() { return config.getInt("Party.AutoKick_Interval", 12); }
-    public int getAutoPartyKickTime() { return config.getInt("Party.Old_Party_Member_Cutoff", 7); }
+    public boolean getPartyFriendlyFire() {
+        return config.getBoolean("Party.FriendlyFire", false);
+    }
+
+    public int getPartyMaxSize() {
+        return config.getInt("Party.MaxSize", -1);
+    }
+
+    public int getAutoPartyKickInterval() {
+        return config.getInt("Party.AutoKick_Interval", 12);
+    }
+
+    public int getAutoPartyKickTime() {
+        return config.getInt("Party.Old_Party_Member_Cutoff", 7);
+    }
+
+    public double getPartyShareBonusBase() {
+        return config.getDouble("Party.Sharing.ExpShare_bonus_base", 1.1D);
+    }
 
-    public double getPartyShareBonusBase() { return config.getDouble("Party.Sharing.ExpShare_bonus_base", 1.1D); }
-    public double getPartyShareBonusIncrease() { return config.getDouble("Party.Sharing.ExpShare_bonus_increase", 0.05D); }
-    public double getPartyShareBonusCap() { return config.getDouble("Party.Sharing.ExpShare_bonus_cap", 1.5D); }
-    public double getPartyShareRange() { return config.getDouble("Party.Sharing.Range", 75.0D); }
+    public double getPartyShareBonusIncrease() {
+        return config.getDouble("Party.Sharing.ExpShare_bonus_increase", 0.05D);
+    }
+
+    public double getPartyShareBonusCap() {
+        return config.getDouble("Party.Sharing.ExpShare_bonus_cap", 1.5D);
+    }
+
+    public double getPartyShareRange() {
+        return config.getDouble("Party.Sharing.Range", 75.0D);
+    }
 
     public int getPartyLevelCap() {
         int cap = config.getInt("Party.Leveling.Level_Cap", 10);
         return (cap <= 0) ? Integer.MAX_VALUE : cap;
     }
 
-    public int getPartyXpCurveMultiplier() { return config.getInt("Party.Leveling.Xp_Curve_Modifier", 3); }
-    public boolean getPartyXpNearMembersNeeded() { return config.getBoolean("Party.Leveling.Near_Members_Needed", false); }
-    public boolean getPartyInformAllMembers() { return config.getBoolean("Party.Leveling.Inform_All_Party_Members_On_LevelUp", false); }
+    public int getPartyXpCurveMultiplier() {
+        return config.getInt("Party.Leveling.Xp_Curve_Modifier", 3);
+    }
+
+    public boolean getPartyXpNearMembersNeeded() {
+        return config.getBoolean("Party.Leveling.Near_Members_Needed", false);
+    }
+
+    public boolean getPartyInformAllMembers() {
+        return config.getBoolean("Party.Leveling.Inform_All_Party_Members_On_LevelUp", false);
+    }
 
-    public int getPartyFeatureUnlockLevel(PartyFeature partyFeature) { return config.getInt("Party.Leveling." + StringUtils.getPrettyPartyFeatureString(partyFeature).replace(" ", "") + "_UnlockLevel", 0); }
+    public int getPartyFeatureUnlockLevel(PartyFeature partyFeature) {
+        return config.getInt("Party.Leveling." + StringUtils.getPrettyPartyFeatureString(partyFeature).replace(" ", "") + "_UnlockLevel", 0);
+    }
 
     /* Party Teleport Settings */
-    public int getPTPCommandCooldown() { return config.getInt("Commands.ptp.Cooldown", 120); }
-    public int getPTPCommandWarmup() { return config.getInt("Commands.ptp.Warmup", 5); }
-    public int getPTPCommandRecentlyHurtCooldown() { return config.getInt("Commands.ptp.RecentlyHurt_Cooldown", 60); }
-    public int getPTPCommandTimeout() { return config.getInt("Commands.ptp.Request_Timeout", 300); }
-    public boolean getPTPCommandConfirmRequired() { return config.getBoolean("Commands.ptp.Accept_Required", true); }
-    public boolean getPTPCommandWorldPermissions() { return config.getBoolean("Commands.ptp.World_Based_Permissions", false); }
+    public int getPTPCommandCooldown() {
+        return config.getInt("Commands.ptp.Cooldown", 120);
+    }
+
+    public int getPTPCommandWarmup() {
+        return config.getInt("Commands.ptp.Warmup", 5);
+    }
+
+    public int getPTPCommandRecentlyHurtCooldown() {
+        return config.getInt("Commands.ptp.RecentlyHurt_Cooldown", 60);
+    }
+
+    public int getPTPCommandTimeout() {
+        return config.getInt("Commands.ptp.Request_Timeout", 300);
+    }
+
+    public boolean getPTPCommandConfirmRequired() {
+        return config.getBoolean("Commands.ptp.Accept_Required", true);
+    }
+
+    public boolean getPTPCommandWorldPermissions() {
+        return config.getBoolean("Commands.ptp.World_Based_Permissions", false);
+    }
 
     /* Inspect command distance */
-    public double getInspectDistance() { return config.getDouble("Commands.inspect.Max_Distance", 30.0D); }
+    public double getInspectDistance() {
+        return config.getDouble("Commands.inspect.Max_Distance", 30.0D);
+    }
 
     /*
      * ABILITY SETTINGS
      */
 
     /* General Settings */
-    public boolean getUrlLinksEnabled() { return config.getBoolean("Commands.Skills.URL_Links"); }
-    public boolean getAbilityMessagesEnabled() { return config.getBoolean("Abilities.Messages", true); }
-    public boolean getAbilitiesEnabled() { return config.getBoolean("Abilities.Enabled", true); }
-    public boolean getAbilitiesOnlyActivateWhenSneaking() { return config.getBoolean("Abilities.Activation.Only_Activate_When_Sneaking", false); }
-    public boolean getAbilitiesGateEnabled() { return config.getBoolean("Abilities.Activation.Level_Gate_Abilities"); }
+    public boolean getUrlLinksEnabled() {
+        return config.getBoolean("Commands.Skills.URL_Links");
+    }
+
+    public boolean getAbilityMessagesEnabled() {
+        return config.getBoolean("Abilities.Messages", true);
+    }
+
+    public boolean getAbilitiesEnabled() {
+        return config.getBoolean("Abilities.Enabled", true);
+    }
+
+    public boolean getAbilitiesOnlyActivateWhenSneaking() {
+        return config.getBoolean("Abilities.Activation.Only_Activate_When_Sneaking", false);
+    }
 
-    public int getCooldown(SuperAbilityType ability) { return config.getInt("Abilities.Cooldowns." + ability.toString()); }
-    public int getMaxLength(SuperAbilityType ability) { return config.getInt("Abilities.Max_Seconds." + ability.toString()); }
+    public boolean getAbilitiesGateEnabled() {
+        return config.getBoolean("Abilities.Activation.Level_Gate_Abilities");
+    }
+
+    public int getCooldown(SuperAbilityType ability) {
+        return config.getInt("Abilities.Cooldowns." + ability.toString());
+    }
+
+    public int getMaxLength(SuperAbilityType ability) {
+        return config.getInt("Abilities.Max_Seconds." + ability.toString());
+    }
 
     /* Durability Settings */
-    public int getAbilityToolDamage() { return config.getInt("Abilities.Tools.Durability_Loss", 1); }
+    public int getAbilityToolDamage() {
+        return config.getInt("Abilities.Tools.Durability_Loss", 1);
+    }
 
     /* Thresholds */
-    public int getTreeFellerThreshold() { return config.getInt("Abilities.Limits.Tree_Feller_Threshold", 1000); }
+    public int getTreeFellerThreshold() {
+        return config.getInt("Abilities.Limits.Tree_Feller_Threshold", 1000);
+    }
 
     /*
      * SKILL SETTINGS
      */
     public boolean getDoubleDropsEnabled(PrimarySkillType skill, Material material) {
         //TODO: Temporary measure to fix an exploit caused by a yet to be fixed Spigot bug (as of 7/3/2020)
-        if(material.toString().equalsIgnoreCase("LILY_PAD"))
+        if (material.toString().equalsIgnoreCase("LILY_PAD"))
             return false;
 
         return config.getBoolean("Bonus_Drops." + StringUtils.getCapitalized(skill.toString()) + "." + StringUtils.getPrettyItemString(material).replace(" ", "_"));
@@ -398,54 +729,134 @@ public class GeneralConfig extends AutoUpdateConfigLoader {
     }
 
     /* Axes */
-    public int getAxesGate() { return config.getInt("Skills.Axes.Ability_Activation_Level_Gate", 10); }
+    public int getAxesGate() {
+        return config.getInt("Skills.Axes.Ability_Activation_Level_Gate", 10);
+    }
 
     /* Acrobatics */
-    public boolean getDodgeLightningDisabled() { return config.getBoolean("Skills.Acrobatics.Prevent_Dodge_Lightning", false); }
-    public int getXPAfterTeleportCooldown() { return config.getInt("Skills.Acrobatics.XP_After_Teleport_Cooldown", 5); }
+    public boolean getDodgeLightningDisabled() {
+        return config.getBoolean("Skills.Acrobatics.Prevent_Dodge_Lightning", false);
+    }
+
+    public int getXPAfterTeleportCooldown() {
+        return config.getInt("Skills.Acrobatics.XP_After_Teleport_Cooldown", 5);
+    }
 
     /* Alchemy */
-    public boolean getEnabledForHoppers() { return config.getBoolean("Skills.Alchemy.Enabled_for_Hoppers", true); }
-    public boolean getPreventHopperTransferIngredients() { return config.getBoolean("Skills.Alchemy.Prevent_Hopper_Transfer_Ingredients", false); }
-    public boolean getPreventHopperTransferBottles() { return config.getBoolean("Skills.Alchemy.Prevent_Hopper_Transfer_Bottles", false); }
+    public boolean getEnabledForHoppers() {
+        return config.getBoolean("Skills.Alchemy.Enabled_for_Hoppers", true);
+    }
+
+    public boolean getPreventHopperTransferIngredients() {
+        return config.getBoolean("Skills.Alchemy.Prevent_Hopper_Transfer_Ingredients", false);
+    }
+
+    public boolean getPreventHopperTransferBottles() {
+        return config.getBoolean("Skills.Alchemy.Prevent_Hopper_Transfer_Bottles", false);
+    }
 
     /* Fishing */
-    public boolean getFishingDropsEnabled() { return config.getBoolean("Skills.Fishing.Drops_Enabled", true); }
-    public boolean getFishingOverrideTreasures() { return config.getBoolean("Skills.Fishing.Override_Vanilla_Treasures", true); }
-    public boolean getFishingExtraFish() { return config.getBoolean("Skills.Fishing.Extra_Fish", true); }
-    public double getFishingLureModifier() { return config.getDouble("Skills.Fishing.Lure_Modifier", 4.0D); }
+    public boolean getFishingDropsEnabled() {
+        return config.getBoolean("Skills.Fishing.Drops_Enabled", true);
+    }
+
+    public boolean getFishingOverrideTreasures() {
+        return config.getBoolean("Skills.Fishing.Override_Vanilla_Treasures", true);
+    }
+
+    public boolean getFishingExtraFish() {
+        return config.getBoolean("Skills.Fishing.Extra_Fish", true);
+    }
+
+    public double getFishingLureModifier() {
+        return config.getDouble("Skills.Fishing.Lure_Modifier", 4.0D);
+    }
 
     /* Mining */
-    public Material getDetonatorItem() { return Material.matchMaterial(config.getString("Skills.Mining.Detonator_Name", "FLINT_AND_STEEL")); }
+    public Material getDetonatorItem() {
+        return Material.matchMaterial(config.getString("Skills.Mining.Detonator_Name", "FLINT_AND_STEEL"));
+    }
 
     /* Excavation */
-    public int getExcavationGate() { return config.getInt("Skills.Excavation.Ability_Activation_Level_Gate", 10); }
+    public int getExcavationGate() {
+        return config.getInt("Skills.Excavation.Ability_Activation_Level_Gate", 10);
+    }
 
     /* Repair */
-    public boolean getRepairAnvilMessagesEnabled() { return config.getBoolean("Skills.Repair.Anvil_Messages", true); }
-    public boolean getRepairAnvilPlaceSoundsEnabled() { return config.getBoolean("Skills.Repair.Anvil_Placed_Sounds", true); }
-    public boolean getRepairAnvilUseSoundsEnabled() { return config.getBoolean("Skills.Repair.Anvil_Use_Sounds", true); }
-    public @Nullable Material getRepairAnvilMaterial() { return Material.matchMaterial(config.getString("Skills.Repair.Anvil_Material", "IRON_BLOCK")); }
-    public boolean getRepairConfirmRequired() { return config.getBoolean("Skills.Repair.Confirm_Required", true); }
-    public boolean getAllowVanillaInventoryRepair() { return config.getBoolean("Skills.Repair.Allow_Vanilla_Anvil_Repair", false); }
-    public boolean getAllowVanillaAnvilRepair() { return config.getBoolean("Skills.Repair.Allow_Vanilla_Inventory_Repair", false); }
-    public boolean getAllowVanillaGrindstoneRepair() { return config.getBoolean("Skills.Repair.Allow_Vanilla_Grindstone_Repair", false); }
+    public boolean getRepairAnvilMessagesEnabled() {
+        return config.getBoolean("Skills.Repair.Anvil_Messages", true);
+    }
+
+    public boolean getRepairAnvilPlaceSoundsEnabled() {
+        return config.getBoolean("Skills.Repair.Anvil_Placed_Sounds", true);
+    }
+
+    public boolean getRepairAnvilUseSoundsEnabled() {
+        return config.getBoolean("Skills.Repair.Anvil_Use_Sounds", true);
+    }
+
+    public @Nullable Material getRepairAnvilMaterial() {
+        return Material.matchMaterial(config.getString("Skills.Repair.Anvil_Material", "IRON_BLOCK"));
+    }
+
+    public boolean getRepairConfirmRequired() {
+        return config.getBoolean("Skills.Repair.Confirm_Required", true);
+    }
+
+    public boolean getAllowVanillaInventoryRepair() {
+        return config.getBoolean("Skills.Repair.Allow_Vanilla_Anvil_Repair", false);
+    }
+
+    public boolean getAllowVanillaAnvilRepair() {
+        return config.getBoolean("Skills.Repair.Allow_Vanilla_Inventory_Repair", false);
+    }
+
+    public boolean getAllowVanillaGrindstoneRepair() {
+        return config.getBoolean("Skills.Repair.Allow_Vanilla_Grindstone_Repair", false);
+    }
 
     /* Salvage */
-    public boolean getSalvageAnvilMessagesEnabled() { return config.getBoolean("Skills.Salvage.Anvil_Messages", true); }
-    public boolean getSalvageAnvilPlaceSoundsEnabled() { return config.getBoolean("Skills.Salvage.Anvil_Placed_Sounds", true); }
-    public boolean getSalvageAnvilUseSoundsEnabled() { return config.getBoolean("Skills.Salvage.Anvil_Use_Sounds", true); }
-    public @Nullable Material getSalvageAnvilMaterial() { return Material.matchMaterial(config.getString("Skills.Salvage.Anvil_Material", "GOLD_BLOCK")); }
-    public boolean getSalvageConfirmRequired() { return config.getBoolean("Skills.Salvage.Confirm_Required", true); }
+    public boolean getSalvageAnvilMessagesEnabled() {
+        return config.getBoolean("Skills.Salvage.Anvil_Messages", true);
+    }
+
+    public boolean getSalvageAnvilPlaceSoundsEnabled() {
+        return config.getBoolean("Skills.Salvage.Anvil_Placed_Sounds", true);
+    }
+
+    public boolean getSalvageAnvilUseSoundsEnabled() {
+        return config.getBoolean("Skills.Salvage.Anvil_Use_Sounds", true);
+    }
+
+    public @Nullable Material getSalvageAnvilMaterial() {
+        return Material.matchMaterial(config.getString("Skills.Salvage.Anvil_Material", "GOLD_BLOCK"));
+    }
+
+    public boolean getSalvageConfirmRequired() {
+        return config.getBoolean("Skills.Salvage.Confirm_Required", true);
+    }
 
     /* Unarmed */
-    public boolean getUnarmedBlockCrackerSmoothbrickToCracked() { return config.getBoolean("Skills.Unarmed.Block_Cracker.SmoothBrick_To_CrackedBrick", true); }
-    public boolean getUnarmedItemPickupDisabled() { return config.getBoolean("Skills.Unarmed.Item_Pickup_Disabled_Full_Inventory", true); }
-    public boolean getUnarmedItemsAsUnarmed() { return config.getBoolean("Skills.Unarmed.Items_As_Unarmed", false); }
-    public int getUnarmedGate() { return config.getInt("Skills.Unarmed.Ability_Activation_Level_Gate", 10); }
+    public boolean getUnarmedBlockCrackerSmoothbrickToCracked() {
+        return config.getBoolean("Skills.Unarmed.Block_Cracker.SmoothBrick_To_CrackedBrick", true);
+    }
+
+    public boolean getUnarmedItemPickupDisabled() {
+        return config.getBoolean("Skills.Unarmed.Item_Pickup_Disabled_Full_Inventory", true);
+    }
+
+    public boolean getUnarmedItemsAsUnarmed() {
+        return config.getBoolean("Skills.Unarmed.Items_As_Unarmed", false);
+    }
+
+    public int getUnarmedGate() {
+        return config.getInt("Skills.Unarmed.Ability_Activation_Level_Gate", 10);
+    }
 
     /* Swords */
-    public int getSwordsGate() { return config.getInt("Skills.Swords.Ability_Activation_Level_Gate", 10); }
+    public int getSwordsGate() {
+        return config.getInt("Skills.Swords.Ability_Activation_Level_Gate", 10);
+    }
 
     /* Taming */
 //    public Material getTamingCOTWMaterial(EntityType type) { return Material.matchMaterial(config.getString("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type) + ".Item_Material")); }
@@ -454,19 +865,43 @@ public class GeneralConfig extends AutoUpdateConfigLoader {
 //    public int getTamingCOTWLength(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type)+ ".Summon_Length"); }
 //    public int getTamingCOTWMaxAmount(EntityType type) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + StringUtils.getPrettyEntityTypeString(type)+ ".Summon_Max_Amount"); }
 
-    public Material getTamingCOTWMaterial(String cotwEntity) { return Material.matchMaterial(config.getString("Skills.Taming.Call_Of_The_Wild." + cotwEntity + ".Item_Material")); }
-    public int getTamingCOTWCost(String cotwEntity) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + cotwEntity + ".Item_Amount"); }
-    public int getTamingCOTWAmount(String cotwEntity) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + cotwEntity + ".Summon_Amount"); }
-    public int getTamingCOTWLength(String cotwEntity) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + cotwEntity+ ".Summon_Length"); }
-    public int getTamingCOTWMaxAmount(String cotwEntity) { return config.getInt("Skills.Taming.Call_Of_The_Wild." + cotwEntity+ ".Per_Player_Limit", 1); }
+    public Material getTamingCOTWMaterial(String cotwEntity) {
+        return Material.matchMaterial(config.getString("Skills.Taming.Call_Of_The_Wild." + cotwEntity + ".Item_Material"));
+    }
+
+    public int getTamingCOTWCost(String cotwEntity) {
+        return config.getInt("Skills.Taming.Call_Of_The_Wild." + cotwEntity + ".Item_Amount");
+    }
+
+    public int getTamingCOTWAmount(String cotwEntity) {
+        return config.getInt("Skills.Taming.Call_Of_The_Wild." + cotwEntity + ".Summon_Amount");
+    }
+
+    public int getTamingCOTWLength(String cotwEntity) {
+        return config.getInt("Skills.Taming.Call_Of_The_Wild." + cotwEntity + ".Summon_Length");
+    }
+
+    public int getTamingCOTWMaxAmount(String cotwEntity) {
+        return config.getInt("Skills.Taming.Call_Of_The_Wild." + cotwEntity + ".Per_Player_Limit", 1);
+    }
 
     /* Woodcutting */
-    public boolean getWoodcuttingDoubleDropsEnabled(BlockData material) { return config.getBoolean("Bonus_Drops.Woodcutting." + StringUtils.getFriendlyConfigBlockDataString(material)); }
-    public boolean getTreeFellerSoundsEnabled() { return config.getBoolean("Skills.Woodcutting.Tree_Feller_Sounds", true); }
-    public int getWoodcuttingGate() { return config.getInt("Skills.Woodcutting.Ability_Activation_Level_Gate", 10); }
+    public boolean getWoodcuttingDoubleDropsEnabled(BlockData material) {
+        return config.getBoolean("Bonus_Drops.Woodcutting." + StringUtils.getFriendlyConfigBlockDataString(material));
+    }
+
+    public boolean getTreeFellerSoundsEnabled() {
+        return config.getBoolean("Skills.Woodcutting.Tree_Feller_Sounds", true);
+    }
+
+    public int getWoodcuttingGate() {
+        return config.getInt("Skills.Woodcutting.Ability_Activation_Level_Gate", 10);
+    }
 
     /* AFK Leveling */
-    public boolean getHerbalismPreventAFK() { return config.getBoolean("Skills.Herbalism.Prevent_AFK_Leveling", true); }
+    public boolean getHerbalismPreventAFK() {
+        return config.getBoolean("Skills.Herbalism.Prevent_AFK_Leveling", true);
+    }
 
     /* Level Caps */
     public int getPowerLevelCap() {
@@ -484,33 +919,88 @@ public class GeneralConfig extends AutoUpdateConfigLoader {
         return config.getInt("Skills." + StringUtils.getCapitalized(skill.toString()) + ".Ability_Activation_Level_Gate");
     }*/
 
-    public boolean getTruncateSkills() { return config.getBoolean("General.TruncateSkills", false); }
+    public boolean getTruncateSkills() {
+        return config.getBoolean("General.TruncateSkills", false);
+    }
 
     /* PVP & PVE Settings */
-    public boolean getPVPEnabled(PrimarySkillType skill) { return config.getBoolean("Skills." + StringUtils.getCapitalized(skill.toString()) + ".Enabled_For_PVP", true); }
-    public boolean getPVEEnabled(PrimarySkillType skill) { return config.getBoolean("Skills." + StringUtils.getCapitalized(skill.toString()) + ".Enabled_For_PVE", true); }
-    
+    public boolean getPVPEnabled(PrimarySkillType skill) {
+        return config.getBoolean("Skills." + StringUtils.getCapitalized(skill.toString()) + ".Enabled_For_PVP", true);
+    }
+
+    public boolean getPVEEnabled(PrimarySkillType skill) {
+        return config.getBoolean("Skills." + StringUtils.getCapitalized(skill.toString()) + ".Enabled_For_PVE", true);
+    }
+
     //public float getMasterVolume() { return (float) config.getDouble("Sounds.MasterVolume", 1.0); }
 
-    public boolean broadcastEventMessages() { return config.getBoolean("General.EventBroadcasts", true);}
-    public boolean playerJoinEventInfo() { return config.getBoolean("General.EventInfoOnPlayerJoin", true);}
-    public boolean adminNotifications() { return config.getBoolean("General.AdminNotifications", true);}
-
-    public boolean shouldLevelUpBroadcasts() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Enabled", true); }
-    public boolean shouldLevelUpBroadcastToConsole() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Targets.Send_To_Console", true); }
-    public boolean isLevelUpBroadcastsPartyMembersOnly() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Targets.Only_Party_Members", false); }
-    public boolean isLevelUpBroadcastsSameWorldOnly() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Targets.Only_Same_World", false); }
-    public boolean shouldLevelUpBroadcastsRestrictDistance() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Targets.Distance_Restrictions.Restrict_Distance", false); }
-    public int getLevelUpBroadcastRadius() { return config.getInt("General.Level_Up_Chat_Broadcasts.Broadcast_Targets.Distance_Restrictions.Restricted_Radius", 100); }
-    public int getLevelUpBroadcastInterval() { return config.getInt("General.Level_Up_Chat_Broadcasts.Milestone_Interval", 100); }
-
-    public boolean shouldPowerLevelUpBroadcasts() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Enabled", true); }
-    public boolean shouldPowerLevelUpBroadcastToConsole() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Broadcast_Targets.Send_To_Console", true); }
-    public boolean isPowerLevelUpBroadcastsPartyMembersOnly() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Broadcast_Targets.Only_Party_Members", false); }
-    public boolean isPowerLevelUpBroadcastsSameWorldOnly() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Broadcast_Targets.Only_Same_World", false); }
-    public boolean shouldPowerLevelUpBroadcastsRestrictDistance() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Broadcast_Targets.Distance_Restrictions.Restrict_Distance", false); }
-    public int getPowerLevelUpBroadcastRadius() { return config.getInt("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Broadcast_Targets.Distance_Restrictions.Restricted_Radius", 100); }
-    public int getPowerLevelUpBroadcastInterval() { return config.getInt("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Milestone_Interval", 100); }
+    public boolean broadcastEventMessages() {
+        return config.getBoolean("General.EventBroadcasts", true);
+    }
+
+    public boolean playerJoinEventInfo() {
+        return config.getBoolean("General.EventInfoOnPlayerJoin", true);
+    }
+
+    public boolean adminNotifications() {
+        return config.getBoolean("General.AdminNotifications", true);
+    }
+
+    public boolean shouldLevelUpBroadcasts() {
+        return config.getBoolean("General.Level_Up_Chat_Broadcasts.Enabled", true);
+    }
+
+    public boolean shouldLevelUpBroadcastToConsole() {
+        return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Targets.Send_To_Console", true);
+    }
+
+    public boolean isLevelUpBroadcastsPartyMembersOnly() {
+        return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Targets.Only_Party_Members", false);
+    }
+
+    public boolean isLevelUpBroadcastsSameWorldOnly() {
+        return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Targets.Only_Same_World", false);
+    }
+
+    public boolean shouldLevelUpBroadcastsRestrictDistance() {
+        return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Targets.Distance_Restrictions.Restrict_Distance", false);
+    }
+
+    public int getLevelUpBroadcastRadius() {
+        return config.getInt("General.Level_Up_Chat_Broadcasts.Broadcast_Targets.Distance_Restrictions.Restricted_Radius", 100);
+    }
+
+    public int getLevelUpBroadcastInterval() {
+        return config.getInt("General.Level_Up_Chat_Broadcasts.Milestone_Interval", 100);
+    }
+
+    public boolean shouldPowerLevelUpBroadcasts() {
+        return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Enabled", true);
+    }
+
+    public boolean shouldPowerLevelUpBroadcastToConsole() {
+        return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Broadcast_Targets.Send_To_Console", true);
+    }
+
+    public boolean isPowerLevelUpBroadcastsPartyMembersOnly() {
+        return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Broadcast_Targets.Only_Party_Members", false);
+    }
+
+    public boolean isPowerLevelUpBroadcastsSameWorldOnly() {
+        return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Broadcast_Targets.Only_Same_World", false);
+    }
+
+    public boolean shouldPowerLevelUpBroadcastsRestrictDistance() {
+        return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Broadcast_Targets.Distance_Restrictions.Restrict_Distance", false);
+    }
+
+    public int getPowerLevelUpBroadcastRadius() {
+        return config.getInt("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Broadcast_Targets.Distance_Restrictions.Restricted_Radius", 100);
+    }
+
+    public int getPowerLevelUpBroadcastInterval() {
+        return config.getInt("General.Level_Up_Chat_Broadcasts.Broadcast_Powerlevels.Milestone_Interval", 100);
+    }
 
     public boolean isGreenThumbReplantableCrop(@NotNull Material material) {
         return config.getBoolean("Green_Thumb_Replanting_Crops." + StringUtils.getCapitalized(material.toString()), true);

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

@@ -2,7 +2,7 @@ package com.gmail.nossr50.config;
 
 import com.gmail.nossr50.util.compat.layers.persistentdata.MobMetaFlagType;
 
-public class PersistentDataConfig extends AutoUpdateConfigLoader {
+public class PersistentDataConfig extends BukkitConfig {
     private static PersistentDataConfig instance;
 
     private PersistentDataConfig() {

+ 39 - 42
src/main/java/com/gmail/nossr50/config/RankConfig.java

@@ -12,24 +12,22 @@ import java.util.List;
 public class RankConfig extends AutoUpdateConfigLoader {
     private static RankConfig instance;
 
-    public RankConfig()
-    {
+    public RankConfig() {
         super("skillranks.yml");
         validate();
         instance = this;
     }
 
-    @Override
-    protected void loadKeys() {
+    public static RankConfig getInstance() {
+        if (instance == null)
+            return new RankConfig();
 
+        return instance;
     }
 
-    public static RankConfig getInstance()
-    {
-        if(instance == null)
-            return new RankConfig();
+    @Override
+    protected void loadKeys() {
 
-        return instance;
     }
 
     @Override
@@ -46,12 +44,13 @@ public class RankConfig extends AutoUpdateConfigLoader {
 
     /**
      * Returns the unlock level for a subskill depending on the gamemode
+     *
      * @param subSkillType target subskill
-     * @param rank the rank we are checking
+     * @param rank         the rank we are checking
+     *
      * @return the level requirement for a subskill at this particular rank
      */
-    public int getSubSkillUnlockLevel(SubSkillType subSkillType, int rank)
-    {
+    public int getSubSkillUnlockLevel(SubSkillType subSkillType, int rank) {
         String key = subSkillType.getRankConfigAddress();
 
         return findRankByRootAddress(rank, key);
@@ -59,33 +58,37 @@ public class RankConfig extends AutoUpdateConfigLoader {
 
     /**
      * Returns the unlock level for a subskill depending on the gamemode
+     *
      * @param subSkillType target subskill
-     * @param rank the rank we are checking
+     * @param rank         the rank we are checking
+     *
      * @return the level requirement for a subskill at this particular rank
      */
-    public int getSubSkillUnlockLevel(SubSkillType subSkillType, int rank, boolean retroMode)
-    {
+    public int getSubSkillUnlockLevel(SubSkillType subSkillType, int rank, boolean retroMode) {
         String key = getRankAddressKey(subSkillType, rank, retroMode);
         return config.getInt(key, getInternalConfig().getInt(key));
     }
 
     /**
      * Returns the unlock level for a subskill depending on the gamemode
+     *
      * @param abstractSubSkill target subskill
-     * @param rank the rank we are checking
+     * @param rank             the rank we are checking
+     *
      * @return the level requirement for a subskill at this particular rank
      */
-    public int getSubSkillUnlockLevel(AbstractSubSkill abstractSubSkill, int rank)
-    {
-        String key = abstractSubSkill.getPrimaryKeyName()+"."+abstractSubSkill.getConfigKeyName();
+    public int getSubSkillUnlockLevel(AbstractSubSkill abstractSubSkill, int rank) {
+        String key = abstractSubSkill.getPrimaryKeyName() + "." + abstractSubSkill.getConfigKeyName();
 
         return findRankByRootAddress(rank, key);
     }
 
     /**
      * Returns the unlock level for a subskill depending on the gamemode
-     * @param key root address of the subskill in the rankskills.yml file
+     *
+     * @param key  root address of the subskill in the rankskills.yml file
      * @param rank the rank we are checking
+     *
      * @return the level requirement for a subskill at this particular rank
      */
     private int findRankByRootAddress(int rank, String key) {
@@ -127,60 +130,55 @@ public class RankConfig extends AutoUpdateConfigLoader {
         String key = getRankAddressKey(subSkillType, rank, retroMode);
         int defaultValue = getInternalConfig().getInt(key);
         config.set(key, defaultValue);
-        mcMMO.p.getLogger().info(key +" SET -> " + defaultValue);
+        mcMMO.p.getLogger().info(key + " SET -> " + defaultValue);
     }
 
     /**
      * Checks for valid keys for subskill ranks
      */
-    private void checkKeys(@NotNull List<String> reasons)
-    {
+    private void checkKeys(@NotNull List<String> reasons) {
         HashSet<SubSkillType> badSkillSetup = new HashSet<>();
-        
+
         //For now we will only check ranks of stuff I've overhauled
         checkConfig(reasons, badSkillSetup, true);
         checkConfig(reasons, badSkillSetup, false);
 
         //Fix bad entries
-        if(badSkillSetup.isEmpty())
+        if (badSkillSetup.isEmpty())
             return;
 
         mcMMO.p.getLogger().info("(FIXING CONFIG) mcMMO is correcting a few mistakes found in your skill rank config setup");
 
-        for(SubSkillType subSkillType : badSkillSetup) {
-            mcMMO.p.getLogger().info("(FIXING CONFIG) Resetting rank config settings for skill named - "+subSkillType.toString());
+        for (SubSkillType subSkillType : badSkillSetup) {
+            mcMMO.p.getLogger().info("(FIXING CONFIG) Resetting rank config settings for skill named - " + subSkillType.toString());
             fixBadEntries(subSkillType);
         }
     }
 
     private void checkConfig(@NotNull List<String> reasons, @NotNull HashSet<SubSkillType> badSkillSetup, boolean retroMode) {
-        for(SubSkillType subSkillType : SubSkillType.values())
-        {
+        for (SubSkillType subSkillType : SubSkillType.values()) {
             //Keeping track of the rank requirements and making sure there are no logical errors
             int curRank = 0;
             int prevRank = 0;
 
-            for(int x = 0; x < subSkillType.getNumRanks(); x++)
-            {
-                int index = x+1;
+            for (int x = 0; x < subSkillType.getNumRanks(); x++) {
+                int index = x + 1;
 
-                if(curRank > 0)
+                if (curRank > 0)
                     prevRank = curRank;
 
                 curRank = getSubSkillUnlockLevel(subSkillType, index, retroMode);
 
                 //Do we really care if its below 0? Probably not
-                if(curRank < 0)
-                {
-                    reasons.add("(CONFIG ISSUE) " + subSkillType.toString() + " should not have any ranks that require a negative level!");
+                if (curRank < 0) {
+                    reasons.add("(CONFIG ISSUE) " + subSkillType + " should not have any ranks that require a negative level!");
                     badSkillSetup.add(subSkillType);
                     continue;
                 }
 
-                if(prevRank > curRank)
-                {
+                if (prevRank > curRank) {
                     //We're going to allow this but we're going to warn them
-                    mcMMO.p.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 + " set up poorly, sequential ranks should have ascending requirements");
                     badSkillSetup.add(subSkillType);
                 }
             }
@@ -188,9 +186,8 @@ public class RankConfig extends AutoUpdateConfigLoader {
     }
 
     private void fixBadEntries(@NotNull SubSkillType subSkillType) {
-        for(int x = 0; x < subSkillType.getNumRanks(); x++)
-        {
-            int index = x+1;
+        for (int x = 0; x < subSkillType.getNumRanks(); x++) {
+            int index = x + 1;
 
             //Reset Retromode entries
             resetRankValue(subSkillType, index, true);

+ 23 - 30
src/main/java/com/gmail/nossr50/config/SoundConfig.java

@@ -3,45 +3,39 @@ package com.gmail.nossr50.config;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.util.sounds.SoundType;
 
-public class SoundConfig extends AutoUpdateConfigLoader {
+public class SoundConfig extends BukkitConfig {
     private static SoundConfig instance;
 
-    public SoundConfig()
-    {
+    public SoundConfig() {
         super("sounds.yml");
         validate();
         instance = this;
     }
 
-    @Override
-    protected void loadKeys() {
+    public static SoundConfig getInstance() {
+        if (instance == null)
+            return new SoundConfig();
 
+        return instance;
     }
 
-    public static SoundConfig getInstance()
-    {
-        if(instance == null)
-            return new SoundConfig();
+    @Override
+    protected void loadKeys() {
 
-        return instance;
     }
 
     @Override
     protected boolean validateKeys() {
-        for(SoundType soundType : SoundType.values())
-        {
-            if(config.getDouble("Sounds."+soundType.toString()+".Volume") < 0)
-            {
-                mcMMO.p.getLogger().info("[mcMMO] Sound volume cannot be below 0 for "+soundType.toString());
+        for (SoundType soundType : SoundType.values()) {
+            if (config.getDouble("Sounds." + soundType.toString() + ".Volume") < 0) {
+                mcMMO.p.getLogger().info("[mcMMO] Sound volume cannot be below 0 for " + soundType);
                 return false;
             }
 
             //Sounds with custom pitching don't use pitch values
-            if(!soundType.usesCustomPitch())
-            {
-                if(config.getDouble("Sounds."+soundType.toString()+".Pitch") < 0)
-                {
-                    mcMMO.p.getLogger().info("[mcMMO] Sound pitch cannot be below 0 for "+soundType.toString());
+            if (!soundType.usesCustomPitch()) {
+                if (config.getDouble("Sounds." + soundType + ".Pitch") < 0) {
+                    mcMMO.p.getLogger().info("[mcMMO] Sound pitch cannot be below 0 for " + soundType);
                     return false;
                 }
             }
@@ -49,23 +43,22 @@ public class SoundConfig extends AutoUpdateConfigLoader {
         return true;
     }
 
-    public float getMasterVolume() { return (float) config.getDouble("Sounds.MasterVolume", 1.0); }
+    public float getMasterVolume() {
+        return (float) config.getDouble("Sounds.MasterVolume", 1.0);
+    }
 
-    public float getVolume(SoundType soundType)
-    {
-        String key = "Sounds."+soundType.toString()+".Volume";
+    public float getVolume(SoundType soundType) {
+        String key = "Sounds." + soundType.toString() + ".Volume";
         return (float) config.getDouble(key);
     }
 
-    public float getPitch(SoundType soundType)
-    {
-        String key = "Sounds."+soundType.toString()+".Pitch";
+    public float getPitch(SoundType soundType) {
+        String key = "Sounds." + soundType.toString() + ".Pitch";
         return (float) config.getDouble(key);
     }
 
-    public boolean getIsEnabled(SoundType soundType)
-    {
-        String key = "Sounds."+soundType.toString()+".Enabled";
+    public boolean getIsEnabled(SoundType soundType) {
+        String key = "Sounds." + soundType.toString() + ".Enabled";
         return config.getBoolean(key, true);
     }
 }

+ 18 - 23
src/main/java/com/gmail/nossr50/config/WorldBlacklist.java

@@ -15,20 +15,28 @@ public class WorldBlacklist {
 
     private final String blackListFileName = "world_blacklist.txt";
 
-    public WorldBlacklist(mcMMO plugin)
-    {
+    public WorldBlacklist(mcMMO plugin) {
         this.plugin = plugin;
         blacklist = new ArrayList<>();
         init();
     }
 
-    public void init()
-    {
+    public static boolean isWorldBlacklisted(World world) {
+
+        for (String s : blacklist) {
+            if (world.getName().equalsIgnoreCase(s))
+                return true;
+        }
+
+        return false;
+    }
+
+    public void init() {
         //Make the blacklist file if it doesn't exist
         File blackListFile = new File(plugin.getDataFolder() + File.separator + blackListFileName);
 
         try {
-            if(!blackListFile.exists())
+            if (!blackListFile.exists())
                 blackListFile.createNewFile();
         } catch (IOException e) {
             e.printStackTrace();
@@ -48,12 +56,11 @@ public class WorldBlacklist {
 
             String currentLine;
 
-            while((currentLine = bufferedReader.readLine()) != null)
-            {
-                if(currentLine.length() == 0)
+            while ((currentLine = bufferedReader.readLine()) != null) {
+                if (currentLine.length() == 0)
                     continue;
 
-                if(!blacklist.contains(currentLine))
+                if (!blacklist.contains(currentLine))
                     blacklist.add(currentLine);
             }
 
@@ -66,11 +73,11 @@ public class WorldBlacklist {
             closeRead(fileReader);
         }
 
-        plugin.getLogger().info(blacklist.size()+" entries in mcMMO World Blacklist");
+        plugin.getLogger().info(blacklist.size() + " entries in mcMMO World Blacklist");
     }
 
     private void closeRead(Reader reader) {
-        if(reader != null) {
+        if (reader != null) {
             try {
                 reader.close();
             } catch (IOException e) {
@@ -78,16 +85,4 @@ public class WorldBlacklist {
             }
         }
     }
-
-    public static boolean isWorldBlacklisted(World world)
-    {
-
-        for(String s : blacklist)
-        {
-            if(world.getName().equalsIgnoreCase(s))
-                return true;
-        }
-
-        return false;
-    }
 }

+ 204 - 87
src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java

@@ -1,6 +1,6 @@
 package com.gmail.nossr50.config.experience;
 
-import com.gmail.nossr50.config.AutoUpdateConfigLoader;
+import com.gmail.nossr50.config.BukkitConfig;
 import com.gmail.nossr50.datatypes.experience.FormulaType;
 import com.gmail.nossr50.datatypes.skills.MaterialType;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
@@ -17,7 +17,7 @@ import org.bukkit.entity.EntityType;
 import java.util.ArrayList;
 import java.util.List;
 
-public class ExperienceConfig extends AutoUpdateConfigLoader {
+public class ExperienceConfig extends BukkitConfig {
     private static ExperienceConfig instance;
 
     private ExperienceConfig() {
@@ -34,7 +34,8 @@ public class ExperienceConfig extends AutoUpdateConfigLoader {
     }
 
     @Override
-    protected void loadKeys() {}
+    protected void loadKeys() {
+    }
 
     @Override
     protected boolean validateKeys() {
@@ -139,84 +140,182 @@ public class ExperienceConfig extends AutoUpdateConfigLoader {
         return noErrorsInConfig(reason);
     }
 
-    public boolean isEarlyGameBoostEnabled() { return config.getBoolean("EarlyGameBoost.Enabled", true); }
+    public boolean isEarlyGameBoostEnabled() {
+        return config.getBoolean("EarlyGameBoost.Enabled", true);
+    }
 
     /*
      * FORMULA SETTINGS
      */
 
     /* EXPLOIT TOGGLES */
-    public boolean isSnowExploitPrevented() { return config.getBoolean("ExploitFix.SnowGolemExcavation", true); }
-    public boolean isEndermanEndermiteFarmingPrevented() { return config.getBoolean("ExploitFix.EndermanEndermiteFarms", true); }
-    public boolean isPistonCheatingPrevented() { return config.getBoolean("ExploitFix.PistonCheating", true); }
-    public boolean isPistonExploitPrevented() { return config.getBoolean("ExploitFix.Pistons", false); }
-    public boolean allowUnsafeEnchantments() { return config.getBoolean("ExploitFix.UnsafeEnchantments", false); }
-    public boolean isCOTWBreedingPrevented() { return config.getBoolean("ExploitFix.COTWBreeding", true); }
-    public boolean isNPCInteractionPrevented() { return config.getBoolean("ExploitFix.PreventPluginNPCInteraction", true); }
+    public boolean isSnowExploitPrevented() {
+        return config.getBoolean("ExploitFix.SnowGolemExcavation", true);
+    }
+
+    public boolean isEndermanEndermiteFarmingPrevented() {
+        return config.getBoolean("ExploitFix.EndermanEndermiteFarms", true);
+    }
+
+    public boolean isPistonCheatingPrevented() {
+        return config.getBoolean("ExploitFix.PistonCheating", true);
+    }
+
+    public boolean isPistonExploitPrevented() {
+        return config.getBoolean("ExploitFix.Pistons", false);
+    }
+
+    public boolean allowUnsafeEnchantments() {
+        return config.getBoolean("ExploitFix.UnsafeEnchantments", false);
+    }
+
+    public boolean isCOTWBreedingPrevented() {
+        return config.getBoolean("ExploitFix.COTWBreeding", true);
+    }
+
+    public boolean isNPCInteractionPrevented() {
+        return config.getBoolean("ExploitFix.PreventPluginNPCInteraction", true);
+    }
+
+    public boolean isFishingExploitingPrevented() {
+        return config.getBoolean("ExploitFix.Fishing", true);
+    }
+
+    public int getFishingExploitingOptionMoveRange() {
+        return config.getInt("Fishing_ExploitFix_Options.MoveRange", 3);
+    }
+
+    public int getFishingExploitingOptionOverFishLimit() {
+        return config.getInt("Fishing_ExploitFix_Options.OverFishLimit", 10);
+    }
 
-    public boolean isFishingExploitingPrevented() { return config.getBoolean("ExploitFix.Fishing", true); }
-    public int getFishingExploitingOptionMoveRange() { return config.getInt("Fishing_ExploitFix_Options.MoveRange", 3); }
-    public int getFishingExploitingOptionOverFishLimit() { return config.getInt("Fishing_ExploitFix_Options.OverFishLimit", 10); }
+    public boolean isAcrobaticsExploitingPrevented() {
+        return config.getBoolean("ExploitFix.Acrobatics", true);
+    }
 
-    public boolean isAcrobaticsExploitingPrevented() { return config.getBoolean("ExploitFix.Acrobatics", true); }
-    public boolean isTreeFellerXPReduced() { return config.getBoolean("ExploitFix.TreeFellerReducedXP", true); }
+    public boolean isTreeFellerXPReduced() {
+        return config.getBoolean("ExploitFix.TreeFellerReducedXP", true);
+    }
 
     /* Curve settings */
-    public FormulaType getFormulaType() { return FormulaType.getFormulaType(config.getString("Experience_Formula.Curve")); }
-    public boolean getCumulativeCurveEnabled() { return config.getBoolean("Experience_Formula.Cumulative_Curve", false); }
+    public FormulaType getFormulaType() {
+        return FormulaType.getFormulaType(config.getString("Experience_Formula.Curve"));
+    }
+
+    public boolean getCumulativeCurveEnabled() {
+        return config.getBoolean("Experience_Formula.Cumulative_Curve", false);
+    }
 
     /* Curve values */
-    public double getMultiplier(FormulaType type) { return config.getDouble("Experience_Formula." + StringUtils.getCapitalized(type.toString()) + "_Values.multiplier"); }
-    public int getBase(FormulaType type) { return config.getInt("Experience_Formula." + StringUtils.getCapitalized(type.toString()) + "_Values.base"); }
-    public double getExponent(FormulaType type) { return config.getDouble("Experience_Formula." + StringUtils.getCapitalized(type.toString()) + "_Values.exponent"); }
+    public double getMultiplier(FormulaType type) {
+        return config.getDouble("Experience_Formula." + StringUtils.getCapitalized(type.toString()) + "_Values.multiplier");
+    }
+
+    public int getBase(FormulaType type) {
+        return config.getInt("Experience_Formula." + StringUtils.getCapitalized(type.toString()) + "_Values.base");
+    }
+
+    public double getExponent(FormulaType type) {
+        return config.getDouble("Experience_Formula." + StringUtils.getCapitalized(type.toString()) + "_Values.exponent");
+    }
 
     /* Global modifier */
-    public double getExperienceGainsGlobalMultiplier() { return config.getDouble("Experience_Formula.Multiplier.Global", 1.0); }
-    public void setExperienceGainsGlobalMultiplier(double value) { config.set("Experience_Formula.Multiplier.Global", value); }
+    public double getExperienceGainsGlobalMultiplier() {
+        return config.getDouble("Experience_Formula.Multiplier.Global", 1.0);
+    }
+
+    public void setExperienceGainsGlobalMultiplier(double value) {
+        config.set("Experience_Formula.Multiplier.Global", value);
+    }
 
     /* PVP modifier */
-    public double getPlayerVersusPlayerXP() { return config.getDouble("Experience_Formula.Multiplier.PVP", 1.0); }
+    public double getPlayerVersusPlayerXP() {
+        return config.getDouble("Experience_Formula.Multiplier.PVP", 1.0);
+    }
 
     /* Spawned Mob modifier */
-    public double getSpawnedMobXpMultiplier() { return config.getDouble("Experience_Formula.Mobspawners.Multiplier", 0.0); }
-    public double getEggXpMultiplier() { return config.getDouble("Experience_Formula.Eggs.Multiplier", 0.0); }
-    public double getTamedMobXpMultiplier() { return config.getDouble("Experience_Formula.Player_Tamed.Multiplier", 0.0); }
-    public double getNetherPortalXpMultiplier() { return config.getDouble("Experience_Formula.Nether_Portal.Multiplier", 0.0); }
-    public double getBredMobXpMultiplier() { return config.getDouble("Experience_Formula.Breeding.Multiplier", 1.0); }
+    public double getSpawnedMobXpMultiplier() {
+        return config.getDouble("Experience_Formula.Mobspawners.Multiplier", 0.0);
+    }
+
+    public double getEggXpMultiplier() {
+        return config.getDouble("Experience_Formula.Eggs.Multiplier", 0.0);
+    }
+
+    public double getTamedMobXpMultiplier() {
+        return config.getDouble("Experience_Formula.Player_Tamed.Multiplier", 0.0);
+    }
+
+    public double getNetherPortalXpMultiplier() {
+        return config.getDouble("Experience_Formula.Nether_Portal.Multiplier", 0.0);
+    }
+
+    public double getBredMobXpMultiplier() {
+        return config.getDouble("Experience_Formula.Breeding.Multiplier", 1.0);
+    }
 
     /* Skill modifiers */
-    public double getFormulaSkillModifier(PrimarySkillType skill) { return config.getDouble("Experience_Formula.Modifier." + StringUtils.getCapitalized(skill.toString())); }
+    public double getFormulaSkillModifier(PrimarySkillType skill) {
+        return config.getDouble("Experience_Formula.Modifier." + StringUtils.getCapitalized(skill.toString()));
+    }
 
     /* Custom XP perk */
-    public double getCustomXpPerkBoost() { return config.getDouble("Experience_Formula.Custom_XP_Perk.Boost", 1.25); }
+    public double getCustomXpPerkBoost() {
+        return config.getDouble("Experience_Formula.Custom_XP_Perk.Boost", 1.25);
+    }
 
     /* Diminished Returns */
-    public float getDiminishedReturnsCap() { return (float) config.getDouble("Dimished_Returns.Guaranteed_Minimum_Percentage", 0.05D); }
-    public boolean getDiminishedReturnsEnabled() { return config.getBoolean("Diminished_Returns.Enabled", false); }
-    public int getDiminishedReturnsThreshold(PrimarySkillType skill) { return config.getInt("Diminished_Returns.Threshold." + StringUtils.getCapitalized(skill.toString()), 20000); }
-    public int getDiminishedReturnsTimeInterval() { return config.getInt("Diminished_Returns.Time_Interval", 10); }
+    public float getDiminishedReturnsCap() {
+        return (float) config.getDouble("Dimished_Returns.Guaranteed_Minimum_Percentage", 0.05D);
+    }
+
+    public boolean getDiminishedReturnsEnabled() {
+        return config.getBoolean("Diminished_Returns.Enabled", false);
+    }
+
+    public int getDiminishedReturnsThreshold(PrimarySkillType skill) {
+        return config.getInt("Diminished_Returns.Threshold." + StringUtils.getCapitalized(skill.toString()), 20000);
+    }
+
+    public int getDiminishedReturnsTimeInterval() {
+        return config.getInt("Diminished_Returns.Time_Interval", 10);
+    }
 
     /* Conversion */
-    public double getExpModifier() { return config.getDouble("Conversion.Exp_Modifier", 1); }
+    public double getExpModifier() {
+        return config.getDouble("Conversion.Exp_Modifier", 1);
+    }
 
     /*
      * XP SETTINGS
      */
 
     /* General Settings */
-    public boolean getExperienceGainsPlayerVersusPlayerEnabled() { return config.getBoolean("Experience_Values.PVP.Rewards", true); }
+    public boolean getExperienceGainsPlayerVersusPlayerEnabled() {
+        return config.getBoolean("Experience_Values.PVP.Rewards", true);
+    }
 
     /* Combat XP Multipliers */
-    public double getCombatXP(EntityType entity) { return config.getDouble("Experience_Values.Combat.Multiplier." + StringUtils.getPrettyEntityTypeString(entity).replace(" ", "_")); }
-    public double getAnimalsXP(EntityType entity) { return config.getDouble("Experience_Values.Combat.Multiplier." + StringUtils.getPrettyEntityTypeString(entity).replace(" ", "_"), getAnimalsXP()); }
-    public double getAnimalsXP() { return config.getDouble("Experience_Values.Combat.Multiplier.Animals", 1.0); }
-    public boolean hasCombatXP(EntityType entity) {return config.contains("Experience_Values.Combat.Multiplier." + StringUtils.getPrettyEntityTypeString(entity).replace(" ", "_")); }
+    public double getCombatXP(EntityType entity) {
+        return config.getDouble("Experience_Values.Combat.Multiplier." + StringUtils.getPrettyEntityTypeString(entity).replace(" ", "_"));
+    }
+
+    public double getAnimalsXP(EntityType entity) {
+        return config.getDouble("Experience_Values.Combat.Multiplier." + StringUtils.getPrettyEntityTypeString(entity).replace(" ", "_"), getAnimalsXP());
+    }
+
+    public double getAnimalsXP() {
+        return config.getDouble("Experience_Values.Combat.Multiplier.Animals", 1.0);
+    }
+
+    public boolean hasCombatXP(EntityType entity) {
+        return config.contains("Experience_Values.Combat.Multiplier." + StringUtils.getPrettyEntityTypeString(entity).replace(" ", "_"));
+    }
 
     /* Materials  */
-    public int getXp(PrimarySkillType skill, Material material)
-    {
+    public int getXp(PrimarySkillType skill, Material material) {
         //TODO: Temporary measure to fix an exploit caused by a yet to be fixed Spigot bug (as of 7/3/2020)
-        if(material.toString().equalsIgnoreCase("LILY_PAD"))
+        if (material.toString().equalsIgnoreCase("LILY_PAD"))
             return 0;
 
         String baseString = "Experience_Values." + StringUtils.getCapitalized(skill.toString()) + ".";
@@ -233,8 +332,7 @@ public class ExperienceConfig extends AutoUpdateConfigLoader {
     }
 
     /* Materials  */
-    public int getXp(PrimarySkillType skill, BlockState blockState)
-    {
+    public int getXp(PrimarySkillType skill, BlockState blockState) {
         Material data = blockState.getType();
 
         String baseString = "Experience_Values." + StringUtils.getCapitalized(skill.toString()) + ".";
@@ -251,8 +349,7 @@ public class ExperienceConfig extends AutoUpdateConfigLoader {
     }
 
     /* Materials  */
-    public int getXp(PrimarySkillType skill, Block block)
-    {
+    public int getXp(PrimarySkillType skill, Block block) {
         Material data = block.getType();
 
         String baseString = "Experience_Values." + StringUtils.getCapitalized(skill.toString()) + ".";
@@ -269,8 +366,7 @@ public class ExperienceConfig extends AutoUpdateConfigLoader {
     }
 
     /* Materials  */
-    public int getXp(PrimarySkillType skill, BlockData data)
-    {
+    public int getXp(PrimarySkillType skill, BlockData data) {
         String baseString = "Experience_Values." + StringUtils.getCapitalized(skill.toString()) + ".";
         String explicitString = baseString + StringUtils.getExplicitConfigBlockDataString(data);
         if (config.contains(explicitString))
@@ -284,8 +380,7 @@ public class ExperienceConfig extends AutoUpdateConfigLoader {
         return 0;
     }
 
-    public boolean doesBlockGiveSkillXP(PrimarySkillType skill, Material data)
-    {
+    public boolean doesBlockGiveSkillXP(PrimarySkillType skill, Material data) {
         String baseString = "Experience_Values." + StringUtils.getCapitalized(skill.toString()) + ".";
         String explicitString = baseString + StringUtils.getExplicitConfigMaterialString(data);
         if (config.contains(explicitString))
@@ -297,8 +392,7 @@ public class ExperienceConfig extends AutoUpdateConfigLoader {
         return config.contains(wildcardString);
     }
 
-    public boolean doesBlockGiveSkillXP(PrimarySkillType skill, BlockData data)
-    {
+    public boolean doesBlockGiveSkillXP(PrimarySkillType skill, BlockData data) {
         String baseString = "Experience_Values." + StringUtils.getCapitalized(skill.toString()) + ".";
         String explicitString = baseString + StringUtils.getExplicitConfigBlockDataString(data);
         if (config.contains(explicitString))
@@ -314,32 +408,35 @@ public class ExperienceConfig extends AutoUpdateConfigLoader {
      * Experience Bar Stuff
      */
 
-    public boolean isPartyExperienceBarsEnabled()
-    {
+    public boolean isPartyExperienceBarsEnabled() {
         return config.getBoolean("Experience_Bars.Update.Party", true);
     }
 
-    public boolean isPassiveGainsExperienceBarsEnabled()
-    {
+    public boolean isPassiveGainsExperienceBarsEnabled() {
         return config.getBoolean("Experience_Bars.Update.Passive", true);
     }
 
-    public boolean getDoExperienceBarsAlwaysUpdateTitle()
-    {
+    public boolean getDoExperienceBarsAlwaysUpdateTitle() {
         return config.getBoolean("Experience_Bars.ThisMayCauseLag.AlwaysUpdateTitlesWhenXPIsGained.Enable", false) || getAddExtraDetails();
     }
 
-    public boolean getAddExtraDetails() { return config.getBoolean("Experience_Bars.ThisMayCauseLag.AlwaysUpdateTitlesWhenXPIsGained.ExtraDetails", false);}
-    public boolean isExperienceBarsEnabled() { return config.getBoolean("Experience_Bars.Enable", true); }
-    public boolean isExperienceBarEnabled(PrimarySkillType primarySkillType) { return config.getBoolean("Experience_Bars."+StringUtils.getCapitalized(primarySkillType.toString())+".Enable", true);}
+    public boolean getAddExtraDetails() {
+        return config.getBoolean("Experience_Bars.ThisMayCauseLag.AlwaysUpdateTitlesWhenXPIsGained.ExtraDetails", false);
+    }
+
+    public boolean isExperienceBarsEnabled() {
+        return config.getBoolean("Experience_Bars.Enable", true);
+    }
+
+    public boolean isExperienceBarEnabled(PrimarySkillType primarySkillType) {
+        return config.getBoolean("Experience_Bars." + StringUtils.getCapitalized(primarySkillType.toString()) + ".Enable", true);
+    }
 
-    public BarColor getExperienceBarColor(PrimarySkillType primarySkillType)
-    {
-        String colorValueFromConfig = config.getString("Experience_Bars."+StringUtils.getCapitalized(primarySkillType.toString())+".Color");
+    public BarColor getExperienceBarColor(PrimarySkillType primarySkillType) {
+        String colorValueFromConfig = config.getString("Experience_Bars." + StringUtils.getCapitalized(primarySkillType.toString()) + ".Color");
 
-        for(BarColor barColor : BarColor.values())
-        {
-            if(barColor.toString().equalsIgnoreCase(colorValueFromConfig))
+        for (BarColor barColor : BarColor.values()) {
+            if (barColor.toString().equalsIgnoreCase(colorValueFromConfig))
                 return barColor;
         }
 
@@ -347,13 +444,11 @@ public class ExperienceConfig extends AutoUpdateConfigLoader {
         return BarColor.WHITE;
     }
 
-    public BarStyle getExperienceBarStyle(PrimarySkillType primarySkillType)
-    {
-        String colorValueFromConfig = config.getString("Experience_Bars."+StringUtils.getCapitalized(primarySkillType.toString())+".BarStyle");
+    public BarStyle getExperienceBarStyle(PrimarySkillType primarySkillType) {
+        String colorValueFromConfig = config.getString("Experience_Bars." + StringUtils.getCapitalized(primarySkillType.toString()) + ".BarStyle");
 
-        for(BarStyle barStyle : BarStyle.values())
-        {
-            if(barStyle.toString().equalsIgnoreCase(colorValueFromConfig))
+        for (BarStyle barStyle : BarStyle.values()) {
+            if (barStyle.toString().equalsIgnoreCase(colorValueFromConfig))
                 return barStyle;
         }
 
@@ -362,29 +457,51 @@ public class ExperienceConfig extends AutoUpdateConfigLoader {
     }
 
     /* Acrobatics */
-    public int getDodgeXPModifier() { return config.getInt("Experience_Values.Acrobatics.Dodge", 120); }
-    public int getRollXPModifier() { return config.getInt("Experience_Values.Acrobatics.Roll", 80); }
-    public int getFallXPModifier() { return config.getInt("Experience_Values.Acrobatics.Fall", 120); }
+    public int getDodgeXPModifier() {
+        return config.getInt("Experience_Values.Acrobatics.Dodge", 120);
+    }
+
+    public int getRollXPModifier() {
+        return config.getInt("Experience_Values.Acrobatics.Roll", 80);
+    }
 
-    public double getFeatherFallXPModifier() { return config.getDouble("Experience_Values.Acrobatics.FeatherFall_Multiplier", 2.0); }
+    public int getFallXPModifier() {
+        return config.getInt("Experience_Values.Acrobatics.Fall", 120);
+    }
+
+    public double getFeatherFallXPModifier() {
+        return config.getDouble("Experience_Values.Acrobatics.FeatherFall_Multiplier", 2.0);
+    }
 
     /* Alchemy */
-    public double getPotionXP(PotionStage stage) { return config.getDouble("Experience_Values.Alchemy.Potion_Stage_" + stage.toNumerical(), 10D); }
+    public double getPotionXP(PotionStage stage) {
+        return config.getDouble("Experience_Values.Alchemy.Potion_Stage_" + stage.toNumerical(), 10D);
+    }
 
     /* Archery */
-    public double getArcheryDistanceMultiplier() { return config.getDouble("Experience_Values.Archery.Distance_Multiplier", 0.025); }
+    public double getArcheryDistanceMultiplier() {
+        return config.getDouble("Experience_Values.Archery.Distance_Multiplier", 0.025);
+    }
 
-    public int getFishingShakeXP() { return config.getInt("Experience_Values.Fishing.Shake", 50); }
+    public int getFishingShakeXP() {
+        return config.getInt("Experience_Values.Fishing.Shake", 50);
+    }
 
     /* Repair */
-    public double getRepairXPBase() { return config.getDouble("Experience_Values.Repair.Base", 1000.0); }
-    public double getRepairXP(MaterialType repairMaterialType) { return config.getDouble("Experience_Values.Repair." + StringUtils.getCapitalized(repairMaterialType.toString())); }
+    public double getRepairXPBase() {
+        return config.getDouble("Experience_Values.Repair.Base", 1000.0);
+    }
+
+    public double getRepairXP(MaterialType repairMaterialType) {
+        return config.getDouble("Experience_Values.Repair." + StringUtils.getCapitalized(repairMaterialType.toString()));
+    }
 
     /* Taming */
-    public int getTamingXP(EntityType type)
-    {
+    public int getTamingXP(EntityType type) {
         return config.getInt("Experience_Values.Taming.Animal_Taming." + StringUtils.getPrettyEntityTypeString(type));
     }
 
-    public boolean preventStoneLavaFarming() { return config.getBoolean("ExploitFix.LavaStoneAndCobbleFarming", true);}
+    public boolean preventStoneLavaFarming() {
+        return config.getBoolean("ExploitFix.LavaStoneAndCobbleFarming", true);
+    }
 }

+ 4 - 6
src/main/java/com/gmail/nossr50/config/mods/CustomArmorConfig.java

@@ -14,14 +14,12 @@ import java.util.List;
 import java.util.Set;
 
 public class CustomArmorConfig extends ConfigLoader {
-    private boolean needsUpdate = false;
-
-    public List<Material> customBoots       = new ArrayList<>();
+    public List<Material> customBoots = new ArrayList<>();
     public List<Material> customChestplates = new ArrayList<>();
-    public List<Material> customHelmets     = new ArrayList<>();
-    public List<Material> customLeggings    = new ArrayList<>();
-
+    public List<Material> customHelmets = new ArrayList<>();
+    public List<Material> customLeggings = new ArrayList<>();
     public List<Repairable> repairables = new ArrayList<>();
+    private boolean needsUpdate = false;
 
     protected CustomArmorConfig(String fileName) {
         super("mods", fileName);

+ 10 - 14
src/main/java/com/gmail/nossr50/config/mods/CustomBlockConfig.java

@@ -12,17 +12,15 @@ import java.util.List;
 import java.util.Set;
 
 public class CustomBlockConfig extends ConfigLoader {
-    private boolean needsUpdate = false;
-
-    public List<Material> customExcavationBlocks  = new ArrayList<>();
-    public List<Material> customHerbalismBlocks   = new ArrayList<>();
-    public List<Material> customMiningBlocks      = new ArrayList<>();
-    public List<Material> customOres              = new ArrayList<>();
-    public List<Material> customLogs              = new ArrayList<>();
-    public List<Material> customLeaves            = new ArrayList<>();
-    public List<Material> customAbilityBlocks     = new ArrayList<>();
-
+    public List<Material> customExcavationBlocks = new ArrayList<>();
+    public List<Material> customHerbalismBlocks = new ArrayList<>();
+    public List<Material> customMiningBlocks = new ArrayList<>();
+    public List<Material> customOres = new ArrayList<>();
+    public List<Material> customLogs = new ArrayList<>();
+    public List<Material> customLeaves = new ArrayList<>();
+    public List<Material> customAbilityBlocks = new ArrayList<>();
     public HashMap<Material, CustomBlock> customBlockMap = new HashMap<>();
+    private boolean needsUpdate = false;
 
     protected CustomBlockConfig(String fileName) {
         super("mods", fileName);
@@ -85,12 +83,10 @@ public class CustomBlockConfig extends ConfigLoader {
             if (skillType.equals("Mining") && config.getBoolean(skillType + "." + blockName + ".Is_Ore")) {
                 customOres.add(blockMaterial);
                 smeltingXp = config.getInt(skillType + "." + blockName + ".Smelting_XP_Gain", xp / 10);
-            }
-            else if (skillType.equals("Woodcutting")) {
+            } else if (skillType.equals("Woodcutting")) {
                 if (config.getBoolean(skillType + "." + blockName + ".Is_Log")) {
                     customLogs.add(blockMaterial);
-                }
-                else {
+                } else {
                     customLeaves.add(blockMaterial);
                     xp = 0; // Leaves don't grant XP
                 }

+ 2 - 3
src/main/java/com/gmail/nossr50/config/mods/CustomEntityConfig.java

@@ -11,7 +11,7 @@ import java.util.HashMap;
 
 public class CustomEntityConfig extends ConfigLoader {
     public HashMap<String, CustomEntity> customEntityClassMap = new HashMap<>();
-    public HashMap<String, CustomEntity> customEntityTypeMap  = new HashMap<>();
+    public HashMap<String, CustomEntity> customEntityTypeMap = new HashMap<>();
 
     protected CustomEntityConfig(String fileName) {
         super("mods", fileName);
@@ -31,8 +31,7 @@ public class CustomEntityConfig extends ConfigLoader {
 
             try {
                 clazz = ClassUtils.getClass(className);
-            }
-            catch (ClassNotFoundException e) {
+            } catch (ClassNotFoundException e) {
                 mcMMO.p.getLogger().warning("Invalid class (" + className + ") detected for " + entityName + ".");
                 mcMMO.p.getLogger().warning("This custom entity may not function properly.");
             }

+ 6 - 9
src/main/java/com/gmail/nossr50/config/mods/CustomToolConfig.java

@@ -16,18 +16,15 @@ import java.util.List;
 import java.util.Set;
 
 public class CustomToolConfig extends ConfigLoader {
-    private boolean needsUpdate = false;
-
-    public List<Material> customAxes     = new ArrayList<>();
-    public List<Material> customBows     = new ArrayList<>();
-    public List<Material> customHoes     = new ArrayList<>();
+    public List<Material> customAxes = new ArrayList<>();
+    public List<Material> customBows = new ArrayList<>();
+    public List<Material> customHoes = new ArrayList<>();
     public List<Material> customPickaxes = new ArrayList<>();
-    public List<Material> customShovels  = new ArrayList<>();
-    public List<Material> customSwords   = new ArrayList<>();
-
+    public List<Material> customShovels = new ArrayList<>();
+    public List<Material> customSwords = new ArrayList<>();
     public HashMap<Material, CustomTool> customToolMap = new HashMap<>();
-
     public List<Repairable> repairables = new ArrayList<>();
+    private boolean needsUpdate = false;
 
     protected CustomToolConfig(String fileName) {
         super("mods", fileName);

+ 4 - 3
src/main/java/com/gmail/nossr50/config/party/ItemWeightConfig.java

@@ -1,13 +1,13 @@
 package com.gmail.nossr50.config.party;
 
-import com.gmail.nossr50.config.ConfigLoader;
+import com.gmail.nossr50.config.BukkitConfig;
 import com.gmail.nossr50.util.text.StringUtils;
 import org.bukkit.Material;
 
 import java.util.HashSet;
 import java.util.Locale;
 
-public class ItemWeightConfig extends ConfigLoader {
+public class ItemWeightConfig extends BukkitConfig {
     private static ItemWeightConfig instance;
 
     private ItemWeightConfig() {
@@ -40,5 +40,6 @@ public class ItemWeightConfig extends ConfigLoader {
     }
 
     @Override
-    protected void loadKeys() {}
+    protected void loadKeys() {
+    }
 }

+ 14 - 19
src/main/java/com/gmail/nossr50/config/skills/alchemy/PotionConfig.java

@@ -95,8 +95,7 @@ public class PotionConfig extends ConfigLoader {
             if (potion != null) {
                 potionMap.put(potionName, potion);
                 pass++;
-            }
-            else {
+            } else {
                 fail++;
             }
         }
@@ -114,13 +113,13 @@ public class PotionConfig extends ConfigLoader {
      */
     private AlchemyPotion loadPotion(ConfigurationSection potion_section) {
         try {
-            
+
 
             String name = potion_section.getString("Name");
             if (name != null) {
                 name = ChatColor.translateAlternateColorCodes('&', name);
             }
-            
+
             PotionData data;
             if (!potion_section.contains("PotionData")) { // Backwards config compatability
                 short dataValue = Short.parseShort(potion_section.getName());
@@ -130,7 +129,7 @@ public class PotionConfig extends ConfigLoader {
                 ConfigurationSection potionData = potion_section.getConfigurationSection("PotionData");
                 data = new PotionData(PotionType.valueOf(potionData.getString("PotionType", "WATER")), potionData.getBoolean("Extended", false), potionData.getBoolean("Upgraded", false));
             }
-            
+
             Material material = Material.POTION;
             String mat = potion_section.getString("Material", null);
             if (mat != null) {
@@ -155,18 +154,16 @@ public class PotionConfig extends ConfigLoader {
 
                     if (type != null) {
                         effects.add(new PotionEffect(type, duration, amplifier));
-                    }
-                    else {
+                    } else {
                         mcMMO.p.getLogger().warning("Failed to parse effect for potion " + name + ": " + effect);
                     }
                 }
             }
-            
+
             Color color;
             if (potion_section.contains("Color")) {
                 color = Color.fromRGB(potion_section.getInt("Color"));
-            }
-            else {
+            } else {
                 color = this.generateColor(effects);
             }
 
@@ -176,16 +173,14 @@ public class PotionConfig extends ConfigLoader {
                     ItemStack ingredient = loadIngredient(child);
                     if (ingredient != null) {
                         children.put(ingredient, potion_section.getConfigurationSection("Children").getString(child));
-                    }
-                    else {
+                    } else {
                         mcMMO.p.getLogger().warning("Failed to parse child for potion " + name + ": " + child);
                     }
                 }
             }
 
             return new AlchemyPotion(material, data, name, lore, effects, color, children);
-        }
-        catch (Exception e) {
+        } catch (Exception e) {
             mcMMO.p.getLogger().warning("Failed to load Alchemy potion: " + potion_section.getName());
             return null;
         }
@@ -243,7 +238,7 @@ public class PotionConfig extends ConfigLoader {
     public AlchemyPotion getPotion(String name) {
         return potionMap.get(name);
     }
-    
+
     public AlchemyPotion getPotion(ItemStack item) {
         for (AlchemyPotion potion : potionMap.values()) {
             if (potion.isSimilar(item)) {
@@ -252,7 +247,7 @@ public class PotionConfig extends ConfigLoader {
         }
         return null;
     }
-    
+
     public Color generateColor(List<PotionEffect> effects) {
         if (effects != null && !effects.isEmpty()) {
             List<Color> colors = new ArrayList<>();
@@ -270,7 +265,7 @@ public class PotionConfig extends ConfigLoader {
         }
         return null;
     }
-    
+
     public Color calculateAverageColor(List<Color> colors) {
         int red = 0;
         int green = 0;
@@ -280,7 +275,7 @@ public class PotionConfig extends ConfigLoader {
             green += color.getGreen();
             blue += color.getBlue();
         }
-        return Color.fromRGB(red/colors.size(), green/colors.size(), blue/colors.size());
+        return Color.fromRGB(red / colors.size(), green / colors.size(), blue / colors.size());
     }
-    
+
 }

+ 17 - 28
src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfig.java

@@ -1,6 +1,6 @@
 package com.gmail.nossr50.config.skills.repair;
 
-import com.gmail.nossr50.config.ConfigLoader;
+import com.gmail.nossr50.config.BukkitConfig;
 import com.gmail.nossr50.datatypes.skills.ItemType;
 import com.gmail.nossr50.datatypes.skills.MaterialType;
 import com.gmail.nossr50.mcMMO;
@@ -13,9 +13,9 @@ import org.bukkit.inventory.ItemStack;
 
 import java.util.*;
 
-public class RepairConfig extends ConfigLoader {
-    private List<Repairable> repairables;
+public class RepairConfig extends BukkitConfig {
     private final HashSet<String> notSupported;
+    private List<Repairable> repairables;
 
     public RepairConfig(String fileName) {
         super(fileName);
@@ -62,33 +62,25 @@ public class RepairConfig extends ConfigLoader {
 
                 if (ItemUtils.isWoodTool(repairItem)) {
                     repairMaterialType = MaterialType.WOOD;
-                }
-                else if (ItemUtils.isStoneTool(repairItem)) {
+                } else if (ItemUtils.isStoneTool(repairItem)) {
                     repairMaterialType = MaterialType.STONE;
-                }
-                else if (ItemUtils.isStringTool(repairItem)) {
+                } else if (ItemUtils.isStringTool(repairItem)) {
                     repairMaterialType = MaterialType.STRING;
-                }
-                else if (ItemUtils.isLeatherArmor(repairItem)) {
+                } else if (ItemUtils.isLeatherArmor(repairItem)) {
                     repairMaterialType = MaterialType.LEATHER;
-                }
-                else if (ItemUtils.isIronArmor(repairItem) || ItemUtils.isIronTool(repairItem)) {
+                } else if (ItemUtils.isIronArmor(repairItem) || ItemUtils.isIronTool(repairItem)) {
                     repairMaterialType = MaterialType.IRON;
-                }
-                else if (ItemUtils.isGoldArmor(repairItem) || ItemUtils.isGoldTool(repairItem)) {
+                } else if (ItemUtils.isGoldArmor(repairItem) || ItemUtils.isGoldTool(repairItem)) {
                     repairMaterialType = MaterialType.GOLD;
-                }
-                else if (ItemUtils.isDiamondArmor(repairItem) || ItemUtils.isDiamondTool(repairItem)) {
+                } else if (ItemUtils.isDiamondArmor(repairItem) || ItemUtils.isDiamondTool(repairItem)) {
                     repairMaterialType = MaterialType.DIAMOND;
                 } else if (ItemUtils.isNetheriteArmor(repairItem) || ItemUtils.isNetheriteTool(repairItem)) {
                     repairMaterialType = MaterialType.NETHERITE;
                 }
-            }
-            else {
+            } else {
                 try {
                     repairMaterialType = MaterialType.valueOf(repairMaterialTypeString);
-                }
-                catch (IllegalArgumentException ex) {
+                } catch (IllegalArgumentException ex) {
                     reason.add(key + " has an invalid MaterialType of " + repairMaterialTypeString);
                 }
             }
@@ -122,16 +114,13 @@ public class RepairConfig extends ConfigLoader {
 
                 if (ItemUtils.isMinecraftTool(repairItem)) {
                     repairItemType = ItemType.TOOL;
-                }
-                else if (ItemUtils.isArmor(repairItem)) {
+                } else if (ItemUtils.isArmor(repairItem)) {
                     repairItemType = ItemType.ARMOR;
                 }
-            }
-            else {
+            } else {
                 try {
                     repairItemType = ItemType.valueOf(repairItemTypeString);
-                }
-                catch (IllegalArgumentException ex) {
+                } catch (IllegalArgumentException ex) {
                     reason.add(key + " has an invalid ItemType of " + repairItemTypeString);
                 }
             }
@@ -146,7 +135,7 @@ public class RepairConfig extends ConfigLoader {
             // Minimum Quantity
             int minimumQuantity = config.getInt("Repairables." + key + ".MinimumQuantity");
 
-            if(minimumQuantity == 0) {
+            if (minimumQuantity == 0) {
                 minimumQuantity = -1;
             }
 
@@ -158,13 +147,13 @@ public class RepairConfig extends ConfigLoader {
         //Report unsupported
         StringBuilder stringBuilder = new StringBuilder();
 
-        if(notSupported.size() > 0) {
+        if (notSupported.size() > 0) {
             stringBuilder.append("mcMMO found the following materials in the Repair config that are not supported by the version of Minecraft running on this server: ");
 
             for (Iterator<String> iterator = notSupported.iterator(); iterator.hasNext(); ) {
                 String unsupportedMaterial = iterator.next();
 
-                if(!iterator.hasNext()) {
+                if (!iterator.hasNext()) {
                     stringBuilder.append(unsupportedMaterial);
                 } else {
                     stringBuilder.append(unsupportedMaterial).append(", ");

+ 10 - 17
src/main/java/com/gmail/nossr50/config/skills/repair/RepairConfigManager.java

@@ -1,28 +1,28 @@
 package com.gmail.nossr50.config.skills.repair;
 
-import com.gmail.nossr50.datatypes.database.UpgradeType;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.skills.repair.repairables.Repairable;
-import com.gmail.nossr50.util.FixSpellingNetheriteUtil;
 
 import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Collection;
+import java.util.HashSet;
 import java.util.regex.Pattern;
 
 public class RepairConfigManager {
-    private final List<Repairable> repairables = new ArrayList<>();
+    public static final String REPAIR_VANILLA_YML = "repair.vanilla.yml";
+    private static final Collection<Repairable> repairables = new HashSet<>();
 
     public RepairConfigManager(mcMMO plugin) {
         Pattern pattern = Pattern.compile("repair\\.(?:.+)\\.yml");
         File dataFolder = plugin.getDataFolder();
-        File vanilla = new File(dataFolder, "repair.vanilla.yml");
 
-        if (!vanilla.exists()) {
-            plugin.saveResource("repair.vanilla.yml", false);
-        }
+        RepairConfig mainRepairConfig = new RepairConfig(REPAIR_VANILLA_YML);
+        repairables.addAll(mainRepairConfig.getLoadedRepairables());
 
         for (String fileName : dataFolder.list()) {
+            if(fileName.equals(REPAIR_VANILLA_YML))
+                continue;
+
             if (!pattern.matcher(fileName).matches()) {
                 continue;
             }
@@ -33,19 +33,12 @@ public class RepairConfigManager {
                 continue;
             }
 
-
-            if(mcMMO.getUpgradeManager().shouldUpgrade(UpgradeType.FIX_SPELLING_NETHERITE_REPAIR)) {
-                //Check spelling mistakes (early versions of 1.16 support had Netherite misspelled)
-                plugin.getLogger().info("Checking for certain invalid material names in Repair config...");
-                FixSpellingNetheriteUtil.processFileCheck(mcMMO.p, fileName, UpgradeType.FIX_SPELLING_NETHERITE_REPAIR);
-            }
-
             RepairConfig rConfig = new RepairConfig(fileName);
             repairables.addAll(rConfig.getLoadedRepairables());
         }
     }
 
-    public List<Repairable> getLoadedRepairables() {
+    public Collection<Repairable> getLoadedRepairables() {
         return repairables;
     }
 }

+ 21 - 32
src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfig.java

@@ -1,6 +1,6 @@
 package com.gmail.nossr50.config.skills.salvage;
 
-import com.gmail.nossr50.config.ConfigLoader;
+import com.gmail.nossr50.config.BukkitConfig;
 import com.gmail.nossr50.datatypes.database.UpgradeType;
 import com.gmail.nossr50.datatypes.skills.ItemType;
 import com.gmail.nossr50.datatypes.skills.MaterialType;
@@ -16,9 +16,9 @@ import org.bukkit.inventory.ItemStack;
 import java.io.IOException;
 import java.util.*;
 
-public class SalvageConfig extends ConfigLoader {
-    private List<Salvageable> salvageables;
+public class SalvageConfig extends BukkitConfig {
     private final HashSet<String> notSupported;
+    private Set<Salvageable> salvageables;
 
     public SalvageConfig(String fileName) {
         super(fileName);
@@ -28,7 +28,7 @@ public class SalvageConfig extends ConfigLoader {
 
     @Override
     protected void loadKeys() {
-        salvageables = new ArrayList<>();
+        salvageables = new HashSet<>();
 
         if (!config.isConfigurationSection("Salvageables")) {
             mcMMO.p.getLogger().severe("Could not find Salvageables section in " + fileName);
@@ -40,9 +40,9 @@ public class SalvageConfig extends ConfigLoader {
 
         //Original version of 1.16 support had maximum quantities that were bad, this fixes it
 
-        if(mcMMO.getUpgradeManager().shouldUpgrade(UpgradeType.FIX_NETHERITE_SALVAGE_QUANTITIES)) {
+        if (mcMMO.getUpgradeManager().shouldUpgrade(UpgradeType.FIX_NETHERITE_SALVAGE_QUANTITIES)) {
             mcMMO.p.getLogger().info("Fixing incorrect Salvage quantities on Netherite gear, this will only run once...");
-            for(String namespacedkey : mcMMO.getMaterialMapStore().getNetheriteArmor()) {
+            for (String namespacedkey : mcMMO.getMaterialMapStore().getNetheriteArmor()) {
                 config.set("Salvageables." + namespacedkey.toUpperCase() + ".MaximumQuantity", 4); //TODO: Doesn't make sense to default to 4 for everything
             }
 
@@ -78,33 +78,25 @@ public class SalvageConfig extends ConfigLoader {
 
                 if (ItemUtils.isWoodTool(salvageItem)) {
                     salvageMaterialType = MaterialType.WOOD;
-                }
-                else if (ItemUtils.isStoneTool(salvageItem)) {
+                } else if (ItemUtils.isStoneTool(salvageItem)) {
                     salvageMaterialType = MaterialType.STONE;
-                }
-                else if (ItemUtils.isStringTool(salvageItem)) {
+                } else if (ItemUtils.isStringTool(salvageItem)) {
                     salvageMaterialType = MaterialType.STRING;
-                }
-                else if (ItemUtils.isLeatherArmor(salvageItem)) {
+                } else if (ItemUtils.isLeatherArmor(salvageItem)) {
                     salvageMaterialType = MaterialType.LEATHER;
-                }
-                else if (ItemUtils.isIronArmor(salvageItem) || ItemUtils.isIronTool(salvageItem)) {
+                } else if (ItemUtils.isIronArmor(salvageItem) || ItemUtils.isIronTool(salvageItem)) {
                     salvageMaterialType = MaterialType.IRON;
-                }
-                else if (ItemUtils.isGoldArmor(salvageItem) || ItemUtils.isGoldTool(salvageItem)) {
+                } else if (ItemUtils.isGoldArmor(salvageItem) || ItemUtils.isGoldTool(salvageItem)) {
                     salvageMaterialType = MaterialType.GOLD;
-                }
-                else if (ItemUtils.isDiamondArmor(salvageItem) || ItemUtils.isDiamondTool(salvageItem)) {
+                } else if (ItemUtils.isDiamondArmor(salvageItem) || ItemUtils.isDiamondTool(salvageItem)) {
                     salvageMaterialType = MaterialType.DIAMOND;
                 } else if (ItemUtils.isNetheriteTool(salvageItem) || ItemUtils.isNetheriteArmor(salvageItem)) {
                     salvageMaterialType = MaterialType.NETHERITE;
                 }
-            }
-            else {
+            } else {
                 try {
                     salvageMaterialType = MaterialType.valueOf(salvageMaterialTypeString.replace(" ", "_").toUpperCase(Locale.ENGLISH));
-                }
-                catch (IllegalArgumentException ex) {
+                } catch (IllegalArgumentException ex) {
                     reason.add(key + " has an invalid MaterialType of " + salvageMaterialTypeString);
                 }
             }
@@ -130,16 +122,13 @@ public class SalvageConfig extends ConfigLoader {
 
                 if (ItemUtils.isMinecraftTool(salvageItem)) {
                     salvageItemType = ItemType.TOOL;
-                }
-                else if (ItemUtils.isArmor(salvageItem)) {
+                } else if (ItemUtils.isArmor(salvageItem)) {
                     salvageItemType = ItemType.ARMOR;
                 }
-            }
-            else {
+            } else {
                 try {
                     salvageItemType = ItemType.valueOf(salvageItemTypeString.replace(" ", "_").toUpperCase(Locale.ENGLISH));
-                }
-                catch (IllegalArgumentException ex) {
+                } catch (IllegalArgumentException ex) {
                     reason.add(key + " has an invalid ItemType of " + salvageItemTypeString);
                 }
             }
@@ -176,13 +165,13 @@ public class SalvageConfig extends ConfigLoader {
         //Report unsupported
         StringBuilder stringBuilder = new StringBuilder();
 
-        if(notSupported.size() > 0) {
+        if (notSupported.size() > 0) {
             stringBuilder.append("mcMMO found the following materials in the Salvage config that are not supported by the version of Minecraft running on this server: ");
 
             for (Iterator<String> iterator = notSupported.iterator(); iterator.hasNext(); ) {
                 String unsupportedMaterial = iterator.next();
 
-                if(!iterator.hasNext()) {
+                if (!iterator.hasNext()) {
                     stringBuilder.append(unsupportedMaterial);
                 } else {
                     stringBuilder.append(unsupportedMaterial).append(", ");
@@ -194,8 +183,8 @@ public class SalvageConfig extends ConfigLoader {
         }
     }
 
-    protected List<Salvageable> getLoadedSalvageables() {
-        return salvageables == null ? new ArrayList<>() : salvageables;
+    protected Collection<Salvageable> getLoadedSalvageables() {
+        return salvageables == null ? new HashSet<>() : salvageables;
     }
 
     private boolean noErrorsInSalvageable(List<String> issues) {

+ 9 - 16
src/main/java/com/gmail/nossr50/config/skills/salvage/SalvageConfigManager.java

@@ -1,9 +1,7 @@
 package com.gmail.nossr50.config.skills.salvage;
 
-import com.gmail.nossr50.datatypes.database.UpgradeType;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.skills.salvage.salvageables.Salvageable;
-import com.gmail.nossr50.util.FixSpellingNetheriteUtil;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -11,18 +9,21 @@ import java.util.List;
 import java.util.regex.Pattern;
 
 public class SalvageConfigManager {
-    private final List<Salvageable> salvageables = new ArrayList<>();
+    public static final String SALVAGE_VANILLA_YML = "salvage.vanilla.yml";
+    private final List<Salvageable> salvageables = new ArrayList<>(); //TODO: Collision checking, make the list a set
+
 
     public SalvageConfigManager(mcMMO plugin) {
         Pattern pattern = Pattern.compile("salvage\\.(?:.+)\\.yml");
         File dataFolder = plugin.getDataFolder();
-        File vanilla = new File(dataFolder, "salvage.vanilla.yml");
 
-        if (!vanilla.exists()) {
-            plugin.saveResource("salvage.vanilla.yml", false);
-        }
+        SalvageConfig mainSalvageConfig = new SalvageConfig(SALVAGE_VANILLA_YML);
+        salvageables.addAll(mainSalvageConfig.getLoadedSalvageables());
 
         for (String fileName : dataFolder.list()) {
+            if(fileName.equals(SALVAGE_VANILLA_YML))
+                continue;
+
             if (!pattern.matcher(fileName).matches()) {
                 continue;
             }
@@ -33,20 +34,12 @@ public class SalvageConfigManager {
                 continue;
             }
 
-
-            if(mcMMO.getUpgradeManager().shouldUpgrade(UpgradeType.FIX_SPELLING_NETHERITE_SALVAGE)) {
-                //Check spelling mistakes (early versions of 1.16 support had Netherite misspelled)
-                plugin.getLogger().info("Checking for certain invalid material names in Salvage config...");
-                FixSpellingNetheriteUtil.processFileCheck(mcMMO.p, fileName, UpgradeType.FIX_SPELLING_NETHERITE_SALVAGE);
-            }
-
-
             SalvageConfig salvageConfig = new SalvageConfig(fileName);
             salvageables.addAll(salvageConfig.getLoadedSalvageables());
         }
     }
 
     public List<Salvageable> getLoadedSalvageables() {
-        return salvageables;
+        return new ArrayList<>(salvageables);
     }
 }

+ 45 - 39
src/main/java/com/gmail/nossr50/config/treasure/FishingTreasureConfig.java

@@ -1,6 +1,6 @@
 package com.gmail.nossr50.config.treasure;
 
-import com.gmail.nossr50.config.ConfigLoader;
+import com.gmail.nossr50.config.BukkitConfig;
 import com.gmail.nossr50.datatypes.treasure.*;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.util.EnchantmentUtils;
@@ -18,14 +18,14 @@ import org.jetbrains.annotations.NotNull;
 
 import java.util.*;
 
-public class FishingTreasureConfig extends ConfigLoader {
+public class FishingTreasureConfig extends BukkitConfig {
 
     public static final String FILENAME = "fishing_treasures.yml";
     private static FishingTreasureConfig instance;
 
-    public @NotNull HashMap<Rarity, List<FishingTreasure>>     fishingRewards      = new HashMap<>();
+    public @NotNull HashMap<Rarity, List<FishingTreasure>> fishingRewards = new HashMap<>();
     public @NotNull HashMap<Rarity, List<EnchantmentTreasure>> fishingEnchantments = new HashMap<>();
-    public @NotNull HashMap<EntityType, List<ShakeTreasure>> shakeMap  = new HashMap<>();
+    public @NotNull HashMap<EntityType, List<ShakeTreasure>> shakeMap = new HashMap<>();
 
     private FishingTreasureConfig() {
         super(FILENAME);
@@ -45,33 +45,39 @@ public class FishingTreasureConfig extends ConfigLoader {
     protected boolean validateKeys() {
         // Validate all the settings!
         List<String> reason = new ArrayList<>();
-        for (String tier : config.getConfigurationSection("Enchantment_Drop_Rates").getKeys(false)) {
-            double totalEnchantDropRate = 0;
-            double totalItemDropRate = 0;
+        ConfigurationSection enchantment_drop_rates = config.getConfigurationSection("Enchantment_Drop_Rates");
 
-            for (Rarity rarity : Rarity.values()) {
-                double enchantDropRate = config.getDouble("Enchantment_Drop_Rates." + tier + "." + rarity.toString());
-                double itemDropRate = config.getDouble("Item_Drop_Rates." + tier + "." + rarity.toString());
+        if(enchantment_drop_rates != null) {
+            for (String tier : enchantment_drop_rates.getKeys(false)) {
+                double totalEnchantDropRate = 0;
+                double totalItemDropRate = 0;
 
-                if ((enchantDropRate < 0.0 || enchantDropRate > 100.0)) {
-                    reason.add("The enchant drop rate for " + tier + " items that are " + rarity.toString() + "should be between 0.0 and 100.0!");
-                }
+                for (Rarity rarity : Rarity.values()) {
+                    double enchantDropRate = config.getDouble("Enchantment_Drop_Rates." + tier + "." + rarity.toString());
+                    double itemDropRate = config.getDouble("Item_Drop_Rates." + tier + "." + rarity);
 
-                if (itemDropRate < 0.0 || itemDropRate > 100.0) {
-                    reason.add("The item drop rate for " + tier + " items that are " + rarity.toString() + "should be between 0.0 and 100.0!");
-                }
+                    if ((enchantDropRate < 0.0 || enchantDropRate > 100.0)) {
+                        reason.add("The enchant drop rate for " + tier + " items that are " + rarity + "should be between 0.0 and 100.0!");
+                    }
 
-                totalEnchantDropRate += enchantDropRate;
-                totalItemDropRate += itemDropRate;
-            }
+                    if (itemDropRate < 0.0 || itemDropRate > 100.0) {
+                        reason.add("The item drop rate for " + tier + " items that are " + rarity + "should be between 0.0 and 100.0!");
+                    }
 
-            if (totalEnchantDropRate < 0 || totalEnchantDropRate > 100.0) {
-                reason.add("The total enchant drop rate for " + tier + " should be between 0.0 and 100.0!");
-            }
+                    totalEnchantDropRate += enchantDropRate;
+                    totalItemDropRate += itemDropRate;
+                }
+
+                if (totalEnchantDropRate < 0 || totalEnchantDropRate > 100.0) {
+                    reason.add("The total enchant drop rate for " + tier + " should be between 0.0 and 100.0!");
+                }
 
-            if (totalItemDropRate < 0 || totalItemDropRate > 100.0) {
-                reason.add("The total item drop rate for " + tier + " should be between 0.0 and 100.0!");
+                if (totalItemDropRate < 0 || totalItemDropRate > 100.0) {
+                    reason.add("The total item drop rate for " + tier + " should be between 0.0 and 100.0!");
+                }
             }
+        } else {
+            mcMMO.p.getLogger().warning("Your fishing treasures config is empty, is this intentional? Delete it to regenerate.");
         }
 
         return noErrorsInConfig(reason);
@@ -89,7 +95,7 @@ public class FishingTreasureConfig extends ConfigLoader {
 
         for (EntityType entity : EntityType.values()) {
             if (entity.isAlive()) {
-                loadTreasures("Shake." + entity.toString());
+                loadTreasures("Shake." + entity);
             }
         }
     }
@@ -175,7 +181,7 @@ public class FishingTreasureConfig extends ConfigLoader {
             if (isFishing) {
                 String rarityStr = config.getString(type + "." + treasureName + ".Rarity");
 
-                if(rarityStr != null) {
+                if (rarityStr != null) {
                     rarity = Rarity.getRarity(rarityStr);
                 } else {
                     mcMMO.p.getLogger().severe("Please edit your config and add a Rarity definition for - " + treasureName);
@@ -192,7 +198,7 @@ public class FishingTreasureConfig extends ConfigLoader {
 
             String customName = null;
 
-            if(hasCustomName(type, treasureName)) {
+            if (hasCustomName(type, treasureName)) {
                 customName = config.getString(type + "." + treasureName + ".Custom_Name");
             }
 
@@ -204,7 +210,7 @@ public class FishingTreasureConfig extends ConfigLoader {
                     item = new ItemStack(mat, amount, data);
                     PotionMeta itemMeta = (PotionMeta) item.getItemMeta();
 
-                    if(itemMeta == null) {
+                    if (itemMeta == null) {
                         mcMMO.p.getLogger().severe("Item meta when adding potion to fishing treasure was null, contact the mcMMO devs!");
                         continue;
                     }
@@ -232,7 +238,7 @@ public class FishingTreasureConfig extends ConfigLoader {
                     }
                     item.setItemMeta(itemMeta);
                 }
-            } else if(material == Material.ENCHANTED_BOOK) {
+            } else if (material == Material.ENCHANTED_BOOK) {
                 //If any whitelisted enchants exist we use whitelist-based matching
                 item = new ItemStack(material, 1);
                 ItemMeta itemMeta = item.getItemMeta();
@@ -276,7 +282,6 @@ public class FishingTreasureConfig extends ConfigLoader {
             }
 
 
-
             if (noErrorsInConfig(reason)) {
                 if (isFishing) {
                     addFishingTreasure(rarity, new FishingTreasure(item, xp));
@@ -307,26 +312,27 @@ public class FishingTreasureConfig extends ConfigLoader {
     /**
      * Matches enchantments on a list (user provided string) to known enchantments in the Spigot API
      * Any matches are added to the passed set
+     *
      * @param enchantListStr the users string list of enchantments
      * @param permissiveList the permissive list of enchantments
      */
     private void matchAndFillSet(@NotNull List<String> enchantListStr, @NotNull Set<Enchantment> permissiveList) {
-        if(enchantListStr.isEmpty()) {
+        if (enchantListStr.isEmpty()) {
             return;
         }
 
-        for(String str : enchantListStr) {
+        for (String str : enchantListStr) {
             boolean foundMatch = false;
-            for(Enchantment enchantment : Enchantment.values()) {
-                if(enchantment.getKey().getKey().equalsIgnoreCase(str)) {
+            for (Enchantment enchantment : Enchantment.values()) {
+                if (enchantment.getKey().getKey().equalsIgnoreCase(str)) {
                     permissiveList.add(enchantment);
                     foundMatch = true;
                     break;
                 }
             }
 
-            if(!foundMatch) {
-                mcMMO.p.getLogger().info("[Fishing Treasure Init] Could not find any enchantments which matched the user defined enchantment named: "+str);
+            if (!foundMatch) {
+                mcMMO.p.getLogger().info("[Fishing Treasure Init] Could not find any enchantments which matched the user defined enchantment named: " + str);
             }
         }
     }
@@ -344,7 +350,7 @@ public class FishingTreasureConfig extends ConfigLoader {
             }
 
             for (String enchantmentName : enchantmentSection.getKeys(false)) {
-                int level = config.getInt("Enchantments_Rarity." + rarity.toString() + "." + enchantmentName);
+                int level = config.getInt("Enchantments_Rarity." + rarity + "." + enchantmentName);
                 Enchantment enchantment = EnchantmentUtils.getByName(enchantmentName);
 
                 if (enchantment == null) {
@@ -374,10 +380,10 @@ public class FishingTreasureConfig extends ConfigLoader {
     }
 
     public double getItemDropRate(int tier, @NotNull Rarity rarity) {
-        return config.getDouble("Item_Drop_Rates.Tier_" + tier + "." + rarity.toString());
+        return config.getDouble("Item_Drop_Rates.Tier_" + tier + "." + rarity);
     }
 
     public double getEnchantmentDropRate(int tier, @NotNull Rarity rarity) {
-        return config.getDouble("Enchantment_Drop_Rates.Tier_" + tier + "." + rarity.toString());
+        return config.getDouble("Enchantment_Drop_Rates.Tier_" + tier + "." + rarity);
     }
 }

+ 22 - 26
src/main/java/com/gmail/nossr50/config/treasure/TreasureConfig.java

@@ -1,6 +1,6 @@
 package com.gmail.nossr50.config.treasure;
 
-import com.gmail.nossr50.config.ConfigLoader;
+import com.gmail.nossr50.config.BukkitConfig;
 import com.gmail.nossr50.datatypes.treasure.ExcavationTreasure;
 import com.gmail.nossr50.datatypes.treasure.HylianTreasure;
 import com.gmail.nossr50.mcMMO;
@@ -20,7 +20,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 
-public class TreasureConfig extends ConfigLoader {
+public class TreasureConfig extends BukkitConfig {
 
     public static final String FILENAME = "treasures.yml";
     public static final String LEVEL_REQUIREMENT_RETRO_MODE = ".Level_Requirement.Retro_Mode";
@@ -32,7 +32,7 @@ public class TreasureConfig extends ConfigLoader {
     private static TreasureConfig instance;
 
     public HashMap<String, List<ExcavationTreasure>> excavationMap = new HashMap<>();
-    public HashMap<String, List<HylianTreasure>>    hylianMap = new HashMap<>();
+    public HashMap<String, List<HylianTreasure>> hylianMap = new HashMap<>();
 
     private TreasureConfig() {
         super(FILENAME);
@@ -115,32 +115,32 @@ public class TreasureConfig extends ConfigLoader {
             DropLevelKeyConversionType conversionType;
 
             //Check for legacy drop level values and convert
-            if(getWrongKeyValue(type, treasureName, DropLevelKeyConversionType.LEGACY) != -1) {
+            if (getWrongKeyValue(type, treasureName, DropLevelKeyConversionType.LEGACY) != -1) {
                 //Legacy Drop level, needs to be converted
                 shouldWeUpdateFile = processAutomaticKeyConversion(type, shouldWeUpdateFile, treasureName, DropLevelKeyConversionType.LEGACY);
             }
 
             //Check for a bad key that was accidentally shipped out to some users
-            if(getWrongKeyValue(type, treasureName, DropLevelKeyConversionType.WRONG_KEY_STANDARD) != -1) {
+            if (getWrongKeyValue(type, treasureName, DropLevelKeyConversionType.WRONG_KEY_STANDARD) != -1) {
                 //Partially converted to the new system, I had a dyslexic moment so some configs have this
                 shouldWeUpdateFile = processAutomaticKeyConversion(type, shouldWeUpdateFile, treasureName, DropLevelKeyConversionType.WRONG_KEY_STANDARD);
             }
 
             //Check for a bad key that was accidentally shipped out to some users
-            if(getWrongKeyValue(type, treasureName, DropLevelKeyConversionType.WRONG_KEY_RETRO) != -1) {
+            if (getWrongKeyValue(type, treasureName, DropLevelKeyConversionType.WRONG_KEY_RETRO) != -1) {
                 //Partially converted to the new system, I had a dyslexic moment so some configs have this
                 shouldWeUpdateFile = processAutomaticKeyConversion(type, shouldWeUpdateFile, treasureName, DropLevelKeyConversionType.WRONG_KEY_RETRO);
             }
 
             int dropLevel = -1;
 
-            if(mcMMO.isRetroModeEnabled()) {
+            if (mcMMO.isRetroModeEnabled()) {
                 dropLevel = config.getInt(type + "." + treasureName + LEVEL_REQUIREMENT_RETRO_MODE, -1);
             } else {
                 dropLevel = config.getInt(type + "." + treasureName + LEVEL_REQUIREMENT_STANDARD_MODE, -1);
             }
 
-            if(dropLevel == -1) {
+            if (dropLevel == -1) {
                 mcMMO.p.getLogger().severe("Could not find a Level_Requirement entry for treasure " + treasureName);
                 mcMMO.p.getLogger().severe("Skipping treasure");
                 continue;
@@ -258,7 +258,7 @@ public class TreasureConfig extends ConfigLoader {
         }
 
         //Apply our fix
-        if(shouldWeUpdateFile) {
+        if (shouldWeUpdateFile) {
             try {
                 config.save(getFile());
             } catch (IOException e) {
@@ -283,7 +283,7 @@ public class TreasureConfig extends ConfigLoader {
                 int wrongKeyValueStandard = getWrongKeyValue(type, treasureName, conversionType);
                 config.set(type + "." + treasureName + WRONG_KEY_ROOT, null); //We also kill the Retro key here as we have enough information for setting in values if needed
 
-                if(wrongKeyValueStandard != -1) {
+                if (wrongKeyValueStandard != -1) {
                     config.set(type + "." + treasureName + LEVEL_REQUIREMENT_STANDARD_MODE, wrongKeyValueStandard);
                     config.set(type + "." + treasureName + LEVEL_REQUIREMENT_RETRO_MODE, wrongKeyValueStandard * 10); //Multiply by 10 for Retro
                 }
@@ -295,7 +295,7 @@ public class TreasureConfig extends ConfigLoader {
                 int wrongKeyValueRetro = getWrongKeyValue(type, treasureName, conversionType);
                 config.set(type + "." + treasureName + WRONG_KEY_ROOT, null); //We also kill the Retro key here as we have enough information for setting in values if needed
 
-                if(wrongKeyValueRetro != -1) {
+                if (wrongKeyValueRetro != -1) {
                     config.set(type + "." + treasureName + LEVEL_REQUIREMENT_RETRO_MODE, wrongKeyValueRetro);
                 }
 
@@ -306,22 +306,12 @@ public class TreasureConfig extends ConfigLoader {
     }
 
     private int getWrongKeyValue(String type, String treasureName, DropLevelKeyConversionType dropLevelKeyConversionType) {
-        switch (dropLevelKeyConversionType) {
-            case LEGACY:
-                return config.getInt(type + "." + treasureName + LEGACY_DROP_LEVEL, -1);
-            case WRONG_KEY_STANDARD:
-                return config.getInt(type + "." + treasureName + WRONG_KEY_VALUE_STANDARD, -1);
-            case WRONG_KEY_RETRO:
-                return config.getInt(type + "." + treasureName + WRONG_KEY_VALUE_RETRO, -1);
-        }
+        return switch (dropLevelKeyConversionType) {
+            case LEGACY -> config.getInt(type + "." + treasureName + LEGACY_DROP_LEVEL, -1);
+            case WRONG_KEY_STANDARD -> config.getInt(type + "." + treasureName + WRONG_KEY_VALUE_STANDARD, -1);
+            case WRONG_KEY_RETRO -> config.getInt(type + "." + treasureName + WRONG_KEY_VALUE_RETRO, -1);
+        };
 
-        return -1;
-    }
-
-    private enum DropLevelKeyConversionType {
-        LEGACY,
-        WRONG_KEY_STANDARD,
-        WRONG_KEY_RETRO
     }
 
     private void AddHylianTreasure(String dropper, HylianTreasure treasure) {
@@ -329,4 +319,10 @@ public class TreasureConfig extends ConfigLoader {
             hylianMap.put(dropper, new ArrayList<>());
         hylianMap.get(dropper).add(treasure);
     }
+
+    private enum DropLevelKeyConversionType {
+        LEGACY,
+        WRONG_KEY_STANDARD,
+        WRONG_KEY_RETRO
+    }
 }

+ 0 - 1
src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java

@@ -120,7 +120,6 @@ public final class FlatFileDatabaseManager implements DatabaseManager {
         BufferedReader in = null;
         FileWriter out = null;
 
-        // This code is O(n) instead of O(n²)
         synchronized (fileWritingLock) {
             try {
                 in = new BufferedReader(new FileReader(usersFilePath));

+ 1 - 1
src/main/java/com/gmail/nossr50/mcMMO.java

@@ -578,7 +578,7 @@ public class mcMMO extends JavaPlugin {
 
         // Load salvage configs, make manager and register them at this time
         SalvageConfigManager sManager = new SalvageConfigManager(this);
-        List<Salvageable> salvageables = new ArrayList<>(sManager.getLoadedSalvageables());
+        List<Salvageable> salvageables = sManager.getLoadedSalvageables();
         salvageableManager = new SimpleSalvageableManager(salvageables.size());
         salvageableManager.registerSalvageables(salvageables);
     }

+ 2 - 2
src/main/java/com/gmail/nossr50/skills/child/ChildConfig.java

@@ -1,6 +1,6 @@
 package com.gmail.nossr50.skills.child;
 
-import com.gmail.nossr50.config.AutoUpdateConfigLoader;
+import com.gmail.nossr50.config.BukkitConfig;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.util.text.StringUtils;
@@ -9,7 +9,7 @@ import org.bukkit.configuration.file.YamlConfiguration;
 import java.util.EnumSet;
 import java.util.Locale;
 
-public class ChildConfig extends AutoUpdateConfigLoader {
+public class ChildConfig extends BukkitConfig {
     public ChildConfig() {
         super("child.yml");
         loadKeys();

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

@@ -33,8 +33,6 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Optional;
-import java.util.stream.Collector;
-import java.util.stream.Collectors;
 
 public class RepairManager extends SkillManager {
     private boolean placedAnvil;

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

@@ -14,7 +14,7 @@ import org.bukkit.entity.Player;
 import java.util.List;
 
 /**
- * A visual representation of a players skill level progress for a PrimarySkillType
+ * A visual representation of a player's skill level progress for a PrimarySkillType
  */
 public class ExperienceBarWrapper {
 

+ 2 - 2
src/main/java/com/gmail/nossr50/util/upgrade/UpgradeManager.java

@@ -1,6 +1,6 @@
 package com.gmail.nossr50.util.upgrade;
 
-import com.gmail.nossr50.config.ConfigLoader;
+import com.gmail.nossr50.config.BukkitConfig;
 import com.gmail.nossr50.datatypes.database.UpgradeType;
 import com.gmail.nossr50.mcMMO;
 
@@ -8,7 +8,7 @@ import java.util.Arrays;
 import java.util.EnumSet;
 import java.util.Set;
 
-public class UpgradeManager extends ConfigLoader {
+public class UpgradeManager extends BukkitConfig {
     private final Set<UpgradeType> setNeededUpgrades;
 
     public UpgradeManager() {

+ 4 - 4
src/main/resources/coreskills.yml

@@ -3,7 +3,7 @@
 
 #Acrobatics
 Acrobatics:
-  # turn this to false to disable all subskills for this skill
-  Enabled: true
-  Roll:
-    Enabled: true
+    # turn this to false to disable all subskills for this skill
+    Enabled: true
+    Roll:
+        Enabled: true

+ 0 - 1
src/main/resources/repair.vanilla.yml

@@ -1,7 +1,6 @@
 #
 #  Repair configuration
 #
-# Any file named repair.*.yml in the mcmmmo folder will be loaded as a repair config
 # All repair configs have a main section titled "Repairables"
 # Afterwards, all sub-items are considered a Repairable to be loaded. The names of each subitem should be the exact material name.
 # The bare minimum of a Repairable is that it have a RepairMaterial and a MaximumDurability

+ 0 - 2
src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java

@@ -3,8 +3,6 @@ package com.gmail.nossr50.util.blockmeta;
 
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.util.BlockUtils;
-import com.gmail.nossr50.util.compat.CompatibilityManager;
-import com.gmail.nossr50.util.platform.PlatformManager;
 import com.google.common.io.Files;
 import org.bukkit.Bukkit;
 import org.bukkit.World;