From 32b7ef501ba95ab115c3ec2dbfd23ad56bc4b133 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 2 Jul 2026 08:34:54 +0000 Subject: [PATCH] Fix goal-priority starvation and spurious anti-cheese triggers for zombies/spiders AdaptiveZombiePackTacticsGoal and AdaptiveSpiderTacticsGoal shared their goalSelector priority with vanilla's melee attack goal, so per WrappedGoal.canBeReplacedBy() they could never interrupt it once a mob was already fighting - the new tactics essentially never ran in combat. Give them strictly lower priority numbers than the vanilla attack goal (and below the disengage/flee goal for spiders) so they can actually take over. Also fix AdaptiveAntiCheeseGoal.canUse(), which fell back to a bare cooldown check when no real trap/obstacle condition applied, causing it to fire every few seconds and briefly steal MOVE/LOOK control for nothing. canUse() now mirrors the actual conditions checked in start() so it only triggers when there's something to correct. --- .../adaptivemobs/ai/AdaptiveGoalInjector.java | 10 +++++--- .../ai/goals/AdaptiveAntiCheeseGoal.java | 24 ++++++++++++++++--- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/fretux/adaptivemobs/ai/AdaptiveGoalInjector.java b/src/main/java/net/fretux/adaptivemobs/ai/AdaptiveGoalInjector.java index f971f5c..81ab166 100644 --- a/src/main/java/net/fretux/adaptivemobs/ai/AdaptiveGoalInjector.java +++ b/src/main/java/net/fretux/adaptivemobs/ai/AdaptiveGoalInjector.java @@ -102,7 +102,9 @@ public final class AdaptiveGoalInjector { mob.goalSelector.addGoal(4, new AdaptiveFlankGoal(pathfinder, tier, 2, 8.0D, 1.0D, true)); } else if (pathfinder != null && mob instanceof Zombie && AMConfig.AI_ZOMBIE.get()) { mob.goalSelector.addGoal(3, new AdaptiveFlankGoal(pathfinder, tier, 2, 2.5D, 1.05D, true)); - mob.goalSelector.addGoal(2, new AdaptiveZombiePackTacticsGoal((Zombie) mob, tier)); + // Priority 1: must be able to interrupt the vanilla melee attack goal (priority 2), + // otherwise it can never take over while the zombie is already fighting. + mob.goalSelector.addGoal(1, new AdaptiveZombiePackTacticsGoal((Zombie) mob, tier)); } else if (pathfinder != null && mob instanceof Creeper creeper && AMConfig.AI_CREEPER.get()) { mob.goalSelector.addGoal(2, new AdaptiveCreeperPressureGoal(creeper, tier)); mob.goalSelector.addGoal(4, new AdaptiveFlankGoal(pathfinder, tier, 2, 3.0D, 1.0D, false)); @@ -159,8 +161,10 @@ public final class AdaptiveGoalInjector { mob.goalSelector.addGoal(3, new AdaptiveCreeperTacticsGoal(creeper, tier)); } if (pathfinder != null && mob instanceof Spider && AMConfig.ENABLE_SPIDER_AI.get() && AMConfig.AI_SPIDER.get()) { - mob.goalSelector.addGoal(3, new AdaptiveSpiderTacticsGoal(pathfinder, tier, mob instanceof CaveSpider)); - mob.goalSelector.addGoal(2, new AdaptiveSpiderDisengageGoal(pathfinder, tier, mob instanceof CaveSpider ? 3 : 4, 0.14D, 1.3D)); + // Priority 2: below disengage (1, flee always wins) but still above the vanilla + // attack goal (3) so it can actually interrupt combat instead of being starved by it. + mob.goalSelector.addGoal(2, new AdaptiveSpiderTacticsGoal(pathfinder, tier, mob instanceof CaveSpider)); + mob.goalSelector.addGoal(1, new AdaptiveSpiderDisengageGoal(pathfinder, tier, mob instanceof CaveSpider ? 3 : 4, 0.14D, 1.3D)); mob.goalSelector.addGoal(5, new AdaptiveLowHealthRetreatGoal(pathfinder, tier, 4, 0.38D, 1.15D)); } if (mob instanceof Witch witch && AMConfig.ENABLE_WITCH_AI.get() && AMConfig.AI_WITCH.get()) { diff --git a/src/main/java/net/fretux/adaptivemobs/ai/goals/AdaptiveAntiCheeseGoal.java b/src/main/java/net/fretux/adaptivemobs/ai/goals/AdaptiveAntiCheeseGoal.java index 4d09d9b..79ae789 100644 --- a/src/main/java/net/fretux/adaptivemobs/ai/goals/AdaptiveAntiCheeseGoal.java +++ b/src/main/java/net/fretux/adaptivemobs/ai/goals/AdaptiveAntiCheeseGoal.java @@ -45,13 +45,31 @@ public class AdaptiveAntiCheeseGoal extends Goal { if (target == null || !target.isAlive()) { return false; } - if (isInTrapVehicle() || isNearTrapVehicle()) { + if (isInTrapVehicle() || isNearTrapVehicle() || nearestTrapBlock() != null) { return true; } - if (tierSupplier.getAsInt() >= 5 && mob instanceof Zombie && isVerticalObstacleCheese(target)) { + if (--cooldown > 0) { + return false; + } + if (mob instanceof Zombie && isVerticalObstacleCheese(target)) { return true; } - return --cooldown <= 0; + if ((mob instanceof AbstractSkeleton || mob instanceof Pillager) && !mob.hasLineOfSight(target)) { + return true; + } + if (mob instanceof Creeper creeper && target.hasLineOfSight(creeper) + && AdaptivePositioningUtils.isOpenToSky(mob) + && Math.sqrt(mob.distanceToSqr(target)) > 4.0D) { + return true; + } + if (mob instanceof EnderMan && (mob.level().getFluidState(mob.blockPosition()).is(FluidTags.WATER) + || target.level().getFluidState(target.blockPosition()).is(FluidTags.WATER))) { + return true; + } + // Nothing to correct right now; keep the cooldown short so we re-check soon instead of + // burning a long cooldown on a tick where no cheese pattern was actually detected. + cooldown = 10 + mob.getRandom().nextInt(15); + return false; } @Override