51 lines
1.9 KiB
C#
51 lines
1.9 KiB
C#
namespace NeonSprawl.Server.Game.PositionState;
|
|
|
|
/// <summary>Pure movement validation for <see cref="MoveCommandRequest"/> targets (NS-19).</summary>
|
|
/// <remarks>
|
|
/// <para><b>Precedence</b> when multiple rules fail: <see cref="MoveCommandReasonCodes.HorizontalStepExceeded"/>,
|
|
/// then <see cref="MoveCommandReasonCodes.VerticalStepExceeded"/>, then <see cref="MoveCommandReasonCodes.OutOfBounds"/>.</para>
|
|
/// <para>Vertical uses <c>abs(ΔY)</c>, so <b>descending</b> (target Y lower than current) is allowed when the
|
|
/// drop is within <see cref="MovementValidationOptions.MaxVerticalStep"/> — same as climbing.</para>
|
|
/// </remarks>
|
|
public static class MoveCommandValidation
|
|
{
|
|
/// <summary>Returns false and sets <paramref name="reasonCode"/> when the move must be rejected.</summary>
|
|
public static bool TryValidate(
|
|
in PositionSnapshot from,
|
|
PositionVector to,
|
|
MovementValidationOptions rules,
|
|
out string reasonCode)
|
|
{
|
|
reasonCode = "";
|
|
|
|
var dx = to.X - from.X;
|
|
var dz = to.Z - from.Z;
|
|
var horizontal = Math.Sqrt(dx * dx + dz * dz);
|
|
if (horizontal > rules.MaxHorizontalStep)
|
|
{
|
|
reasonCode = MoveCommandReasonCodes.HorizontalStepExceeded;
|
|
return false;
|
|
}
|
|
|
|
var dy = Math.Abs(to.Y - from.Y);
|
|
if (dy > rules.MaxVerticalStep)
|
|
{
|
|
reasonCode = MoveCommandReasonCodes.VerticalStepExceeded;
|
|
return false;
|
|
}
|
|
|
|
if (rules.DistrictBoundsEnabled)
|
|
{
|
|
if (to.X < rules.DistrictMinX || to.X > rules.DistrictMaxX ||
|
|
to.Y < rules.DistrictMinY || to.Y > rules.DistrictMaxY ||
|
|
to.Z < rules.DistrictMinZ || to.Z > rules.DistrictMaxZ)
|
|
{
|
|
reasonCode = MoveCommandReasonCodes.OutOfBounds;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|