From 00a6d527178cfa2cb4ec400b8ffe35537bcb8117 Mon Sep 17 00:00:00 2001 From: t00thpick1 Date: Sat, 2 Jan 2021 18:57:51 -0500 Subject: [PATCH 1/8] Refactor region file loading for better nullability analysis --- .../util/blockmeta/HashChunkManager.java | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java b/src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java index 95397f89d..6bc87ae30 100644 --- a/src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java +++ b/src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java @@ -38,9 +38,9 @@ public class HashChunkManager implements ChunkManager { rf.close(); regionMap.clear(); } - + private synchronized @Nullable ChunkStore readChunkStore(@NotNull World world, int cx, int cz) throws IOException { - McMMOSimpleRegionFile rf = getSimpleRegionFile(world, cx, cz, false); + McMMOSimpleRegionFile rf = getReadableSimpleRegionFile(world, cx, cz); if (rf == null) return null; // If there is no region file, there can't be a chunk try (DataInputStream in = rf.getInputStream(cx, cz)) { // Get input stream for chunk @@ -54,7 +54,7 @@ public class HashChunkManager implements ChunkManager { if (!data.isDirty()) return; // Don't save unchanged data try { - McMMOSimpleRegionFile rf = getSimpleRegionFile(world, data.getChunkX(), data.getChunkZ(), true); + McMMOSimpleRegionFile rf = getWriteableSimpleRegionFile(world, data.getChunkX(), data.getChunkZ()); try (DataOutputStream out = rf.getOutputStream(data.getChunkX(), data.getChunkZ())) { BitSetChunkStore.Serialization.writeChunkStore(out, data); } @@ -65,21 +65,33 @@ public class HashChunkManager implements ChunkManager { } } - private synchronized @Nullable McMMOSimpleRegionFile getSimpleRegionFile(@NotNull World world, int cx, int cz, boolean createIfAbsent) { + private synchronized @NotNull McMMOSimpleRegionFile getWriteableSimpleRegionFile(@NotNull World world, int cx, int cz) { CoordinateKey regionKey = toRegionKey(world.getUID(), cx, cz); return regionMap.computeIfAbsent(regionKey, k -> { - File worldRegionsDirectory = new File(world.getWorldFolder(), "mcmmo_regions"); - if (!createIfAbsent && !worldRegionsDirectory.isDirectory()) - return null; // Don't create the directory on read-only operations - worldRegionsDirectory.mkdirs(); // Ensure directory exists - File regionFile = new File(worldRegionsDirectory, "mcmmo_" + regionKey.x + "_" + regionKey.z + "_.mcm"); - if (!createIfAbsent && !regionFile.exists()) + File regionFile = getRegionFile(world, regionKey); + regionFile.getParentFile().mkdirs(); + return new McMMOSimpleRegionFile(regionFile, regionKey.x, regionKey.z); + }); + } + + private synchronized @Nullable McMMOSimpleRegionFile getReadableSimpleRegionFile(@NotNull World world, int cx, int cz) { + CoordinateKey regionKey = toRegionKey(world.getUID(), cx, cz); + + return regionMap.computeIfAbsent(regionKey, k -> { + File regionFile = getRegionFile(world, regionKey); + if (!regionFile.exists()) return null; // Don't create the file on read-only operations return new McMMOSimpleRegionFile(regionFile, regionKey.x, regionKey.z); }); } + private @NotNull File getRegionFile(@NotNull World world, @NotNull CoordinateKey regionKey) { + if (world.getUID() != regionKey.worldID) + throw new IllegalArgumentException(); + return new File(new File(world.getWorldFolder(), "mcmmo_regions"), "mcmmo_" + regionKey.x + "_" + regionKey.z + "_.mcm"); + } + private @Nullable ChunkStore loadChunk(int cx, int cz, @NotNull World world) { try { return readChunkStore(world, cx, cz); From 4fa3d913bfc9566f8e94a2d8a9d3f6eae0543439 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sat, 2 Jan 2021 16:15:04 -0800 Subject: [PATCH 2/8] More annotations for blockmeta.. again --- .../com/gmail/nossr50/util/blockmeta/HashChunkManager.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java b/src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java index 6bc87ae30..c1114130c 100644 --- a/src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java +++ b/src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java @@ -240,15 +240,15 @@ public class HashChunkManager implements ChunkManager { cStore.set(ix, y, iz, value); } - private CoordinateKey blockCoordinateToChunkKey(@NotNull UUID worldUid, int x, int y, int z) { + private @NotNull CoordinateKey blockCoordinateToChunkKey(@NotNull UUID worldUid, int x, int y, int z) { return toChunkKey(worldUid, x >> 4, z >> 4); } - private CoordinateKey toChunkKey(@NotNull UUID worldUid, int cx, int cz){ + private @NotNull CoordinateKey toChunkKey(@NotNull UUID worldUid, int cx, int cz){ return new CoordinateKey(worldUid, cx, cz); } - private CoordinateKey toRegionKey(@NotNull UUID worldUid, int cx, int cz) { + private @NotNull CoordinateKey toRegionKey(@NotNull UUID worldUid, int cx, int cz) { // Compute region index (32x32 chunk regions) int rx = cx >> 5; int rz = cz >> 5; From 597eb7f8dd1d862152d24e20dc0c8f1186adfee7 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sat, 2 Jan 2021 16:39:26 -0800 Subject: [PATCH 3/8] Tweaks to the random chance classes --- .../nossr50/skills/axes/AxesManager.java | 23 +-- .../nossr50/skills/swords/SwordsManager.java | 8 +- .../skills/unarmed/UnarmedManager.java | 9 +- .../util/random/RandomChanceExecution.java | 2 + .../util/random/RandomChanceSkill.java | 38 ++--- .../util/random/RandomChanceSkillStatic.java | 8 +- .../util/random/RandomChanceStatic.java | 3 +- .../nossr50/util/random/RandomChanceUtil.java | 146 ++++++------------ 8 files changed, 91 insertions(+), 146 deletions(-) diff --git a/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java b/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java index 2a5d648b5..ead48f6d8 100644 --- a/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java +++ b/src/main/java/com/gmail/nossr50/skills/axes/AxesManager.java @@ -17,6 +17,7 @@ import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.event.entity.EntityDamageEvent.DamageModifier; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; import java.util.Map; @@ -32,28 +33,28 @@ public class AxesManager extends SkillManager { return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.AXES_AXE_MASTERY); } - public boolean canCriticalHit(LivingEntity target) { + public boolean canCriticalHit(@NotNull LivingEntity target) { if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.AXES_CRITICAL_STRIKES)) return false; return target.isValid() && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.AXES_CRITICAL_STRIKES); } - public boolean canImpact(LivingEntity target) { + public boolean canImpact(@NotNull LivingEntity target) { if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.AXES_ARMOR_IMPACT)) return false; return target.isValid() && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.AXES_ARMOR_IMPACT) && Axes.hasArmor(target); } - public boolean canGreaterImpact(LivingEntity target) { + public boolean canGreaterImpact(@NotNull LivingEntity target) { if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.AXES_GREATER_IMPACT)) return false; return target.isValid() && Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.AXES_GREATER_IMPACT) && !Axes.hasArmor(target); } - public boolean canUseSkullSplitter(LivingEntity target) { + public boolean canUseSkullSplitter(@NotNull LivingEntity target) { if(!RankUtils.hasUnlockedSubskill(getPlayer(), SubSkillType.AXES_SKULL_SPLITTER)) return false; @@ -68,7 +69,7 @@ public class AxesManager extends SkillManager { * Handle the effects of the Axe Mastery ability */ public double axeMastery() { - if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.AXES_AXE_MASTERY, getPlayer(), mmoPlayer.getAttackStrength())) { + if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.AXES_AXE_MASTERY, getPlayer())) { return 0; } @@ -82,7 +83,7 @@ public class AxesManager extends SkillManager { * @param damage The amount of damage initially dealt by the event */ public double criticalHit(LivingEntity target, double damage) { - if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.AXES_CRITICAL_STRIKES, getPlayer(), mmoPlayer.getAttackStrength())) { + if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.AXES_CRITICAL_STRIKES, getPlayer())) { return 0; } @@ -113,12 +114,12 @@ public class AxesManager extends SkillManager { * * @param target The {@link LivingEntity} being affected by Impact */ - public void impactCheck(LivingEntity target) { + public void impactCheck(@NotNull LivingEntity target) { double durabilityDamage = getImpactDurabilityDamage(); for (ItemStack armor : target.getEquipment().getArmorContents()) { if (armor != null && ItemUtils.isArmor(armor)) { - if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_STATIC_CHANCE, SubSkillType.AXES_ARMOR_IMPACT, getPlayer(), mmoPlayer.getAttackStrength())) { + if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_STATIC_CHANCE, SubSkillType.AXES_ARMOR_IMPACT, getPlayer())) { SkillUtils.handleDurabilityChange(armor, durabilityDamage, 1); } } @@ -134,9 +135,9 @@ public class AxesManager extends SkillManager { * * @param target The {@link LivingEntity} being affected by the ability */ - public double greaterImpact(LivingEntity target) { + public double greaterImpact(@NotNull LivingEntity target) { //static chance (3rd param) - if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_STATIC_CHANCE, SubSkillType.AXES_GREATER_IMPACT, getPlayer(), mmoPlayer.getAttackStrength())) { + if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_STATIC_CHANCE, SubSkillType.AXES_GREATER_IMPACT, getPlayer())) { return 0; } @@ -166,7 +167,7 @@ public class AxesManager extends SkillManager { * @param target The {@link LivingEntity} being affected by the ability * @param damage The amount of damage initially dealt by the event */ - public void skullSplitterCheck(LivingEntity target, double damage, Map modifiers) { + public void skullSplitterCheck(@NotNull LivingEntity target, double damage, Map modifiers) { CombatUtils.applyAbilityAoE(getPlayer(), target, damage / Axes.skullSplitterModifier, modifiers, skill); } } diff --git a/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java b/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java index ebcc93993..1c3fa3766 100644 --- a/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/swords/SwordsManager.java @@ -62,7 +62,7 @@ public class SwordsManager extends SkillManager { */ public void ruptureCheck(@NotNull LivingEntity target) throws IllegalStateException { if(BleedTimerTask.isBleedOperationAllowed()) { - if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.SWORDS_RUPTURE, getPlayer(), this.mmoPlayer.getAttackStrength())) { + if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.SWORDS_RUPTURE, getPlayer())) { if (target instanceof Player) { Player defender = (Player) target; @@ -98,7 +98,7 @@ public class SwordsManager extends SkillManager { return 0; } - public int getToolTier(ItemStack itemStack) + public int getToolTier(@NotNull ItemStack itemStack) { if(ItemUtils.isNetheriteTool(itemStack)) return 5; @@ -128,7 +128,7 @@ public class SwordsManager extends SkillManager { * @param attacker The {@link LivingEntity} being affected by the ability * @param damage The amount of damage initially dealt by the event */ - public void counterAttackChecks(LivingEntity attacker, double damage) { + public void counterAttackChecks(@NotNull LivingEntity attacker, double damage) { if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.SWORDS_COUNTER_ATTACK, getPlayer())) { CombatUtils.dealDamage(attacker, damage / Swords.counterAttackModifier, getPlayer()); @@ -146,7 +146,7 @@ public class SwordsManager extends SkillManager { * @param target The {@link LivingEntity} being affected by the ability * @param damage The amount of damage initially dealt by the event */ - public void serratedStrikes(LivingEntity target, double damage, Map modifiers) { + public void serratedStrikes(@NotNull LivingEntity target, double damage, Map modifiers) { CombatUtils.applyAbilityAoE(getPlayer(), target, damage / Swords.serratedStrikesModifier, modifiers, skill); } } diff --git a/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java b/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java index c20620cf8..73bf3dce9 100644 --- a/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java +++ b/src/main/java/com/gmail/nossr50/skills/unarmed/UnarmedManager.java @@ -25,6 +25,7 @@ import org.bukkit.entity.Item; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; public class UnarmedManager extends SkillManager { @@ -70,7 +71,7 @@ public class UnarmedManager extends SkillManager { return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.UNARMED_BLOCK_CRACKER); } - public boolean blockCrackerCheck(BlockState blockState) { + public boolean blockCrackerCheck(@NotNull BlockState blockState) { if (!RandomChanceUtil.isActivationSuccessful(SkillActivationType.ALWAYS_FIRES, SubSkillType.UNARMED_BLOCK_CRACKER, getPlayer())) { return false; } @@ -101,8 +102,8 @@ public class UnarmedManager extends SkillManager { * * @param defender The defending player */ - public void disarmCheck(Player defender) { - if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.UNARMED_DISARM, getPlayer(), mmoPlayer.getAttackStrength()) && !hasIronGrip(defender)) { + public void disarmCheck(@NotNull Player defender) { + if (RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.UNARMED_DISARM, getPlayer()) && !hasIronGrip(defender)) { if (EventUtils.callDisarmEvent(defender).isCancelled()) { return; } @@ -179,7 +180,7 @@ public class UnarmedManager extends SkillManager { * @param defender The defending player * @return true if the defender was not disarmed, false otherwise */ - private boolean hasIronGrip(Player defender) { + private boolean hasIronGrip(@NotNull Player defender) { if (!Misc.isNPCEntityExcludingVillagers(defender) && Permissions.isSubSkillEnabled(defender, SubSkillType.UNARMED_IRON_GRIP) && RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.UNARMED_IRON_GRIP, defender)) { diff --git a/src/main/java/com/gmail/nossr50/util/random/RandomChanceExecution.java b/src/main/java/com/gmail/nossr50/util/random/RandomChanceExecution.java index 8d0da9285..e5d51d740 100644 --- a/src/main/java/com/gmail/nossr50/util/random/RandomChanceExecution.java +++ b/src/main/java/com/gmail/nossr50/util/random/RandomChanceExecution.java @@ -3,6 +3,7 @@ package com.gmail.nossr50.util.random; public interface RandomChanceExecution { /** * Gets the XPos used in the formula for success + * * @return value of x for our success probability graph */ double getXPos(); @@ -10,6 +11,7 @@ public interface RandomChanceExecution { /** * The maximum odds for this RandomChanceExecution * For example, if this value is 10, then 10% odds would be the maximum and would be achieved only when xPos equaled the LinearCurvePeak + * * @return maximum probability odds from 0.00 (no chance of ever happened) to 100.0 (probability can be guaranteed) */ double getProbabilityCap(); diff --git a/src/main/java/com/gmail/nossr50/util/random/RandomChanceSkill.java b/src/main/java/com/gmail/nossr50/util/random/RandomChanceSkill.java index 5d47b44bd..67221a433 100644 --- a/src/main/java/com/gmail/nossr50/util/random/RandomChanceSkill.java +++ b/src/main/java/com/gmail/nossr50/util/random/RandomChanceSkill.java @@ -7,18 +7,19 @@ 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.jetbrains.annotations.Nullable; public class RandomChanceSkill implements RandomChanceExecution { - protected final PrimarySkillType primarySkillType; - protected final SubSkillType subSkillType; + protected final @NotNull PrimarySkillType primarySkillType; + protected final @NotNull SubSkillType subSkillType; protected final double probabilityCap; protected final boolean isLucky; protected int skillLevel; protected double resultModifier; - public RandomChanceSkill(Player player, SubSkillType subSkillType, double resultModifier) - { + public RandomChanceSkill(@Nullable Player player, @NotNull SubSkillType subSkillType, double resultModifier) { this.primarySkillType = subSkillType.getParentSkill(); this.subSkillType = subSkillType; this.probabilityCap = RandomChanceUtil.LINEAR_CURVE_VAR; @@ -30,7 +31,7 @@ public class RandomChanceSkill implements RandomChanceExecution { this.skillLevel = 0; } - if(player != null) + if (player != null) isLucky = Permissions.lucky(player, primarySkillType); else isLucky = false; @@ -38,8 +39,7 @@ public class RandomChanceSkill implements RandomChanceExecution { this.resultModifier = resultModifier; } - public RandomChanceSkill(Player player, SubSkillType subSkillType) - { + public RandomChanceSkill(@Nullable Player player, @NotNull SubSkillType subSkillType) { this.primarySkillType = subSkillType.getParentSkill(); this.subSkillType = subSkillType; this.probabilityCap = RandomChanceUtil.LINEAR_CURVE_VAR; @@ -51,7 +51,7 @@ public class RandomChanceSkill implements RandomChanceExecution { this.skillLevel = 0; } - if(player != null) + if (player != null) isLucky = Permissions.lucky(player, primarySkillType); else isLucky = false; @@ -59,9 +59,8 @@ public class RandomChanceSkill implements RandomChanceExecution { this.resultModifier = 1.0D; } - public RandomChanceSkill(Player player, SubSkillType subSkillType, boolean hasCap) - { - if(hasCap) + public RandomChanceSkill(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean hasCap) { + if (hasCap) this.probabilityCap = AdvancedConfig.getInstance().getMaximumProbability(subSkillType); else this.probabilityCap = RandomChanceUtil.LINEAR_CURVE_VAR; @@ -76,7 +75,7 @@ public class RandomChanceSkill implements RandomChanceExecution { this.skillLevel = 0; } - if(player != null) + if (player != null) isLucky = Permissions.lucky(player, primarySkillType); else isLucky = false; @@ -84,9 +83,8 @@ public class RandomChanceSkill implements RandomChanceExecution { this.resultModifier = 1.0D; } - public RandomChanceSkill(Player player, SubSkillType subSkillType, boolean hasCap, double resultModifier) - { - if(hasCap) + public RandomChanceSkill(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean hasCap, double resultModifier) { + if (hasCap) this.probabilityCap = AdvancedConfig.getInstance().getMaximumProbability(subSkillType); else this.probabilityCap = RandomChanceUtil.LINEAR_CURVE_VAR; @@ -101,7 +99,7 @@ public class RandomChanceSkill implements RandomChanceExecution { this.skillLevel = 0; } - if(player != null) + if (player != null) isLucky = Permissions.lucky(player, primarySkillType); else isLucky = false; @@ -111,23 +109,25 @@ public class RandomChanceSkill implements RandomChanceExecution { /** * The subskill corresponding to this RandomChanceSkill + * * @return this subskill */ - public SubSkillType getSubSkill() { + public @NotNull SubSkillType getSubSkill() { return subSkillType; } /** * Gets the skill level of the player who owns this RandomChanceSkill + * * @return the current skill level relating to this RandomChanceSkill */ - public int getSkillLevel() - { + public int getSkillLevel() { return skillLevel; } /** * Modify the skill level used for this skill's RNG calculations + * * @param newSkillLevel new skill level */ public void setSkillLevel(int newSkillLevel) { diff --git a/src/main/java/com/gmail/nossr50/util/random/RandomChanceSkillStatic.java b/src/main/java/com/gmail/nossr50/util/random/RandomChanceSkillStatic.java index 6223dcda8..ab5f33ecd 100644 --- a/src/main/java/com/gmail/nossr50/util/random/RandomChanceSkillStatic.java +++ b/src/main/java/com/gmail/nossr50/util/random/RandomChanceSkillStatic.java @@ -2,19 +2,19 @@ package com.gmail.nossr50.util.random; import com.gmail.nossr50.datatypes.skills.SubSkillType; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class RandomChanceSkillStatic extends RandomChanceSkill { private final double xPos; - public RandomChanceSkillStatic(double xPos, Player player, SubSkillType subSkillType) - { + public RandomChanceSkillStatic(double xPos, @Nullable Player player, @NotNull SubSkillType subSkillType) { super(player, subSkillType); this.xPos = xPos; } - public RandomChanceSkillStatic(double xPos, Player player, SubSkillType subSkillType, double resultModifier) - { + public RandomChanceSkillStatic(double xPos, @Nullable Player player, @NotNull SubSkillType subSkillType, double resultModifier) { super(player, subSkillType, resultModifier); this.xPos = xPos; diff --git a/src/main/java/com/gmail/nossr50/util/random/RandomChanceStatic.java b/src/main/java/com/gmail/nossr50/util/random/RandomChanceStatic.java index 30f84cfbf..3204a348d 100644 --- a/src/main/java/com/gmail/nossr50/util/random/RandomChanceStatic.java +++ b/src/main/java/com/gmail/nossr50/util/random/RandomChanceStatic.java @@ -5,8 +5,7 @@ public class RandomChanceStatic implements RandomChanceExecution { private final double probabilityCap; private final boolean isLucky; - public RandomChanceStatic(double xPos, boolean isLucky) - { + public RandomChanceStatic(double xPos, boolean isLucky) { this.xPos = xPos; this.probabilityCap = xPos; this.isLucky = isLucky; diff --git a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java b/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java index 29866144d..885ff3a90 100644 --- a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java +++ b/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java @@ -10,13 +10,14 @@ import com.gmail.nossr50.util.EventUtils; import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.skills.SkillActivationType; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.text.DecimalFormat; import java.util.concurrent.ThreadLocalRandom; -public class RandomChanceUtil -{ - public static final DecimalFormat percent = new DecimalFormat("##0.00%"); +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; @@ -26,14 +27,12 @@ public class RandomChanceUtil * non-RNG skills just fire the cancellable event and succeed if they go uncancelled * * @param skillActivationType this value represents what kind of activation procedures this sub-skill uses - * @param subSkillType The identifier for this specific sub-skill - * @param player The owner of this sub-skill + * @param subSkillType The identifier for this specific sub-skill + * @param player The owner of this sub-skill * @return returns true if all conditions are met and the event is not cancelled */ - public static boolean isActivationSuccessful(SkillActivationType skillActivationType, SubSkillType subSkillType, Player player) - { - switch(skillActivationType) - { + public static boolean isActivationSuccessful(@NotNull SkillActivationType skillActivationType, @NotNull SubSkillType subSkillType, @Nullable Player player) { + switch (skillActivationType) { case RANDOM_LINEAR_100_SCALE_WITH_CAP: return checkRandomChanceExecutionSuccess(player, subSkillType, true); case RANDOM_STATIC_CHANCE: @@ -46,36 +45,8 @@ public class RandomChanceUtil } } - /** - * This method is the final step in determining if a Sub-Skill / Secondary Skill in mcMMO successfully activates either from chance or otherwise - * Random skills check for success based on numbers and then fire a cancellable event, if that event is not cancelled they succeed - * non-RNG skills just fire the cancellable event and succeed if they go uncancelled - * - * @param skillActivationType this value represents what kind of activation procedures this sub-skill uses - * @param subSkillType The identifier for this specific sub-skill - * @param player The owner of this sub-skill - * @return returns true if all conditions are met and the event is not cancelled - */ - public static boolean isActivationSuccessful(SkillActivationType skillActivationType, SubSkillType subSkillType, Player player, double resultModifier) - { - switch(skillActivationType) - { - case RANDOM_LINEAR_100_SCALE_WITH_CAP: - return checkRandomChanceExecutionSuccess(player, subSkillType, true); - case RANDOM_STATIC_CHANCE: - return checkRandomStaticChanceExecutionSuccess(player, subSkillType, resultModifier); - case ALWAYS_FIRES: - SubSkillEvent event = EventUtils.callSubSkillEvent(player, subSkillType); - return !event.isCancelled(); - default: - return false; - } - } - - public static double getActivationChance(SkillActivationType skillActivationType, SubSkillType subSkillType, Player player) - { - switch(skillActivationType) - { + public static double getActivationChance(@NotNull SkillActivationType skillActivationType, @NotNull SubSkillType subSkillType, @Nullable Player player) { + switch (skillActivationType) { case RANDOM_LINEAR_100_SCALE_WITH_CAP: return getRandomChanceExecutionSuccess(player, subSkillType, true); case RANDOM_STATIC_CHANCE: @@ -87,10 +58,10 @@ public class RandomChanceUtil /** * Checks whether or not the random chance succeeds + * * @return true if the random chance succeeds */ - public static boolean checkRandomChanceExecutionSuccess(Player player, PrimarySkillType primarySkillType, double chance) - { + public static boolean checkRandomChanceExecutionSuccess(@NotNull Player player, @NotNull PrimarySkillType primarySkillType, double chance) { //Check the odds chance *= 100; @@ -113,11 +84,11 @@ public class RandomChanceUtil /** * Used for stuff like Excavation, Fishing, etc... + * * @param randomChance * @return */ - public static boolean checkRandomChanceExecutionSuccess(RandomChanceSkillStatic randomChance, double resultModifier) - { + public static boolean checkRandomChanceExecutionSuccess(@NotNull RandomChanceSkillStatic randomChance, double resultModifier) { double chanceOfSuccess = calculateChanceOfSuccess(randomChance); //Check the odds @@ -126,16 +97,15 @@ public class RandomChanceUtil /** * Used for stuff like Excavation, Fishing, etc... + * * @param randomChance * @return */ - public static boolean checkRandomChanceExecutionSuccess(RandomChanceSkillStatic randomChance) - { + public static boolean checkRandomChanceExecutionSuccess(@NotNull RandomChanceSkillStatic randomChance) { return checkRandomChanceExecutionSuccess(randomChance, 1.0F); } - public static boolean checkRandomChanceExecutionSuccess(RandomChanceSkill randomChance) - { + public static boolean checkRandomChanceExecutionSuccess(@NotNull RandomChanceSkill randomChance) { double chanceOfSuccess = calculateChanceOfSuccess(randomChance); //Check the odds @@ -151,14 +121,15 @@ public class RandomChanceUtil /** * Gets the Static Chance for something to activate + * * @param randomChance * @return */ - public static double getRandomChanceExecutionChance(RandomChanceExecution randomChance) { + public static double getRandomChanceExecutionChance(@NotNull RandomChanceExecution randomChance) { return getChanceOfSuccess(randomChance.getXPos(), randomChance.getProbabilityCap(), LINEAR_CURVE_VAR); } - public static double getRandomChanceExecutionChance(RandomChanceStatic randomChance) { + public static double getRandomChanceExecutionChance(@NotNull RandomChanceStatic randomChance) { double chanceOfSuccess = getChanceOfSuccess(randomChance.getXPos(), randomChance.getProbabilityCap(), LINEAR_CURVE_VAR); chanceOfSuccess = addLuck(randomChance.isLucky(), chanceOfSuccess); @@ -171,7 +142,7 @@ public class RandomChanceUtil return chanceOfSuccess; }*/ - private static double calculateChanceOfSuccess(RandomChanceSkill randomChance) { + private static double calculateChanceOfSuccess(@NotNull RandomChanceSkill randomChance) { double skillLevel = randomChance.getSkillLevel(); double maximumProbability = randomChance.getProbabilityCap(); double maximumBonusLevel = randomChance.getMaximumBonusLevelCap(); @@ -192,7 +163,7 @@ public class RandomChanceUtil return chanceOfSuccess; } - private static double calculateChanceOfSuccess(RandomChanceSkillStatic randomChance) { + private static double calculateChanceOfSuccess(@NotNull RandomChanceSkillStatic randomChance) { double chanceOfSuccess = getChanceOfSuccess(randomChance.getXPos(), 100, 100); //Add Luck @@ -207,27 +178,23 @@ public class RandomChanceUtil * * @return the chance of success from 0-100 (100 = guaranteed) */ - private static int getChanceOfSuccess(double skillLevel, double maxProbability, double maxLevel) - { + private static int getChanceOfSuccess(double skillLevel, double maxProbability, double maxLevel) { //return (int) (x / (y / LINEAR_CURVE_VAR)); - return (int) (maxProbability * (skillLevel/maxLevel)); + return (int) (maxProbability * (skillLevel / maxLevel)); // max probability * (weight/maxlevel) = chance of success } - private static int getChanceOfSuccess(double x, double y) - { + private static int getChanceOfSuccess(double x, double y) { return (int) (x / (y / LINEAR_CURVE_VAR)); // max probability * (weight/maxlevel) = chance of success } - public static double getRandomChanceExecutionSuccess(Player player, SubSkillType subSkillType, boolean hasCap) - { + public static double getRandomChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean hasCap) { RandomChanceSkill rcs = new RandomChanceSkill(player, subSkillType, hasCap); return calculateChanceOfSuccess(rcs); } - public static double getRandomStaticChanceExecutionSuccess(Player player, SubSkillType subSkillType) - { + public static double getRandomStaticChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType) { try { return getRandomChanceExecutionChance(new RandomChanceSkillStatic(getStaticRandomChance(subSkillType), player, subSkillType)); } catch (InvalidStaticChance invalidStaticChance) { @@ -238,29 +205,24 @@ public class RandomChanceUtil return 0.1337; //Puts on shades } - public static boolean checkRandomChanceExecutionSuccess(Player player, SubSkillType subSkillType, boolean hasCap) - { + public static boolean checkRandomChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean hasCap) { return checkRandomChanceExecutionSuccess(new RandomChanceSkill(player, subSkillType, hasCap)); } - public static boolean checkRandomChanceExecutionSuccess(Player player, SubSkillType subSkillType) - { + public static boolean checkRandomChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType) { return checkRandomChanceExecutionSuccess(new RandomChanceSkill(player, subSkillType)); } - public static boolean checkRandomChanceExecutionSuccess(Player player, SubSkillType subSkillType, boolean hasCap, double resultModifier) - { + public static boolean checkRandomChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType, boolean hasCap, double resultModifier) { return checkRandomChanceExecutionSuccess(new RandomChanceSkill(player, subSkillType, hasCap, resultModifier)); } - public static boolean checkRandomChanceExecutionSuccess(Player player, SubSkillType subSkillType, double resultModifier) - { + public static boolean checkRandomChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType, double resultModifier) { return checkRandomChanceExecutionSuccess(new RandomChanceSkill(player, subSkillType, resultModifier)); } - public static boolean checkRandomStaticChanceExecutionSuccess(Player player, SubSkillType subSkillType, double resultModifier) - { + public static boolean checkRandomStaticChanceExecutionSuccess(@Nullable Player player, @NotNull SubSkillType subSkillType) { try { return checkRandomChanceExecutionSuccess(new RandomChanceSkillStatic(getStaticRandomChance(subSkillType), player, subSkillType)); } catch (InvalidStaticChance invalidStaticChance) { @@ -271,21 +233,15 @@ public class RandomChanceUtil return false; } - public static boolean checkRandomStaticChanceExecutionSuccess(Player player, SubSkillType subSkillType) - { - return checkRandomStaticChanceExecutionSuccess(player, subSkillType, 1.0F); - } - /** * Grabs static activation rolls for Secondary Abilities + * * @param subSkillType The secondary ability to grab properties of - * @throws InvalidStaticChance if the skill has no defined static chance this exception will be thrown and you should know you're a naughty boy * @return The static activation roll involved in the RNG calculation + * @throws InvalidStaticChance if the skill has no defined static chance this exception will be thrown and you should know you're a naughty boy */ - public static double getStaticRandomChance(SubSkillType subSkillType) throws InvalidStaticChance - { - switch(subSkillType) - { + public static double getStaticRandomChance(@NotNull SubSkillType subSkillType) throws InvalidStaticChance { + switch (subSkillType) { case AXES_ARMOR_IMPACT: return AdvancedConfig.getInstance().getImpactChance(); case AXES_GREATER_IMPACT: @@ -297,24 +253,12 @@ public class RandomChanceUtil } } - public static boolean sendSkillEvent(Player player, SubSkillType subSkillType, double activationChance) - { + public static boolean sendSkillEvent(Player player, SubSkillType subSkillType, double activationChance) { SubSkillRandomCheckEvent event = new SubSkillRandomCheckEvent(player, subSkillType, activationChance); return !event.isCancelled(); } - /*public static boolean treasureDropSuccessful(Player player, double dropChance, int activationChance) { - SubSkillRandomCheckEvent event = new SubSkillRandomCheckEvent(player, SubSkillType.EXCAVATION_ARCHAEOLOGY, dropChance / activationChance); - mcMMO.p.getServer().getPluginManager().callEvent(event); - return (event.getChance() * activationChance) > (Misc.getRandom().nextDouble() * activationChance) && !event.isCancelled(); - }*/ - - public static boolean isActivationSuccessful(SkillActivationType skillActivationType, AbstractSubSkill abstractSubSkill, Player player) - { - return isActivationSuccessful(skillActivationType, abstractSubSkill.getSubSkillType(), player); - } - - public static String[] calculateAbilityDisplayValues(SkillActivationType skillActivationType, Player player, SubSkillType subSkillType) { + public static String @NotNull [] calculateAbilityDisplayValues(@NotNull SkillActivationType skillActivationType, @NotNull Player player, @NotNull SubSkillType subSkillType) { double successChance = getActivationChance(skillActivationType, subSkillType, player); String[] displayValues = new String[2]; @@ -326,7 +270,7 @@ public class RandomChanceUtil return displayValues; } - public static String[] calculateAbilityDisplayValuesStatic(Player player, PrimarySkillType primarySkillType, double chance) { + public static String @NotNull [] calculateAbilityDisplayValuesStatic(@NotNull Player player, @NotNull PrimarySkillType primarySkillType, double chance) { RandomChanceStatic rcs = new RandomChanceStatic(chance, false); double successChance = getRandomChanceExecutionChance(rcs); @@ -343,7 +287,7 @@ public class RandomChanceUtil return displayValues; } - public static String[] calculateAbilityDisplayValuesCustom(SkillActivationType skillActivationType, Player player, SubSkillType subSkillType, double multiplier) { + public static String @NotNull [] calculateAbilityDisplayValuesCustom(@NotNull SkillActivationType skillActivationType, @NotNull Player player, @NotNull SubSkillType subSkillType, double multiplier) { double successChance = getActivationChance(skillActivationType, subSkillType, player); successChance *= multiplier; //Currently only used for graceful roll String[] displayValues = new String[2]; @@ -358,17 +302,15 @@ public class RandomChanceUtil return displayValues; } - public static double addLuck(Player player, PrimarySkillType primarySkillType, double chance) - { - if(Permissions.lucky(player, primarySkillType)) + public static double addLuck(@NotNull Player player, @NotNull PrimarySkillType primarySkillType, double chance) { + if (Permissions.lucky(player, primarySkillType)) return chance * 1.333D; else return chance; } - public static double addLuck(boolean isLucky, double chance) - { - if(isLucky) + public static double addLuck(boolean isLucky, double chance) { + if (isLucky) return chance * 1.333D; else return chance; From 4aa17e61fc6b9d4e80912d22fb9e299f78e74ad7 Mon Sep 17 00:00:00 2001 From: t00thpick1 Date: Sat, 2 Jan 2021 20:38:27 -0500 Subject: [PATCH 4/8] More efficient acrobatics location memory class --- .../datatypes/BlockLocationHistory.java | 41 +++++++++++++ .../nossr50/datatypes/LimitedSizeList.java | 57 ------------------- .../skills/acrobatics/AcrobaticsManager.java | 6 +- 3 files changed, 44 insertions(+), 60 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/datatypes/BlockLocationHistory.java delete mode 100644 src/main/java/com/gmail/nossr50/datatypes/LimitedSizeList.java diff --git a/src/main/java/com/gmail/nossr50/datatypes/BlockLocationHistory.java b/src/main/java/com/gmail/nossr50/datatypes/BlockLocationHistory.java new file mode 100644 index 000000000..6674cd020 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/datatypes/BlockLocationHistory.java @@ -0,0 +1,41 @@ +package com.gmail.nossr50.datatypes; + +import com.google.common.collect.HashMultiset; +import org.bukkit.Location; + +import java.util.LinkedList; + +/** + * This class works with the assumption that you only pass in Block Locations. If locations have differing pitch/yaw, the logic breaks + */ +public class BlockLocationHistory { + private final LinkedList limitedSizeOrderedList = new LinkedList<>(); + private final HashMultiset lookup = HashMultiset.create(); + private final int maxSize; + + public BlockLocationHistory(int maxSize) { + this.maxSize = maxSize; + } + + /** + * Adds a block location to the history. If the history memory would exceed the max size, it will remove the least recently added block location + * + * @param newItem + */ + public void add(Location newItem) { + limitedSizeOrderedList.addFirst(newItem); + lookup.add(newItem); + if (limitedSizeOrderedList.size() > maxSize) + lookup.remove(limitedSizeOrderedList.removeLast()); + } + + /** + * Returns true if the block location is in the recorded history + * + * @param targetLoc the block location to search for + * @return true if the block location is in the recorded history + */ + public boolean contains(Location targetLoc) { + return lookup.contains(targetLoc); + } +} diff --git a/src/main/java/com/gmail/nossr50/datatypes/LimitedSizeList.java b/src/main/java/com/gmail/nossr50/datatypes/LimitedSizeList.java deleted file mode 100644 index c57b4996f..000000000 --- a/src/main/java/com/gmail/nossr50/datatypes/LimitedSizeList.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.gmail.nossr50.datatypes; - - -import org.bukkit.Location; - -public class LimitedSizeList { - public Location[] limitedSizeOrderedList; - private final int size; - - - public LimitedSizeList(int size) - { - this.size = size; - limitedSizeOrderedList = new Location[size]; - } - - /** - * Adds objects to our limited size ordered list - * New objects are added to the front - * @param newItem - */ - public void add(Location newItem) - { - Location[] newList = new Location[size]; - - for(int i = 0; i < size-1; i++) - { - if(i != 0) - newList[i] = limitedSizeOrderedList[i-1]; - else - newList[i] = newItem; - } - - limitedSizeOrderedList = newList; - } - - /** - * Returns true if the object is anywhere in our list - * @param targetLoc the object to check for - * @return true if the object is in our list - */ - public boolean contains(Location targetLoc) - { - for(Location iter : limitedSizeOrderedList) - { - if(iter == null) - continue; - - if(iter.getX() == targetLoc.getX() - && iter.getY() == targetLoc.getY() - && iter.getZ() == targetLoc.getZ()) - return true; - } - - return false; - } -} diff --git a/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java b/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java index ce8e6d93b..a4903e123 100644 --- a/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java +++ b/src/main/java/com/gmail/nossr50/skills/acrobatics/AcrobaticsManager.java @@ -1,7 +1,7 @@ package com.gmail.nossr50.skills.acrobatics; import com.gmail.nossr50.config.experience.ExperienceConfig; -import com.gmail.nossr50.datatypes.LimitedSizeList; +import com.gmail.nossr50.datatypes.BlockLocationHistory; import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.player.McMMOPlayer; @@ -28,13 +28,13 @@ public class AcrobaticsManager extends SkillManager { public AcrobaticsManager(McMMOPlayer mcMMOPlayer) { super(mcMMOPlayer, PrimarySkillType.ACROBATICS); - fallLocationMap = new LimitedSizeList(50); + fallLocationMap = new BlockLocationHistory(50); } private long rollXPCooldown = 0; private final long rollXPInterval = (1000 * 3); //1 Minute private long rollXPIntervalLengthen = (1000 * 10); //10 Seconds - private final LimitedSizeList fallLocationMap; + private final BlockLocationHistory fallLocationMap; public boolean hasFallenInLocationBefore(Location location) { From 9e2d5aada86efb09ebd9323471715210b4df131c Mon Sep 17 00:00:00 2001 From: t00thpick1 Date: Sat, 2 Jan 2021 20:38:35 -0500 Subject: [PATCH 5/8] Whitespace fix --- .../java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java b/src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java index c1114130c..5f38022d5 100644 --- a/src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java +++ b/src/main/java/com/gmail/nossr50/util/blockmeta/HashChunkManager.java @@ -38,7 +38,7 @@ public class HashChunkManager implements ChunkManager { rf.close(); regionMap.clear(); } - + private synchronized @Nullable ChunkStore readChunkStore(@NotNull World world, int cx, int cz) throws IOException { McMMOSimpleRegionFile rf = getReadableSimpleRegionFile(world, cx, cz); if (rf == null) From a57e6d3bbeb13f02687c7523d72a408bdd7db625 Mon Sep 17 00:00:00 2001 From: t00thpick1 Date: Sat, 2 Jan 2021 20:53:25 -0500 Subject: [PATCH 6/8] Add unit test for BlockLocationHistory Move ChunkStoreTest to correct package --- .../datatypes/BlockLocationHistoryTest.java | 37 +++++++++++++++++++ .../util/blockmeta}/ChunkStoreTest.java | 4 +- 2 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 src/test/java/com/gmail/nossr50/datatypes/BlockLocationHistoryTest.java rename src/test/java/{ => com/gmail/nossr50/util/blockmeta}/ChunkStoreTest.java (99%) diff --git a/src/test/java/com/gmail/nossr50/datatypes/BlockLocationHistoryTest.java b/src/test/java/com/gmail/nossr50/datatypes/BlockLocationHistoryTest.java new file mode 100644 index 000000000..5e9499a17 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/datatypes/BlockLocationHistoryTest.java @@ -0,0 +1,37 @@ +package com.gmail.nossr50.datatypes; + +import org.bukkit.Location; +import org.junit.Assert; +import org.junit.Test; + +public class BlockLocationHistoryTest { + @Test + public void testRemovesOldestElement() { + BlockLocationHistory history = new BlockLocationHistory(2); + Location locationA = new Location(null, 0, 1, 2); + Location locationB = new Location(null, 1, 2, 3); + Location locationC = new Location(null, 2, 3, 4); + + history.add(locationA); + history.add(locationB); + history.add(locationC); + Assert.assertFalse(history.contains(locationA)); + Assert.assertTrue(history.contains(locationB)); + Assert.assertTrue(history.contains(locationC)); + } + + @Test + public void testSupportsDuplicateElement() { + BlockLocationHistory history = new BlockLocationHistory(2); + Location locationA = new Location(null, 0, 1, 2); + Location locationB = new Location(null, 1, 2, 3); + + history.add(locationA); + history.add(locationA); + history.add(locationB); + Assert.assertTrue(history.contains(locationA)); + Assert.assertTrue(history.contains(locationB)); + history.add(locationB); + Assert.assertFalse(history.contains(locationA)); + } +} diff --git a/src/test/java/ChunkStoreTest.java b/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java similarity index 99% rename from src/test/java/ChunkStoreTest.java rename to src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java index 2290ee103..5f1af96da 100644 --- a/src/test/java/ChunkStoreTest.java +++ b/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java @@ -1,10 +1,10 @@ -import com.gmail.nossr50.util.blockmeta.*; +package com.gmail.nossr50.util.blockmeta; + import com.google.common.io.Files; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.block.Block; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.junit.*; import org.junit.runner.RunWith; import org.mockito.Mockito; From 7931a095fe009bfe3f4f584017ad05616449335e Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 3 Jan 2021 12:21:32 -0800 Subject: [PATCH 7/8] Add some tests for com.gmail.nossr50.util.random classes --- Changelog.txt | 2 + .../commands/experience/AddlevelsCommand.java | 2 +- .../commands/experience/AddxpCommand.java | 2 +- .../experience/ExperienceCommand.java | 2 +- .../commands/experience/MmoeditCommand.java | 2 +- .../experience/SkillresetCommand.java | 4 +- .../commands/hardcore/HardcoreCommand.java | 2 +- .../nossr50/commands/skills/SkillCommand.java | 6 +- .../commands/skills/SkillGuideCommand.java | 2 +- .../config/treasure/TreasureConfig.java | 1 - .../database/FlatfileDatabaseManager.java | 2 +- .../nossr50/datatypes/player/McMMOPlayer.java | 7 +- .../datatypes/skills/PrimarySkillType.java | 6 +- .../nossr50/listeners/PlayerListener.java | 2 +- .../nossr50/listeners/WorldListener.java | 4 - .../commands/McrankCommandDisplayTask.java | 2 +- .../commands/MctopCommandDisplayTask.java | 4 +- .../skills/herbalism/HerbalismManager.java | 1 - .../commands/CommandRegistrationManager.java | 2 +- .../util/experience/ExperienceBarManager.java | 2 +- .../util/random/RandomChanceSkill.java | 57 +++------ .../nossr50/util/random/RandomChanceUtil.java | 18 ++- .../util/scoreboards/ScoreboardManager.java | 4 +- .../gmail/nossr50/util/skills/PerksUtils.java | 1 - src/test/java/com/gmail/nossr50/TestUtil.java | 17 +++ .../util/blockmeta/ChunkStoreTest.java | 12 +- .../nossr50/util/random/RandomChanceTest.java | 116 ++++++++++++++++++ 27 files changed, 195 insertions(+), 87 deletions(-) create mode 100644 src/test/java/com/gmail/nossr50/TestUtil.java create mode 100644 src/test/java/com/gmail/nossr50/util/random/RandomChanceTest.java diff --git a/Changelog.txt b/Changelog.txt index 5a72330a5..e4c81a0c3 100644 --- a/Changelog.txt +++ b/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 diff --git a/src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java index 6c736fd2c..8863ab524 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java +++ b/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())); } } diff --git a/src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java index 03ad449bb..7799ef9af 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/AddxpCommand.java +++ b/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())); } } diff --git a/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java index 2443e6d62..6ff0b93ed 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/ExperienceCommand.java +++ b/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)); } } diff --git a/src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java index 9aa02b164..8ef5635e5 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java +++ b/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)); } } diff --git a/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java index 3df1976d9..091ccadca 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/SkillresetCommand.java +++ b/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)); } } diff --git a/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreCommand.java b/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreCommand.java index 6375265b2..2b78c5deb 100644 --- a/src/main/java/com/gmail/nossr50/commands/hardcore/HardcoreCommand.java +++ b/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()))); } } \ No newline at end of file diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java index e550913fa..d7d5bc7df 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillCommand.java +++ b/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)))); } } diff --git a/src/main/java/com/gmail/nossr50/commands/skills/SkillGuideCommand.java b/src/main/java/com/gmail/nossr50/commands/skills/SkillGuideCommand.java index a7879bb8d..f45ceadd3 100644 --- a/src/main/java/com/gmail/nossr50/commands/skills/SkillGuideCommand.java +++ b/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); } diff --git a/src/main/java/com/gmail/nossr50/config/treasure/TreasureConfig.java b/src/main/java/com/gmail/nossr50/config/treasure/TreasureConfig.java index 51e01307e..370f2baa3 100755 --- a/src/main/java/com/gmail/nossr50/config/treasure/TreasureConfig.java +++ b/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; diff --git a/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java b/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java index 4c9753373..e9b5aafed 100644 --- a/src/main/java/com/gmail/nossr50/database/FlatfileDatabaseManager.java +++ b/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; } diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index cc5aebefe..85dd12fe4 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/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); } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java index 6acc8cf5d..f8e0afb5b 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java +++ b/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); } diff --git a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java b/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java index b410a330d..81496c046 100644 --- a/src/main/java/com/gmail/nossr50/listeners/PlayerListener.java +++ b/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)); diff --git a/src/main/java/com/gmail/nossr50/listeners/WorldListener.java b/src/main/java/com/gmail/nossr50/listeners/WorldListener.java index 650a0e0cc..a08071a04 100644 --- a/src/main/java/com/gmail/nossr50/listeners/WorldListener.java +++ b/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; diff --git a/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java b/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java index 353e0ea04..a0e26d306 100644 --- a/src/main/java/com/gmail/nossr50/runnables/commands/McrankCommandDisplayTask.java +++ b/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); diff --git a/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java b/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java index 664a1da10..4901f6bb8 100644 --- a/src/main/java/com/gmail/nossr50/runnables/commands/MctopCommandDisplayTask.java +++ b/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()))); } } diff --git a/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java b/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java index b997f9c89..72fc0e1bb 100644 --- a/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java +++ b/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; } diff --git a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java b/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java index 215c160d8..f072d2440 100644 --- a/src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java +++ b/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; diff --git a/src/main/java/com/gmail/nossr50/util/experience/ExperienceBarManager.java b/src/main/java/com/gmail/nossr50/util/experience/ExperienceBarManager.java index 7a49a1260..22e14de09 100644 --- a/src/main/java/com/gmail/nossr50/util/experience/ExperienceBarManager.java +++ b/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"); } diff --git a/src/main/java/com/gmail/nossr50/util/random/RandomChanceSkill.java b/src/main/java/com/gmail/nossr50/util/random/RandomChanceSkill.java index 67221a433..c77a9e9a1 100644 --- a/src/main/java/com/gmail/nossr50/util/random/RandomChanceSkill.java +++ b/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; - } } diff --git a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java b/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java index 885ff3a90..a6f27ef54 100644 --- a/src/main/java/com/gmail/nossr50/util/random/RandomChanceUtil.java +++ b/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); + } } diff --git a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java b/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java index ad32306ae..119138ca6 100644 --- a/src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java +++ b/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())); diff --git a/src/main/java/com/gmail/nossr50/util/skills/PerksUtils.java b/src/main/java/com/gmail/nossr50/util/skills/PerksUtils.java index 588b944e1..1aa39105a 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/PerksUtils.java +++ b/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; diff --git a/src/test/java/com/gmail/nossr50/TestUtil.java b/src/test/java/com/gmail/nossr50/TestUtil.java new file mode 100644 index 000000000..341bf4fc0 --- /dev/null +++ b/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(); + } +} diff --git a/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java b/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java index 5f1af96da..450cd7222 100644 --- a/src/test/java/com/gmail/nossr50/util/blockmeta/ChunkStoreTest.java +++ b/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) diff --git a/src/test/java/com/gmail/nossr50/util/random/RandomChanceTest.java b/src/test/java/com/gmail/nossr50/util/random/RandomChanceTest.java new file mode 100644 index 000000000..b6e2e51f8 --- /dev/null +++ b/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); + } +} From 7ea6809fd39219129243d7d5b7e8d8eccd46b033 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sun, 3 Jan 2021 12:22:58 -0800 Subject: [PATCH 8/8] 2.1.168 --- Changelog.txt | 1 - pom.xml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index e4c81a0c3..b30478c11 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -3,7 +3,6 @@ Version 2.1.168 (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 Add McMMOPlayerPreXpGainEvent event for plugins to modify given exp (thanks electronicboy) diff --git a/pom.xml b/pom.xml index 85553551c..7063867ce 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.168-SNAPSHOT + 2.1.168 mcMMO https://github.com/mcMMO-Dev/mcMMO