Limit XP on certain plants which can become unnaturally tall Fixes #5045

This commit is contained in:
nossr50 2024-07-27 15:42:18 -07:00
parent 486dc1344d
commit afa4260d0d
4 changed files with 52 additions and 3 deletions

View File

@ -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) 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) Blast Mining will no longer drop mob spawners (see notes)
(Codebase) Added more unit tests for Probability and RNG (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: 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. 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. 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 Version 2.2.017
Fixed a bug with default Mace permissions (thanks SrBedrock) Fixed a bug with default Mace permissions (thanks SrBedrock)
Fixed Blast Mining being almost completely broken Fixed Blast Mining being almost completely broken

View File

@ -496,4 +496,8 @@ public class ExperienceConfig extends BukkitConfig {
public boolean preventStoneLavaFarming() { public boolean preventStoneLavaFarming() {
return config.getBoolean("ExploitFix.LavaStoneAndCobbleFarming", true); return config.getBoolean("ExploitFix.LavaStoneAndCobbleFarming", true);
} }
public boolean limitXPOnTallPlants() {
return config.getBoolean("ExploitFix.LimitTallPlantFarming", true);
}
} }

View File

@ -46,6 +46,18 @@ import static com.gmail.nossr50.util.ItemUtils.removeItemIncludingOffHand;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
public class HerbalismManager extends SkillManager { public class HerbalismManager extends SkillManager {
private final static HashMap<String, Integer> 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) { public HerbalismManager(McMMOPlayer mcMMOPlayer) {
super(mcMMOPlayer, PrimarySkillType.HERBALISM); super(mcMMOPlayer, PrimarySkillType.HERBALISM);
} }
@ -408,6 +420,7 @@ public class HerbalismManager extends SkillManager {
public void awardXPForPlantBlocks(HashSet<Block> brokenPlants) { public void awardXPForPlantBlocks(HashSet<Block> brokenPlants) {
int xpToReward = 0; int xpToReward = 0;
int firstXpReward = -1;
for(Block brokenPlantBlock : brokenPlants) { for(Block brokenPlantBlock : brokenPlants) {
BlockState brokenBlockNewState = brokenPlantBlock.getState(); 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 its a Crop we need to reward XP when its fully grown
if (isAgeableAndFullyMature(plantData) && !isBizarreAgeable(plantData)) { if (isAgeableAndFullyMature(plantData) && !isBizarreAgeable(plantData)) {
xpToReward += ExperienceConfig.getInstance().getXp(PrimarySkillType.HERBALISM, brokenBlockNewState.getType()); xpToReward += ExperienceConfig.getInstance().getXp(PrimarySkillType.HERBALISM, brokenBlockNewState.getType());
if (firstXpReward == -1)
firstXpReward = xpToReward;
} }
//Mark it as natural again as it is being broken //Mark it as natural again as it is being broken
@ -441,10 +456,14 @@ public class HerbalismManager extends SkillManager {
if (isAgeableMature(plantAgeable) || isBizarreAgeable(plantData)) { if (isAgeableMature(plantAgeable) || isBizarreAgeable(plantData)) {
xpToReward += ExperienceConfig.getInstance().getXp(PrimarySkillType.HERBALISM, brokenBlockNewState.getType()); xpToReward += ExperienceConfig.getInstance().getXp(PrimarySkillType.HERBALISM, brokenBlockNewState.getType());
if (firstXpReward == -1)
firstXpReward = xpToReward;
} }
} else { } else {
xpToReward += ExperienceConfig.getInstance().getXp(PrimarySkillType.HERBALISM, brokenPlantBlock.getType()); xpToReward += ExperienceConfig.getInstance().getXp(PrimarySkillType.HERBALISM, brokenPlantBlock.getType());
if (firstXpReward == -1)
firstXpReward = xpToReward;
} }
} }
} }
@ -455,9 +474,30 @@ public class HerbalismManager extends SkillManager {
//Reward XP //Reward XP
if (xpToReward > 0) { if (xpToReward > 0) {
// 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); 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) { public boolean isAgeableMature(Ageable ageable) {
return ageable.getAge() == ageable.getMaximumAge() return ageable.getAge() == ageable.getMaximumAge()
@ -572,7 +612,8 @@ public class HerbalismManager extends SkillManager {
if (isChorusBranch(brokenBlock.getType())) { if (isChorusBranch(brokenBlock.getType())) {
brokenBlocks = getBrokenChorusBlocks(brokenBlock); brokenBlocks = getBrokenChorusBlocks(brokenBlock);
} else { } else {
brokenBlocks = getBlocksBrokenAboveOrBelow(brokenBlock, false, mcMMO.getMaterialMapStore().isMultiBlockHangingPlant(brokenBlock.getType())); brokenBlocks = getBlocksBrokenAboveOrBelow(
brokenBlock, false, mcMMO.getMaterialMapStore().isMultiBlockHangingPlant(brokenBlock.getType()));
} }
return brokenBlocks; return brokenBlocks;

View File

@ -34,6 +34,8 @@ ExploitFix:
# mcMMO normally doesn't process attacks against an Entity if it is an NPC from another plugin # 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 # 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 PreventPluginNPCInteraction: true
# This will limit XP gained from unnaturally tall plants, like those created by Bone Meal
LimitTallPlantFarming: true
Fishing_ExploitFix_Options: Fishing_ExploitFix_Options:
MoveRange: 3 MoveRange: 3
OverFishLimit: 10 OverFishLimit: 10