Browse Source

Add some tests for com.gmail.nossr50.util.random classes

nossr50 4 years ago
parent
commit
7931a095fe
27 changed files with 195 additions and 87 deletions
  1. 2 0
      Changelog.txt
  2. 1 1
      src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java
  3. 1 1
      src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java
  4. 1 1
      src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java
  5. 1 1
      src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java
  6. 2 2
      src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java
  7. 1 1
      src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreCommand.java
  8. 3 3
      src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java
  9. 1 1
      src/main/java/com/gmail/nossr50/commands/skills/SkillGuideCommand.java
  10. 0 1
      src/main/java/com/gmail/nossr50/config/treasure/TreasureConfig.java
  11. 1 1
      src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java
  12. 3 4
      src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java
  13. 5 1
      src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java
  14. 1 1
      src/main/java/com/gmail/nossr50/listeners/PlayerListener.java
  15. 0 4
      src/main/java/com/gmail/nossr50/listeners/WorldListener.java
  16. 1 1
      src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java
  17. 2 2
      src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java
  18. 0 1
      src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java
  19. 1 1
      src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java
  20. 1 1
      src/main/java/com/gmail/nossr50/util/experience/ExperienceBarManager.java
  21. 17 40
      src/main/java/com/gmail/nossr50/util/random/RandomChanceSkill.java
  22. 13 5
      src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java
  23. 2 2
      src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java
  24. 0 1
      src/main/java/com/gmail/nossr50/util/skills/PerksUtils.java
  25. 17 0
      src/test/java/com/gmail/nossr50/TestUtil.java
  26. 2 10
      src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java
  27. 116 0
      src/test/java/com/gmail/nossr50/util/random/RandomChanceTest.java

+ 2 - 0
Changelog.txt

@@ -1,6 +1,8 @@
 Version 2.1.168
     Fixed an IndexOutOfBoundsException error when trying to access UserBlockTracker from an invalid range (thanks t00thpick1)
     (API) UserBlockTracker is now the interface by which our block-tracker will be known (thanks t00thpick1)
+    Optimized memory access for Acrobatics fall anti-exploit mechanics (thanks t00thpick1)
+
 
 Version 2.1.167
     Fixed a serious dupe bug

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java

@@ -46,6 +46,6 @@ public class AddlevelsCommand extends ExperienceCommand {
         if(isSilent)
             return;
 
-        player.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.1", value, skill.getName()));
+        player.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.1", value, skill.getLocalizedName()));
     }
 }

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java

@@ -49,6 +49,6 @@ public class AddxpCommand extends ExperienceCommand {
         if(isSilent)
             return;
 
-        player.sendMessage(LocaleLoader.getString("Commands.addxp.AwardSkill", value, skill.getName()));
+        player.sendMessage(LocaleLoader.getString("Commands.addxp.AwardSkill", value, skill.getLocalizedName()));
     }
 }

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java

@@ -159,7 +159,7 @@ public abstract class ExperienceCommand implements TabExecutor {
             sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardAll.2", playerName));
         }
         else {
-            sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", skill.getName(), playerName));
+            sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", skill.getLocalizedName(), playerName));
         }
     }
 

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java

@@ -52,6 +52,6 @@ public class MmoeditCommand extends ExperienceCommand {
         if(isSilent)
             return;
 
-        player.sendMessage(LocaleLoader.getString("Commands.mmoedit.Modified.1", skill.getName(), value));
+        player.sendMessage(LocaleLoader.getString("Commands.mmoedit.Modified.1", skill.getLocalizedName(), value));
     }
 }

+ 2 - 2
src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java

@@ -143,7 +143,7 @@ public class SkillresetCommand implements TabExecutor {
     }
 
     protected void handlePlayerMessageSkill(Player player, PrimarySkillType skill) {
-        player.sendMessage(LocaleLoader.getString("Commands.Reset.Single", skill.getName()));
+        player.sendMessage(LocaleLoader.getString("Commands.Reset.Single", skill.getLocalizedName()));
     }
 
     private boolean validateArguments(CommandSender sender, String skillName) {
@@ -155,7 +155,7 @@ public class SkillresetCommand implements TabExecutor {
             sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardAll.2", playerName));
         }
         else {
-            sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", skill.getName(), playerName));
+            sender.sendMessage(LocaleLoader.getString("Commands.addlevels.AwardSkill.2", skill.getLocalizedName(), playerName));
         }
     }
 

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreCommand.java

@@ -59,6 +59,6 @@ public class HardcoreCommand extends HardcoreModeCommand {
             skill.setHardcoreStatLossEnabled(enable);
         }
 
-        mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Hardcore.Mode." + (enable ? "Enabled" : "Disabled"), LocaleLoader.getString("Hardcore.DeathStatLoss.Name"), (skill == null ? "all skills" : skill.getName())));
+        mcMMO.p.getServer().broadcastMessage(LocaleLoader.getString("Hardcore.Mode." + (enable ? "Enabled" : "Disabled"), LocaleLoader.getString("Hardcore.DeathStatLoss.Name"), (skill == null ? "all skills" : skill.getLocalizedName())));
     }
 }

+ 3 - 3
src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java

@@ -45,7 +45,7 @@ public abstract class SkillCommand implements TabExecutor {
 
     public SkillCommand(PrimarySkillType skill) {
         this.skill = skill;
-        skillName = skill.getName();
+        skillName = skill.getLocalizedName();
         skillGuideCommand = new SkillGuideCommand(skill);
     }
 
@@ -173,10 +173,10 @@ public abstract class SkillCommand implements TabExecutor {
             {
                 if(i+1 < parentList.size())
                 {
-                    parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", parentList.get(i).getName(), mcMMOPlayer.getSkillLevel(parentList.get(i))));
+                    parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", parentList.get(i).getLocalizedName(), mcMMOPlayer.getSkillLevel(parentList.get(i))));
                     parentMessage.append(ChatColor.GRAY).append(", ");
                 } else {
-                    parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", parentList.get(i).getName(), mcMMOPlayer.getSkillLevel(parentList.get(i))));
+                    parentMessage.append(LocaleLoader.getString("Effects.Child.ParentList", parentList.get(i).getLocalizedName(), mcMMOPlayer.getSkillLevel(parentList.get(i))));
                 }
             }
 

+ 1 - 1
src/main/java/com/gmail/nossr50/commands/skills/SkillGuideCommand.java

@@ -18,7 +18,7 @@ public class SkillGuideCommand implements CommandExecutor {
     private final String invalidPage = LocaleLoader.getString("Guides.Page.Invalid");
 
     public SkillGuideCommand(PrimarySkillType skill) {
-        header = LocaleLoader.getString("Guides.Header", skill.getName());
+        header = LocaleLoader.getString("Guides.Header", skill.getLocalizedName());
         guide = getGuide(skill);
     }
 

+ 0 - 1
src/main/java/com/gmail/nossr50/config/treasure/TreasureConfig.java

@@ -8,7 +8,6 @@ import org.bukkit.ChatColor;
 import org.bukkit.Material;
 import org.bukkit.Tag;
 import org.bukkit.configuration.ConfigurationSection;
-import org.bukkit.entity.EntityType;
 import org.bukkit.inventory.ItemStack;
 import org.bukkit.inventory.meta.ItemMeta;
 import org.bukkit.inventory.meta.PotionMeta;

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

@@ -919,7 +919,7 @@ public final class FlatfileDatabaseManager implements DatabaseManager {
                                 }
                                 int cap = Config.getInstance().getLevelCap(skill);
                                 if (Integer.parseInt(character[index]) > cap) {
-                                    mcMMO.p.getLogger().warning("Truncating " + skill.getName() + " to configured max level for player " + character[USERNAME]);
+                                    mcMMO.p.getLogger().warning("Truncating " + skill.getLocalizedName() + " to configured max level for player " + character[USERNAME]);
                                     character[index] = cap + "";
                                     updated = true;
                                 }

+ 3 - 4
src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java

@@ -57,7 +57,6 @@ import com.gmail.nossr50.util.sounds.SoundManager;
 import com.gmail.nossr50.util.sounds.SoundType;
 import net.kyori.adventure.identity.Identified;
 import net.kyori.adventure.identity.Identity;
-import org.apache.commons.lang.Validate;
 import org.bukkit.Bukkit;
 import org.bukkit.GameMode;
 import org.bukkit.Location;
@@ -193,7 +192,7 @@ public class McMMOPlayer implements Identified {
         if(hasReachedPowerLevelCap()) {
             NotificationManager.sendPlayerInformationChatOnly(player, "LevelCap.PowerLevel", String.valueOf(Config.getInstance().getPowerLevelCap()));
         } else if(hasReachedLevelCap(primarySkillType)) {
-            NotificationManager.sendPlayerInformationChatOnly(player, "LevelCap.Skill", String.valueOf(Config.getInstance().getLevelCap(primarySkillType)), primarySkillType.getName());
+            NotificationManager.sendPlayerInformationChatOnly(player, "LevelCap.Skill", String.valueOf(Config.getInstance().getLevelCap(primarySkillType)), primarySkillType.getLocalizedName());
         }
 
         //Updates from Party sources
@@ -828,7 +827,7 @@ public class McMMOPlayer implements Identified {
             int diff = RankUtils.getSuperAbilityUnlockRequirement(skill.getAbility()) - getSkillLevel(skill);
 
             //Inform the player they are not yet skilled enough
-            NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_COOLDOWN, "Skills.AbilityGateRequirementFail", String.valueOf(diff), skill.getName());
+            NotificationManager.sendPlayerInformation(player, NotificationType.ABILITY_COOLDOWN, "Skills.AbilityGateRequirementFail", String.valueOf(diff), skill.getLocalizedName());
             return;
         }
 
@@ -984,7 +983,7 @@ public class McMMOPlayer implements Identified {
         String allCDStr = aSuperAbilityCD + ", " + bSuperAbilityCD;
 
         NotificationManager.sendPlayerInformation(player, NotificationType.TOOL, "Skills.TooTired.Extra",
-                primarySkillType.getName(),
+                primarySkillType.getLocalizedName(),
                 allCDStr);
     }
 

+ 5 - 1
src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java

@@ -234,10 +234,14 @@ public enum PrimarySkillType {
         return null;
     }
 
-    public String getName() {
+    public String getLocalizedName() {
         return StringUtils.getCapitalized(LocaleLoader.getString(StringUtils.getCapitalized(this.toString()) + ".SkillName"));
     }
 
+    public String getName() {
+        return StringUtils.getCapitalized(StringUtils.getCapitalized(this.toString()));
+    }
+
     public boolean getPermissions(Player player) {
         return Permissions.skillEnabled(player, this);
     }

+ 1 - 1
src/main/java/com/gmail/nossr50/listeners/PlayerListener.java

@@ -937,7 +937,7 @@ public class PlayerListener implements Listener {
             // Do these ACTUALLY have to be lower case to work properly?
             for (PrimarySkillType skill : PrimarySkillType.values()) {
                 String skillName = skill.toString().toLowerCase(Locale.ENGLISH);
-                String localizedName = skill.getName().toLowerCase(Locale.ENGLISH);
+                String localizedName = skill.getLocalizedName().toLowerCase(Locale.ENGLISH);
 
                 if (lowerCaseCommand.equals(localizedName)) {
                     event.setMessage(message.replace(command, skillName));

+ 0 - 4
src/main/java/com/gmail/nossr50/listeners/WorldListener.java

@@ -3,18 +3,14 @@ package com.gmail.nossr50.listeners;
 import com.gmail.nossr50.config.WorldBlacklist;
 import com.gmail.nossr50.mcMMO;
 import org.bukkit.Chunk;
-import org.bukkit.World;
 import org.bukkit.block.BlockState;
 import org.bukkit.event.EventHandler;
 import org.bukkit.event.EventPriority;
 import org.bukkit.event.Listener;
 import org.bukkit.event.world.ChunkUnloadEvent;
 import org.bukkit.event.world.StructureGrowEvent;
-import org.bukkit.event.world.WorldInitEvent;
 import org.bukkit.event.world.WorldUnloadEvent;
 
-import java.io.File;
-
 public class WorldListener implements Listener {
     private final mcMMO plugin;
 

+ 1 - 1
src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java

@@ -53,7 +53,7 @@ public class McrankCommandDisplayTask extends BukkitRunnable {
 //            }
 
             rank = skills.get(skill);
-            sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Skill", skill.getName(), (rank == null ? LocaleLoader.getString("Commands.mcrank.Unranked") : rank)));
+            sender.sendMessage(LocaleLoader.getString("Commands.mcrank.Skill", skill.getLocalizedName(), (rank == null ? LocaleLoader.getString("Commands.mcrank.Unranked") : rank)));
         }
 
         rank = skills.get(null);

+ 2 - 2
src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java

@@ -61,10 +61,10 @@ public class MctopCommandDisplayTask extends BukkitRunnable {
         }
         else {
             if(sender instanceof Player) {
-                sender.sendMessage(LocaleLoader.getString("Commands.Skill.Leaderboard", skill.getName()));
+                sender.sendMessage(LocaleLoader.getString("Commands.Skill.Leaderboard", skill.getLocalizedName()));
             }
             else {
-                sender.sendMessage(ChatColor.stripColor(LocaleLoader.getString("Commands.Skill.Leaderboard", skill.getName())));
+                sender.sendMessage(ChatColor.stripColor(LocaleLoader.getString("Commands.Skill.Leaderboard", skill.getLocalizedName())));
             }
         }
 

+ 0 - 1
src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java

@@ -740,7 +740,6 @@ public class HerbalismManager extends SkillManager {
             return false;
         }
 
-
         if (!playerInventory.containsAtLeast(seedStack, 1)) {
             return false;
         }

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

@@ -37,7 +37,7 @@ public final class CommandRegistrationManager {
     private static void registerSkillCommands() {
         for (PrimarySkillType skill : PrimarySkillType.values()) {
             String commandName = skill.toString().toLowerCase(Locale.ENGLISH);
-            String localizedName = skill.getName().toLowerCase(Locale.ENGLISH);
+            String localizedName = skill.getLocalizedName().toLowerCase(Locale.ENGLISH);
 
             PluginCommand command;
 

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

@@ -149,7 +149,7 @@ public class ExperienceBarManager {
     private void informPlayer(@NotNull ExperienceBarManager.@NotNull XPBarSettingTarget settingTarget, @Nullable PrimarySkillType skillType) {
         //Inform player of setting change
         if(settingTarget != XPBarSettingTarget.RESET) {
-            NotificationManager.sendPlayerInformationChatOnlyPrefixed(mcMMOPlayer.getPlayer(), "Commands.XPBar.SettingChanged", skillType.getName(), settingTarget.toString());
+            NotificationManager.sendPlayerInformationChatOnlyPrefixed(mcMMOPlayer.getPlayer(), "Commands.XPBar.SettingChanged", skillType.getLocalizedName(), settingTarget.toString());
         } else {
             NotificationManager.sendPlayerInformationChatOnlyPrefixed(mcMMOPlayer.getPlayer(), "Commands.XPBar.Reset");
         }

+ 17 - 40
src/main/java/com/gmail/nossr50/util/random/RandomChanceSkill.java

@@ -1,8 +1,6 @@
 package com.gmail.nossr50.util.random;
 
-import com.gmail.nossr50.config.AdvancedConfig;
 import com.gmail.nossr50.datatypes.player.McMMOPlayer;
-import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.SubSkillType;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.player.UserManager;
@@ -11,109 +9,92 @@ import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 public class RandomChanceSkill implements RandomChanceExecution {
-
-    protected final @NotNull PrimarySkillType primarySkillType;
-    protected final @NotNull SubSkillType subSkillType;
     protected final double probabilityCap;
     protected final boolean isLucky;
     protected int skillLevel;
-    protected double resultModifier;
+    protected final double resultModifier;
+    protected final double maximumBonusLevelCap;
 
     public RandomChanceSkill(@Nullable Player player, @NotNull SubSkillType subSkillType, double resultModifier) {
-        this.primarySkillType = subSkillType.getParentSkill();
-        this.subSkillType = subSkillType;
         this.probabilityCap = RandomChanceUtil.LINEAR_CURVE_VAR;
 
         final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
         if (player != null && mcMMOPlayer != null) {
-            this.skillLevel = mcMMOPlayer.getSkillLevel(primarySkillType);
+            this.skillLevel = mcMMOPlayer.getSkillLevel(subSkillType.getParentSkill());
         } else {
             this.skillLevel = 0;
         }
 
         if (player != null)
-            isLucky = Permissions.lucky(player, primarySkillType);
+            isLucky = Permissions.lucky(player, subSkillType.getParentSkill());
         else
             isLucky = false;
 
         this.resultModifier = resultModifier;
+        this.maximumBonusLevelCap = RandomChanceUtil.getMaxBonusLevelCap(subSkillType);
     }
 
     public RandomChanceSkill(@Nullable Player player, @NotNull SubSkillType subSkillType) {
-        this.primarySkillType = subSkillType.getParentSkill();
-        this.subSkillType = subSkillType;
         this.probabilityCap = RandomChanceUtil.LINEAR_CURVE_VAR;
 
         final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
         if (player != null && mcMMOPlayer != null) {
-            this.skillLevel = mcMMOPlayer.getSkillLevel(primarySkillType);
+            this.skillLevel = mcMMOPlayer.getSkillLevel(subSkillType.getParentSkill());
         } else {
             this.skillLevel = 0;
         }
 
         if (player != null)
-            isLucky = Permissions.lucky(player, primarySkillType);
+            isLucky = Permissions.lucky(player, subSkillType.getParentSkill());
         else
             isLucky = false;
 
         this.resultModifier = 1.0D;
+        this.maximumBonusLevelCap = RandomChanceUtil.getMaxBonusLevelCap(subSkillType);
     }
 
     public RandomChanceSkill(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean hasCap) {
         if (hasCap)
-            this.probabilityCap = AdvancedConfig.getInstance().getMaximumProbability(subSkillType);
+            this.probabilityCap = RandomChanceUtil.getMaximumProbability(subSkillType);
         else
             this.probabilityCap = RandomChanceUtil.LINEAR_CURVE_VAR;
 
-        this.primarySkillType = subSkillType.getParentSkill();
-        this.subSkillType = subSkillType;
-
         final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
         if (player != null && mcMMOPlayer != null) {
-            this.skillLevel = mcMMOPlayer.getSkillLevel(primarySkillType);
+            this.skillLevel = mcMMOPlayer.getSkillLevel(subSkillType.getParentSkill());
         } else {
             this.skillLevel = 0;
         }
 
         if (player != null)
-            isLucky = Permissions.lucky(player, primarySkillType);
+            isLucky = Permissions.lucky(player, subSkillType.getParentSkill());
         else
             isLucky = false;
 
         this.resultModifier = 1.0D;
+        this.maximumBonusLevelCap = RandomChanceUtil.getMaxBonusLevelCap(subSkillType);
     }
 
     public RandomChanceSkill(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean hasCap, double resultModifier) {
         if (hasCap)
-            this.probabilityCap = AdvancedConfig.getInstance().getMaximumProbability(subSkillType);
+            this.probabilityCap = RandomChanceUtil.getMaximumProbability(subSkillType);
         else
             this.probabilityCap = RandomChanceUtil.LINEAR_CURVE_VAR;
 
-        this.primarySkillType = subSkillType.getParentSkill();
-        this.subSkillType = subSkillType;
-
         final McMMOPlayer mcMMOPlayer = UserManager.getPlayer(player);
         if (player != null && mcMMOPlayer != null) {
-            this.skillLevel = mcMMOPlayer.getSkillLevel(primarySkillType);
+            this.skillLevel = mcMMOPlayer.getSkillLevel(subSkillType.getParentSkill());
         } else {
             this.skillLevel = 0;
         }
 
         if (player != null)
-            isLucky = Permissions.lucky(player, primarySkillType);
+            isLucky = Permissions.lucky(player, subSkillType.getParentSkill());
         else
             isLucky = false;
 
         this.resultModifier = resultModifier;
-    }
-
-    /**
-     * The subskill corresponding to this RandomChanceSkill
-     *
-     * @return this subskill
-     */
-    public @NotNull SubSkillType getSubSkill() {
-        return subSkillType;
+        this.maximumBonusLevelCap = RandomChanceUtil.getMaxBonusLevelCap(subSkillType);
     }
 
     /**
@@ -142,7 +123,7 @@ public class RandomChanceSkill implements RandomChanceExecution {
      * @return the maximum bonus from skill level for this skill
      */
     public double getMaximumBonusLevelCap() {
-        return AdvancedConfig.getInstance().getMaxBonusLevel(subSkillType);
+        return maximumBonusLevelCap;
     }
 
     /**
@@ -173,8 +154,4 @@ public class RandomChanceSkill implements RandomChanceExecution {
     public double getResultModifier() {
         return resultModifier;
     }
-
-    public void setResultModifier(double resultModifier) {
-        this.resultModifier = resultModifier;
-    }
 }

+ 13 - 5
src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java

@@ -3,7 +3,6 @@ package com.gmail.nossr50.util.random;
 import com.gmail.nossr50.config.AdvancedConfig;
 import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.datatypes.skills.SubSkillType;
-import com.gmail.nossr50.datatypes.skills.subskills.AbstractSubSkill;
 import com.gmail.nossr50.events.skills.secondaryabilities.SubSkillEvent;
 import com.gmail.nossr50.events.skills.secondaryabilities.SubSkillRandomCheckEvent;
 import com.gmail.nossr50.util.EventUtils;
@@ -20,6 +19,7 @@ public class RandomChanceUtil {
     public static final @NotNull DecimalFormat percent = new DecimalFormat("##0.00%");
     //public static final DecimalFormat decimal = new DecimalFormat("##0.00");
     public static final double LINEAR_CURVE_VAR = 100.0D;
+    public static final double LUCKY_MODIFIER = 1.333D;
 
     /**
      * This method is the final step in determining if a Sub-Skill / Secondary Skill in mcMMO successfully activates either from chance or otherwise
@@ -142,7 +142,7 @@ public class RandomChanceUtil {
         return chanceOfSuccess;
     }*/
 
-    private static double calculateChanceOfSuccess(@NotNull RandomChanceSkill randomChance) {
+    public static double calculateChanceOfSuccess(@NotNull RandomChanceSkill randomChance) {
         double skillLevel = randomChance.getSkillLevel();
         double maximumProbability = randomChance.getProbabilityCap();
         double maximumBonusLevel = randomChance.getMaximumBonusLevelCap();
@@ -163,7 +163,7 @@ public class RandomChanceUtil {
         return chanceOfSuccess;
     }
 
-    private static double calculateChanceOfSuccess(@NotNull RandomChanceSkillStatic randomChance) {
+    public static double calculateChanceOfSuccess(@NotNull RandomChanceSkillStatic randomChance) {
         double chanceOfSuccess = getChanceOfSuccess(randomChance.getXPos(), 100, 100);
 
         //Add Luck
@@ -304,15 +304,23 @@ public class RandomChanceUtil {
 
     public static double addLuck(@NotNull Player player, @NotNull PrimarySkillType primarySkillType, double chance) {
         if (Permissions.lucky(player, primarySkillType))
-            return chance * 1.333D;
+            return chance * LUCKY_MODIFIER;
         else
             return chance;
     }
 
     public static double addLuck(boolean isLucky, double chance) {
         if (isLucky)
-            return chance * 1.333D;
+            return chance * LUCKY_MODIFIER;
         else
             return chance;
     }
+
+    public static double getMaximumProbability(@NotNull SubSkillType subSkillType) {
+        return AdvancedConfig.getInstance().getMaximumProbability(subSkillType);
+    }
+
+    public static double getMaxBonusLevelCap(@NotNull SubSkillType subSkillType) {
+        return AdvancedConfig.getInstance().getMaxBonusLevel(subSkillType);
+    }
 }

+ 2 - 2
src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java

@@ -93,7 +93,7 @@ public class ScoreboardManager {
             int i = 0;
             for (PrimarySkillType type : PrimarySkillType.values()) {
                 // Include child skills
-                skillLabelBuilder.put(type, getShortenedName(colors.get(i) + type.getName(), false));
+                skillLabelBuilder.put(type, getShortenedName(colors.get(i) + type.getLocalizedName(), false));
 
                 if (type.getAbility() != null) {
                     abilityLabelBuilder.put(type.getAbility(), getShortenedName(colors.get(i) + type.getAbility().getLocalizedName()));
@@ -115,7 +115,7 @@ public class ScoreboardManager {
         else {
             for (PrimarySkillType type : PrimarySkillType.values()) {
                 // Include child skills
-                skillLabelBuilder.put(type, getShortenedName(ChatColor.GREEN + type.getName()));
+                skillLabelBuilder.put(type, getShortenedName(ChatColor.GREEN + type.getLocalizedName()));
 
                 if (type.getAbility() != null) {
                     abilityLabelBuilder.put(type.getAbility(), formatAbility(type.getAbility().getLocalizedName()));

+ 0 - 1
src/main/java/com/gmail/nossr50/util/skills/PerksUtils.java

@@ -5,7 +5,6 @@ import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
 import com.gmail.nossr50.events.skills.SkillActivationPerkEvent;
 import com.gmail.nossr50.util.Permissions;
 import com.gmail.nossr50.util.player.UserManager;
-
 import org.bukkit.Bukkit;
 import org.bukkit.ChatColor;
 import org.bukkit.entity.Player;

+ 17 - 0
src/test/java/com/gmail/nossr50/TestUtil.java

@@ -0,0 +1,17 @@
+package com.gmail.nossr50;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+
+//TODO: Move generic test stuff here
+public class TestUtil {
+    public static void recursiveDelete(@NotNull File directoryToBeDeleted) {
+        if (directoryToBeDeleted.isDirectory()) {
+            for (File file : directoryToBeDeleted.listFiles()) {
+                recursiveDelete(file);
+            }
+        }
+        directoryToBeDeleted.delete();
+    }
+}

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

@@ -1,5 +1,6 @@
 package com.gmail.nossr50.util.blockmeta;
 
+import com.gmail.nossr50.TestUtil;
 import com.google.common.io.Files;
 import org.bukkit.Bukkit;
 import org.bukkit.World;
@@ -31,7 +32,7 @@ public class ChunkStoreTest {
 
     @AfterClass
     public static void tearDownClass() {
-        recursiveDelete(tempDir);
+        TestUtil.recursiveDelete(tempDir);
     }
 
     private World mockWorld;
@@ -184,15 +185,6 @@ public class ChunkStoreTest {
                     Assert.assertTrue(expected.isTrue(x, y, z) == actual.isTrue(x, y, z));
     }
 
-    private static void recursiveDelete(@NotNull File directoryToBeDeleted) {
-        if (directoryToBeDeleted.isDirectory()) {
-            for (File file : directoryToBeDeleted.listFiles()) {
-                recursiveDelete(file);
-            }
-        }
-        directoryToBeDeleted.delete();
-    }
-
     private static byte[] serializeChunkstore(@NotNull ChunkStore chunkStore) throws IOException {
         ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
         if (chunkStore instanceof BitSetChunkStore)

+ 116 - 0
src/test/java/com/gmail/nossr50/util/random/RandomChanceTest.java

@@ -0,0 +1,116 @@
+package com.gmail.nossr50.util.random;
+
+import com.gmail.nossr50.datatypes.player.McMMOPlayer;
+import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
+import com.gmail.nossr50.datatypes.skills.SubSkillType;
+import com.gmail.nossr50.util.Permissions;
+import com.gmail.nossr50.util.player.UserManager;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import static org.mockito.Mockito.mock;
+
+//TODO: Rewrite the entire com.gmail.nossr50.util.random package, it was written in haste and it disgusts me
+//TODO: Add more tests for the other types of random dice rolls
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({RandomChanceUtil.class, UserManager.class})
+public class RandomChanceTest {
+
+    private Player luckyPlayer;
+    private McMMOPlayer mmoPlayerLucky;
+
+    private Player normalPlayer;
+    private McMMOPlayer mmoPlayerNormal;
+
+    private SubSkillType subSkillType;
+    private PrimarySkillType primarySkillType;
+
+    private final String testASCIIHeader = "---- mcMMO Tests ----";
+
+    @Before
+    public void setUpMock() {
+        primarySkillType = PrimarySkillType.HERBALISM;
+        subSkillType = SubSkillType.HERBALISM_GREEN_THUMB;
+
+        //TODO: Likely needs to be changed per skill if more tests were added
+        PowerMockito.stub(PowerMockito.method(RandomChanceUtil.class, "getMaximumProbability", subSkillType.getClass())).toReturn(100D);
+        PowerMockito.stub(PowerMockito.method(RandomChanceUtil.class, "getMaxBonusLevelCap", subSkillType.getClass())).toReturn(1000D);
+
+        normalPlayer = mock(Player.class);
+        luckyPlayer = mock(Player.class);
+
+        mmoPlayerNormal = mock(McMMOPlayer.class);
+        mmoPlayerLucky = mock(McMMOPlayer.class);
+
+        PowerMockito.mockStatic(UserManager.class);
+        Mockito.when(UserManager.getPlayer(normalPlayer)).thenReturn(mmoPlayerNormal);
+        Mockito.when(UserManager.getPlayer(luckyPlayer)).thenReturn(mmoPlayerLucky);
+
+        Mockito.when(mmoPlayerNormal.getPlayer()).thenReturn(normalPlayer);
+        Mockito.when(mmoPlayerLucky.getPlayer()).thenReturn(luckyPlayer);
+
+        //Lucky player has the lucky permission
+        //Normal player doesn't have any lucky permission
+        Mockito.when(Permissions.lucky(luckyPlayer, primarySkillType)).thenReturn(true);
+        Mockito.when(Permissions.lucky(normalPlayer, primarySkillType)).thenReturn(false);
+
+        Mockito.when(mmoPlayerNormal.getSkillLevel(primarySkillType)).thenReturn(800);
+        Mockito.when(mmoPlayerLucky.getSkillLevel(primarySkillType)).thenReturn(800);
+    }
+
+    @Test
+    public void testLuckyChance() {
+        System.out.println(testASCIIHeader);
+        System.out.println("Testing success odds to fall within expected values...");
+        assertEquals(80D, getSuccessChance(mmoPlayerNormal),0D);
+        assertEquals(80D * RandomChanceUtil.LUCKY_MODIFIER, getSuccessChance(mmoPlayerLucky),0D);
+    }
+
+    @Test
+    public void testNeverFailsSuccessLuckyPlayer() {
+        System.out.println(testASCIIHeader);
+        System.out.println("Test - Lucky Player with 80% base success should never fail (10,000 iterations)");
+        for(int x = 0; x < 10000; x++) {
+            Assert.assertTrue(RandomChanceUtil.checkRandomChanceExecutionSuccess(luckyPlayer, SubSkillType.HERBALISM_GREEN_THUMB, true));
+            if(x == 10000-1)
+                System.out.println("They never failed!");
+        }
+    }
+
+    @Test
+    public void testFailsAboutExpected() {
+        System.out.println(testASCIIHeader);
+        System.out.println("Test - Player with 800 skill should fail about 20% of the time (100,000 iterations)");
+        double ratioDivisor = 1000; //1000 because we run the test 100,000 times
+        double expectedFailRate = 20D;
+
+        double win = 0, loss = 0;
+        for(int x = 0; x < 100000; x++) {
+            if(RandomChanceUtil.checkRandomChanceExecutionSuccess(normalPlayer, SubSkillType.HERBALISM_GREEN_THUMB, true)) {
+                win++;
+            } else {
+                loss++;
+            }
+        }
+
+        double lossRatio = (loss / ratioDivisor);
+        Assert.assertEquals(lossRatio, expectedFailRate, 1D);
+    }
+
+    private double getSuccessChance(@NotNull McMMOPlayer mmoPlayer) {
+        RandomChanceSkill randomChanceSkill = new RandomChanceSkill(mmoPlayer.getPlayer(), subSkillType, true);
+        return RandomChanceUtil.calculateChanceOfSuccess(randomChanceSkill);
+    }
+
+    private void assertEquals(double expected, double actual, double delta) {
+        Assert.assertEquals(expected, actual, delta);
+    }
+}