mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2026-08-29 13:04:59 +00:00
feat: converge grounded path segment completion
This commit is contained in:
parent
3b4e552d70
commit
6b449cc72a
12 changed files with 489 additions and 43 deletions
|
|
@ -47,25 +47,11 @@ namespace MinecraftClient.Pathing.Execution.Templates
|
|||
if (physics.OnGround && dy > 0.1)
|
||||
input.Jump = true;
|
||||
|
||||
if (physics.OnGround && Math.Abs(dy) < 0.15)
|
||||
if (physics.OnGround && Math.Abs(dy) < 0.2)
|
||||
{
|
||||
TransitionBrakingDecision decision = TransitionBrakingPlanner.Plan(_segment, _nextSegment, pos, physics, world);
|
||||
TemplateHelper.ApplyDecision(input, decision);
|
||||
if (decision.HoldBack)
|
||||
TemplateHelper.FaceSegmentHeading(physics, _segment);
|
||||
|
||||
if (_segment.ExitTransition == PathTransitionType.ContinueStraight && horizDistSq < 0.25)
|
||||
GroundedSegmentController.Apply(_segment, _nextSegment, pos, physics, input, world);
|
||||
if (GroundedSegmentController.ShouldComplete(_segment, pos, physics))
|
||||
return TemplateState.Complete;
|
||||
|
||||
if (_segment.ExitTransition != PathTransitionType.ContinueStraight
|
||||
&& TemplateHelper.IsSettledAtEnd(pos, ExpectedEnd, physics, horizThresholdSq: 0.0025))
|
||||
{
|
||||
return TemplateState.Complete;
|
||||
}
|
||||
}
|
||||
else if (horizDistSq < 0.25 && Math.Abs(dy) < 0.8)
|
||||
{
|
||||
return TemplateState.Complete;
|
||||
}
|
||||
|
||||
double movedSq = TemplateHelper.HorizontalDistanceSq(pos, _lastPos);
|
||||
|
|
|
|||
|
|
@ -59,26 +59,14 @@ namespace MinecraftClient.Pathing.Execution.Templates
|
|||
float targetPitch = TemplateHelper.CalculatePitch(dx, dy, dz);
|
||||
physics.Pitch = TemplateHelper.SmoothPitch(physics.Pitch, targetPitch);
|
||||
|
||||
if (physics.OnGround && Math.Abs(dy) < (_hasFallen ? 0.8 : 0.5))
|
||||
if (physics.OnGround && Math.Abs(dy) < (_hasFallen ? 1.0 : 0.6))
|
||||
{
|
||||
if (horizDistSq > 0.01)
|
||||
physics.Yaw = TemplateHelper.SmoothYaw(physics.Yaw, targetYaw);
|
||||
|
||||
TransitionBrakingDecision decision = TransitionBrakingPlanner.Plan(_segment, _nextSegment, pos, physics, world);
|
||||
TemplateHelper.ApplyDecision(input, decision);
|
||||
if (decision.HoldBack)
|
||||
TemplateHelper.FaceSegmentHeading(physics, _segment);
|
||||
|
||||
if (_segment.ExitTransition == PathTransitionType.ContinueStraight)
|
||||
{
|
||||
double completionThreshold = _hasFallen ? 0.5 : 0.25;
|
||||
if (horizDistSq < completionThreshold)
|
||||
return TemplateState.Complete;
|
||||
}
|
||||
else if (TemplateHelper.IsSettledAtEnd(pos, ExpectedEnd, physics, horizThresholdSq: 0.0025))
|
||||
{
|
||||
GroundedSegmentController.Apply(_segment, _nextSegment, pos, physics, input, world);
|
||||
if (GroundedSegmentController.ShouldComplete(_segment, pos, physics))
|
||||
return TemplateState.Complete;
|
||||
}
|
||||
}
|
||||
else if (physics.OnClimbable)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
using MinecraftClient.Mapping;
|
||||
using MinecraftClient.Physics;
|
||||
|
||||
namespace MinecraftClient.Pathing.Execution.Templates
|
||||
{
|
||||
internal static class GroundedSegmentController
|
||||
{
|
||||
internal static void Apply(PathSegment segment, PathSegment? nextSegment, Location pos, PlayerPhysics physics, MovementInput input, World world)
|
||||
{
|
||||
TransitionBrakingDecision decision = TransitionBrakingPlanner.Plan(segment, nextSegment, pos, physics, world);
|
||||
TemplateHelper.ApplyDecision(input, decision);
|
||||
if (decision.HoldBack)
|
||||
TemplateHelper.FaceSegmentHeading(physics, segment);
|
||||
}
|
||||
|
||||
internal static bool ShouldComplete(PathSegment segment, Location pos, PlayerPhysics physics)
|
||||
{
|
||||
return segment.ExitTransition switch
|
||||
{
|
||||
PathTransitionType.ContinueStraight => TemplateHelper.IsNear(pos, segment.End, horizThresholdSq: 0.09),
|
||||
PathTransitionType.PrepareJump => TemplateHelper.HasReachedSegmentEndPlane(pos, segment)
|
||||
&& TemplateHelper.ProjectHorizontalSpeedAlongSegment(physics, segment) > 0.02,
|
||||
_ => physics.OnGround && TemplateHelper.IsSettledOnTargetBlock(pos, segment.End, physics)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
using System;
|
||||
using MinecraftClient.Mapping;
|
||||
using MinecraftClient.Physics;
|
||||
|
||||
namespace MinecraftClient.Pathing.Execution.Templates
|
||||
{
|
||||
public static class TemplateFootingHelper
|
||||
{
|
||||
private const double HalfWidth = PhysicsConsts.PlayerWidth / 2.0;
|
||||
|
||||
public static bool IsFootprintInsideTargetBlock(Location pos, Location target, double epsilon = 1.0E-4)
|
||||
{
|
||||
double minX = pos.X - HalfWidth;
|
||||
double maxX = pos.X + HalfWidth;
|
||||
double minZ = pos.Z - HalfWidth;
|
||||
double maxZ = pos.Z + HalfWidth;
|
||||
|
||||
double blockMinX = Math.Floor(target.X);
|
||||
double blockMaxX = blockMinX + 1.0;
|
||||
double blockMinZ = Math.Floor(target.Z);
|
||||
double blockMaxZ = blockMinZ + 1.0;
|
||||
|
||||
return minX >= blockMinX - epsilon
|
||||
&& maxX <= blockMaxX + epsilon
|
||||
&& minZ >= blockMinZ - epsilon
|
||||
&& maxZ <= blockMaxZ + epsilon;
|
||||
}
|
||||
|
||||
public static bool WillLeaveTargetBlockNextTick(Location pos, PlayerPhysics physics, Location target, double epsilon = 1.0E-4)
|
||||
{
|
||||
Location nextPos = new(
|
||||
pos.X + physics.DeltaMovement.X,
|
||||
pos.Y,
|
||||
pos.Z + physics.DeltaMovement.Z);
|
||||
return !IsFootprintInsideTargetBlock(nextPos, target, epsilon);
|
||||
}
|
||||
|
||||
public static bool WillCrossSupportExitNextTick(Location pos, PlayerPhysics physics, PathSegment segment, double epsilon = 1.0E-4)
|
||||
{
|
||||
double nextX = pos.X + physics.DeltaMovement.X;
|
||||
double nextZ = pos.Z + physics.DeltaMovement.Z;
|
||||
|
||||
double blockMinX = Math.Floor(segment.End.X);
|
||||
double blockMaxX = blockMinX + 1.0;
|
||||
double blockMinZ = Math.Floor(segment.End.Z);
|
||||
double blockMaxZ = blockMinZ + 1.0;
|
||||
|
||||
if (segment.HeadingX > 0 && nextX > blockMaxX - HalfWidth + epsilon)
|
||||
return true;
|
||||
if (segment.HeadingX < 0 && nextX < blockMinX + HalfWidth - epsilon)
|
||||
return true;
|
||||
if (segment.HeadingZ > 0 && nextZ > blockMaxZ - HalfWidth + epsilon)
|
||||
return true;
|
||||
if (segment.HeadingZ < 0 && nextZ < blockMinZ + HalfWidth - epsilon)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -90,14 +90,57 @@ namespace MinecraftClient.Pathing.Execution.Templates
|
|||
input.Back = decision.HoldBack;
|
||||
}
|
||||
|
||||
internal static bool HasReachedSegmentEndPlane(Location pos, PathSegment segment, double tolerance = 0.05)
|
||||
{
|
||||
GetNormalizedSegmentDirection(segment, out double dirX, out double dirZ);
|
||||
double relX = pos.X - segment.End.X;
|
||||
double relZ = pos.Z - segment.End.Z;
|
||||
return relX * dirX + relZ * dirZ >= -tolerance;
|
||||
}
|
||||
|
||||
internal static double ProjectHorizontalSpeedAlongSegment(PlayerPhysics physics, PathSegment segment)
|
||||
{
|
||||
GetNormalizedSegmentDirection(segment, out double dirX, out double dirZ);
|
||||
return physics.DeltaMovement.X * dirX + physics.DeltaMovement.Z * dirZ;
|
||||
}
|
||||
|
||||
internal static bool IsSettledOnTargetBlock(Location pos, Location target, PlayerPhysics physics,
|
||||
double speedThresholdSq = 0.0016)
|
||||
{
|
||||
double horizontalSpeedSq = physics.DeltaMovement.X * physics.DeltaMovement.X
|
||||
+ physics.DeltaMovement.Z * physics.DeltaMovement.Z;
|
||||
return TemplateFootingHelper.IsFootprintInsideTargetBlock(pos, target)
|
||||
&& !TemplateFootingHelper.WillLeaveTargetBlockNextTick(pos, physics, target)
|
||||
&& horizontalSpeedSq <= speedThresholdSq;
|
||||
}
|
||||
|
||||
internal static bool IsSettledAtEnd(Location pos, Location target, PlayerPhysics physics,
|
||||
double horizThresholdSq = 0.0025, double speedThresholdSq = 0.0016)
|
||||
{
|
||||
if (IsSettledOnTargetBlock(pos, target, physics, speedThresholdSq))
|
||||
return true;
|
||||
|
||||
double dx = target.X - pos.X;
|
||||
double dz = target.Z - pos.Z;
|
||||
double horizontalSpeedSq = physics.DeltaMovement.X * physics.DeltaMovement.X
|
||||
+ physics.DeltaMovement.Z * physics.DeltaMovement.Z;
|
||||
return dx * dx + dz * dz <= horizThresholdSq && horizontalSpeedSq <= speedThresholdSq;
|
||||
}
|
||||
|
||||
private static void GetNormalizedSegmentDirection(PathSegment segment, out double dirX, out double dirZ)
|
||||
{
|
||||
dirX = segment.End.X - segment.Start.X;
|
||||
dirZ = segment.End.Z - segment.Start.Z;
|
||||
double len = Math.Sqrt(dirX * dirX + dirZ * dirZ);
|
||||
if (len < 1.0E-6)
|
||||
{
|
||||
dirX = 0.0;
|
||||
dirZ = 0.0;
|
||||
return;
|
||||
}
|
||||
|
||||
dirX /= len;
|
||||
dirZ /= len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,22 +40,21 @@ namespace MinecraftClient.Pathing.Execution.Templates
|
|||
physics.Yaw = TemplateHelper.SmoothYaw(physics.Yaw, targetYaw);
|
||||
physics.Pitch = TemplateHelper.SmoothPitch(physics.Pitch, targetPitch);
|
||||
|
||||
TransitionBrakingDecision decision = TransitionBrakingPlanner.Plan(_segment, _nextSegment, pos, physics, world);
|
||||
TemplateHelper.ApplyDecision(input, decision);
|
||||
if (decision.HoldBack)
|
||||
TemplateHelper.FaceSegmentHeading(physics, _segment);
|
||||
GroundedSegmentController.Apply(_segment, _nextSegment, pos, physics, input, world);
|
||||
|
||||
if (_segment.ExitTransition == PathTransitionType.ContinueStraight && TemplateHelper.IsNear(pos, ExpectedEnd, horizThresholdSq: 0.09))
|
||||
return TemplateState.Complete;
|
||||
|
||||
if (_segment.ExitTransition != PathTransitionType.ContinueStraight && TemplateHelper.IsSettledAtEnd(pos, ExpectedEnd, physics))
|
||||
if (GroundedSegmentController.ShouldComplete(_segment, pos, physics))
|
||||
return TemplateState.Complete;
|
||||
|
||||
double movedSq = TemplateHelper.HorizontalDistanceSq(pos, _lastPos);
|
||||
_stuckTicks = movedSq < 0.0005 ? _stuckTicks + 1 : 0;
|
||||
_lastPos = pos;
|
||||
|
||||
int maxTicks = _segment.ExitTransition == PathTransitionType.ContinueStraight ? 100 : 140;
|
||||
int maxTicks = _segment.ExitTransition switch
|
||||
{
|
||||
PathTransitionType.ContinueStraight => 100,
|
||||
PathTransitionType.PrepareJump => 80,
|
||||
_ => 140
|
||||
};
|
||||
if (_stuckTicks > 40 || _tickCount > maxTicks)
|
||||
return TemplateState.Failed;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue