From afa4260d0d0c43da54f45c1c195460e94e157d84 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Sat, 27 Jul 2024 15:42:18 -0700 Subject: [PATCH] Limit XP on certain plants which can become unnaturally tall Fixes #5045 --- Changelog.txt | 4 +- .../config/experience/ExperienceConfig.java | 4 ++ .../skills/herbalism/HerbalismManager.java | 45 ++++++++++++++++++- src/main/resources/experience.yml | 2 + 4 files changed, 52 insertions(+), 3 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 195e7498e..78c9e1142 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -2,11 +2,13 @@ Version 2.2.018 Fixed a probability bug where certain skills would max out in chance to succeed well before they were supposed to (such as Dodge) Blast Mining will no longer drop mob spawners (see notes) (Codebase) Added more unit tests for Probability and RNG + The Herbalism XP gained when breaking certain plants that can grow unnaturally tall vertically (bamboo, kelp) is now capped to the most it could give when naturally grown, this can be disabled in experience.yml + Added 'ExploitFix.LimitTallPlantFarming' to experience.yml NOTES: This probability bug was a big oopsie and showed a gap in unit test coverage, I've added that coverage and a bug like this in theory shouldn't happen again. In a future version I will add configuration for admins to control what blocks are not allowed to be dropped by blast mining. - + A setting has been added to disable player-created super tall plants from giving full XP, this is on by default, you can tun it off in experience.yml via 'ExploitFix.LimitTallPlantFarming' Version 2.2.017 Fixed a bug with default Mace permissions (thanks SrBedrock) Fixed Blast Mining being almost completely broken diff --git a/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java b/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java index 4eddee5db..cd9e5a768 100644 --- a/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java +++ b/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java @@ -496,4 +496,8 @@ public class ExperienceConfig extends BukkitConfig { public boolean preventStoneLavaFarming() { return config.getBoolean("ExploitFix.LavaStoneAndCobbleFarming", true); } + + public boolean limitXPOnTallPlants() { + return config.getBoolean("ExploitFix.LimitTallPlantFarming", true); + } } 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 0e39750ca..a5f1bf17a 100644 --- a/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java +++ b/src/main/java/com/gmail/nossr50/skills/herbalism/HerbalismManager.java @@ -46,6 +46,18 @@ import static com.gmail.nossr50.util.ItemUtils.removeItemIncludingOffHand; import static java.util.Objects.requireNonNull; public class HerbalismManager extends SkillManager { + private final static HashMap plantBreakLimits; + + static { + plantBreakLimits = new HashMap<>(); + plantBreakLimits.put("cactus", 3); + plantBreakLimits.put("bamboo", 20); + plantBreakLimits.put("sugar_cane", 3); + plantBreakLimits.put("kelp", 26); + plantBreakLimits.put("kelp_plant", 26); + plantBreakLimits.put("chorus_plant", 22); + } + public HerbalismManager(McMMOPlayer mcMMOPlayer) { super(mcMMOPlayer, PrimarySkillType.HERBALISM); } @@ -408,6 +420,7 @@ public class HerbalismManager extends SkillManager { public void awardXPForPlantBlocks(HashSet brokenPlants) { int xpToReward = 0; + int firstXpReward = -1; for(Block brokenPlantBlock : brokenPlants) { BlockState brokenBlockNewState = brokenPlantBlock.getState(); @@ -424,6 +437,8 @@ public class HerbalismManager extends SkillManager { //If its a Crop we need to reward XP when its fully grown if (isAgeableAndFullyMature(plantData) && !isBizarreAgeable(plantData)) { xpToReward += ExperienceConfig.getInstance().getXp(PrimarySkillType.HERBALISM, brokenBlockNewState.getType()); + if (firstXpReward == -1) + firstXpReward = xpToReward; } //Mark it as natural again as it is being broken @@ -441,10 +456,14 @@ public class HerbalismManager extends SkillManager { if (isAgeableMature(plantAgeable) || isBizarreAgeable(plantData)) { xpToReward += ExperienceConfig.getInstance().getXp(PrimarySkillType.HERBALISM, brokenBlockNewState.getType()); + if (firstXpReward == -1) + firstXpReward = xpToReward; } } else { xpToReward += ExperienceConfig.getInstance().getXp(PrimarySkillType.HERBALISM, brokenPlantBlock.getType()); + if (firstXpReward == -1) + firstXpReward = xpToReward; } } } @@ -455,10 +474,31 @@ public class HerbalismManager extends SkillManager { //Reward XP if (xpToReward > 0) { - applyXpGain(xpToReward, XPGainReason.PVE, XPGainSource.SELF); + // get first block from hash set using stream API + final Block firstBlock = brokenPlants.stream().findFirst().orElse(null); + if (firstBlock != null + && firstXpReward != -1 + && ExperienceConfig.getInstance().limitXPOnTallPlants() + && plantBreakLimits.containsKey(firstBlock.getType().getKey().getKey())) { + int limit = plantBreakLimits.get(firstBlock.getType().getKey().getKey()) * firstXpReward; + // Plant may be unnaturally tall, limit XP + applyXpGain(Math.min(xpToReward, limit), XPGainReason.PVE, XPGainSource.SELF); + } else { + applyXpGain(xpToReward, XPGainReason.PVE, XPGainSource.SELF); + } } } + private int getNaturalGrowthLimit(Material brokenPlant) { + // This is an exploit counter-measure to prevent players from growing unnaturally tall plants and reaping XP + if (plantBreakLimits.containsKey(brokenPlant.getKey().getKey())) { + return plantBreakLimits.get(brokenPlant.getKey().getKey()); + } else { + return 0; + } + } + + public boolean isAgeableMature(Ageable ageable) { return ageable.getAge() == ageable.getMaximumAge() && ageable.getAge() != 0; @@ -572,7 +612,8 @@ public class HerbalismManager extends SkillManager { if (isChorusBranch(brokenBlock.getType())) { brokenBlocks = getBrokenChorusBlocks(brokenBlock); } else { - brokenBlocks = getBlocksBrokenAboveOrBelow(brokenBlock, false, mcMMO.getMaterialMapStore().isMultiBlockHangingPlant(brokenBlock.getType())); + brokenBlocks = getBlocksBrokenAboveOrBelow( + brokenBlock, false, mcMMO.getMaterialMapStore().isMultiBlockHangingPlant(brokenBlock.getType())); } return brokenBlocks; diff --git a/src/main/resources/experience.yml b/src/main/resources/experience.yml index 08b53f7b7..54605ef4b 100644 --- a/src/main/resources/experience.yml +++ b/src/main/resources/experience.yml @@ -34,6 +34,8 @@ ExploitFix: # mcMMO normally doesn't process attacks against an Entity if it is an NPC from another plugin # Of course, mcMMO doesn't know for sure whether something is an NPC, it checks a few known things, see our source code to see how PreventPluginNPCInteraction: true + # This will limit XP gained from unnaturally tall plants, like those created by Bone Meal + LimitTallPlantFarming: true Fishing_ExploitFix_Options: MoveRange: 3 OverFishLimit: 10