feat: add 4-block jumps, diagonal parkour, high-fall water/ladder support

MoveParkour rewritten to support both cardinal and diagonal sprint jumps
with unified (xOff, zOff) interface. New capabilities:

- 4-block cardinal sprint jumps with edge-approach timing in template
- Diagonal parkour: (2,1), (1,2), (2,2), (3,1), (1,3) in all quadrants
- Ascending parkour extended to dist=3 (cardinal)
- Overshoot safety check after landing destination
- Block parkour from climbable starting blocks (vine/ladder)

MoveDescend/MoveFall enhanced with Baritone-style dynamic fall scanning:
- Water landing: accepts falls of any height into water
- Mid-fall ladder/vine grab: resets effective fall height (<=11 blocks)
- CalculationContext gains MaxFallHeightWater, AllowLadderGrabDuringFall

SprintJumpTemplate gains distance-based approach timing:
- Long jumps (>=3.5 blocks): delays jump until 0.5 blocks from center
- Medium jumps (>=2.5): 0.35 blocks approach
- Landing tolerance scales with jump distance

All movements verified on 1.21.11 local server.

Made-with: Cursor
This commit is contained in:
BruceChen 2026-04-11 14:45:54 +08:00
parent a9c9a6a669
commit 53082d387e
9 changed files with 365 additions and 89 deletions

View file

@ -1,10 +1,12 @@
using MinecraftClient.Mapping;
using MinecraftClient.Pathing.Core;
namespace MinecraftClient.Pathing.Moves.Impl
{
/// <summary>
/// Straight-down fall at the current X,Z position, for drops greater than MaxFallHeight
/// that MoveDescend won't cover. Scans downward for a safe landing.
/// Straight-down fall at the current X,Z position.
/// Supports water landing and mid-fall ladder/vine grabbing.
/// Used for drops where MoveDescend's 1-block horizontal offset doesn't apply.
/// </summary>
public sealed class MoveFall : IMove
{
@ -28,39 +30,62 @@ namespace MinecraftClient.Pathing.Moves.Impl
return;
}
double costSoFar = 0;
int effectiveStartHeight = y;
for (int fallDist = 1; fallDist <= _maxScanDepth; fallDist++)
{
int landY = y - fallDist;
if (landY < -64) break;
if (ctx.CanWalkOn(x, landY - 1, z))
Material ontoMat = ctx.GetMaterial(x, landY, z);
int unprotectedFallHeight = fallDist - (y - effectiveStartHeight);
// Water landing: safe regardless of height
if (MoveHelper.IsWater(ontoMat))
{
if (!ctx.CanWalkThrough(x, landY, z))
{
result.SetImpossible();
return;
}
if (MoveHelper.IsHazardous(ctx.GetMaterial(x, landY - 1, z)))
{
result.SetImpossible();
return;
}
double fallDamageThreshold = 3;
double cost = ActionCosts.FallCost(fallDist);
if (fallDist > fallDamageThreshold)
cost += (fallDist - fallDamageThreshold) * 5.0;
result.Set(x, landY, z, cost);
double waterCost = ActionCosts.FallCost(unprotectedFallHeight) + costSoFar;
result.Set(x, landY, z, waterCost);
return;
}
if (!ctx.CanWalkThrough(x, landY, z))
// Mid-fall ladder/vine grab (resets effective fall height)
if (ctx.AllowLadderGrabDuringFall && unprotectedFallHeight <= 11
&& ontoMat.CanBeClimbedOn())
{
costSoFar += ActionCosts.FallCost(unprotectedFallHeight - 1);
costSoFar += ActionCosts.LadderDownOne;
effectiveStartHeight = landY;
continue;
}
if (ctx.CanWalkThrough(x, landY, z))
continue;
// Hit something solid
if (!ctx.CanWalkOn(x, landY, z))
{
result.SetImpossible();
return;
}
if (MoveHelper.IsHazardous(ontoMat))
{
result.SetImpossible();
return;
}
// Solid landing within safe height
if (unprotectedFallHeight <= ctx.MaxFallHeight + 1)
{
double cost = ActionCosts.FallCost(unprotectedFallHeight) + costSoFar;
result.Set(x, landY + 1, z, cost);
return;
}
// Too high for safe landing
result.SetImpossible();
return;
}
result.SetImpossible();