Minecraft-Console-Client/MinecraftClient/Pathing/Moves/JumpDescriptor.cs

57 lines
1.8 KiB
C#
Raw Normal View History

pathing: unify jump moves into MoveJump + IMoveExpander 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
2026-04-19 17:03:26 +00:00
namespace MinecraftClient.Pathing.Moves;
/// <summary>
/// Kind of jump-family move. Each flavor selects a different evaluator path
/// inside <see cref="JumpFeasibility"/> while sharing low-level primitives
/// (head clearance, destination clearance, flight-path sweep, cost model).
/// </summary>
public enum JumpFlavor
{
/// <summary>
/// Single-block cardinal or diagonal walk at the same Y. No jump input.
/// Covers the old <c>MoveTraverse</c> and <c>MoveDiagonal</c>.
/// </summary>
Walk,
/// <summary>
/// Single-block vertical step (dy = +1 up or dy = -1 down), cardinal or
/// diagonal. Covers <c>MoveAscend</c>, <c>MoveDiagonalAscend</c>, and
/// <c>MoveDiagonalDescend</c>.
/// </summary>
Step,
/// <summary>
/// Multi-block sprint jump, cardinal or diagonal. Covers <c>MoveParkour</c>.
/// </summary>
SprintJump,
/// <summary>
/// Dominant-axis sprint jump that uses an inner wall for support. Covers
/// <c>MoveSidewallParkour</c>.
/// </summary>
Sidewall,
}
/// <summary>
/// Fully describes a single jump-family move (Walk / Step / SprintJump /
/// Sidewall). All geometry that downstream planners or templates need can be
/// derived from this value, so A* only needs to enumerate descriptors rather
/// than hard-coded IMove subclasses.
/// </summary>
public readonly record struct JumpDescriptor(
int XOffset,
int ZOffset,
int YDelta,
JumpFlavor Flavor)
{
public bool IsCardinal => (XOffset == 0) != (ZOffset == 0);
public bool IsDiagonal => XOffset != 0 && ZOffset != 0;
public int HorizontalMajor
=> System.Math.Max(System.Math.Abs(XOffset), System.Math.Abs(ZOffset));
public int HorizontalMinor
=> System.Math.Min(System.Math.Abs(XOffset), System.Math.Abs(ZOffset));
}