diff --git a/MinecraftClient/Pathing/Execution/Templates/SprintJumpTemplate.cs b/MinecraftClient/Pathing/Execution/Templates/SprintJumpTemplate.cs index dc70940f..eed7b472 100644 --- a/MinecraftClient/Pathing/Execution/Templates/SprintJumpTemplate.cs +++ b/MinecraftClient/Pathing/Execution/Templates/SprintJumpTemplate.cs @@ -18,6 +18,7 @@ namespace MinecraftClient.Pathing.Execution.Templates public Location ExpectedEnd { get; } private readonly double _horizDist; + private readonly bool _isDiagonal; private int _tickCount; private Phase _phase = Phase.Approach; @@ -28,6 +29,7 @@ namespace MinecraftClient.Pathing.Execution.Templates double dx = end.X - start.X; double dz = end.Z - start.Z; _horizDist = Math.Sqrt(dx * dx + dz * dz); + _isDiagonal = Math.Abs(dx) > 0.5 && Math.Abs(dz) > 0.5; } public TemplateState Tick(Location pos, PlayerPhysics physics, MovementInput input) @@ -57,10 +59,12 @@ namespace MinecraftClient.Pathing.Execution.Templates // toward the block edge. Baritone waits until playerFeet is in // the next block (~0.5 blocks from center) for dist >= 4. // For medium jumps (dist 3), wait 0.35 blocks (Baritone: 0.7). + // For short diagonal jumps (<= 3 blocks), jump immediately + // to avoid overshooting the small starting platform. double minApproachSq; if (_horizDist >= 3.5) minApproachSq = 0.25; // 0.5 blocks - else if (_horizDist >= 2.5) + else if (_horizDist >= 2.5 && !_isDiagonal) minApproachSq = 0.12; // ~0.35 blocks else minApproachSq = 0.0; diff --git a/MinecraftClient/Pathing/Moves/Impl/MoveParkour.cs b/MinecraftClient/Pathing/Moves/Impl/MoveParkour.cs index fc442b9c..410e5586 100644 --- a/MinecraftClient/Pathing/Moves/Impl/MoveParkour.cs +++ b/MinecraftClient/Pathing/Moves/Impl/MoveParkour.cs @@ -103,32 +103,14 @@ namespace MinecraftClient.Pathing.Moves.Impl int xAbs = Math.Abs(XOffset); int zAbs = Math.Abs(ZOffset); - // Check intermediate space for passability (the player's bounding box sweeps - // through a rectangle from start to end; check all blocks in that rectangle) - for (int i = 0; i <= xAbs; i++) + // Check intermediate blocks along the flight path. + // Cardinal: check all blocks in the column along the primary axis. + // Diagonal: check blocks along the diagonal strip, not the full rectangle. + // Player AABB is 0.6 wide, so only blocks near the diagonal line matter. + if (!CheckFlightPath(ctx, x, y, z, xSign, zSign, xAbs, zAbs)) { - for (int j = 0; j <= zAbs; j++) - { - if (i == 0 && j == 0) continue; - if (i == xAbs && j == zAbs) continue; - - int gx = x + xSign * i; - int gz = z + zSign * j; - - if (!ctx.CanWalkThrough(gx, y, gz) || - !ctx.CanWalkThrough(gx, y + 1, gz) || - !ctx.CanWalkThrough(gx, y + 2, gz)) - { - result.SetImpossible(); - return; - } - - if (_yDelta > 0 && !ctx.CanWalkThrough(gx, y + 3, gz)) - { - result.SetImpossible(); - return; - } - } + result.SetImpossible(); + return; } // Gap check: first block(s) adjacent to start must lack ground. @@ -159,6 +141,23 @@ namespace MinecraftClient.Pathing.Moves.Impl } } + // For diagonal parkour, the player's AABB (0.6 wide) must clear both + // cardinal neighbors at the start. A wall on either side will clip the + // AABB during the initial sprint, preventing enough X or Z velocity to + // reach the target. Require BOTH cardinal exits to be passable. + if (xAbs > 0 && zAbs > 0) + { + bool canExitViaX = ctx.CanWalkThrough(x + xSign, y, z) && + ctx.CanWalkThrough(x + xSign, y + 1, z); + bool canExitViaZ = ctx.CanWalkThrough(x, y, z + zSign) && + ctx.CanWalkThrough(x, y + 1, z + zSign); + if (!canExitViaX || !canExitViaZ) + { + result.SetImpossible(); + return; + } + } + // Overshoot safety: after landing, player continues moving. // The block(s) past the destination in the jump direction must be passable. int overX = destX + xSign; @@ -190,6 +189,85 @@ namespace MinecraftClient.Pathing.Moves.Impl result.Set(destX, destY, destZ, cost); } + /// + /// Check body clearance along the flight path from start toward the destination. + /// For cardinal moves, checks a straight line. For diagonal moves, checks + /// only blocks near the actual diagonal trajectory rather than the full bounding + /// rectangle, allowing jumps that pass a wall on one side. + /// + private bool CheckFlightPath( + CalculationContext ctx, int x, int y, int z, + int xSign, int zSign, int xAbs, int zAbs) + { + if (xAbs == 0 || zAbs == 0) + { + // Cardinal: single axis, check each block along the line + for (int step = 1; step < Math.Max(xAbs, zAbs); step++) + { + int gx = x + xSign * (xAbs > 0 ? step : 0); + int gz = z + zSign * (zAbs > 0 ? step : 0); + if (!ClearColumn(ctx, gx, y, gz)) + return false; + } + return true; + } + + // Diagonal: walk the diagonal and check each block the AABB touches. + // At each step t along the diagonal, the player center is near + // (x + t*xSign, z + t*zSign). The AABB extends 0.3 blocks each side, + // so check the diagonal cell and one neighbor on each axis-aligned side + // only when the trajectory is close to a cell boundary (always for short + // diagonals). We enumerate cells by stepping through the longer axis + // and computing the corresponding position on the shorter axis. + int maxSteps = Math.Max(xAbs, zAbs); + for (int step = 1; step < maxSteps; step++) + { + // Proportional position along each axis + double fx = (double)step * xAbs / maxSteps; + double fz = (double)step * zAbs / maxSteps; + + int ix = (int)Math.Round(fx); + int iz = (int)Math.Round(fz); + + int gx = x + xSign * ix; + int gz = z + zSign * iz; + + if (!ClearColumn(ctx, gx, y, gz)) + return false; + + // Also check the neighboring cell across the shorter axis when close + // to a cell boundary (player AABB overlaps adjacent cell) + if (xAbs != zAbs) + { + double fracX = fx - Math.Floor(fx); + double fracZ = fz - Math.Floor(fz); + if (fracX > 0.2 && fracX < 0.8 && ix > 0 && ix < xAbs) + { + if (!ClearColumn(ctx, x + xSign * (ix - 1), y, gz)) + return false; + } + if (fracZ > 0.2 && fracZ < 0.8 && iz > 0 && iz < zAbs) + { + if (!ClearColumn(ctx, gx, y, z + zSign * (iz - 1))) + return false; + } + } + } + + return true; + } + + private bool ClearColumn(CalculationContext ctx, int gx, int y, int gz) + { + if (!ctx.CanWalkThrough(gx, y, gz) || + !ctx.CanWalkThrough(gx, y + 1, gz) || + !ctx.CanWalkThrough(gx, y + 2, gz)) + return false; + if (_yDelta > 0 && !ctx.CanWalkThrough(gx, y + 3, gz)) + return false; + return true; + } + public override string ToString() { double dist = Math.Sqrt((double)(XOffset * XOffset + ZOffset * ZOffset)); diff --git a/MinecraftClient/Pathing/Moves/Impl/MoveSprintDescend.cs b/MinecraftClient/Pathing/Moves/Impl/MoveSprintDescend.cs index 6acd9813..9a1c6d66 100644 --- a/MinecraftClient/Pathing/Moves/Impl/MoveSprintDescend.cs +++ b/MinecraftClient/Pathing/Moves/Impl/MoveSprintDescend.cs @@ -46,21 +46,24 @@ namespace MinecraftClient.Pathing.Moves.Impl int xAbs = Math.Abs(XOffset); int zAbs = Math.Abs(ZOffset); - // The flight path sweeps through intermediate blocks at current Y. - // Check body clearance for all intermediate and destination columns. - for (int i = 0; i <= xAbs; i++) + // Check body clearance at the destination column and along the flight path. + if (!ctx.CanWalkThrough(destX, y, destZ) || !ctx.CanWalkThrough(destX, y + 1, destZ)) { - for (int j = 0; j <= zAbs; j++) - { - if (i == 0 && j == 0) continue; - int gx = x + xSign * i; - int gz = z + zSign * j; - if (!ctx.CanWalkThrough(gx, y, gz) || !ctx.CanWalkThrough(gx, y + 1, gz)) - { - result.SetImpossible(); - return; - } - } + result.SetImpossible(); + return; + } + + // For cardinal (2,0)/(0,2): check the one intermediate column. + // For diagonal (1,1): destination IS one step away, no intermediate. + if (xAbs == 2 && zAbs == 0) + { + if (!ctx.CanWalkThrough(x + xSign, y, z) || !ctx.CanWalkThrough(x + xSign, y + 1, z)) + { result.SetImpossible(); return; } + } + else if (xAbs == 0 && zAbs == 2) + { + if (!ctx.CanWalkThrough(x, y, z + zSign) || !ctx.CanWalkThrough(x, y + 1, z + zSign)) + { result.SetImpossible(); return; } } // The first step in the primary direction must lack ground (this IS a drop).