Procházet zdrojové kódy

Merge branch 'master' of github.com:mcMMO-Dev/mcmmo into configurable

nossr50 před 5 roky
rodič
revize
4b6e2c35b2
24 změnil soubory, kde provedl 186 přidání a 29 odebrání
  1. 13 0
      Changelog.txt
  2. 4 0
      mcmmo-core/src/main/java/com/gmail/nossr50/config/antiexploit/ConfigExploitPrevention.java
  3. 17 0
      mcmmo-core/src/main/java/com/gmail/nossr50/config/antiexploit/ConfigSectionExploitExcavation.java
  4. 7 0
      mcmmo-core/src/main/java/com/gmail/nossr50/config/antiexploit/ConfigSectionExploitSkills.java
  5. 1 0
      mcmmo-core/src/main/java/com/gmail/nossr50/config/sound/ConfigSound.java
  6. 50 2
      mcmmo-core/src/main/java/com/gmail/nossr50/core/MaterialMapStore.java
  7. 5 5
      mcmmo-core/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java
  8. 3 1
      mcmmo-core/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java
  9. 3 1
      mcmmo-core/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java
  10. 41 4
      mcmmo-core/src/main/java/com/gmail/nossr50/listeners/BlockListener.java
  11. 10 0
      mcmmo-core/src/main/java/com/gmail/nossr50/listeners/EntityListener.java
  12. 3 2
      mcmmo-core/src/main/java/com/gmail/nossr50/listeners/InteractionManager.java
  13. 5 3
      mcmmo-core/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java
  14. 2 1
      mcmmo-core/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java
  15. 2 1
      mcmmo-core/src/main/java/com/gmail/nossr50/util/MiscTools.java
  16. 3 1
      mcmmo-core/src/main/java/com/gmail/nossr50/util/StringUtils.java
  17. 3 5
      mcmmo-core/src/main/java/com/gmail/nossr50/util/random/RandomChanceTools.java
  18. 1 1
      mcmmo-core/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java
  19. 2 0
      mcmmo-core/src/main/java/com/gmail/nossr50/util/sounds/SoundManager.java
  20. 1 0
      mcmmo-core/src/main/java/com/gmail/nossr50/util/sounds/SoundType.java
  21. 1 1
      mcmmo-core/src/main/resources/config.yml
  22. 1 0
      mcmmo-core/src/main/resources/experience.yml
  23. 4 1
      mcmmo-core/src/main/resources/fishing_treasures.yml
  24. 4 0
      mcmmo-core/src/main/resources/sounds.yml

+ 13 - 0
Changelog.txt

@@ -201,6 +201,19 @@ Version 2.2.0
     Added API method to check if a skill was being level capped
     Added 'UndefinedSkillBehaviour' for trying to use a method that has no behaviour defined for the provided skill
 
+Version 2.1.114
+    Fix some more locale usages, should aim to further prevent issues with oddball locales
+
+Version 2.1.113
+    Activating Berserk on a soft block (glass, snow, dirts) will break that material right away instead of only breaking subsequent blocks hit by the player
+    Berserk will now break glass and glass pane blocks
+    Hitting glass with berserk readied will activate it
+    Added GLASS settings to sounds.yml for Berserk
+    Fixed bug where BlockCracker didn't work on infested_stone_bricks
+    Fixed a bug where beacons could be duplicated
+    Check player's PTP world permissions before executing a party teleport
+    Improved how mcMMO handles randomness
+
 Version 2.1.112
     Correct locale usage for enum access, now enforces using the english locale to prevent issues with oddball locales for configs/commands
     Fixed a NPE that can occur if a player engages in combat with specific skills before their profile is loaded

+ 4 - 0
mcmmo-core/src/main/java/com/gmail/nossr50/config/antiexploit/ConfigExploitPrevention.java

@@ -119,4 +119,8 @@ public class ConfigExploitPrevention {
     public ConfigSectionExploitTaming getConfigSectionExploitTaming() {
         return configSectionExploitSkills.getConfigSectionExploitTaming();
     }
+
+    public boolean isSnowGolemExploitPrevented() {
+        return configSectionExploitSkills.isSnowGolemExploitPrevented();
+    }
 }

+ 17 - 0
mcmmo-core/src/main/java/com/gmail/nossr50/config/antiexploit/ConfigSectionExploitExcavation.java

@@ -0,0 +1,17 @@
+package com.gmail.nossr50.config.antiexploit;
+
+import ninja.leaping.configurate.objectmapping.Setting;
+import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable;
+
+@ConfigSerializable
+public class ConfigSectionExploitExcavation {
+
+    public static final boolean DEFAULT_SNOW_GOLEM = true;
+    @Setting(value = "Snow-Golem-Exploit", comment = "If set to true, the snow made by snow golems will not reward XP." +
+            "\nDefault value: "+DEFAULT_SNOW_GOLEM)
+    private boolean snowGolemExploit = DEFAULT_SNOW_GOLEM;
+
+    public boolean isSnowGolemExploitPrevented() {
+        return snowGolemExploit;
+    }
+}

+ 7 - 0
mcmmo-core/src/main/java/com/gmail/nossr50/config/antiexploit/ConfigSectionExploitSkills.java

@@ -26,6 +26,9 @@ public class ConfigSectionExploitSkills {
     @Setting(value = "Taming", comment = "Exploit settings related to Taming")
     private ConfigSectionExploitTaming configSectionExploitTaming = new ConfigSectionExploitTaming();
 
+    @Setting(value = "Excavation", comment = "Exploit settings related to Excavation.")
+    private ConfigSectionExploitExcavation configSectionExploitExcavation = new ConfigSectionExploitExcavation();
+
     public ConfigSectionExploitAcrobatics getConfigSectionExploitAcrobatics() {
         return configSectionExploitAcrobatics;
     }
@@ -46,6 +49,10 @@ public class ConfigSectionExploitSkills {
         return configSectionExploitMining.isPreventCobblestoneStoneGeneratorXP();
     }
 
+    public boolean isSnowGolemExploitPrevented() {
+        return configSectionExploitExcavation.isSnowGolemExploitPrevented();
+    }
+
     public boolean areSummonsBreedable() {
         return configSectionExploitTaming.areSummonsBreedable();
     }

+ 1 - 0
mcmmo-core/src/main/java/com/gmail/nossr50/config/sound/ConfigSound.java

@@ -29,6 +29,7 @@ public class ConfigSound {
         SOUND_SETTINGS_MAP_DEFAULT.put(SoundType.ABILITY_ACTIVATED_BERSERK, new SoundSetting(0.5, 1.7));
         SOUND_SETTINGS_MAP_DEFAULT.put(SoundType.TIRED, new SoundSetting(1.0, 1.7));
         SOUND_SETTINGS_MAP_DEFAULT.put(SoundType.BLEED, new SoundSetting(2.0, 2.0));
+        SOUND_SETTINGS_MAP_DEFAULT.put(SoundType.GLASS, new SoundSetting(1.0, 1.0));
     }
 
     @Setting(value = "Sound-Settings", comment = "Adjust sound settings for various mcMMO sounds here." +

+ 50 - 2
mcmmo-core/src/main/java/com/gmail/nossr50/core/MaterialMapStore.java

@@ -3,6 +3,7 @@ package com.gmail.nossr50.core;
 import org.bukkit.Material;
 
 import java.util.HashSet;
+import java.util.Locale;
 
 /**
  * Stores hash tables for item and block names
@@ -21,6 +22,7 @@ public class MaterialMapStore {
     private HashSet<String> canMakeShroomyWhiteList;
     private HashSet<String> multiBlockPlant;
     private HashSet<String> foodItemWhiteList;
+    private HashSet<String> glassBlocks;
 
     public MaterialMapStore() {
         abilityBlackList = new HashSet<>();
@@ -32,6 +34,7 @@ public class MaterialMapStore {
         canMakeShroomyWhiteList = new HashSet<>();
         multiBlockPlant = new HashSet<>();
         foodItemWhiteList = new HashSet<>();
+        glassBlocks = new HashSet<>();
 
         fillHardcodedHashSets();
     }
@@ -79,6 +82,44 @@ public class MaterialMapStore {
         fillShroomyWhiteList();
         fillMultiBlockEntitiesList();
         fillFoodWhiteList();
+        fillGlassBlockWhiteList();
+    }
+
+    private void fillGlassBlockWhiteList() {
+        glassBlocks.add("glass");
+        glassBlocks.add("glass_pane");
+        glassBlocks.add("black_stained_glass");
+        glassBlocks.add("black_stained_glass_pane");
+        glassBlocks.add("blue_stained_glass");
+        glassBlocks.add("blue_stained_glass_pane");
+        glassBlocks.add("brown_stained_glass");
+        glassBlocks.add("brown_stained_glass_pane");
+        glassBlocks.add("cyan_stained_glass");
+        glassBlocks.add("cyan_stained_glass_pane");
+        glassBlocks.add("gray_stained_glass");
+        glassBlocks.add("gray_stained_glass_pane");
+        glassBlocks.add("green_stained_glass");
+        glassBlocks.add("green_stained_glass_pane");
+        glassBlocks.add("light_blue_stained_glass");
+        glassBlocks.add("light_blue_stained_glass_pane");
+        glassBlocks.add("light_gray_stained_glass");
+        glassBlocks.add("light_gray_stained_glass_pane");
+        glassBlocks.add("lime_stained_glass");
+        glassBlocks.add("lime_stained_glass_pane");
+        glassBlocks.add("magenta_stained_glass");
+        glassBlocks.add("magenta_stained_glass_pane");
+        glassBlocks.add("orange_stained_glass");
+        glassBlocks.add("orange_stained_glass_pane");
+        glassBlocks.add("pink_stained_glass");
+        glassBlocks.add("pink_stained_glass_pane");
+        glassBlocks.add("purple_stained_glass");
+        glassBlocks.add("purple_stained_glass_pane");
+        glassBlocks.add("red_stained_glass");
+        glassBlocks.add("red_stained_glass_pane");
+        glassBlocks.add("white_stained_glass");
+        glassBlocks.add("white_stained_glass_pane");
+        glassBlocks.add("yellow_stained_glass");
+        glassBlocks.add("yellow_stained_glass_pane");
     }
 
     private void fillFoodWhiteList() {
@@ -120,6 +161,10 @@ public class MaterialMapStore {
         foodItemWhiteList.add("tropical_fish");
     }
 
+    public boolean isGlass(Material material) {
+        return glassBlocks.contains(material.getKey().getKey());
+    }
+
     public boolean isFood(Material material) {
         return foodItemWhiteList.contains(material.getKey().getKey());
     }
@@ -146,6 +191,8 @@ public class MaterialMapStore {
 
     private void fillBlockCrackerWhiteList() {
         blockCrackerWhiteList.add("stone_bricks");
+        blockCrackerWhiteList.add("infested_stone_bricks");
+
     }
 
     private void fillHerbalismAbilityBlackList() {
@@ -426,7 +473,8 @@ public class MaterialMapStore {
         toolBlackList.add("stonecutter");
     }
 
-    private void addToHashSet(String string, HashSet<String> stringHashSet) {
-        stringHashSet.add(string.toLowerCase());
+    private void addToHashSet(String string, HashSet<String> stringHashSet)
+    {
+        stringHashSet.add(string.toLowerCase(Locale.ENGLISH));
     }
 }

+ 5 - 5
mcmmo-core/src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java

@@ -361,7 +361,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
     public List<PlayerStat> readLeaderboard(PrimarySkillType skill, int pageNumber, int statsPerPage) {
         List<PlayerStat> stats = new ArrayList<>();
 
-        String query = skill == null ? ALL_QUERY_VERSION : skill.name().toLowerCase();
+        String query = skill == null ? ALL_QUERY_VERSION : skill.name().toLowerCase(Locale.ENGLISH);
         ResultSet resultSet = null;
         PreparedStatement statement = null;
         Connection connection = null;
@@ -403,7 +403,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
         try {
             connection = getConnection(PoolIdentifier.MISC);
             for (PrimarySkillType primarySkillType : pluginRef.getSkillTools().NON_CHILD_SKILLS) {
-                String skillName = primarySkillType.name().toLowerCase();
+                String skillName = primarySkillType.name().toLowerCase(Locale.ENGLISH);
                 // Get count of all users with higher skill level than player
                 String sql = "SELECT COUNT(*) AS rank FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id WHERE " + skillName + " > 0 " +
                         "AND " + skillName + " > (SELECT " + skillName + " FROM " + tablePrefix + "users JOIN " + tablePrefix + "skills ON user_id = id " +
@@ -914,7 +914,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
 
                     //Shrink skills above the cap
                     int cap = pluginRef.getPlayerLevelingSettings().getSkillLevelCap(skill);
-                    statement = connection.prepareStatement("UPDATE `" + tablePrefix + "skills` SET `" + skill.name().toLowerCase() + "` = " + cap + " WHERE `" + skill.name().toLowerCase() + "` > " + cap);
+                    statement = connection.prepareStatement("UPDATE `" + tablePrefix + "skills` SET `" + skill.name().toLowerCase(Locale.ENGLISH) + "` = " + cap + " WHERE `" + skill.name().toLowerCase(Locale.ENGLISH) + "` > " + cap);
                     statement.executeUpdate();
                     tryClose(statement);
                 }
@@ -951,7 +951,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
                 break;
         }
         if (connection == null) {
-            throw new RuntimeException("getConnection() for " + identifier.name().toLowerCase() + " pool timed out.  Increase max connections settings.");
+            throw new RuntimeException("getConnection() for " + identifier.name().toLowerCase(Locale.ENGLISH) + " pool timed out.  Increase max connections settings.");
         }
         return connection;
     }
@@ -1249,7 +1249,7 @@ public final class SQLDatabaseManager implements DatabaseManager {
                 pluginRef.getLogger().info("Indexing tables, this may take a while on larger databases");
 
                 for (PrimarySkillType skill : pluginRef.getSkillTools().NON_CHILD_SKILLS) {
-                    String skill_name = skill.name().toLowerCase();
+                    String skill_name = skill.name().toLowerCase(Locale.ENGLISH);
 
                     try {
                         statement.executeUpdate("ALTER TABLE `" + tablePrefix + "skills` ADD INDEX `idx_" + skill_name + "` (`" + skill_name + "`) USING BTREE");

+ 3 - 1
mcmmo-core/src/main/java/com/gmail/nossr50/datatypes/skills/SubSkillType.java

@@ -4,6 +4,8 @@ import com.gmail.nossr50.config.HOCONUtil;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.util.StringUtils;
 
+import java.util.Locale;
+
 public enum SubSkillType {
     /* !! Warning -- Do not let subskills share a name with any existing PrimarySkillType as it will clash with the static import !! */
 
@@ -142,7 +144,7 @@ public enum SubSkillType {
      */
     public String getPermissionNodeAddress(mcMMO pluginRef) {
         //TODO: This could be optimized
-        return "mcmmo.ability." + getParentSkill(pluginRef).toString().toLowerCase() + "." + getConfigName(toString()).toLowerCase();
+        return "mcmmo.ability." + getParentSkill(pluginRef).toString().toLowerCase() + "." + getConfigName(toString()).toLowerCase(Locale.ENGLISH);
     }
 
     /**

+ 3 - 1
mcmmo-core/src/main/java/com/gmail/nossr50/datatypes/skills/subskills/acrobatics/Roll.java

@@ -20,6 +20,8 @@ import org.bukkit.event.EventPriority;
 import org.bukkit.event.entity.EntityDamageEvent;
 import org.bukkit.inventory.ItemStack;
 
+import java.util.Locale;
+
 public class Roll extends AcrobaticsSubSkill {
 
     private final mcMMO pluginRef;
@@ -95,7 +97,7 @@ public class Roll extends AcrobaticsSubSkill {
      */
     @Override
     public String getPermissionNode() {
-        return ("mcmmo.ability." + getPrimaryKeyName() + "." + getConfigKeyName()).toLowerCase();
+        return ("mcmmo.ability." + getPrimaryKeyName() + "." + getConfigKeyName()).toLowerCase(Locale.ENGLISH);
     }
 
     /**

+ 41 - 4
mcmmo-core/src/main/java/com/gmail/nossr50/listeners/BlockListener.java

@@ -160,7 +160,7 @@ public class BlockListener implements Listener {
         if (pluginRef.getDynamicSettingsManager().isWorldBlacklisted(event.getBlock().getWorld().getName()))
             return;
 
-        if (pluginRef.getBlockTools().shouldBeWatched(event.getNewState())) {
+        if (pluginRef.getConfigManager().getConfigExploitPrevention().isSnowGolemExploitPrevented() && pluginRef.getBlockTools().shouldBeWatched(event.getNewState())) {
             pluginRef.getPlaceStore().setTrue(event.getNewState().getBlock());
         }
     }
@@ -481,8 +481,27 @@ public class BlockListener implements Listener {
                 mcMMOPlayer.checkAbilityActivation(PrimarySkillType.MINING);
             } else if (mcMMOPlayer.getToolPreparationMode(ToolType.SHOVEL) && pluginRef.getItemTools().isShovel(heldItem) && pluginRef.getBlockTools().affectedByGigaDrillBreaker(blockState) && pluginRef.getPermissionTools().gigaDrillBreaker(player)) {
                 mcMMOPlayer.checkAbilityActivation(PrimarySkillType.EXCAVATION);
-            } else if (mcMMOPlayer.getToolPreparationMode(ToolType.FISTS) && heldItem.getType() == Material.AIR && (pluginRef.getBlockTools().affectedByGigaDrillBreaker(blockState) || blockState.getType() == Material.SNOW || pluginRef.getBlockTools().affectedByBlockCracker(blockState) && pluginRef.getPermissionTools().berserk(player))) {
+            } else if (mcMMOPlayer.getToolPreparationMode(ToolType.FISTS)
+                    && heldItem.getType() == Material.AIR
+                    && ((pluginRef.getBlockTools().affectedByGigaDrillBreaker(blockState)
+                        || blockState.getType() == Material.SNOW
+                        || pluginRef.getBlockTools().affectedByBlockCracker(blockState)
+                        || pluginRef.getMaterialMapStore().isGlass(blockState.getType()))
+                    && pluginRef.getPermissionTools().berserk(player))) {
                 mcMMOPlayer.checkAbilityActivation(PrimarySkillType.UNARMED);
+
+                if(mcMMOPlayer.getSuperAbilityMode(SuperAbilityType.BERSERK)) {
+                    if (pluginRef.getSkillTools().superAbilityBlockCheck(SuperAbilityType.BERSERK, blockState)
+                            && pluginRef.getEventManager().simulateBlockBreak(blockState.getBlock(), player, true)) {
+                        event.setInstaBreak(true);
+
+                        if(blockState.getType().getKey().getKey().contains("glass")) {
+                            pluginRef.getSoundManager().worldSendSound(player.getWorld(), blockState.getLocation(), SoundType.GLASS);
+                        } else {
+                            pluginRef.getSoundManager().sendSound(player, blockState.getLocation(), SoundType.POP);
+                        }
+                    }
+                }
             }
         }
 
@@ -556,12 +575,30 @@ public class BlockListener implements Listener {
                     && pluginRef.getEventManager().simulateBlockBreak(block, player, true)) {
                 event.setInstaBreak(true);
                 pluginRef.getSoundManager().sendSound(player, block.getLocation(), SoundType.POP);
-            } else if (mcMMOPlayer.getUnarmedManager().canUseBlockCracker() && pluginRef.getBlockTools().affectedByBlockCracker(blockState) && pluginRef.getEventManager().simulateBlockBreak(block, player, true)) {
+            } else if (mcMMOPlayer.getUnarmedManager().canUseBlockCracker()
+                    && pluginRef.getBlockTools().affectedByBlockCracker(blockState)
+                    && pluginRef.getEventManager().simulateBlockBreak(block, player, true)) {
                 if (mcMMOPlayer.getUnarmedManager().blockCrackerCheck(blockState)) {
                     blockState.update();
                 }
             }
-        } else if (mcMMOPlayer.getWoodcuttingManager().canUseLeafBlower(heldItem) && pluginRef.getBlockTools().isLeaves(blockState) && pluginRef.getEventManager().simulateBlockBreak(block, player, true)) {
+            //Only run if insta-break isn't on, this is because we turn it on in another event of this same type but different priority under certain conditions
+            else if (!event.getInstaBreak()
+                    && pluginRef.getBlockTools().canActivateAbilities(blockState)
+                    && pluginRef.getEventManager().simulateBlockBreak(block, player, true)) {
+                event.setInstaBreak(true);
+
+                //Break Glass
+                if(blockState.getType().getKey().getKey().contains("glass")) {
+                    pluginRef.getSoundManager().worldSendSound(player.getWorld(), block.getLocation(), SoundType.GLASS);
+                } else {
+                    pluginRef.getSoundManager().sendSound(player, block.getLocation(), SoundType.POP);
+                }
+            }
+        }
+        else if (mcMMOPlayer.getWoodcuttingManager().canUseLeafBlower(heldItem)
+                && pluginRef.getBlockTools().isLeaves(blockState)
+                && pluginRef.getEventManager().simulateBlockBreak(block, player, true)) {
             event.setInstaBreak(true);
             pluginRef.getSoundManager().sendSound(player, block.getLocation(), SoundType.POP);
         }

+ 10 - 0
mcmmo-core/src/main/java/com/gmail/nossr50/listeners/EntityListener.java

@@ -59,9 +59,16 @@ public class EntityListener implements Listener {
         }
 
         //Prevent entities from giving XP if they target endermite
+<<<<<<< HEAD:mcmmo-core/src/main/java/com/gmail/nossr50/listeners/EntityListener.java
         if (event.getTarget() instanceof Endermite) {
             if (event.getEntity().hasMetadata(MetadataConstants.UNNATURAL_MOB_METAKEY))
                 event.getEntity().setMetadata(MetadataConstants.UNNATURAL_MOB_METAKEY, MetadataConstants.metadataValue);
+=======
+        if(event.getTarget() instanceof Endermite)
+        {
+            if(!event.getEntity().hasMetadata(mcMMO.entityMetadataKey))
+                event.getEntity().setMetadata(mcMMO.entityMetadataKey, mcMMO.metadataValue);
+>>>>>>> 550a3df6169b457fdea552b58861bb42c53420c2:src/main/java/com/gmail/nossr50/listeners/EntityListener.java
         }
     }
 
@@ -794,6 +801,7 @@ public class EntityListener implements Listener {
     }
 
     /**
+<<<<<<< HEAD:mcmmo-core/src/main/java/com/gmail/nossr50/listeners/EntityListener.java
      * Handle EntityExplode events that involve modifying the event.
      *
      * @param event The event to modify
@@ -814,6 +822,8 @@ public class EntityListener implements Listener {
     }
 
     /**
+=======
+>>>>>>> 550a3df6169b457fdea552b58861bb42c53420c2:src/main/java/com/gmail/nossr50/listeners/EntityListener.java
      * Handle FoodLevelChange events that involve modifying the event.
      *
      * @param event The event to modify

+ 3 - 2
mcmmo-core/src/main/java/com/gmail/nossr50/listeners/InteractionManager.java

@@ -9,6 +9,7 @@ import org.bukkit.event.Event;
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Locale;
 
 public class InteractionManager {
     private static HashMap<InteractType, ArrayList<Interaction>> interactRegister;
@@ -46,7 +47,7 @@ public class InteractionManager {
         //Register skill
         arrayRef.add(abstractSubSkill);
 
-        String lowerCaseName = abstractSubSkill.getConfigKeyName().toLowerCase();
+        String lowerCaseName = abstractSubSkill.getConfigKeyName().toLowerCase(Locale.ENGLISH);
 
         //Register in name map
         subSkillNameMap.putIfAbsent(lowerCaseName, abstractSubSkill);
@@ -62,7 +63,7 @@ public class InteractionManager {
      * @return null if the subskill is not registered
      */
     public static AbstractSubSkill getAbstractByName(String name) {
-        return subSkillNameMap.get(name.toLowerCase());
+        return subSkillNameMap.get(name.toLowerCase(Locale.ENGLISH));
     }
 
     /**

+ 5 - 3
mcmmo-core/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java

@@ -34,6 +34,8 @@ import org.bukkit.event.player.*;
 import org.bukkit.inventory.EquipmentSlot;
 import org.bukkit.inventory.ItemStack;
 
+import java.util.Locale;
+
 public class PlayerListener implements Listener {
     private final mcMMO pluginRef;
 
@@ -880,12 +882,12 @@ public class PlayerListener implements Listener {
         if (!pluginRef.getConfigManager().getConfigLanguage().getTargetLanguage().equalsIgnoreCase("en_US")) {
             String message = event.getMessage();
             String command = message.substring(1).split(" ")[0];
-            String lowerCaseCommand = command.toLowerCase();
+            String lowerCaseCommand = command.toLowerCase(Locale.ENGLISH);
 
             // Do these ACTUALLY have to be lower case to work properly?
             for (PrimarySkillType primarySkillType : PrimarySkillType.values()) {
-                String skillName = primarySkillType.toString().toLowerCase();
-                String localizedName = pluginRef.getSkillTools().getLocalizedSkillName(primarySkillType).toLowerCase();
+                String skillName = primarySkillType.toString().toLowerCase(Locale.ENGLISH);
+                String localizedName = pluginRef.getSkillTools().getLocalizedSkillName(primarySkillType).toLowerCase(Locale.ENGLISH);
 
                 if (command.equalsIgnoreCase(localizedName)) {
                     event.setMessage(message.replace(command, skillName));

+ 2 - 1
mcmmo-core/src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java

@@ -155,7 +155,8 @@ public class MiningManager extends SkillManager {
 
             if (pluginRef.getBlockTools().isOre(blockState)) {
                 ores.add(blockState);
-            } else {
+            //A bug where beacons can drop when yield is set to 0 on explosion events is prevented here
+            } else if(blockState.getType() != Material.BEACON) {
                 debris.add(blockState);
             }
         }

+ 2 - 1
mcmmo-core/src/main/java/com/gmail/nossr50/util/MiscTools.java

@@ -12,6 +12,7 @@ import org.bukkit.inventory.ItemStack;
 import org.bukkit.util.Vector;
 
 import java.util.Collection;
+import java.util.Locale;
 import java.util.Random;
 import java.util.Set;
 
@@ -208,7 +209,7 @@ public final class MiscTools {
         String[] materialSplit = materialName.split("_");
 
         if (materialSplit.length > 1) {
-            return materialSplit[0].toLowerCase();
+            return materialSplit[0].toLowerCase(Locale.ENGLISH);
         }
 
         return "UnknownMods";

+ 3 - 1
mcmmo-core/src/main/java/com/gmail/nossr50/util/StringUtils.java

@@ -7,6 +7,8 @@ import org.bukkit.block.data.Ageable;
 import org.bukkit.block.data.BlockData;
 import org.bukkit.entity.EntityType;
 
+import java.util.Locale;
+
 public class StringUtils {
 
     /**
@@ -16,7 +18,7 @@ public class StringUtils {
      * @return the capitalized string
      */
     public static String getCapitalized(String target) {
-        return target.substring(0, 1).toUpperCase() + target.substring(1).toLowerCase();
+        return target.substring(0, 1).toUpperCase() + target.substring(1).toLowerCase(Locale.ENGLISH);
     }
 
     /**

+ 3 - 5
mcmmo-core/src/main/java/com/gmail/nossr50/util/random/RandomChanceTools.java

@@ -10,7 +10,7 @@ import com.gmail.nossr50.util.skills.SkillActivationType;
 import org.bukkit.entity.Player;
 
 import java.text.DecimalFormat;
-import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
 
 public class RandomChanceTools {
     
@@ -79,10 +79,8 @@ public class RandomChanceTools {
         return rollDice(chance, 10000);
     }
 
-    public boolean rollDice(double chanceOfSuccess, int bound) {
-        Random random = new Random();
-
-        return chanceOfSuccess > random.nextInt(bound);
+    public static boolean rollDice(double chanceOfSuccess, int bound) {
+        return chanceOfSuccess > ThreadLocalRandom.current().nextInt(bound);
     }
 
     /**

+ 1 - 1
mcmmo-core/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java

@@ -163,7 +163,7 @@ public class ScoreboardWrapper {
         revertTask = new ScoreboardChangeTask().runTaskLater(pluginRef, ticks);
 
         // TODO is there any way to do the time that looks acceptable?
-        // player.sendMessage(pluginRef.getLocaleManager().getString("Commands.ConfigScoreboard.Timer", StringUtils.capitalize(sidebarType.toString().toLowerCase()), ticks / 20F));
+        // player.sendMessage(LocaleLoader.getString("Commands.Scoreboard.Timer", StringUtils.capitalize(sidebarType.toString().toLowerCase(Locale.ENGLISH)), ticks / 20F));
 
         if (pluginRef.getUserManager().getPlayer(playerName) == null)
             return;

+ 2 - 0
mcmmo-core/src/main/java/com/gmail/nossr50/util/sounds/SoundManager.java

@@ -93,6 +93,8 @@ public class SoundManager {
             case DEFLECT_ARROWS:
             case BLEED:
                 return Sound.ENTITY_ENDER_EYE_DEATH;
+            case GLASS:
+                return Sound.BLOCK_GLASS_BREAK;
             default:
                 return null;
         }

+ 1 - 0
mcmmo-core/src/main/java/com/gmail/nossr50/util/sounds/SoundType.java

@@ -14,6 +14,7 @@ public enum SoundType {
     ABILITY_ACTIVATED_GENERIC,
     ABILITY_ACTIVATED_BERSERK,
     BLEED,
+    GLASS,
     TIRED;
 
     public boolean usesCustomPitch() {

+ 1 - 1
mcmmo-core/src/main/resources/config.yml

@@ -436,7 +436,7 @@ Bonus_Drops:
         Melon_Slice: true
         Nether_Wart: true
         Potatoes: true
-        Potatoe: true
+        Potato: true
         Pumpkin: true
         Red_Mushroom: true
         Sugar_Cane: true

+ 1 - 0
mcmmo-core/src/main/resources/experience.yml

@@ -33,6 +33,7 @@ ExploitFix:
     LavaStoneAndCobbleFarming: true
     TreeFellerReducedXP: true
     PistonCheating: true
+    SnowGolemExcavation: true
 Experience_Bars:
     # Turn this to false if you wanna disable XP bars
     Enable: true

+ 4 - 1
mcmmo-core/src/main/resources/fishing_treasures.yml

@@ -561,6 +561,7 @@ Enchantment_Drop_Rates:
         LEGENDARY: 0.75
 #
 #  Settings for Excavation's Archaeology
+#  If you are in retro mode, Drop_Level is multiplied by 10.
 ###
 Excavation:
     CAKE:
@@ -691,6 +692,7 @@ Excavation:
         Drops_From: [Dirt, Coarse_Dirt, Podzol, Grass_Block, Sand, Red_Sand, Gravel, Clay, Mycelium, Soul_Sand]
 #
 #  Settings for Hylian Luck
+#  If you are in retro mode, Drop_Level is multiplied by 10.
 ###
 Hylian_Luck:
     MELON_SEEDS:
@@ -748,7 +750,8 @@ Hylian_Luck:
         Drop_Level: 0
         Drops_From: [Pots]
 #
-#	Settings for Shake
+#  Settings for Shake
+#  If you are in retro mode, Drop_Level is multiplied by 10.
 ###
 Shake:
     BLAZE:

+ 4 - 0
mcmmo-core/src/main/resources/sounds.yml

@@ -4,6 +4,10 @@ Sounds:
     # 1.0 = Max volume
     # 0.0 = No Volume
     MasterVolume: 1.0
+    GLASS:
+        Enable: true
+        Volume: 1.0
+        Pitch: 1.0
     ANVIL:
         Enable: true
         Volume: 1.0