mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2026-08-15 13:04:36 +00:00
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
53 lines
1.8 KiB
C#
53 lines
1.8 KiB
C#
using System;
|
|
using MinecraftClient.Pathing.Core;
|
|
|
|
namespace MinecraftClient.Pathing.Moves;
|
|
|
|
/// <summary>
|
|
/// A feasible neighbor emitted by an <see cref="IMoveExpander"/>. Carries the
|
|
/// per-node data the A* main loop needs to update its open set (destination,
|
|
/// cost, parkour profile, move type).
|
|
/// </summary>
|
|
public readonly struct MoveNeighbor
|
|
{
|
|
public readonly int DestX;
|
|
public readonly int DestY;
|
|
public readonly int DestZ;
|
|
public readonly double Cost;
|
|
public readonly ParkourProfile ParkourProfile;
|
|
public readonly MoveType MoveType;
|
|
|
|
public MoveNeighbor(in MoveResult result, MoveType moveType)
|
|
{
|
|
DestX = result.DestX;
|
|
DestY = result.DestY;
|
|
DestZ = result.DestZ;
|
|
Cost = result.Cost;
|
|
ParkourProfile = result.ParkourProfile;
|
|
MoveType = moveType;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Emits feasible neighbors from a given node. Replaces the old
|
|
/// "iterate every pre-instantiated IMove" pattern: A* asks each expander to
|
|
/// fill a stack-allocated buffer with all feasible neighbors, and the
|
|
/// expander can prune whole categories (e.g. skip Sidewall when no wall is
|
|
/// near) without instantiating per-direction IMove objects.
|
|
/// </summary>
|
|
public interface IMoveExpander
|
|
{
|
|
/// <summary>
|
|
/// Probe the world and populate <paramref name="buffer"/> with feasible
|
|
/// neighbors. Returns the number of neighbors written. Implementations
|
|
/// must not write past the buffer; callers must size it to the expander's
|
|
/// max output.
|
|
/// </summary>
|
|
int Expand(CalculationContext ctx, int x, int y, int z, Span<MoveNeighbor> buffer);
|
|
|
|
/// <summary>
|
|
/// Upper bound on the number of neighbors this expander can emit from a
|
|
/// single node. Used by the driver to size the per-node buffer.
|
|
/// </summary>
|
|
int MaxNeighbors { get; }
|
|
}
|