Minecraft-Console-Client/MinecraftClient/Pathing/Moves/Impl/MoveDescend.cs
BruceChen 1abab20f17 feat: add Phase 1 core pathfinding architecture
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
2026-04-12 18:43:32 +00:00

66 lines
2 KiB
C#

using MinecraftClient.Pathing.Core;
namespace MinecraftClient.Pathing.Moves.Impl
{
/// <summary>
/// Walk off a ledge and drop 1-N blocks in a cardinal direction.
/// Scans downward for a landing spot within MaxFallHeight.
/// </summary>
public sealed class MoveDescend : IMove
{
public MoveType Type => MoveType.Descend;
public int XOffset { get; }
public int ZOffset { get; }
public bool DynamicY => true;
public MoveDescend(int xOffset, int zOffset)
{
XOffset = xOffset;
ZOffset = zOffset;
}
public void Calculate(CalculationContext ctx, int x, int y, int z, ref MoveResult result)
{
int destX = x + XOffset;
int destZ = z + ZOffset;
if (!ctx.CanWalkThrough(destX, y, destZ) || !ctx.CanWalkThrough(destX, y + 1, destZ))
{
result.SetImpossible();
return;
}
for (int fallDist = 1; fallDist <= ctx.MaxFallHeight; fallDist++)
{
int landY = y - fallDist;
if (ctx.CanWalkOn(destX, landY - 1, destZ))
{
if (!ctx.CanWalkThrough(destX, landY, destZ))
{
result.SetImpossible();
return;
}
double cost = ActionCosts.WalkOffBlock + ActionCosts.FallCost(fallDist);
if (MoveHelper.IsHazardous(ctx.GetMaterial(destX, landY - 1, destZ)))
{
result.SetImpossible();
return;
}
result.Set(destX, landY, destZ, cost);
return;
}
if (!ctx.CanWalkThrough(destX, landY, destZ))
{
result.SetImpossible();
return;
}
}
result.SetImpossible();
}
}
}