mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2026-08-29 13:04:59 +00:00
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
This commit is contained in:
parent
3efe63c54d
commit
1abab20f17
23 changed files with 1222 additions and 0 deletions
50
MinecraftClient/Pathing/Moves/Impl/MoveAscend.cs
Normal file
50
MinecraftClient/Pathing/Moves/Impl/MoveAscend.cs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
using MinecraftClient.Pathing.Core;
|
||||
|
||||
namespace MinecraftClient.Pathing.Moves.Impl
|
||||
{
|
||||
/// <summary>
|
||||
/// Jump up 1 block in a cardinal direction.
|
||||
/// Requires: headroom at (x, y+2, z), body space at dest (y+1, y+2), ground at dest (y).
|
||||
/// </summary>
|
||||
public sealed class MoveAscend : IMove
|
||||
{
|
||||
public MoveType Type => MoveType.Ascend;
|
||||
public int XOffset { get; }
|
||||
public int ZOffset { get; }
|
||||
public bool DynamicY => false;
|
||||
|
||||
public MoveAscend(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;
|
||||
int destY = y + 1;
|
||||
|
||||
if (!ctx.CanWalkThrough(x, y + 2, z))
|
||||
{
|
||||
result.SetImpossible();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ctx.CanWalkThrough(destX, destY, destZ) || !ctx.CanWalkThrough(destX, destY + 1, destZ))
|
||||
{
|
||||
result.SetImpossible();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ctx.CanWalkOn(destX, y, destZ))
|
||||
{
|
||||
result.SetImpossible();
|
||||
return;
|
||||
}
|
||||
|
||||
double cost = ctx.SprintCost + ctx.JumpPenalty;
|
||||
result.Set(destX, destY, destZ, cost);
|
||||
}
|
||||
}
|
||||
}
|
||||
64
MinecraftClient/Pathing/Moves/Impl/MoveClimb.cs
Normal file
64
MinecraftClient/Pathing/Moves/Impl/MoveClimb.cs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
using MinecraftClient.Mapping;
|
||||
using MinecraftClient.Pathing.Core;
|
||||
|
||||
namespace MinecraftClient.Pathing.Moves.Impl
|
||||
{
|
||||
/// <summary>
|
||||
/// Climb up or down a ladder/vine at the current X,Z position.
|
||||
/// </summary>
|
||||
public sealed class MoveClimb : IMove
|
||||
{
|
||||
public MoveType Type => MoveType.Climb;
|
||||
public int XOffset => 0;
|
||||
public int ZOffset => 0;
|
||||
public bool DynamicY => false;
|
||||
|
||||
private readonly bool _up;
|
||||
|
||||
public MoveClimb(bool up)
|
||||
{
|
||||
_up = up;
|
||||
}
|
||||
|
||||
public void Calculate(CalculationContext ctx, int x, int y, int z, ref MoveResult result)
|
||||
{
|
||||
var currentMat = ctx.GetMaterial(x, y, z);
|
||||
if (!MoveHelper.IsClimbable(currentMat))
|
||||
{
|
||||
result.SetImpossible();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_up)
|
||||
{
|
||||
int destY = y + 1;
|
||||
if (!ctx.CanWalkThrough(x, destY + 1, z))
|
||||
{
|
||||
result.SetImpossible();
|
||||
return;
|
||||
}
|
||||
|
||||
var aboveMat = ctx.GetMaterial(x, destY, z);
|
||||
if (MoveHelper.IsClimbable(aboveMat) || !ctx.GetMaterial(x, destY, z).IsSolid())
|
||||
{
|
||||
result.Set(x, destY, z, ActionCosts.LadderUpOne);
|
||||
return;
|
||||
}
|
||||
|
||||
result.SetImpossible();
|
||||
}
|
||||
else
|
||||
{
|
||||
int destY = y - 1;
|
||||
var belowMat = ctx.GetMaterial(x, destY, z);
|
||||
if (MoveHelper.IsClimbable(belowMat) || !belowMat.IsSolid())
|
||||
{
|
||||
result.Set(x, destY, z, ActionCosts.LadderDownOne);
|
||||
return;
|
||||
}
|
||||
|
||||
result.SetImpossible();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
66
MinecraftClient/Pathing/Moves/Impl/MoveDescend.cs
Normal file
66
MinecraftClient/Pathing/Moves/Impl/MoveDescend.cs
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
54
MinecraftClient/Pathing/Moves/Impl/MoveDiagonal.cs
Normal file
54
MinecraftClient/Pathing/Moves/Impl/MoveDiagonal.cs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
using MinecraftClient.Pathing.Core;
|
||||
|
||||
namespace MinecraftClient.Pathing.Moves.Impl
|
||||
{
|
||||
/// <summary>
|
||||
/// Diagonal walk (1 block in both X and Z, same Y).
|
||||
/// Checks both intermediate cardinal columns for clearance.
|
||||
/// </summary>
|
||||
public sealed class MoveDiagonal : IMove
|
||||
{
|
||||
public MoveType Type => MoveType.Diagonal;
|
||||
public int XOffset { get; }
|
||||
public int ZOffset { get; }
|
||||
public bool DynamicY => false;
|
||||
|
||||
public MoveDiagonal(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;
|
||||
}
|
||||
|
||||
if (!ctx.CanWalkOn(destX, y - 1, destZ))
|
||||
{
|
||||
result.SetImpossible();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ctx.CanWalkThrough(x + XOffset, y, z) || !ctx.CanWalkThrough(x + XOffset, y + 1, z))
|
||||
{
|
||||
result.SetImpossible();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ctx.CanWalkThrough(x, y, z + ZOffset) || !ctx.CanWalkThrough(x, y + 1, z + ZOffset))
|
||||
{
|
||||
result.SetImpossible();
|
||||
return;
|
||||
}
|
||||
|
||||
result.Set(destX, y, destZ, ctx.SprintCost * ActionCosts.DiagonalMultiplier);
|
||||
}
|
||||
}
|
||||
}
|
||||
54
MinecraftClient/Pathing/Moves/Impl/MoveTraverse.cs
Normal file
54
MinecraftClient/Pathing/Moves/Impl/MoveTraverse.cs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
using MinecraftClient.Pathing.Core;
|
||||
|
||||
namespace MinecraftClient.Pathing.Moves.Impl
|
||||
{
|
||||
/// <summary>
|
||||
/// Flat cardinal walk (1 block in +/-X or +/-Z, same Y).
|
||||
/// Checks body+head passable and ground below destination.
|
||||
/// </summary>
|
||||
public sealed class MoveTraverse : IMove
|
||||
{
|
||||
public MoveType Type => MoveType.Traverse;
|
||||
public int XOffset { get; }
|
||||
public int ZOffset { get; }
|
||||
public bool DynamicY => false;
|
||||
|
||||
public MoveTraverse(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))
|
||||
{
|
||||
result.SetImpossible();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ctx.CanWalkThrough(destX, y + 1, destZ))
|
||||
{
|
||||
result.SetImpossible();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ctx.CanWalkOn(destX, y - 1, destZ))
|
||||
{
|
||||
result.SetImpossible();
|
||||
return;
|
||||
}
|
||||
|
||||
double cost = ctx.SprintCost;
|
||||
|
||||
var destFloorMat = ctx.GetMaterial(destX, y - 1, destZ);
|
||||
if (destFloorMat == Mapping.Material.SoulSand)
|
||||
cost *= 1.0 / Physics.PhysicsConsts.SoulSandSpeedFactor;
|
||||
|
||||
result.Set(destX, y, destZ, cost);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue