v3.1.5 — stop combat scream-loop
Phase 0 hot patch from the architectural-rethink plan (see plans/synthetic-shimmying-piglet.md). Unblocks combat without the full v3.2.0 target-ownership rewrite.
The bug
Squire entered combat (scream fired, tactic was set), then target got cleared, state fell back to IDLE, vanilla NearestAttackableTargetGoal immediately re-targeted the same mob, combat-enter fired again → scream again. Cycle: screams every 5 ticks, never swings. Confirmed via /squire info diagnostic in v3.1.4.
Root cause
CombatHandler.tick called s.setTarget(null) on its follow-range check when the target exceeded 32 blocks. Vanilla's target goals run on their own cadence and don't coordinate with the custom FSM — every clear produced an immediate re-set. Race.
Fix
- The follow-range check no longer clears the target. It just stops pathing and returns
COMBAT_APPROACH, allowing resumption when the target re-enters range. Target lifecycle is now owned by the combat-exit transition (fires on null/dead target) and — in v3.2.0 — by a newSquireTargetSuggestionGoalthat will replace the racing vanilla goals entirely. - Added
ChatHandler.sendLineWithCooldownas defense-in-depth.COMBAT_STARTevents are now rate-limited to one chat line per 2 seconds per squire,WORK_TASK_COMPLETEto one per 3 seconds. Even if a future state bug causes another storm, chat stays sane.
Install
Drop squire-mod-v2-3.1.5.jar into your mods/ folder. NeoForge 1.21.1, Minecraft 1.21.1.
Full Changelog: v3.1.4...v3.1.5