mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2026-08-15 13:04:36 +00:00
pathing: sidewall runup precondition via EntryPreparation
Introduce an EntryPreparationState carried on PathNode + A* context so sidewall parkour can explicitly request one or more runway traverses before takeoff instead of silently dropping the move. ParkourFeasibility gains TryGetRequiredStaticEntryRunupSteps + HasPreparedRunup helpers so long descends (major=5, dy=-1) only remain feasible when the preceding node proved the runup. Widen HasDominantAxisRunUp to accept cold-start sprint-jumps within ~3.1-3.5 blocks horizontally so lone overhang / staircase takeoffs stay feasible without a 2-block runway (matches Baritone's MomentumBehavior .ALLOWED contract). Add a runtime SidewallParkourController that implements the corner commitment + wall-hug chain during execution. Extend pathing test fixtures with InitialMomentumTicks, add sidewall accepted/rejected scenarios, and refresh timing + contract baselines to reflect the new planner shapes. Document the design in docs/superpowers/specs and plans. Made-with: Cursor
This commit is contained in:
parent
95b20d9d1c
commit
da52aa5c3c
15 changed files with 2925 additions and 25 deletions
|
|
@ -146,6 +146,27 @@ public sealed class LivePathingRegressionTests
|
|||
segment => Assert.Equal(ParkourProfile.Default, segment.ParkourProfile));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AStar_LinearFlatGap4_DoesNotInsertRunupSetupSegments()
|
||||
{
|
||||
PathingExecutionScenario scenario = LinearParkourScenarioBuilder.Create("linear-flat-gap4", gap: 4, deltaY: 0);
|
||||
PathResult result = PathingScenarioRunner.PlanOnly(scenario);
|
||||
List<PathSegment> segments = PathSegmentBuilder.FromPath(result.Path);
|
||||
|
||||
Assert.Equal(PathStatus.Success, result.Status);
|
||||
int firstParkourIndex = segments.FindIndex(segment => segment.MoveType == MoveType.Parkour);
|
||||
|
||||
Assert.Equal(3, firstParkourIndex);
|
||||
Assert.All(
|
||||
segments.Take(firstParkourIndex),
|
||||
segment =>
|
||||
{
|
||||
Assert.Equal(MoveType.Traverse, segment.MoveType);
|
||||
Assert.True(segment.End.X > segment.Start.X, segment.ToString());
|
||||
});
|
||||
Assert.Equal(new Location(3.5, 80, 0.5), segments[firstParkourIndex - 1].End);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("linear-ascend-gap2-dy+1", 2, 1)]
|
||||
[InlineData("linear-descend-gap4-dy-1", 4, -1)]
|
||||
|
|
@ -225,6 +246,30 @@ public sealed class LivePathingRegressionTests
|
|||
Assert.Equal(scenario.Goal.Z + 0.5, segments[^1].End.Z);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("sidewall-descend-gap5-dy-1-wo0", 5, 0)]
|
||||
[InlineData("sidewall-descend-gap5-dy-1-wo1", 5, 1)]
|
||||
public void AStar_SidewallLongDescendStaticEntry_PrependsExplicitRunupTraverses(string scenarioId, int gap, int wallOffset)
|
||||
{
|
||||
PathingExecutionScenario scenario = SidewallParkourScenarioBuilder.Create(
|
||||
scenarioId,
|
||||
gap,
|
||||
deltaY: -1,
|
||||
wallOffset);
|
||||
PathResult result = PathingScenarioRunner.PlanOnly(scenario);
|
||||
List<PathSegment> segments = PathSegmentBuilder.FromPath(result.Path);
|
||||
|
||||
Assert.Equal(PathStatus.Success, result.Status);
|
||||
|
||||
int firstParkourIndex = segments.FindIndex(segment => segment.MoveType == MoveType.Parkour);
|
||||
Assert.True(firstParkourIndex >= 2, string.Join('\n', segments));
|
||||
Assert.All(
|
||||
segments.Take(firstParkourIndex),
|
||||
segment => Assert.Equal(MoveType.Traverse, segment.MoveType));
|
||||
Assert.Equal(new Location(100.5, 80, 100.5), segments[firstParkourIndex - 1].End);
|
||||
Assert.Equal(ParkourProfile.Sidewall, segments[firstParkourIndex].ParkourProfile);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(SidewallParkourScenarioBuilder.RejectedCases), MemberType = typeof(SidewallParkourScenarioBuilder))]
|
||||
public void AStar_SidewallRejectedCases_RejectBeforeExecution(string scenarioId, int gap, int deltaY, int wallOffset)
|
||||
|
|
|
|||
|
|
@ -225,6 +225,22 @@ public sealed class PathSegmentManagerTests
|
|||
$"replanCount={manager.ReplanCount}\ninfo={string.Join('\n', infoLogs)}\ndebug={string.Join('\n', debugLogs)}");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(SidewallParkourScenarioBuilder.AcceptedCases), MemberType = typeof(SidewallParkourScenarioBuilder))]
|
||||
public void Tick_SidewallAcceptedCases_CompletesWithoutReplan(string scenarioId, int gap, int deltaY, int wallOffset)
|
||||
{
|
||||
PathingExecutionScenario scenario = SidewallParkourScenarioBuilder.Create(scenarioId, gap, deltaY, wallOffset);
|
||||
PathingScenarioResult result = PathingScenarioRunner.RunAccepted(scenario);
|
||||
Location goalLocation = new(scenario.Goal.X + 0.5, scenario.Goal.Y, scenario.Goal.Z + 0.5);
|
||||
|
||||
Assert.True(
|
||||
result.Completed
|
||||
&& result.ReplanCount == 0
|
||||
&& TemplateFootingHelper.IsFootprintInsideTargetBlock(result.FinalPosition, goalLocation),
|
||||
$"scenario={scenarioId} completed={result.Completed} replans={result.ReplanCount} final={result.FinalPosition} " +
|
||||
$"goal={goalLocation} planStatus={result.PlanResult.Status}\ninfo={string.Join('\n', result.InfoLogs)}\ndebug={string.Join('\n', result.DebugLogs)}");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(LinearParkourScenarioBuilder.AcceptedCases), MemberType = typeof(LinearParkourScenarioBuilder))]
|
||||
public void Tick_LinearAcceptedChain_CompletesWithoutReplan(string scenarioId, int gap, int deltaY)
|
||||
|
|
|
|||
|
|
@ -10,5 +10,6 @@ internal sealed record PathingExecutionScenario
|
|||
public required Location Start { get; init; }
|
||||
public required GoalBlock Goal { get; init; }
|
||||
public required float StartYaw { get; init; }
|
||||
public int InitialMomentumTicks { get; init; }
|
||||
public required int MaxExecutionTicks { get; init; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -640,7 +640,278 @@ public sealed class SprintJumpTemplateScenarioTests
|
|||
Assert.True(input.Jump);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SprintJumpTemplate_SidewallFlatGap2_FinalStop_CompletesInsideLandingBlock()
|
||||
{
|
||||
World world = SidewallParkourScenarioBuilder.BuildWorld(gap: 2, deltaY: 0, wallOffset: 0);
|
||||
var segment = new PathSegment
|
||||
{
|
||||
Start = new Location(100.5, 80, 100.5),
|
||||
End = new Location(99.5, 80, 102.5),
|
||||
MoveType = MoveType.Parkour,
|
||||
ParkourProfile = ParkourProfile.Sidewall,
|
||||
ExitTransition = PathTransitionType.FinalStop
|
||||
};
|
||||
|
||||
var physics = TemplateSimulationRunner.CreateGroundedPhysics(segment.Start, yaw: 0f);
|
||||
PathSegment[] segments = [segment];
|
||||
|
||||
TemplateState state = RunSegment(segments, index: 0, physics, world, out Location finalPos, out string trace);
|
||||
|
||||
Assert.True(
|
||||
state == TemplateState.Complete,
|
||||
$"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segment}\n{trace}");
|
||||
Assert.True(
|
||||
TemplateFootingHelper.IsFootprintInsideTargetBlock(finalPos, segment.End),
|
||||
$"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segment}\n{trace}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SprintJumpTemplate_SidewallFlatGap2_SecondPrepareJump_CompletesFromChainCarry()
|
||||
{
|
||||
PathingExecutionScenario scenario = SidewallParkourScenarioBuilder.Create("sidewall-flat-gap2-wo0", gap: 2, deltaY: 0, wallOffset: 0);
|
||||
(World world, List<PathSegment> segments, PlayerPhysics physics) = BuildPlannedScenario(scenario);
|
||||
|
||||
RunSegmentsThrough(segments, world, physics, lastCompletedIndex: 0);
|
||||
|
||||
TemplateState state = RunSegment(segments, index: 1, physics, world, out Location finalPos, out string trace);
|
||||
|
||||
Assert.True(state == TemplateState.Complete, $"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[1]}\n{trace}");
|
||||
Assert.True(
|
||||
TemplateFootingHelper.IsFootprintInsideTargetBlock(finalPos, segments[1].End),
|
||||
$"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[1]}\n{trace}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SprintJumpTemplate_SidewallFlatGap3Wo1_FirstPrepareJump_CompletesFromStart()
|
||||
{
|
||||
PathingExecutionScenario scenario = SidewallParkourScenarioBuilder.Create("sidewall-flat-gap3-wo1", gap: 3, deltaY: 0, wallOffset: 1);
|
||||
(World world, List<PathSegment> segments, PlayerPhysics physics) = BuildPlannedScenario(scenario);
|
||||
|
||||
TemplateState state = RunSegment(segments, index: 0, physics, world, out Location finalPos, out string trace);
|
||||
|
||||
Assert.True(state == TemplateState.Complete, $"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[0]}\n{trace}");
|
||||
Assert.True(
|
||||
TemplateFootingHelper.IsFootprintInsideTargetBlock(finalPos, segments[0].End),
|
||||
$"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[0]}\n{trace}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SprintJumpTemplate_SidewallFlatGap4Wo0_FirstPrepareJump_CompletesFromStart()
|
||||
{
|
||||
PathingExecutionScenario scenario = SidewallParkourScenarioBuilder.Create("sidewall-flat-gap4-wo0", gap: 4, deltaY: 0, wallOffset: 0);
|
||||
(World world, List<PathSegment> segments, PlayerPhysics physics) = BuildPlannedScenario(scenario);
|
||||
|
||||
TemplateState state = RunSegment(segments, index: 0, physics, world, out Location finalPos, out string trace);
|
||||
|
||||
Assert.True(state == TemplateState.Complete, $"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[0]}\n{trace}");
|
||||
Assert.True(
|
||||
TemplateFootingHelper.IsFootprintInsideTargetBlock(finalPos, segments[0].End),
|
||||
$"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[0]}\n{trace}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SprintJumpTemplate_SidewallFlatGap3Wo1_SecondPrepareJump_CompletesFromChainCarry()
|
||||
{
|
||||
PathingExecutionScenario scenario = SidewallParkourScenarioBuilder.Create("sidewall-flat-gap3-wo1", gap: 3, deltaY: 0, wallOffset: 1);
|
||||
(World world, List<PathSegment> segments, PlayerPhysics physics) = BuildPlannedScenario(scenario);
|
||||
|
||||
RunSegmentsThrough(segments, world, physics, lastCompletedIndex: 0);
|
||||
|
||||
TemplateState state = RunSegment(segments, index: 1, physics, world, out Location finalPos, out string trace);
|
||||
|
||||
Assert.True(state == TemplateState.Complete, $"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[1]}\n{trace}");
|
||||
Assert.True(
|
||||
TemplateFootingHelper.IsFootprintInsideTargetBlock(finalPos, segments[1].End),
|
||||
$"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[1]}\n{trace}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SprintJumpTemplate_SidewallAscendGap3Wo1_FirstPrepareJump_CompletesFromStart()
|
||||
{
|
||||
PathingExecutionScenario scenario = SidewallParkourScenarioBuilder.Create("sidewall-ascend-gap3-dy+1-wo1", gap: 3, deltaY: 1, wallOffset: 1);
|
||||
(World world, List<PathSegment> segments, PlayerPhysics physics) = BuildPlannedScenario(scenario);
|
||||
|
||||
TemplateState state = RunSegment(segments, index: 0, physics, world, out Location finalPos, out string trace);
|
||||
|
||||
Assert.True(state == TemplateState.Complete, $"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[0]}\n{trace}");
|
||||
Assert.True(
|
||||
TemplateFootingHelper.IsFootprintInsideTargetBlock(finalPos, segments[0].End),
|
||||
$"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[0]}\n{trace}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SprintJumpTemplate_SidewallDescendGap2DyMinus1Wo0_FirstPrepareJump_CompletesFromStart()
|
||||
{
|
||||
PathingExecutionScenario scenario = SidewallParkourScenarioBuilder.Create("sidewall-descend-gap2-dy-1-wo0", gap: 2, deltaY: -1, wallOffset: 0);
|
||||
(World world, List<PathSegment> segments, PlayerPhysics physics) = BuildPlannedScenario(scenario);
|
||||
|
||||
TemplateState state = RunSegment(segments, index: 0, physics, world, out Location finalPos, out string trace);
|
||||
|
||||
Assert.True(state == TemplateState.Complete, $"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[0]}\n{trace}");
|
||||
Assert.True(
|
||||
TemplateFootingHelper.IsFootprintInsideTargetBlock(finalPos, segments[0].End),
|
||||
$"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[0]}\n{trace}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SprintJumpTemplate_SidewallDescendGap2DyMinus2Wo0_FirstPrepareJump_CompletesFromStart()
|
||||
{
|
||||
PathingExecutionScenario scenario = SidewallParkourScenarioBuilder.Create("sidewall-descend-gap2-dy-2-wo0", gap: 2, deltaY: -2, wallOffset: 0);
|
||||
(World world, List<PathSegment> segments, PlayerPhysics physics) = BuildPlannedScenario(scenario);
|
||||
|
||||
TemplateState state = RunSegment(segments, index: 0, physics, world, out Location finalPos, out string trace);
|
||||
|
||||
Assert.True(state == TemplateState.Complete, $"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[0]}\n{trace}");
|
||||
Assert.True(
|
||||
TemplateFootingHelper.IsFootprintInsideTargetBlock(finalPos, segments[0].End),
|
||||
$"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[0]}\n{trace}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SprintJumpTemplate_SidewallDescendGap2DyMinus1Wo0_FinalStop_CompletesFromChainCarry()
|
||||
{
|
||||
PathingExecutionScenario scenario = SidewallParkourScenarioBuilder.Create("sidewall-descend-gap2-dy-1-wo0", gap: 2, deltaY: -1, wallOffset: 0);
|
||||
(World world, List<PathSegment> segments, PlayerPhysics physics) = BuildPlannedScenario(scenario);
|
||||
|
||||
RunSegmentsThrough(segments, world, physics, lastCompletedIndex: 1);
|
||||
|
||||
TemplateState state = RunSegment(segments, index: 2, physics, world, out Location finalPos, out string trace);
|
||||
|
||||
Assert.True(state == TemplateState.Complete, $"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[2]}\n{trace}");
|
||||
Assert.True(
|
||||
TemplateFootingHelper.IsFootprintInsideTargetBlock(finalPos, segments[2].End),
|
||||
$"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[2]}\n{trace}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SprintJumpTemplate_SidewallDescendGap2DyMinus2Wo0_FinalStop_CompletesFromChainCarry()
|
||||
{
|
||||
PathingExecutionScenario scenario = SidewallParkourScenarioBuilder.Create("sidewall-descend-gap2-dy-2-wo0", gap: 2, deltaY: -2, wallOffset: 0);
|
||||
(World world, List<PathSegment> segments, PlayerPhysics physics) = BuildPlannedScenario(scenario);
|
||||
|
||||
RunSegmentsThrough(segments, world, physics, lastCompletedIndex: 1);
|
||||
|
||||
TemplateState state = RunSegment(segments, index: 2, physics, world, out Location finalPos, out string trace);
|
||||
|
||||
Assert.True(state == TemplateState.Complete, $"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[2]}\n{trace}");
|
||||
Assert.True(
|
||||
TemplateFootingHelper.IsFootprintInsideTargetBlock(finalPos, segments[2].End),
|
||||
$"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[2]}\n{trace}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SprintJumpTemplate_SidewallDescendGap5DyMinus1Wo0_FirstPrepareJump_CompletesFromStart()
|
||||
{
|
||||
PathingExecutionScenario scenario = SidewallParkourScenarioBuilder.Create("sidewall-descend-gap5-dy-1-wo0", gap: 5, deltaY: -1, wallOffset: 0);
|
||||
(World world, List<PathSegment> segments, PlayerPhysics physics) = BuildPlannedScenario(scenario);
|
||||
|
||||
TemplateState state = RunSegment(segments, index: 0, physics, world, out Location finalPos, out string trace);
|
||||
|
||||
Assert.True(state == TemplateState.Complete, $"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[0]}\n{trace}");
|
||||
Assert.True(
|
||||
TemplateFootingHelper.IsFootprintInsideTargetBlock(finalPos, segments[0].End),
|
||||
$"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[0]}\n{trace}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SprintJumpTemplate_SidewallDescendGap5DyMinus1Wo1_FirstPrepareJump_CompletesFromStart()
|
||||
{
|
||||
PathingExecutionScenario scenario = SidewallParkourScenarioBuilder.Create("sidewall-descend-gap5-dy-1-wo1", gap: 5, deltaY: -1, wallOffset: 1);
|
||||
(World world, List<PathSegment> segments, PlayerPhysics physics) = BuildPlannedScenario(scenario);
|
||||
|
||||
TemplateState state = RunSegment(segments, index: 0, physics, world, out Location finalPos, out string trace);
|
||||
|
||||
Assert.True(state == TemplateState.Complete, $"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[0]}\n{trace}");
|
||||
Assert.True(
|
||||
TemplateFootingHelper.IsFootprintInsideTargetBlock(finalPos, segments[0].End),
|
||||
$"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[0]}\n{trace}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SprintJumpTemplate_SidewallDescendGap5DyMinus2Wo0_FirstPrepareJump_CompletesFromStart()
|
||||
{
|
||||
PathingExecutionScenario scenario = SidewallParkourScenarioBuilder.Create("sidewall-descend-gap5-dy-2-wo0", gap: 5, deltaY: -2, wallOffset: 0);
|
||||
(World world, List<PathSegment> segments, PlayerPhysics physics) = BuildPlannedScenario(scenario);
|
||||
|
||||
TemplateState state = RunSegment(segments, index: 0, physics, world, out Location finalPos, out string trace);
|
||||
|
||||
Assert.True(state == TemplateState.Complete, $"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[0]}\n{trace}");
|
||||
Assert.True(
|
||||
TemplateFootingHelper.IsFootprintInsideTargetBlock(finalPos, segments[0].End),
|
||||
$"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[0]}\n{trace}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SprintJumpTemplate_SidewallDescendGap5DyMinus2Wo0_FinalStop_CompletesFromChainCarry()
|
||||
{
|
||||
PathingExecutionScenario scenario = SidewallParkourScenarioBuilder.Create("sidewall-descend-gap5-dy-2-wo0", gap: 5, deltaY: -2, wallOffset: 0);
|
||||
(World world, List<PathSegment> segments, PlayerPhysics physics) = BuildPlannedScenario(scenario);
|
||||
|
||||
RunSegmentsThrough(segments, world, physics, lastCompletedIndex: 1);
|
||||
|
||||
TemplateState state = RunSegment(segments, index: 2, physics, world, out Location finalPos, out string trace);
|
||||
|
||||
Assert.True(state == TemplateState.Complete, $"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[2]}\n{trace}");
|
||||
Assert.True(
|
||||
TemplateFootingHelper.IsFootprintInsideTargetBlock(finalPos, segments[2].End),
|
||||
$"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[2]}\n{trace}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SprintJumpTemplate_SidewallDescendGap3DyMinus1Wo0_FinalStop_CompletesFromChainCarry()
|
||||
{
|
||||
PathingExecutionScenario scenario = SidewallParkourScenarioBuilder.Create("sidewall-descend-gap3-dy-1-wo0", gap: 3, deltaY: -1, wallOffset: 0);
|
||||
(World world, List<PathSegment> segments, PlayerPhysics physics) = BuildPlannedScenario(scenario);
|
||||
|
||||
RunSegmentsThrough(segments, world, physics, lastCompletedIndex: 1);
|
||||
|
||||
TemplateState state = RunSegment(segments, index: 2, physics, world, out Location finalPos, out string trace);
|
||||
|
||||
Assert.True(state == TemplateState.Complete, $"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[2]}\n{trace}");
|
||||
Assert.True(
|
||||
TemplateFootingHelper.IsFootprintInsideTargetBlock(finalPos, segments[2].End),
|
||||
$"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[2]}\n{trace}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SprintJumpTemplate_SidewallFlatGap2_FinalStop_CompletesFromChainCarry()
|
||||
{
|
||||
PathingExecutionScenario scenario = SidewallParkourScenarioBuilder.Create("sidewall-flat-gap2-wo0", gap: 2, deltaY: 0, wallOffset: 0);
|
||||
(World world, List<PathSegment> segments, PlayerPhysics physics) = BuildPlannedScenario(scenario);
|
||||
|
||||
RunSegmentsThrough(segments, world, physics, lastCompletedIndex: 1);
|
||||
|
||||
TemplateState state = RunSegment(segments, index: 2, physics, world, out Location finalPos, out string trace);
|
||||
|
||||
Assert.True(state == TemplateState.Complete, $"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[2]}\n{trace}");
|
||||
Assert.True(
|
||||
TemplateFootingHelper.IsFootprintInsideTargetBlock(finalPos, segments[2].End),
|
||||
$"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[2]}\n{trace}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SprintJumpTemplate_SidewallDescendGap4DyMinus1Wo0_FinalStop_CompletesInsideLandingBlock()
|
||||
{
|
||||
PathingExecutionScenario scenario = SidewallParkourScenarioBuilder.Create("sidewall-descend-gap4-dy-1-wo0", gap: 4, deltaY: -1, wallOffset: 0);
|
||||
(World world, List<PathSegment> segments, PlayerPhysics physics) = BuildPlannedScenario(scenario);
|
||||
|
||||
RunSegmentsThrough(segments, world, physics, lastCompletedIndex: 1);
|
||||
|
||||
TemplateState state = RunSegment(segments, index: 2, physics, world, out Location finalPos, out string trace);
|
||||
|
||||
Assert.True(state == TemplateState.Complete, $"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[2]}\n{trace}");
|
||||
Assert.True(
|
||||
TemplateFootingHelper.IsFootprintInsideTargetBlock(finalPos, segments[2].End),
|
||||
$"state={state} finalPos={finalPos} vel={physics.DeltaMovement} segment={segments[2]}\n{trace}");
|
||||
}
|
||||
|
||||
private static (World World, List<PathSegment> Segments, PlayerPhysics Physics) BuildPlannedLinearScenario(PathingExecutionScenario scenario)
|
||||
{
|
||||
return BuildPlannedScenario(scenario);
|
||||
}
|
||||
|
||||
private static (World World, List<PathSegment> Segments, PlayerPhysics Physics) BuildPlannedScenario(PathingExecutionScenario scenario)
|
||||
{
|
||||
PathResult planResult = PathingScenarioRunner.PlanOnly(scenario);
|
||||
|
||||
|
|
@ -685,7 +956,7 @@ public sealed class SprintJumpTemplateScenarioTests
|
|||
state = template.Tick(pos, physics, input, world);
|
||||
tail.Enqueue(
|
||||
$"tick={tick} state={state} pos={pos} vel={physics.DeltaMovement} yaw={physics.Yaw:F1} onGround={physics.OnGround} " +
|
||||
$"input(F={input.Forward},B={input.Back},J={input.Jump},S={input.Sprint})");
|
||||
$"input(F={input.Forward},B={input.Back},L={input.Left},R={input.Right},J={input.Jump},S={input.Sprint})");
|
||||
if (tail.Count > 40)
|
||||
tail.Dequeue();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue