fix: improve pathfinding execution for climbing and block classification

- 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
This commit is contained in:
BruceChen 2026-04-11 02:47:31 +08:00
parent 77c5f88168
commit a6261e4019
2 changed files with 76 additions and 3 deletions

View file

@ -1730,11 +1730,20 @@ namespace MinecraftClient
int sx = (int)Math.Floor(location.X);
int sy = (int)Math.Floor(location.Y);
int sz = (int)Math.Floor(location.Z);
// If floored Y lands inside a solid block (e.g. player on top of it), step up
if (!ctx.CanWalkThrough(sx, sy, sz) && ctx.CanWalkThrough(sx, sy + 1, sz))
sy++;
int gx = (int)Math.Floor(goal.X);
int gy = (int)Math.Floor(goal.Y);
int gz = (int)Math.Floor(goal.Z);
Log.Info($"[Goto] A* search from ({sx},{sy},{sz}) to ({gx},{gy},{gz})...");
if (!ctx.CanWalkThrough(gx, gy, gz) && ctx.CanWalkThrough(gx, gy + 1, gz))
gy++;
Log.Info($"[Goto] A* search from ({sx},{sy},{sz}) to ({gx},{gy},{gz}) " +
$"[raw pos=({location.X:F2},{location.Y:F2},{location.Z:F2})]");
using var cts = new CancellationTokenSource();
var result = finder.Calculate(ctx, sx, sy, sz,
@ -3293,12 +3302,20 @@ namespace MinecraftClient
/// <summary>
/// Check if the player has approximately reached a waypoint.
/// Uses both horizontal and vertical distance for climb/descend waypoints.
/// </summary>
private bool ReachedWaypoint(Location target)
{
double dx = target.X - location.X;
double dz = target.Z - location.Z;
return dx * dx + dz * dz < 0.25; // within ~0.5 blocks horizontally
double dy = target.Y - location.Y;
double horizDistSq = dx * dx + dz * dz;
// Vertical waypoint (climbing/falling): require reaching target Y level
if (horizDistSq < 0.5 && Math.Abs(dy) > 0.8)
return false;
return horizDistSq < 0.25 && Math.Abs(dy) < 0.8;
}
/// <summary>
@ -3312,7 +3329,41 @@ namespace MinecraftClient
double dy = target.Y - location.Y;
double distSqr = dx * dx + dz * dz;
if (distSqr < 0.01) return; // Close enough horizontally
// Climbing: target is above/below with small horizontal offset
if (playerPhysics.OnClimbable && Math.Abs(dy) > 0.5 && distSqr < 1.0)
{
if (dy > 0)
{
physicsInput.Jump = true;
// Push against the wall for HorizontalCollision-triggered climbing
if (distSqr > 0.01)
{
float yaw = (float)(-Math.Atan2(dx, dz) / Math.PI * 180.0);
if (yaw < 0) yaw += 360;
playerPhysics.Yaw = yaw;
playerYaw = yaw;
physicsInput.Forward = true;
}
else
{
physicsInput.Forward = true;
}
}
else
{
physicsInput.Sneak = false;
}
return;
}
// Non-climbing vertical jump
if (distSqr < 0.1 && dy > 0.5 && playerPhysics.OnGround)
{
physicsInput.Jump = true;
return;
}
if (distSqr < 0.01) return;
// Calculate yaw to face target
float targetYaw = (float)(-Math.Atan2(dx, dz) / Math.PI * 180.0);

View file

@ -19,6 +19,10 @@ namespace MinecraftClient.Pathing.Moves
return true;
if (mat.IsLiquid())
return false;
if (mat.CanBeClimbedOn())
return true;
if (IsOpenGate(mat))
return true;
if (mat.IsSolid())
return false;
if (mat.CanHarmPlayers())
@ -38,6 +42,10 @@ namespace MinecraftClient.Pathing.Moves
return false;
if (mat.CanHarmPlayers())
return false;
if (mat.CanBeClimbedOn())
return false;
if (IsOpenGate(mat))
return false;
return mat.IsSolid();
}
@ -65,5 +73,19 @@ namespace MinecraftClient.Pathing.Moves
{
return mat == Material.Water;
}
/// <summary>
/// Conservative check for gate-type blocks. Since we cannot read block state
/// (open/closed) during planning, treat all fence gates as passable.
/// </summary>
private static bool IsOpenGate(Material mat)
{
return mat is Material.AcaciaFenceGate or Material.BirchFenceGate
or Material.CrimsonFenceGate or Material.DarkOakFenceGate
or Material.JungleFenceGate or Material.MangroveWood
or Material.OakFenceGate or Material.SpruceFenceGate
or Material.WarpedFenceGate or Material.CherryFenceGate
or Material.BambooFenceGate or Material.PaleOakFenceGate;
}
}
}