Skip to content

Pathfinding optimization#3076

Draft
BruceChenQAQ wants to merge 86 commits intoMCCTeam:masterfrom
BruceChenQAQ:master
Draft

Pathfinding optimization#3076
BruceChenQAQ wants to merge 86 commits intoMCCTeam:masterfrom
BruceChenQAQ:master

Conversation

@BruceChenQAQ
Copy link
Copy Markdown
Collaborator

No description provided.

…gine

Implement the three Phase 0 prerequisites for the pathfinding rewrite:

- Pose system (vanilla Player.updatePlayerPose): dynamic AABB height based
  on current pose -- Standing (1.8), Sneaking (1.5), Swimming/Crawling (0.6).
  Automatically downgrades pose when headroom is insufficient (Standing ->
  Sneaking -> Swimming), matching vanilla 1.14+ forced-crawl behavior.

- Slime block bounce (vanilla SlimeBlock.bounceUp / stepOn): reverses
  downward velocity on landing, with sneaking suppression via
  isSuppressingBounce(). Also applies the horizontal slowdown effect
  from SlimeBlock.stepOn when walking on slime with low vertical velocity.

- Per-pose dimension constants in PhysicsConsts with eye heights for each
  pose, sourced from vanilla Avatar.POSES (26.1 decompiled).

- Debug logging for pose transitions, slime bounces, and periodic physics
  state dumps routed through McClient's ILogger.

Tested on a real 1.21.11 server: crawling triggers correctly under 1-block
ceilings, sneaking under 1.5-block ceilings, slime bounce produces correct
decaying oscillation, and pose recovery works when obstacles are removed.

Made-with: Cursor
Implements the new Baritone-inspired A* pathfinding system:
- Core types: PathNode, PathResult, MoveResult, MoveType, ActionCosts
- BinaryHeapOpenSet min-heap for A* open set
- AStarPathFinder with timeout, cancellation, partial path support
- CalculationContext for thread-safe world state snapshots
- MoveHelper for block passability checks
- IGoal interface + GoalBlock, GoalXZ, GoalNear, GoalComposite
- IMove interface + MoveTraverse, MoveDiagonal, MoveAscend, MoveDescend, MoveClimb
- /pathfind command for testing the new pathfinder

Made-with: Cursor
The X and Z fields shared bit 36, causing nodes like (1,80,0)
and (0,80,0) to hash to the same value. Fixed by using proper
non-overlapping bit allocation: X in bits 38-63, Z in bits 12-37,
Y in bits 0-11. Added diagnostic logging to pathfind command.

Made-with: Cursor
Remove verbose per-node insertion tracking from A*. Keep essential
logging: start, goal reached, partial/failed results. Clean up
pathfind command with exception handling and cleaner output.

Made-with: Cursor
- Add MoveFall move for straight-down falls beyond MoveDescend range
- Register MoveFall in default move set
- Create /goto command using new A* pathfinder
- Add MoveToAStar() method to McClient bridging A* results to existing
  path execution system (Queue<Location> + UpdatePathfindingInput)
- Add translation entries for goto command

Made-with: Cursor
- Fix MoveHelper.CanWalkThrough to treat climbable blocks (ladders, vines)
  as passable, not solid -- MCC's IsSolid() incorrectly classifies them
- Fix MoveHelper.CanWalkOn to exclude climbable blocks from ground check
- Add fence gate passability in MoveHelper
- Fix start position calculation in MoveToAStar to handle solid-block
  floor rounding (player at y=79.9 → floor y=79 inside solid)
- Fix ReachedWaypoint to require vertical proximity for climb waypoints,
  preventing premature waypoint consumption during ladder ascent
- Fix SetInputToward to handle ladder climbing with Jump input and proper
  wall-facing when OnClimbable

Made-with: Cursor
…dling

Refactor movement tick into AdvanceWaypoint(), add look-ahead logic that
detects vertical-only waypoints and merges to the next horizontal waypoint
early to handle ladder-to-platform transitions, and add jump input when
horizontally aligned but needing to reach a higher Y level.

Made-with: Cursor
Phase 2.2: MoveParkour for sprint-jump across 1-2 block gaps (distance 2-3)
and ascending parkour (distance 2, +1Y). Registered in BuildDefaultMoves
with CalculationContext.AllowParkour gating.

Phase 3.1-3.2: Template execution engine replacing the waypoint queue system.
- IActionTemplate interface with per-tick state machine pattern
- Templates: Walk, Ascend, Descend, Climb, Fall, SprintJump
- ActionTemplateFactory maps MoveType to the correct template
- PathExecutor drives sequential template execution with logging
- PathSegmentManager handles replanning on failure (up to 5 retries)
- McClient integration: MoveToAStar now creates PathSegmentManager,
  UpdatePathfindingInput delegates to it, CancelMovement/ClientIsMoving
  updated for both old and new systems.

Tested on 1.21.11: straight walk, zigzag maze, stair ascent,
1-gap and 2-gap sprint jumps all pass.

Made-with: Cursor
…anilla

Two bugs in CollisionDetector caused persistent Y-axis bouncing (0.6 block
oscillation) while walking on flat ground:

1. GetAxisStepOrder used a complex 6-branch sorting that often placed
   horizontal axes before Y. Vanilla's Direction.Axis.axisStepOrder always
   resolves Y first, then the larger horizontal axis. Replaced with the
   simple two-case vanilla logic.

2. The horizontal-blocked checks (blockedX/blockedZ) used exact != which
   triggered on floating-point noise (~1e-15) from sin/cos in movement
   input. Vanilla uses Mth.equal (1e-5 threshold). This false positive
   caused step-up to fire every few ticks on flat terrain.

Also includes DescendTemplate robustness fixes from the previous session
(fail on unintended climbing, suppress forward input on climbable blocks).

Made-with: Cursor
…mentum

Templates now set Forward/Sprint input before checking completion
conditions. This prevents a 1-tick input gap during template transitions
that caused the player to lose sprint speed, making parkour jumps fail
due to insufficient horizontal velocity.

Made-with: Cursor
…port

MoveParkour rewritten to support both cardinal and diagonal sprint jumps
with unified (xOff, zOff) interface. New capabilities:

- 4-block cardinal sprint jumps with edge-approach timing in template
- Diagonal parkour: (2,1), (1,2), (2,2), (3,1), (1,3) in all quadrants
- Ascending parkour extended to dist=3 (cardinal)
- Overshoot safety check after landing destination
- Block parkour from climbable starting blocks (vine/ladder)

MoveDescend/MoveFall enhanced with Baritone-style dynamic fall scanning:
- Water landing: accepts falls of any height into water
- Mid-fall ladder/vine grab: resets effective fall height (<=11 blocks)
- CalculationContext gains MaxFallHeightWater, AllowLadderGrabDuringFall

SprintJumpTemplate gains distance-based approach timing:
- Long jumps (>=3.5 blocks): delays jump until 0.5 blocks from center
- Medium jumps (>=2.5): 0.35 blocks approach
- Landing tolerance scales with jump distance

All movements verified on 1.21.11 local server.

Made-with: Cursor
- Fix MoveHelper.IsOpenGate: MangroveWood -> MangroveFenceGate
- Fix ResetStateForTransfer to cancel and clear pathSegmentManager
- Fix GetCurrentMovementGoal to return correct goal during A* navigation
- Fix SetMovementSpeed(Sneak) speed value consistency (2 -> 1)
- Migrate /pathfind command to use MoveToAStar + PathSegmentManager
- Add NavigateToGoal(IGoal) to McClient for flexible goal navigation
- Refactor MoveToAStar to delegate to NavigateToGoal
- Add ChatBot API: NavigateTo, CancelMovement, GetCurrentMovementGoal
- Expose PathSegmentManager.Goal property for external goal inspection

Made-with: Cursor
WalkTemplate now detects when physics.OnClimbable is true (player entering
a ladder/vine block) and switches from Sprint to Jump input, with extended
stuck detection thresholds. This prevents the template from failing when
the path walks through climbable blocks.

Tested on 1.21.11: all movement types pass (walk, diagonal, ascend, descend,
climb, parkour 2-4 gap, mixed courses with direction changes).

Made-with: Cursor
- ClimbTemplate: add explicit descent handling with horizontal drift
  correction instead of relying on no-input gravity alone
- DescendTemplate: on climbable blocks, suppress Forward input to
  prevent HorizontalCollision-triggered upward bumps, allowing gravity
  to slide the player down naturally
- MoveClimb: restrict climb-up past the top of a climbable column --
  only allow if there is solid ground to stand on at destination,
  preventing impossible vine-top exits where the player would fall back

Made-with: Cursor
…king

- WalkTemplate: remove OnClimbable jump/sprint logic that caused the
  player to jump when walking past vine blocks during flat traversal
- TemplateHelper: add CalculatePitch() for computing the look angle
  toward a 3D target relative to eye height
- All templates (Walk, Ascend, Descend, Climb, SprintJump): set
  physics.Pitch each tick so the player visually looks toward the
  current path target direction
- McClient: sync playerPitch and set _yaw/_pitch after pathfinding
  ticks so rotation is included in position update packets sent to
  the server

Made-with: Cursor
- Add MoveDiagonalAscend and MoveDiagonalDescend for "corner" moves:
  step diagonally around a wall edge while ascending/descending 1 block.
  Requires at least one intermediate cardinal direction to be passable.

- Fix pitch calculation: look toward target's eye level (same height
  delta as feet delta) instead of subtracting eye height, which caused
  the player to stare at the ground during flat walks.

- Add Yaw/Pitch smoothing via SmoothYaw/SmoothPitch in TemplateHelper.
  Max 35 deg/tick for yaw, 25 deg/tick for pitch. Prevents instant
  camera snaps between path segments while still being responsive
  enough for sprint-jumps and tight maneuvers.

- Apply smoothing to all five action templates (Walk, Ascend, Descend,
  Climb, SprintJump).

Made-with: Cursor
- MoveDiagonal: allow single-side-blocked diagonals (corner walk) so
  the bot can hug an open side to cut around a wall; both-sides-blocked
  remains impossible. Walk-speed cost when one side is blocked.
- MoveSprintDescend: sprint off a ledge covering 2 horizontal blocks
  while dropping 1-3 blocks. Registered for cardinal and diagonal
  offsets.
- MoveParkour: support negative yDelta (-1, -2) for descending parkour
  where the bot sprint-jumps across a gap and lands on a lower
  platform. Registered cardinal (dist 2-4, y-1/-2) and diagonal
  variants.
- DescendTemplate: sprint when horizontal distance > 1.5 blocks.
- SprintJumpTemplate: increase vertical landing tolerance for descend.

Made-with: Cursor
…end checks

- MoveParkour: replace full-rectangle intermediate check with diagonal
  strip check (CheckFlightPath) so walls outside the actual flight
  corridor no longer block valid parkour jumps.
- MoveParkour: require both cardinal neighbors passable for diagonal
  parkour takeoff; a wall on either side clips the AABB and prevents
  reaching the target.
- MoveSprintDescend: replace full-rectangle check with explicit
  per-axis intermediate column check.
- SprintJumpTemplate: track diagonal jumps and skip approach delay for
  short diagonal jumps to avoid overshooting small starting platforms.

Made-with: Cursor
…live test fixes

Theory simulator:
- Add 2D side-wall jump physics with yaw sweep for worst-case margin
- Generate sidewall theory cases (flat/ascend/descend, wall_offset 0/1)
- Add momentum-capabilities.json with band compression and max_reach
- Extend models, capabilities, canonical, and renderers for sidewall

Full-coverage parkour test suite (tools/test-parkour.py):
- Derive test matrix from momentum-capabilities.json
- Build linear/neo/ceiling courses via RCON with 7-block clear margin
- Use /goto for pathfinding, parse A* and PathMgr log output
- Stop-at-first-failure per (family, subfamily, dy, ceil, wo) group
- Hierarchical --filter (e.g. linear/flat, ceiling/headhitter/ceil2.5)
- Exclude sidewall from default matrix (identical max_reach to linear)

Pathing execution fixes:
- Align parkour contracts and timing budgets with live test results
- Fix jump-entry yaw snapping for grounded handoffs
- Template helper and sprint jump template refinements

Made-with: Cursor
Move PathSegmentManager's Replan to Task.Run so the main tick only reads
results and swaps executors, and introduce a _nextExecutor pre-planning
slot so upcoming segments can prepare while the current one finishes.

Relax per-tick yaw/pitch rate limiting: allow instantaneous snapping
before jump ticks (Baritone does this and servers do not kick for it).

Align jump-template success/failure contracts with Baritone:
- Success key shifts from "speed squared" to "feet-on-target block".
- Failure window widened to the ~200 tick range.
- AscendTemplate gets a headBonkClear + edge/side proximity
  precondition so launches only happen from a safe takeoff.

Expose an initialMomentumTicks option on TemplateSimulationRunner so
follow-up sidewall scenarios can warm up physics before a template
starts.

Made-with: Cursor
Introduce an EntryPreparationState carried on PathNode + A* context so
sidewall parkour can explicitly request one or more runway traverses
before takeoff instead of silently dropping the move. ParkourFeasibility
gains TryGetRequiredStaticEntryRunupSteps + HasPreparedRunup helpers so
long descends (major=5, dy=-1) only remain feasible when the preceding
node proved the runup.

Widen HasDominantAxisRunUp to accept cold-start sprint-jumps within
~3.1-3.5 blocks horizontally so lone overhang / staircase takeoffs stay
feasible without a 2-block runway (matches Baritone's MomentumBehavior
.ALLOWED contract).

Add a runtime SidewallParkourController that implements the corner
commitment + wall-hug chain during execution.

Extend pathing test fixtures with InitialMomentumTicks, add sidewall
accepted/rejected scenarios, and refresh timing + contract baselines to
reflect the new planner shapes. Document the design in
docs/superpowers/specs and plans.

Made-with: Cursor
Replace seven hand-written IMove classes (MoveTraverse, MoveDiagonal,
MoveAscend, MoveDiagonalAscend, MoveDiagonalDescend, MoveParkour,
MoveSidewallParkour) with a single MoveJump driven by a JumpDescriptor
(XOffset, ZOffset, YDelta, JumpFlavor). JumpFeasibility is the single
source of truth for the physics/cost rules of every jump-family move.

A* no longer iterates a flat IMove[]. The Calculate loop now drives
an IMoveExpander[] that writes into a stackalloc Span<MoveNeighbor>,
eliminating per-iteration heap traffic. JumpExpander enumerates every
jump-family descriptor dynamically; LegacyMoveExpander wraps the
remaining dynamic-landing moves (MoveDescend, MoveSprintDescend,
MoveClimb, MoveFall) so callers that still pass a custom IMove[]
keep working.

Add two O(1) short-circuits at the top of JumpExpander.Expand:
- Hoist the per-node parkour preconditions (AllowParkour + CanSprint,
  standing block climbability, feet-liquid, head clearance at y+2)
  so ~170 SprintJump + Sidewall descriptors never call JumpFeasibility
  when the node cannot take off at all.
- Precompute an 8-way "first step has no floor" table indexed by
  (sign(dx), sign(dz)) so SprintJump descriptors in a direction that
  has a walkable floor underneath are dropped without Evaluate.
- Add a conservative "any cardinal wall at y or y+1" probe that skips
  all 112 Sidewall descriptors when no wall exists adjacent to the
  takeoff.

Move tests switch to the new MoveJump.* factory methods. Behavior is
verified by the existing test suite: the 21 pre-existing baseline
failures are preserved exactly, 0 regressions introduced.

Made-with: Cursor
Fix a cluster of execution-layer issues that caused replans and void
falls when traversing narrow ledges and multi-block descents between
(251.5,141,210.5) and (252.5,138,220.5):

- WalkTemplate / GroundedSegmentController: suppress the pre-rotation
  bias toward the next segment's exit heading on stable-footing Turn
  exits where the next segment is not a jump.  The next template
  snaps yaw on its first tick anyway, and pre-rotating mid-stride on
  a 1-block walkway pushes sprint drift perpendicular to the path and
  walks the bot off the edge.  Turn exits into a jump still get the
  bias so the takeoff direction stays aligned.

- GroundedSegmentController.ShouldComplete: relax the headingReady
  gate for Turn exits with stable footing so the segment can complete
  once yaw is aligned with either the current or the next segment
  heading (within 25/15 deg).  Without this the removed bias would
  leave the bot stuck at the end of a walkway waiting for a rotation
  that never happens.

- DescendTemplate: restrict the airborne exit-heading bias so it only
  kicks in when the footprint is inside the landing block, or on
  single-step drops where the fall is too short for lateral drift to
  miss the landing column.  On 2+ block drops the bot now keeps yaw
  pointed at the landing center for the whole fall.

- DescendTemplate: add a multi-block overshoot guard on PrepareJump
  exits.  Once airborne and past the landing end-plane on a 2+ Y
  drop, release forward/sprint and press back briefly so air drag
  pulls the bot back into the 1x1 landing column instead of sailing
  one block past it into the neighbouring void.

Live round-trip between the two goal coordinates now completes with
zero replans in three consecutive runs in each direction.  Full unit
test suite is unchanged from the pre-existing baseline (22 failing
tests, all orthogonal to this change).

Made-with: Cursor
Two complementary fixes for live-server "stuck on a step then replan"
on the 252.5,138,220.5 -> 244.5,122,188.5 route.

Search layer (ParkourFeasibility.HasRunUp): a long flat sprint parkour
(5 c2c, horiz~5) cannot launch from a cold start. Vanilla physics show
that gap=4 dy=0 reaches 5.1075m only with 12 momentum ticks of straight
sprint windup; a 0t standing jump tops out at gap=3 (=4 c2c). When the
previous move type is not Parkour/Descend (i.e. no carried airborne
momentum) we now require two aligned back-runway blocks instead of one
so the executor actually has room to spin sprint up.

Execution layer (GroundedSegmentController.ShouldComplete): the
LandingRecovery early-out used to live below the MinExitSpeed gate. A
Descend that landed inside the destination block but naturally settled
to zero speed (e.g. when the next segment is a fresh Traverse rather
than a chained Parkour) would fail the 0.03 MinExitSpeed check and idle
inside the target block until the per-segment timeout fired, triggering
an unnecessary replan. Move the LandingRecovery footprint check above
the speed gate so a fully-decelerated handoff is accepted.

Verified live on 1.21.11-Vanilla:
- 252.5,138,220.5 -> 244.5,122,188.5: 24 segments, 0 replans (was: 1)
- 244.5,122,188.5 -> 252.5,138,220.5: 48 segments, 0 replans
- 251.5,141,210.5 -> 252.5,138,220.5: 34 segments, 0 replans
- 252.5,138,220.5 -> 251.5,141,210.5: 24 segments, 0 replans

Test suite: 297 passed / 22 known pre-existing failures, no new
regressions vs 5de169d.

Made-with: Cursor
* JumpFeasibility.EvaluateStepDescend now requires BOTH cardinal
  shoulder columns to be passable. Axis-separated collision
  resolution at the corner zeros one velocity component when a
  shoulder is walled, sliding the bot straight down past the intended
  diagonal landing into a multi-block fall-through (observed on the
  251 -> 244 route around (249,136,207)).
* ParkourFeasibility now distinguishes Parkour-carry from
  Descend-carry for flat (yDelta == 0) jumps. A Descend often
  overshoots the takeoff block, killing the sprint runway the
  SprintJumpTemplate needs to reach 5 c2c. Treat Descend-carry like a
  cold start: 3.5 m threshold and 2 aligned back-runway blocks. This
  prevents the planner from picking impossible 5 c2c flat jumps right
  after a Descend (e.g. (248,122,197) -> (248,122,192)).

Verified live on 1.21.11 across all 6 directions between
(251.5,141,210.5), (252.5,138,220.5) and (244.5,122,188.5):
0 replans, 0 segment failures, no mid-path stalls.

Made-with: Cursor
When a Descend segment is followed by another Descend (or Traverse/
Diagonal) with a different heading, PathSegmentBuilder.Classify
correctly assigned ExitTransition=LandingRecovery, but BuildHints fell
into the `if (turning)` branch first and returned hints with
RequireStableFooting=true. That gate forces GroundedSegmentController to
wait for IsSettledOnTargetBlock (footprint inside, won't leave next tick,
horizontal speed^2 <= 0.0016), so a multi-block diagonal Descend that
landed inside the target block while still carrying ~0.02 m/tick of
residual jump momentum oscillated in place for ~60 ticks (3 seconds)
until the speed decayed.

Move the LandingRecovery branch ahead of the turning branch so the
Descend-carry handoff uses RequireStableFooting=false and the
ShouldComplete shortcut (LandingRecovery + footprint inside target on
the ground) fires the moment the bot reaches the landing column.

Adds two regression tests covering the Descend->turning-Descend handoff
and a sanity guard that ordinary Traverse->turning-Traverse still uses
the turning branch.

Also lifts DiagnosticsTailSize from 64 to 200 and emits an automatic
"slow segment" tick dump from PathSegmentManager whenever a segment
takes >=25 ticks, which is what surfaced this stall.

Made-with: Cursor
The cardinal-jump side-wall gate previously demanded BOTH lateral
columns be passable along the trajectory, and the landing-overshoot
gate rejected jumps with a wall one block past the landing on the
takeoff axis. Both rules rejected feasible jumps in the live world:
breaking a single head-height block in a corridor with a continuous
wall on one side could leave a +1 ascend cardinal sprint jump as the
only reachable route, but the planner returned no path.

Side-wall check now accepts when at least one lateral side is
passable. The bot footprint (0.6m centred) stays >=0.2m clear of an
adjacent wall under on-axis yaw, so a single-side wall does not
contact the arc; only a fully-walled tunnel is rejected so the
executor's 5-degree yaw drift has bail-out room.

Landing-overshoot check is now a no-op. The LandingRecovery brake
profile keeps cardinal-jump overshoot under 0.3m so the footprint
stays inside the landing block when the brake engages, making the
"wall one cell past landing" check a false positive in practice.

Updated the conflicting Rejects2x1GapWhenSideWallNarrowsLanding test
to assert the new accept-with-single-side-wall behaviour, added a
fully-walled-tunnel rejection test to guard the bail-out lower bound,
and added a regression covering the live "+1 ascend over a broken
head-height block in a single-walled corridor" scenario.

Made-with: Cursor
Two coupled fixes for live 258<->237 / 237<->244 routes that previously
hit 5 replans and gave up on Ascend exit=Turn segments.

DescendTemplate: when biasTowardExitInAir is false on a multi-block
diagonal descend, the per-tick targetYaw rotates as the bot drifts past
the landing column mid-fall (e.g. dx=-1 dz=-1 drop yaw cycles 135 -> 90
-> 0 -> 315 over six air ticks). With Forward held, that rotating yaw
pushes air-control momentum perpendicular to the planned trajectory,
sliding the bot ~0.5 m off the landing onto an adjacent block one tier
below. Lock airborne yaw to the segment's start->end heading for those
descends so air drift stays aligned with the diagonal.

AscendTemplate: add a post-landing completion shortcut for non-FinalStop
exits. Once the jump arc puts the bot back on ground at the target's
elevation with its center inside the target column, hand off to the
next template (which snaps yaw on its first tick). Holding the segment
runs both AscendTemplate's top-level yaw smoothing toward a moving
targetYaw AND GroundedSegmentController's segment/exit-heading rotation
each tick. The competing yaw targets oscillate the bot ~80 ticks until
it walks off the 1-block landing's edge and the segment fails. Mirrors
the existing PrepareJump completion gate. FinalStop is excluded so the
last segment still uses IsSettledAtEnd to detect a true stop.

Live verification on 1.21.11 (round-trip 244<->237 plus the originally
failing 237->244 route): four navigations, 0 replans, all 25/41/24/41
segments completed.

Made-with: Cursor
The previous shortcut completed an Ascend on any non-FinalStop exit as
soon as the bot's center entered the target column. This made the next
segment start with the bot offset along the prior heading (e.g. +0.45 m
past target column center), which compounded with sprint-jump distance
on the next segment.

Live regression on (237.5, 97, 172.5) -> (252.5, 138, 220.5):
Ascend (258.5,127,222.5)->(257.5,128,223.5) PrepareJump completed at
(257.78,128.00,223.95). Followed by Parkour (257.5,128,223.5)->
(256.5,128,225.5), the sprint-jump launched from progress=+0.38 and
covered ~3.6 m, overshooting the 2.236 m landing target by ~1.7 m. Bot
fell at (255.30,123.94,226.27) and triggered repeated replans until the
5-replan budget was exhausted.

Restrict the shortcut to ExitTransition == Turn, the original target
case where the AscendTemplate yaw and GroundedSegmentController's
exit-heading yaw disagree and oscillate the bot off the landing block.
For PrepareJump/ContinueStraight/LandingRecovery, the GSC handoff is
correct because the next segment shares the segment heading.

Verified zero replans on:
- (237.5,97,172.5) -> (252.5,138,220.5) (79 segments)
- (252.5,138,220.5) -> (237.5,97,172.5) (39 segments)
- (237.5,97,172.5) -> (244.5,122,188.5) (41 segments)
- (244.5,122,188.5) -> (237.5,97,172.5) (25 segments)

Pathing test suite: 23 failures (matches baseline, no new regressions).

Made-with: Cursor
Two related fixes for the (255,117,220) -> (237,97,172) route reported
where the bot fell out of a 22-block water descent and landed on the
rim, and where /pathdiag noticeably froze and warped the bot.

DescendTemplate: long-fall water-column overshoot
=================================================
On segment 7 of the route, a 22-block descend Descend (254.5,113,224.5)
-> (253.5,91,224.5), the bot's footprint enters the target column at
the very first airborne tick (X=253.6 footprint inside [253,254], Z=224.7
footprint inside [224,225]). The previous code immediately set
biasTowardExitInAir = true, rotating yaw to the next segment's exit
heading (-Z) for the entire 20+ tick fall. Forward held during the
fall pushed -Z momentum each tick (~0.05 m/tick equilibrium), so by
landing time the bot had drifted ~1 m past the water column and landed
on the dry rim (Z=223.42 vs target Z=224.5). On a real server this
plunge from 22 blocks onto a non-water block would kill the bot.

Two changes in DescendTemplate.cs:

1. Gate the footprint-inside-target bias for non-single-step descends
   behind a "near landing" check (remainingFallY <= 1.5 m, ~3 ticks of
   free-fall). The bias still applies on single-step descends (where
   the fall is too short for drift to matter) and on the final approach
   ticks of multi-block falls.

2. Extend the existing riskyOvershoot Back-input brake to fire on any
   multi-block descend whose footprint is already inside the target,
   not just the PrepareJump exit case. Once the bot is in the column,
   the segment's horizontal travel is done; releasing Forward and
   pressing Back kills any residual horizontal velocity so the bot
   falls straight into the water/landing block instead of accumulating
   air-control momentum from holding Forward for 20+ ticks.

Verified on 1.21.11 with /pathdiag on: segment 7 now lands at
(253.59,91,224.42), 0.09 m off target X and 0.08 m off target Z, well
inside the target water column.

PathSegmentManager: PathDiag main-thread offload
=================================================
Diagnostic dumps were emitted line-by-line through _infoLog?.Invoke(),
which calls Log.Info -> ConsoleIO.WriteLogLine -> file logger on the
main 20 TPS tick. A slow-segment dump or failure trace produces
25-200 synchronous log calls; on the affected route a single batch
took 200-500 ms on the tick thread, freezing the position-packet
stream long enough for the server to lose track and then snap the
bot forward when the tick resumed. Symptom on the user side: every
time /pathdiag is on, the bot freezes for ~half a second, then
"teleports" through the queued segments, then freezes again.

Each diagnostic emission point now snapshots its lines into a List
and dispatches them through DispatchDiagnosticsBatch, which appends
to a single chained Task running on TaskScheduler.Default. The chain
preserves emission order across batches so concurrent slow-segment
and seg-> headers do not interleave. The tick path now does O(1)
work per dump (build list, ContinueWith) instead of O(N) console
writes.

Verified by running the same /goto twice (with and without pathdiag):
both runs produced identical trajectories and identical replan
counts, confirming the diagnostics path no longer perturbs movement.

Pathing test suite: 23 failures, identical to baseline. Live regression
on prior 4 zero-replan routes ((237<->252, 237<->244)) all still
complete cleanly.

Made-with: Cursor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant