feat(runtime): classify retail authoritative position routes

This commit is contained in:
Erik 2026-08-01 18:23:07 +02:00
parent 0fbc7a1fb7
commit 3f800a4aec
2 changed files with 1107 additions and 0 deletions

View file

@ -0,0 +1,554 @@
using System.Numerics;
using AcDream.Core.Net.Messages;
using AcDream.Core.Physics;
using AcDream.Runtime.Entities;
namespace AcDream.Runtime.Physics;
internal enum RuntimePositionEntityKind : byte
{
Unknown,
LocalPlayer,
Remote,
Projectile,
}
internal enum RuntimeCreateResidenceKind : byte
{
Unknown,
TopLevel,
Parented,
PickedUp,
}
internal enum RuntimeAcceptedPositionSource : byte
{
Unknown,
PositionEvent,
SameIncarnationCreate,
}
internal enum RuntimeLeaveWorldCause : byte
{
Unknown,
Pickup,
Parent,
}
internal enum RuntimeAuthoritativePositionDisposition : byte
{
RejectedAuthority,
RejectedData,
AwaitFreshPosition,
NoPositionOperation,
Interpolate,
SetPosition,
SetPositionSimple,
}
internal enum RuntimeTeleportHookPhase : byte
{
None,
BeforePositionOperation,
AfterPositionOperation,
AfterEnterWorld,
}
/// <summary>
/// Exact accepted-wire authority for one presentation-independent position
/// route. <see cref="RuntimeEntityKey"/> identifies the incarnation while
/// <see cref="PositionAuthorityVersion"/> rejects a superseded accepted pose.
/// The previous and accepted TELEPORT_TS values remain explicit so the pure
/// classifier can apply retail's wrap-safe freshness rule without consulting
/// App state.
/// </summary>
internal readonly record struct RuntimeAuthoritativePositionAuthority(
RuntimeGenerationToken Generation,
RuntimeEntityKey Entity,
ulong PositionAuthorityVersion,
ushort AcceptedPositionSequence,
ushort PreviousTeleportSequence,
ushort AcceptedTeleportSequence,
PositionTimestampDisposition TimestampDisposition)
{
internal bool IsStructurallyValid => Generation.Value != 0UL
&& Entity.LocalEntityId != 0u
&& PositionAuthorityVersion != 0UL
&& TimestampDisposition is PositionTimestampDisposition.Apply
or PositionTimestampDisposition.ForcePosition;
internal bool TeleportAdvanced =>
TimestampDisposition is PositionTimestampDisposition.Apply
&& PhysicsTimestampGate.IsNewer(
PreviousTeleportSequence,
AcceptedTeleportSequence);
internal bool TeleportRegressed =>
PhysicsTimestampGate.IsNewer(
AcceptedTeleportSequence,
PreviousTeleportSequence);
}
/// <summary>
/// Placement facts which must not be collapsed into presentation visibility.
/// Hidden and NoDraw objects still run retail SetPosition. Hidden suppresses
/// the complete collision batch after its retail state rewrite; NoDraw is
/// render-only. Source/peer ReportCollisions and IgnoreCollisions decisions
/// remain downstream in RuntimeCollisionReportingState.
/// </summary>
internal readonly record struct RuntimePositionPlacementFacts(
PhysicsStateFlags PhysicsState,
bool HasAuthoredMoverShape)
{
internal bool CollisionBatchEligible =>
(PhysicsState & PhysicsStateFlags.Hidden) == 0;
}
internal readonly record struct RuntimeCreatePositionRouteRequest(
RuntimeAuthoritativePositionAuthority Authority,
RuntimePositionEntityKind EntityKind,
RuntimeCreateResidenceKind Residence,
CreateObject.ServerPosition? AcceptedWirePosition,
RuntimePositionPlacementFacts PlacementFacts);
internal readonly record struct RuntimeAcceptedPositionRouteRequest(
RuntimeAuthoritativePositionAuthority Authority,
RuntimePositionEntityKind EntityKind,
RuntimeAcceptedPositionSource Source,
CreateObject.ServerPosition AcceptedWirePosition,
uint? PlacementFrame,
Vector3? PositionPackVelocity,
uint? CommittedCellId,
bool HasContact,
float PlayerDistance,
bool UsePositionFromServer,
bool HasAnimations,
RuntimePositionPlacementFacts PlacementFacts);
internal readonly record struct RuntimeLeaveWorldRouteRequest(
RuntimeAuthoritativePositionAuthority Authority,
RuntimePositionEntityKind EntityKind,
RuntimeLeaveWorldCause Cause,
RuntimePositionPlacementFacts PlacementFacts);
/// <summary>
/// Immutable action plan for retail HandleReceivedPosition/MoveOrTeleport.
/// It deliberately contains no renderer, world entity, UI, or host callback.
/// Graphical and headless hosts will consume the same plan during Group 2.
/// </summary>
internal readonly record struct RuntimeAuthoritativePositionRoute(
RuntimeAuthoritativePositionAuthority Authority,
RuntimeAuthoritativePositionDisposition Disposition,
RuntimeSetPositionOperationKind OperationKind,
PhysicsSetPositionFlags SetPositionFlags,
uint PlacementFrame,
bool UnparentBeforeRouting,
bool ApplyPlacementFrameBeforeRouting,
bool LeaveWorld,
RuntimeTeleportHookPhase TeleportHookPhase,
bool StopInterpolating,
bool ConstrainAfterRouting,
bool PreserveHeading,
bool ZeroVelocity,
bool SendPositionImmediately,
bool CollisionBatchEligible)
{
internal bool Accepted => Disposition is not
RuntimeAuthoritativePositionDisposition.RejectedAuthority
and not RuntimeAuthoritativePositionDisposition.RejectedData;
internal bool PerformsSetPosition => Disposition is
RuntimeAuthoritativePositionDisposition.SetPosition
or RuntimeAuthoritativePositionDisposition.SetPositionSimple;
internal bool RunsTeleportHook =>
TeleportHookPhase is not RuntimeTeleportHookPhase.None;
}
/// <summary>
/// Pure retail route classifier for new CreateObject residence,
/// SmartBox::HandleReceivedPosition (0x00453FD0), and
/// CPhysicsObj::MoveOrTeleport (0x00516330).
/// </summary>
internal static class RuntimeAuthoritativePositionRouteClassifier
{
private const float MaxPhysicsDistance = 96f;
private const PhysicsSetPositionFlags InitialCreateFlags =
PhysicsSetPositionFlags.Placement | PhysicsSetPositionFlags.Slide;
private const PhysicsSetPositionFlags AuthoritativeTeleportFlags =
PhysicsSetPositionFlags.Teleport
| PhysicsSetPositionFlags.Slide
| PhysicsSetPositionFlags.SendPositionEvent;
internal static RuntimeAuthoritativePositionRoute ClassifyCreate(
in RuntimeCreatePositionRouteRequest request)
{
if (!ValidCreateAuthority(request.Authority)
|| !ValidEntityKind(request.EntityKind)
|| request.Residence is RuntimeCreateResidenceKind.Unknown)
{
return RejectedAuthority(request.Authority);
}
RuntimeSetPositionOperationKind operation = OperationKind(
request.EntityKind,
initialCreate: true);
bool reporting = request.PlacementFacts.CollisionBatchEligible;
if (request.Residence is RuntimeCreateResidenceKind.Parented
or RuntimeCreateResidenceKind.PickedUp)
{
return new RuntimeAuthoritativePositionRoute(
request.Authority,
RuntimeAuthoritativePositionDisposition.AwaitFreshPosition,
operation,
PhysicsSetPositionFlags.None,
0u,
UnparentBeforeRouting: false,
ApplyPlacementFrameBeforeRouting: false,
LeaveWorld: true,
TeleportHookPhase: RuntimeTeleportHookPhase.None,
StopInterpolating: false,
ConstrainAfterRouting: false,
PreserveHeading: false,
ZeroVelocity: false,
SendPositionImmediately: false,
reporting);
}
if (request.AcceptedWirePosition is not { } position
|| !ValidPosition(position))
{
return RejectedData(request.Authority, operation, reporting);
}
// New CreateObject enters through CPhysicsObj::enter_world(Position*)
// -> enter_world(1), which uses 0x11 for every top-level object.
// Static state and an authored-shapeless Setup do not suppress the
// SetPosition transaction; Core supplies retail's placement dummy
// sphere when required.
return new RuntimeAuthoritativePositionRoute(
request.Authority,
RuntimeAuthoritativePositionDisposition.SetPosition,
operation,
InitialCreateFlags,
0u,
UnparentBeforeRouting: false,
ApplyPlacementFrameBeforeRouting: false,
LeaveWorld: false,
TeleportHookPhase: request.EntityKind
is RuntimePositionEntityKind.LocalPlayer
? RuntimeTeleportHookPhase.AfterEnterWorld
: RuntimeTeleportHookPhase.None,
StopInterpolating: false,
ConstrainAfterRouting: false,
PreserveHeading: false,
ZeroVelocity: false,
SendPositionImmediately: false,
reporting);
}
internal static RuntimeAuthoritativePositionRoute ClassifyAcceptedPosition(
in RuntimeAcceptedPositionRouteRequest request)
{
RuntimeSetPositionOperationKind operation = OperationKind(
request.EntityKind,
initialCreate: false);
bool reporting = request.PlacementFacts.CollisionBatchEligible;
if (!ValidAcceptedAuthority(request.Authority, request.EntityKind)
|| request.Source is RuntimeAcceptedPositionSource.Unknown
|| !ValidEntityKind(request.EntityKind))
{
return RejectedAuthority(request.Authority, operation, reporting);
}
if (!ValidPosition(request.AcceptedWirePosition))
return RejectedData(request.Authority, operation, reporting);
bool force = request.Authority.TimestampDisposition
is PositionTimestampDisposition.ForcePosition;
if (force)
{
// The FORCE_POSITION branch precedes unset_parent and
// SetPlacementFrame in HandleReceivedPosition.
return new RuntimeAuthoritativePositionRoute(
request.Authority,
RuntimeAuthoritativePositionDisposition.SetPositionSimple,
operation,
AuthoritativeTeleportFlags,
request.PlacementFrame ?? 0u,
UnparentBeforeRouting: false,
ApplyPlacementFrameBeforeRouting: false,
LeaveWorld: false,
TeleportHookPhase: RuntimeTeleportHookPhase.None,
StopInterpolating: false,
ConstrainAfterRouting: false,
PreserveHeading: true,
ZeroVelocity: false,
SendPositionImmediately: true,
reporting);
}
uint placement = request.PlacementFrame ?? 0u;
if (request.EntityKind is RuntimePositionEntityKind.LocalPlayer)
{
if (request.Authority.TeleportAdvanced)
{
return new RuntimeAuthoritativePositionRoute(
request.Authority,
RuntimeAuthoritativePositionDisposition.SetPosition,
operation,
AuthoritativeTeleportFlags,
placement,
UnparentBeforeRouting: true,
ApplyPlacementFrameBeforeRouting: !request.HasAnimations,
LeaveWorld: false,
TeleportHookPhase: RuntimeTeleportHookPhase.AfterPositionOperation,
StopInterpolating: false,
ConstrainAfterRouting: true,
PreserveHeading: false,
ZeroVelocity: true,
SendPositionImmediately: false,
reporting);
}
bool interpolate = request.UsePositionFromServer
&& request.HasContact;
return new RuntimeAuthoritativePositionRoute(
request.Authority,
interpolate
? RuntimeAuthoritativePositionDisposition.Interpolate
: RuntimeAuthoritativePositionDisposition.NoPositionOperation,
operation,
PhysicsSetPositionFlags.None,
placement,
UnparentBeforeRouting: true,
ApplyPlacementFrameBeforeRouting: !request.HasAnimations,
LeaveWorld: false,
TeleportHookPhase: RuntimeTeleportHookPhase.None,
StopInterpolating: false,
ConstrainAfterRouting: true,
PreserveHeading: false,
ZeroVelocity: false,
SendPositionImmediately: false,
reporting);
}
// Accepted wire position is intentionally distinct from committed
// residence. A target frame with a nonzero cell does not make a
// cellless canonical body resident; only a later Runtime SetPosition
// or simulation commit may change FullCellId.
bool cellless = !request.CommittedCellId.HasValue
|| request.CommittedCellId.Value == 0u;
if (request.Authority.TeleportAdvanced || cellless)
{
return new RuntimeAuthoritativePositionRoute(
request.Authority,
RuntimeAuthoritativePositionDisposition.SetPosition,
operation,
AuthoritativeTeleportFlags,
placement,
UnparentBeforeRouting: true,
ApplyPlacementFrameBeforeRouting: !request.HasAnimations,
LeaveWorld: false,
TeleportHookPhase: RuntimeTeleportHookPhase.BeforePositionOperation,
StopInterpolating: false,
ConstrainAfterRouting: true,
PreserveHeading: false,
ZeroVelocity: false,
SendPositionImmediately: false,
reporting);
}
// Same-incarnation CreateObject passes arg5=true directly to
// HandleReceivedPosition; it never consults the body's current
// contact bit for MoveOrTeleport classification.
bool effectiveContact = request.Source
is RuntimeAcceptedPositionSource.SameIncarnationCreate
|| request.HasContact;
if (!effectiveContact)
{
return new RuntimeAuthoritativePositionRoute(
request.Authority,
RuntimeAuthoritativePositionDisposition.NoPositionOperation,
operation,
PhysicsSetPositionFlags.None,
placement,
UnparentBeforeRouting: true,
ApplyPlacementFrameBeforeRouting: !request.HasAnimations,
LeaveWorld: false,
TeleportHookPhase: RuntimeTeleportHookPhase.None,
StopInterpolating: false,
ConstrainAfterRouting: false,
PreserveHeading: false,
ZeroVelocity: false,
SendPositionImmediately: false,
reporting);
}
// Retail has no explicit NaN policy here. Reject a nonfinite derived
// distance at the modern authority boundary rather than recreating an
// x87 unordered-compare accident as gameplay behavior.
if (!float.IsFinite(request.PlayerDistance)
|| request.PlayerDistance < 0f)
{
return RejectedData(request.Authority, operation, reporting);
}
bool nearby = request.PlayerDistance < MaxPhysicsDistance;
return new RuntimeAuthoritativePositionRoute(
request.Authority,
nearby
? RuntimeAuthoritativePositionDisposition.Interpolate
: RuntimeAuthoritativePositionDisposition.SetPositionSimple,
operation,
nearby ? PhysicsSetPositionFlags.None : AuthoritativeTeleportFlags,
placement,
UnparentBeforeRouting: true,
ApplyPlacementFrameBeforeRouting: !request.HasAnimations,
LeaveWorld: false,
TeleportHookPhase: RuntimeTeleportHookPhase.None,
StopInterpolating: !nearby,
ConstrainAfterRouting: true,
PreserveHeading: false,
ZeroVelocity: false,
SendPositionImmediately: false,
reporting);
}
internal static RuntimeAuthoritativePositionRoute ClassifyLeaveWorld(
in RuntimeLeaveWorldRouteRequest request)
{
RuntimeSetPositionOperationKind operation = OperationKind(
request.EntityKind,
initialCreate: false);
bool reporting = request.PlacementFacts.CollisionBatchEligible;
if (!ValidCreateAuthority(request.Authority)
|| !ValidEntityKind(request.EntityKind)
|| request.Cause is RuntimeLeaveWorldCause.Unknown)
{
return RejectedAuthority(request.Authority, operation, reporting);
}
return new RuntimeAuthoritativePositionRoute(
request.Authority,
RuntimeAuthoritativePositionDisposition.AwaitFreshPosition,
operation,
PhysicsSetPositionFlags.None,
0u,
UnparentBeforeRouting: false,
ApplyPlacementFrameBeforeRouting: false,
LeaveWorld: true,
TeleportHookPhase: RuntimeTeleportHookPhase.None,
StopInterpolating: false,
ConstrainAfterRouting: false,
PreserveHeading: false,
ZeroVelocity: false,
SendPositionImmediately: false,
reporting);
}
private static bool ValidCreateAuthority(
in RuntimeAuthoritativePositionAuthority authority) =>
authority.IsStructurallyValid
&& authority.TimestampDisposition is PositionTimestampDisposition.Apply
&& authority.PreviousTeleportSequence == authority.AcceptedTeleportSequence;
private static bool ValidAcceptedAuthority(
in RuntimeAuthoritativePositionAuthority authority,
RuntimePositionEntityKind kind)
{
if (!authority.IsStructurallyValid || authority.TeleportRegressed)
return false;
return authority.TimestampDisposition switch
{
PositionTimestampDisposition.Apply => true,
PositionTimestampDisposition.ForcePosition =>
kind is RuntimePositionEntityKind.LocalPlayer
&& authority.PreviousTeleportSequence
== authority.AcceptedTeleportSequence,
_ => false,
};
}
private static bool ValidEntityKind(RuntimePositionEntityKind kind) =>
kind is RuntimePositionEntityKind.LocalPlayer
or RuntimePositionEntityKind.Remote
or RuntimePositionEntityKind.Projectile;
private static bool ValidPosition(in CreateObject.ServerPosition position)
{
var origin = new Vector3(
position.PositionX,
position.PositionY,
position.PositionZ);
var orientation = new Quaternion(
position.RotationX,
position.RotationY,
position.RotationZ,
position.RotationW);
return float.IsFinite(origin.X)
&& float.IsFinite(origin.Y)
&& float.IsFinite(origin.Z)
&& float.IsFinite(orientation.X)
&& float.IsFinite(orientation.Y)
&& float.IsFinite(orientation.Z)
&& float.IsFinite(orientation.W)
&& PositionFrameValidation.IsValid(
position.LandblockId,
origin,
orientation);
}
private static RuntimeSetPositionOperationKind OperationKind(
RuntimePositionEntityKind kind,
bool initialCreate) => kind switch
{
RuntimePositionEntityKind.LocalPlayer when initialCreate =>
RuntimeSetPositionOperationKind.InitialLogin,
RuntimePositionEntityKind.LocalPlayer =>
RuntimeSetPositionOperationKind.LocalAuthoritative,
RuntimePositionEntityKind.Projectile =>
RuntimeSetPositionOperationKind.ProjectileAuthoritative,
_ => RuntimeSetPositionOperationKind.RemoteAuthoritative,
};
private static RuntimeAuthoritativePositionRoute RejectedAuthority(
in RuntimeAuthoritativePositionAuthority authority,
RuntimeSetPositionOperationKind operation =
RuntimeSetPositionOperationKind.RemoteAuthoritative,
bool reporting = false) => new(
authority,
RuntimeAuthoritativePositionDisposition.RejectedAuthority,
operation,
PhysicsSetPositionFlags.None,
0u,
UnparentBeforeRouting: false,
ApplyPlacementFrameBeforeRouting: false,
LeaveWorld: false,
TeleportHookPhase: RuntimeTeleportHookPhase.None,
StopInterpolating: false,
ConstrainAfterRouting: false,
PreserveHeading: false,
ZeroVelocity: false,
SendPositionImmediately: false,
reporting);
private static RuntimeAuthoritativePositionRoute RejectedData(
in RuntimeAuthoritativePositionAuthority authority,
RuntimeSetPositionOperationKind operation,
bool reporting) => new(
authority,
RuntimeAuthoritativePositionDisposition.RejectedData,
operation,
PhysicsSetPositionFlags.None,
0u,
UnparentBeforeRouting: false,
ApplyPlacementFrameBeforeRouting: false,
LeaveWorld: false,
TeleportHookPhase: RuntimeTeleportHookPhase.None,
StopInterpolating: false,
ConstrainAfterRouting: false,
PreserveHeading: false,
ZeroVelocity: false,
SendPositionImmediately: false,
reporting);
}