using System.Numerics;
using AcDream.Core.Physics;
using AcDream.Core.Physics.Motion;
using AcDream.Runtime.Entities;
using AcDream.Runtime.Physics;
namespace AcDream.Runtime.Gameplay;
internal enum RuntimeLocalPlayerPhysicsPublicationStatus
{
Prepared,
Committed,
RejectedAuthority,
RejectedToken,
Discarded,
}
internal enum RuntimeLocalPlayerPhysicsActivationStatus
{
Evaluated,
DeferredCell,
RejectedPlacement,
RejectedAuthority,
RejectedToken,
}
internal enum RuntimeLocalPlayerShadowDisposition : byte
{
RegisteredAuthoredPayload,
ProvenShapeless,
}
internal readonly record struct RuntimeLocalPlayerPhysicsActivationPreparation(
float Radius,
float Height,
RuntimeLocalPlayerShadowDisposition ShadowDisposition)
{
internal bool IsValid => float.IsFinite(Radius)
&& Radius >= 0f
&& float.IsFinite(Height)
&& Height >= 0f
&& ShadowDisposition is RuntimeLocalPlayerShadowDisposition
.RegisteredAuthoredPayload
or RuntimeLocalPlayerShadowDisposition.ProvenShapeless;
}
internal readonly record struct RuntimeLocalPlayerPhysicsPublicationToken(
RuntimeEntityKey Entity,
RuntimeEntityPlacementToken Placement,
ulong PublicationId,
uint LocalPlayerServerGuid,
long LocalPlayerIdentityRevision,
ulong PhysicsOwnershipEpoch,
ulong ObjectClockEpoch,
ulong ControllerOwnershipEpoch,
ulong SessionGenerationAuthority)
{
internal bool IsValid => PublicationId != 0UL
&& LocalPlayerServerGuid != 0u
&& Placement.IsValid
&& Entity == Placement.Entity;
}
internal readonly record struct RuntimeLocalPlayerPhysicsActivationToken(
RuntimeEntityKey Entity,
RuntimeEntityPlacementToken Placement,
ulong ActivationId,
uint LocalPlayerServerGuid,
long LocalPlayerIdentityRevision,
ulong PhysicsOwnershipEpoch,
ulong ObjectClockEpoch,
ulong ControllerOwnershipEpoch,
ulong SessionGenerationAuthority)
{
internal bool IsValid => ActivationId != 0UL
&& LocalPlayerServerGuid != 0u
&& Placement.IsValid
&& Entity == Placement.Entity;
}
internal readonly record struct RuntimeLocalPlayerPhysicsActivationReceipt(
RuntimeLocalPlayerPhysicsActivationToken Token,
ulong EvaluationId,
RuntimeDormantSetPositionEvaluation Placement)
{
internal bool IsValid => Token.IsValid
&& EvaluationId != 0UL
&& Placement.Placement == Token.Placement;
}
internal readonly record struct RuntimeLocalPlayerPhysicsCandidateSnapshot(
Vector3 Position,
Quaternion Orientation,
uint CellId,
Vector3 CellLocalPosition,
PhysicsStateFlags State,
TransientStateFlags TransientState,
bool InWorld);
public readonly record struct
RuntimeLocalPlayerPhysicsPublicationOwnershipSnapshot(
bool IsBound,
bool IsDisposed,
int CandidateCount,
int PendingActivationCount,
ulong LastPublicationId)
{
internal bool IsConverged => !IsBound
|| (IsDisposed
&& CandidateCount == 0
&& PendingActivationCount == 0);
}
///
/// Dormant, presentation-independent owner of local-player body/controller
/// candidates. Preparation owns a private body and clock. Commit is one
/// callback-free update-thread transaction which assigns that exact body to
/// the canonical entity and a dormant movement controller. It deliberately
/// does not activate the controller or
/// consume SetPosition or publish world residence, host, shadow, ordinary
/// workset, FullCell, or presentation state; those belong to the subsequent
/// activation transaction.
///
internal sealed class RuntimeLocalPlayerPhysicsPublicationState : IDisposable
{
private sealed class Candidate
{
internal required RuntimeLocalPlayerPhysicsPublicationToken Token
{ get; init; }
internal required RuntimeEntityRecord Record { get; init; }
internal required RuntimeSetPositionCommand PlacementCommand
{ get; init; }
internal required PlayerMovementController Controller { get; init; }
internal required PhysicsBody Body { get; init; }
internal required EntityPhysicsHost PhysicsHost { get; init; }
internal required MovementManager Movement { get; init; }
internal required MotionInterpreter Motion { get; init; }
internal required RuntimeLocalPlayerPhysicsActivationPreparation
ActivationPreparation { get; init; }
internal required Activation PreparedActivation { get; init; }
}
private sealed class Activation
{
internal required RuntimeLocalPlayerPhysicsActivationToken Token
{ get; init; }
internal required RuntimeEntityRecord Record { get; init; }
internal required RuntimeSetPositionCommand PlacementCommand
{ get; init; }
internal required PlayerMovementController Controller { get; init; }
internal required PhysicsBody Body { get; init; }
internal required EntityPhysicsHost PhysicsHost { get; init; }
internal required MovementManager Movement { get; init; }
internal required MotionInterpreter Motion { get; init; }
internal required RuntimeLocalPlayerPhysicsActivationPreparation
ActivationPreparation { get; init; }
internal RuntimeLocalPlayerPhysicsActivationReceipt Receipt
{ get; set; }
internal RuntimeDormantSetPositionCommitReceipt PendingFinalCommit
{ get; set; }
}
private readonly RuntimeEntityDirectory _entities;
private readonly RuntimePhysicsState _physics;
private readonly RuntimeLocalPlayerMovementState _movement;
private readonly RuntimeLocalPlayerIdentityState _identity;
private Candidate? _candidate;
private Activation? _activation;
private ulong _nextPublicationId;
private ulong _nextActivationId;
private ulong _nextEvaluationId;
private long _activationDispatchFailureCount;
private bool _disposed;
internal RuntimeLocalPlayerPhysicsPublicationState(
RuntimeEntityDirectory entities,
RuntimePhysicsState physics,
RuntimeLocalPlayerMovementState movement,
RuntimeLocalPlayerIdentityState identity)
{
_entities = entities ?? throw new ArgumentNullException(nameof(entities));
_physics = physics ?? throw new ArgumentNullException(nameof(physics));
_movement = movement ?? throw new ArgumentNullException(nameof(movement));
_identity = identity ?? throw new ArgumentNullException(nameof(identity));
}
internal RuntimeLocalPlayerPhysicsPublicationStatus Prepare(
RuntimeEntityRecord record,
in RuntimeEntityPlacementToken placement,
in RuntimeSetPositionCommand command,
PlayerMovementConstructionOptions options,
in RuntimeLocalPlayerPhysicsActivationPreparation activationPreparation,
out RuntimeLocalPlayerPhysicsPublicationToken token)
{
ObjectDisposedException.ThrowIf(_disposed, this);
ArgumentNullException.ThrowIfNull(record);
token = default;
if (!activationPreparation.IsValid
|| !CanPrepare(record, placement, command))
return RuntimeLocalPlayerPhysicsPublicationStatus.RejectedAuthority;
// Exhaustion is checked before allocating or replacing a private
// candidate. A checked overflow must not strand an unowned controller
// or discard an already-prepared exact receipt.
ulong publicationId = checked(_nextPublicationId + 1UL);
ulong activationId = checked(_nextActivationId + 1UL);
RuntimeLocalPlayerPhysicsActivationPreparation preparedActivation =
activationPreparation;
var controller = PlayerMovementController.CreatePublicationCandidate(
_physics.Engine,
options);
controller.LocalEntityId = record.Key!.Value.LocalEntityId;
controller.StepUpHeight = command.Physics.StepUpHeight;
controller.StepDownHeight = command.Physics.StepDownHeight;
controller.SphereList = command.Physics.Spheres;
controller.ObjectScale = command.Physics.Scale;
controller.PreparePositionForCommit(
command.Physics.Position,
command.Physics.CellId,
command.Physics.CellLocalPosition);
controller.SetBodyOrientation(command.Physics.Orientation);
controller.ApplyPhysicsState(record.FinalPhysicsState);
PhysicsBody body = controller.PhysicsBody;
var physics = record.Snapshot.Physics;
body.Friction = NormalizeFriction(
physics?.Friction ?? record.Snapshot.Friction);
body.Elasticity = NormalizeElasticity(
physics?.Elasticity
?? record.Snapshot.Elasticity
?? body.Elasticity);
if (physics?.Velocity is { } initialVelocity)
body.set_velocity(initialVelocity);
if (physics?.AngularVelocity is { } initialOmega)
body.Omega = initialOmega;
MovementManager movement = controller.Movement;
MotionInterpreter motion = controller.Motion;
EntityPhysicsHost physicsHost = null!;
movement.MoveToFactory = () =>
{
var moveTo = new MoveToManager(
motion,
stopCompletely: () =>
_ = controller.StopCompletelyAtPhysicsObjectBoundary(),
// App/Runtime movement managers use one normalized world
// coordinate frame. PhysicsBody.CellPosition deliberately
// retains retail's landblock-local origin for cell transit;
// publishing it here made every remote TargetManager chase a
// different point whenever the player and world origin were
// not the same landblock.
getPosition: () => new Position(
body.CellPosition.ObjCellId,
body.Position,
body.Orientation),
getHeading: () => MoveToMath.GetHeading(body.Orientation),
setHeading: (heading, _) => body.Orientation =
MoveToMath.SetHeading(body.Orientation, heading),
getOwnRadius: () => preparedActivation.Radius,
getOwnHeight: () => preparedActivation.Height,
contact: () => body.InContact,
isInterpolating: static () => false,
getVelocity: () => body.Velocity,
getSelfId: () => record.ServerGuid,
setTarget: (context, target, radius, quantum) =>
physicsHost.SetTarget(context, target, radius, quantum),
clearTarget: () => physicsHost.ClearTarget(),
getTargetQuantum: () =>
physicsHost.TargetManager.GetTargetQuantum(),
setTargetQuantum: quantum =>
physicsHost.TargetManager.SetTargetQuantum(quantum),
curTime: () => controller.SimTimeSeconds);
moveTo.StickTo = (target, radius, height) =>
physicsHost.PositionManager.StickTo(target, radius, height);
moveTo.Unstick = physicsHost.PositionManager.UnStick;
return moveTo;
};
physicsHost = new EntityPhysicsHost(
record.ServerGuid,
getPosition: () => new Position(
body.CellPosition.ObjCellId,
body.Position,
body.Orientation),
getVelocity: () => body.Velocity,
getRadius: () => preparedActivation.Radius,
inContact: () => body.InContact,
minterpMaxSpeed: () => motion.GetAdjustedMaxSpeed(),
curTime: () => controller.SimTimeSeconds,
physicsTimerTime: () => controller.SimTimeSeconds,
// 2026-08-08 vendor-approach root cause: this seam is retail's
// CObjectMaint::GetObjectA — it must resolve ANY in-world object
// so TargetManager.SetTarget's add_voyeur can deliver the
// immediate initial snapshot that a deferred MoveToObject/
// TurnToObject needs before it queues a single node (UseTime's
// object-move gate stays closed until that first
// HandleUpdateTarget). The previous binding went straight to
// _physics.TryGetPhysicsHost, which answers only entities whose
// host is ALREADY installed (remote-motion-bound movers) — a
// never-animated NPC/static target resolved to null, add_voyeur
// never ran, and the armed approach sat inert (no nodes, no
// movement, no completion) until user input or the 10 s
// staleness timeout cancelled it. ResolveObjectTableHost routes
// through the host-bound canonical resolver (the SAME
// lazy-minimal-host lookup every remote host's GetObjectA uses)
// and falls back to the exact installed-host lookup when no
// resolver is bound (no-window hosts).
getObjectA: _physics.ResolveObjectTableHost,
// C3c: the [autowalk-target]/[autowalk-end] probes moved here
// with controller construction (previously App-side in
// PlayerModeController.BuildControllerAndCamera); they stay on
// the PhysicsDiagnostics owner exactly as before.
handleUpdateTarget: info =>
{
movement.HandleUpdateTarget(info);
},
interruptCurrentMovement: () =>
{
movement.CancelMoveTo(WeenieError.ActionCancelled);
});
movement.MakeMoveToManager();
motion.UnstickFromObject = physicsHost.PositionManager.UnStick;
motion.InterruptCurrentMovement = () =>
{
movement.CancelMoveTo(WeenieError.ActionCancelled);
};
controller.PositionManager = physicsHost.PositionManager;
// This checkpoint publishes ownership only. The subsequent canonical
// SetPosition transaction is the sole authority which may enter the
// body into world simulation and activate its ordinary workset.
body.InWorld = false;
body.TransientState &= ~TransientStateFlags.Active;
controller.SealPublicationCandidate();
// Candidate construction is intentionally private, but every accepted
// authority is rechecked after it so future content/configuration work
// cannot accidentally create a callback-shaped stale publication.
if (!CanPrepare(record, placement, command))
{
controller.DiscardRuntimeCandidate();
return RuntimeLocalPlayerPhysicsPublicationStatus.RejectedAuthority;
}
DiscardCurrent();
_nextPublicationId = publicationId;
_nextActivationId = activationId;
token = new RuntimeLocalPlayerPhysicsPublicationToken(
record.Key.Value,
placement,
publicationId,
_identity.ServerGuid,
_identity.Revision,
record.PhysicsOwnershipEpoch,
record.ObjectClockEpoch,
_movement.ControllerOwnershipEpoch,
_entities.SessionLifetimeVersion);
ulong expectedControllerEpoch = checked(
_movement.ControllerOwnershipEpoch + 1UL);
var activationEnvelope = new Activation
{
Token = new RuntimeLocalPlayerPhysicsActivationToken(
token.Entity,
token.Placement,
activationId,
token.LocalPlayerServerGuid,
token.LocalPlayerIdentityRevision,
checked(token.PhysicsOwnershipEpoch + 1UL),
token.ObjectClockEpoch,
expectedControllerEpoch,
token.SessionGenerationAuthority),
Record = record,
PlacementCommand = command,
Controller = controller,
Body = body,
PhysicsHost = physicsHost,
Movement = movement,
Motion = motion,
ActivationPreparation = preparedActivation,
};
_candidate = new Candidate
{
Token = token,
Record = record,
PlacementCommand = command,
Controller = controller,
Body = body,
PhysicsHost = physicsHost,
Movement = movement,
Motion = motion,
ActivationPreparation = preparedActivation,
PreparedActivation = activationEnvelope,
};
return RuntimeLocalPlayerPhysicsPublicationStatus.Prepared;
}
private static float NormalizeFriction(float? value) =>
value is >= 0f and <= 1f && float.IsFinite(value.Value)
? value.Value
: PhysicsBody.DefaultFriction;
private static float NormalizeElasticity(float value)
{
if (float.IsNaN(value) || value <= 0f)
return 0f;
return MathF.Min(value, 0.1f);
}
internal RuntimeLocalPlayerPhysicsPublicationStatus Commit(
in RuntimeLocalPlayerPhysicsPublicationToken token) =>
Commit(token, out _);
internal RuntimeLocalPlayerPhysicsPublicationStatus Commit(
in RuntimeLocalPlayerPhysicsPublicationToken token,
out RuntimeLocalPlayerPhysicsActivationToken activationToken)
{
ObjectDisposedException.ThrowIf(_disposed, this);
activationToken = default;
if (!token.IsValid
|| _candidate is not { } candidate
|| candidate.Token != token)
{
return RuntimeLocalPlayerPhysicsPublicationStatus.RejectedToken;
}
if (!IsCurrent(candidate))
{
DiscardCurrent();
return RuntimeLocalPlayerPhysicsPublicationStatus.RejectedAuthority;
}
// Seal the exact SetPosition owner before the irreversible no-fail
// suffix. Any internal invariant failure therefore leaves every
// canonical body/controller owner untouched.
_physics.SetPosition.PrepareDormantLocalActivationOwnership(
candidate.Record,
candidate.Body,
candidate.PreparedActivation.Token.Placement);
// All validation is complete. The remaining stores are callback-free,
// non-allocating, and cannot fail on this single Runtime update thread.
// The controller remains RuntimeOwnedDormant; the subsequent world
// activation transaction is the only authority allowed to make it live.
candidate.Controller.CommitRuntimeOwnership(
candidate.Record.ObjectClock);
candidate.Record.SetPhysicsBody(candidate.Body);
_movement.CommitRuntimeOwnedController(candidate.Controller);
activationToken = candidate.PreparedActivation.Token;
_activation = candidate.PreparedActivation;
_candidate = null;
return RuntimeLocalPlayerPhysicsPublicationStatus.Committed;
}
internal RuntimeLocalPlayerPhysicsActivationStatus EvaluateActivation(
in RuntimeLocalPlayerPhysicsActivationToken token,
out RuntimeLocalPlayerPhysicsActivationReceipt receipt)
{
ObjectDisposedException.ThrowIf(_disposed, this);
receipt = default;
if (!token.IsValid
|| _activation is not { } activation
|| activation.Token != token)
{
return RuntimeLocalPlayerPhysicsActivationStatus.RejectedToken;
}
if (!IsActivationCurrent(activation))
{
DiscardActivation();
return RuntimeLocalPlayerPhysicsActivationStatus.RejectedAuthority;
}
if (!_physics.SetPosition.TryEvaluateDormantLocalActivation(
activation.Record,
activation.Body,
token.Placement,
activation.PlacementCommand,
out RuntimeDormantSetPositionEvaluation placement))
{
if (ReferenceEquals(_activation, activation)
&& IsActivationCurrent(activation)
&& _physics.SetPosition.IsDormantLocalActivationAwaitingCell(
activation.Record,
activation.Body,
token.Placement,
activation.PlacementCommand))
{
return RuntimeLocalPlayerPhysicsActivationStatus.DeferredCell;
}
// #357: an evaluation abort while the dormant lease is STILL
// CURRENT is transient — the collision-authority seal was refused
// by a still-registered admission (a login recenter admits nine
// landblocks at once and the placement's ring search can touch a
// neighbour mid-admission) or a reentrant collision/restriction
// mutation observed mid-transaction. The operation remains in
// AwaitingPreparation and the SAME token evaluates successfully
// once the authority settles, so the correct status is
// DeferredCell (retry). Falling through to RejectedAuthority here
// is what terminally dropped the local player from the
// first-entry conductor and hung login at ready=True with the
// world never revealed.
if (ReferenceEquals(_activation, activation)
&& IsActivationCurrent(activation)
&& _physics.SetPosition.IsDormantLocalActivationLeaseCurrent(
activation.Record,
activation.Body,
token.Placement,
activation.PlacementCommand))
{
return RuntimeLocalPlayerPhysicsActivationStatus.DeferredCell;
}
if (ReferenceEquals(_activation, activation)
&& !IsActivationCurrent(activation))
{
DiscardActivation();
}
return RuntimeLocalPlayerPhysicsActivationStatus.RejectedAuthority;
}
receipt = new RuntimeLocalPlayerPhysicsActivationReceipt(
token,
checked(++_nextEvaluationId),
placement);
activation.Receipt = receipt;
if (placement.Result.IsDeferred)
return RuntimeLocalPlayerPhysicsActivationStatus.DeferredCell;
return placement.Result.IsCommitted
? RuntimeLocalPlayerPhysicsActivationStatus.Evaluated
: RuntimeLocalPlayerPhysicsActivationStatus.RejectedPlacement;
}
internal bool IsEvaluationCurrent(
in RuntimeLocalPlayerPhysicsActivationReceipt receipt)
{
ObjectDisposedException.ThrowIf(_disposed, this);
if (!receipt.IsValid
|| _activation is not { } activation
|| activation.Token != receipt.Token
|| activation.Receipt != receipt)
{
return false;
}
return IsActivationCurrent(activation)
&& _physics.SetPosition.IsDormantLocalEvaluationCurrent(
activation.Record,
activation.Body,
receipt.Placement);
}
internal RuntimeDormantSetPositionCommitStatus CommitActivation(
in RuntimeLocalPlayerPhysicsActivationReceipt receipt,
out RuntimePlacementProjectionToken projection)
{
ObjectDisposedException.ThrowIf(_disposed, this);
projection = default;
if (!receipt.IsValid
|| _activation is not { } activation
|| activation.Token != receipt.Token
|| activation.Receipt != receipt)
{
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
if (activation.PendingFinalCommit.Status
is RuntimeDormantSetPositionCommitStatus
.AwaitingFinalShadowPreparation)
{
return FinalizeActivation(
activation,
activation.PendingFinalCommit,
out projection);
}
if (!IsActivationCurrent(activation)
|| !_physics.SetPosition.IsDormantLocalEvaluationCurrent(
activation.Record,
activation.Body,
receipt.Placement))
{
activation.Receipt = default;
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
bool provenShapeless = activation.ActivationPreparation
.ShadowDisposition
is RuntimeLocalPlayerShadowDisposition.ProvenShapeless;
if (!_physics.SetPosition.TryPrepareDormantLocalActivationCommit(
activation.Record,
activation.Body,
receipt.Placement,
provenShapeless,
out PreparedDormantSetPositionCommit? prepared)
|| prepared is null
|| !IsActivationCurrent(activation))
{
activation.Receipt = default;
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
if (!_physics.SetPosition.TryApplyDormantLocalActivationCommit(
activation.Record,
activation.Body,
activation.Controller,
activation.PhysicsHost,
prepared,
out RuntimeDormantSetPositionCommitReceipt committed))
{
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
if (committed.Status is RuntimeDormantSetPositionCommitStatus.DeferredCell)
{
activation.Receipt = default;
_physics.SetPosition.DispatchDormantLocalActivationShadow(committed);
return committed.Status;
}
// Named retail SetPosition: contact prefix, ground edge, second
// acceleration/sliding, collision callbacks, physical response, then
// shadow/live publication.
try
{
activation.Controller.BeginDormantSetPositionGroundPhase();
if (committed.HitGround)
activation.Movement.HitGround();
else if (committed.LeaveGround)
activation.Motion.LeaveGround();
}
catch
{
_activationDispatchFailureCount++;
}
finally
{
activation.Controller.EndDormantSetPositionGroundPhase();
}
if (committed.Status is RuntimeDormantSetPositionCommitStatus
.AwaitingFinalShadowPreparation
&& (!IsActivationPrephaseEnvelopeCurrent(activation, committed)
|| !RefreshDormantVector(activation, committed)
|| !RefreshDormantState(activation)
|| !_physics.SetPosition.CommitDormantLocalActivationPostGround(
activation.Record,
activation.Body,
committed)))
{
AbortActivation(
activation, committed, collisionAlreadyDispatched: false);
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
try
{
SetPositionCollisionBatchDispatchResult collisionDispatch =
_physics.SetPosition.DispatchDormantLocalActivationCollision(
committed);
if (collisionDispatch.Status
is not SetPositionCollisionBatchDispatchStatus.Completed)
{
AbortActivation(
activation, committed, collisionAlreadyDispatched: true);
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
}
catch
{
_activationDispatchFailureCount++;
AbortActivation(
activation, committed, collisionAlreadyDispatched: true);
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
if (!IsActivationResponseEnvelopeCurrent(activation, committed))
{
AbortActivation(
activation, committed, collisionAlreadyDispatched: true);
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
activation.Controller.RefreshDormantRuntimePhysicsState(
activation.Record.FinalPhysicsState,
recalculateAcceleration: false);
_ = RefreshDormantVector(activation, committed);
if (committed.Status is RuntimeDormantSetPositionCommitStatus
.AwaitingFinalShadowPreparation
&& !IsActivationPrephaseEnvelopeCurrent(activation, committed)
|| !_physics.SetPosition.CommitDormantLocalActivationPostCollision(
activation.Record,
activation.Body,
committed))
{
AbortActivation(
activation, committed, collisionAlreadyDispatched: true);
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
if (committed.Status is RuntimeDormantSetPositionCommitStatus
.RejectedPlacement)
{
activation.Receipt = default;
activation.PendingFinalCommit = committed;
return committed.Status;
}
activation.PendingFinalCommit = committed;
return FinalizeActivation(activation, committed, out projection);
}
private RuntimeDormantSetPositionCommitStatus FinalizeActivation(
Activation activation,
in RuntimeDormantSetPositionCommitReceipt prephase,
out RuntimePlacementProjectionToken projection)
{
projection = default;
if (!IsActivationPrephaseEnvelopeCurrent(activation, prephase))
{
AbortActivation(
activation, prephase, collisionAlreadyDispatched: true);
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
activation.Controller.RefreshDormantRuntimePhysicsState(
activation.Record.FinalPhysicsState,
recalculateAcceleration: false);
bool provenShapeless = activation.ActivationPreparation
.ShadowDisposition is RuntimeLocalPlayerShadowDisposition.ProvenShapeless;
if (!_physics.SetPosition.TryPrepareDormantLocalActivationFinalCommit(
activation.Record,
activation.Body,
prephase,
provenShapeless,
out PreparedDormantActivationFinalCommit? prepared)
|| prepared is null)
{
if (IsActivationPrephaseEnvelopeCurrent(activation, prephase))
return prephase.Status;
AbortActivation(
activation, prephase, collisionAlreadyDispatched: true);
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
if (!IsActivationPrephaseEnvelopeCurrent(activation, prephase))
{
AbortActivation(
activation, prephase, collisionAlreadyDispatched: true);
return RuntimeDormantSetPositionCommitStatus.RejectedAuthority;
}
if (!_physics.SetPosition.TryApplyDormantLocalActivationFinalCommit(
activation.Record,
activation.Body,
activation.Controller,
activation.PhysicsHost,
prephase,
prepared,
out RuntimeDormantSetPositionCommitReceipt committed))
{
return prephase.Status;
}
activation.Receipt = default;
activation.PendingFinalCommit = default;
_activation = null;
_physics.SetPosition.DispatchDormantLocalActivationShadow(committed);
if (!IsCommittedActivationSuffixCurrent(activation, committed))
return committed.Status;
ArmFirstEntryConstraintLeash(activation);
SettleFirstEntryGroundContact(activation);
_physics.SetPosition.DispatchDormantLocalActivationPlacement(committed);
projection = committed.Projection.Token;
return committed.Status;
}
///
/// C3c-R1: the login-entry constraint-leash arm the flip deleted with
/// the App-side CommitPreparedPosition caller. Ordering, with
/// file:line justification:
///
/// - NOT at Prepare — PreparePositionForCommit (:219)
/// runs with publishSharedState: false and the controller's
/// PositionManager binds only later at :318, so the leash cannot
/// exist there (nor should it: the position is not accepted yet).
/// - NOT at publication Commit — the activation's placement
/// evaluation (retail find-placement ring search) may still move or
/// reject the position.
/// - HERE, after TryApplyDormantLocalActivationFinalCommit
/// (RuntimeSetPositionState.cs:2494-2516 commits the final cell,
/// activates the controller, and publishes the shared current cell) and
/// inside the same IsCommittedActivationSuffixCurrent gate the
/// settle uses — a stale suffix skips the arm exactly like the settle
/// (never armed on stale authority).
/// - BEFORE — retail
/// arms anchored to the RECEIVED position
/// (SmartBox::HandleReceivedPosition 0x00453FD0) and only then
/// simulates the first gravity frame, which the settle compresses; the
/// anchor is therefore the committed placement, not the post-settle
/// pose.
/// - Exactly once — _activation is nulled at :716 before
/// this suffix, so a resumed AwaitingFinalShadowPreparation
/// retry can never re-enter it after a successful final commit.
///
///
private void ArmFirstEntryConstraintLeash(Activation activation)
{
// Same containment as the settle below: the placement commit has
// already succeeded; a leash-arm failure must not unwind the suffix.
try
{
activation.Controller.ArmConstraintLeashAtCommittedPlacement();
}
catch
{
_activationDispatchFailureCount++;
}
}
///
/// C3c-F5: retail seeds the LOCAL player's ground contact from the first
/// gravity frame after enter_world, never from the placement
/// itself — SmartBox::HandleCreateObject (0x00454C80) runs
/// init_player (0x00455010) then CPhysicsObj::enter_world
/// (0x00455095 → 0x00516170), whose SetPosition validates the
/// spot but records no touch and whose tail only sets ACTIVE (0x80).
/// Every retail CPhysicsObj then simulates, falls the few centimetres
/// onto the floor, and the transition's touch grants the contact plane
/// + CONTACT/ON_WALKABLE. The dormant activation's just-finished commit
/// is the faithful SetPosition port, so a fresh login body would start
/// airborne here; this compresses the settle exactly like the #270
/// remote-spawn seed (the shared ):
/// a short downward sweep whose real touch produces the state retail's
/// first frame would. No floor within reach (a genuine airborne spawn)
/// leaves the body airborne — the ordinary per-tick gravity fall owns
/// it from there. The body transients this commits ARE the controller's
/// grounded state (PlayerMovementController.CanSendPositionEvent
/// reads InContact && OnWalkable off the same body) and
/// the outbound wire contact bit (LocalPlayerOutboundController
/// serializes that predicate) — the flag ACE's "You can't do that while
/// in the air!" gate reads.
///
private void SettleFirstEntryGroundContact(Activation activation)
{
// Same post-commit callback-dispatch containment as the ground-edge
// dispatch in CommitActivation: the placement commit has already
// succeeded; a HitGround-side failure must not unwind the suffix.
try
{
_ = SpawnPlacementSettler.TrySettle(
_physics.Engine,
activation.Body,
activation.Body.Position,
activation.Body.CellPosition.ObjCellId,
activation.ActivationPreparation.Radius,
activation.ActivationPreparation.Height,
ObjectInfoState.IsPlayer
| ObjectInfoState.EdgeSlide
| activation.Controller.OwnPvpFlags,
activation.Controller.LocalEntityId,
activation.Movement.HitGround,
activation.Motion.LeaveGround);
}
catch
{
_activationDispatchFailureCount++;
}
}
private bool IsActivationPrephaseEnvelopeCurrent(
Activation activation,
in RuntimeDormantSetPositionCommitReceipt receipt) =>
IsActivationOwnershipEnvelopeCurrent(activation)
&& _physics.IsCollisionEvaluationFatalAuthorityCurrent(
receipt.CollisionAuthority)
&& _physics.SetPosition.IsDormantLocalActivationPrephaseCurrent(
activation.Record,
activation.Body,
receipt);
private bool IsActivationResponseEnvelopeCurrent(
Activation activation,
in RuntimeDormantSetPositionCommitReceipt receipt) =>
IsActivationOwnershipEnvelopeCurrent(activation)
&& _physics.IsCollisionEvaluationFatalAuthorityCurrent(
receipt.CollisionAuthority)
&& _physics.SetPosition.IsDormantLocalActivationResponseCurrent(
activation.Record,
activation.Body,
receipt);
private bool IsActivationOwnershipEnvelopeCurrent(
Activation activation) =>
activation.Controller.IsRuntimeOwnedDormant
&& !activation.Controller.IsDormantSetPositionGroundPhaseActive
&& activation.Controller.OwnsPhysicsBody(activation.Body)
&& _entities.SessionLifetimeVersion
== activation.Token.SessionGenerationAuthority
&& _entities.IsCurrent(activation.Record)
&& activation.Record.Key == activation.Token.Entity
&& !_identity.IsDisposed
&& _identity.ServerGuid == activation.Token.LocalPlayerServerGuid
&& _identity.ServerGuid == activation.Record.ServerGuid
&& _identity.Revision == activation.Token.LocalPlayerIdentityRevision
&& activation.Record.PhysicsOwnershipEpoch
== activation.Token.PhysicsOwnershipEpoch
&& activation.Record.ObjectClockEpoch
== activation.Token.ObjectClockEpoch
&& _movement.CanCommitRuntimeOwnedController(
activation.Token.ControllerOwnershipEpoch,
activation.Controller)
&& ReferenceEquals(activation.Record.PhysicsBody, activation.Body)
&& activation.Record.PhysicsHost is null
&& activation.Record.RemoteMotion is null
&& activation.Record.Projectile is null
&& !activation.Record.PhysicsBodyAcquisitionInProgress
&& !activation.Record.RemoteMotionBindingInProgress
&& !activation.Record.ProjectileBindingInProgress
&& !activation.Record.RequiresRemotePlacementRuntime
&& !activation.Record.DeleteAcceptedForTeardown;
private static bool RefreshDormantState(Activation activation)
{
activation.Controller.RefreshDormantRuntimePhysicsState(
activation.Record.FinalPhysicsState,
recalculateAcceleration: false);
return true;
}
private static bool RefreshDormantVector(
Activation activation,
in RuntimeDormantSetPositionCommitReceipt receipt)
{
if (activation.Record.VectorAuthorityVersion
== receipt.SourceVectorAuthorityVersion)
return true;
var physics = activation.Record.Snapshot.Physics;
activation.Controller.RefreshDormantRuntimeVector(
physics?.Velocity,
physics?.AngularVelocity);
return true;
}
private void AbortActivation(
Activation activation,
in RuntimeDormantSetPositionCommitReceipt receipt,
bool collisionAlreadyDispatched)
{
_physics.SetPosition.RetireDormantLocalActivation(
receipt,
collisionAlreadyDispatched);
activation.Receipt = default;
activation.PendingFinalCommit = default;
if (ReferenceEquals(_activation, activation))
DiscardActivation();
}
internal bool DiscardActivation(
in RuntimeLocalPlayerPhysicsActivationToken token)
{
ObjectDisposedException.ThrowIf(_disposed, this);
if (!token.IsValid
|| _activation is not { } activation
|| activation.Token != token)
{
return false;
}
DiscardActivation();
return true;
}
internal RuntimeLocalPlayerPhysicsPublicationStatus Discard(
in RuntimeLocalPlayerPhysicsPublicationToken token)
{
ObjectDisposedException.ThrowIf(_disposed, this);
if (!token.IsValid
|| _candidate is not { } candidate
|| candidate.Token != token)
{
return RuntimeLocalPlayerPhysicsPublicationStatus.RejectedToken;
}
DiscardCurrent();
return RuntimeLocalPlayerPhysicsPublicationStatus.Discarded;
}
internal bool TryCaptureCandidateSnapshot(
in RuntimeLocalPlayerPhysicsPublicationToken token,
out RuntimeLocalPlayerPhysicsCandidateSnapshot snapshot)
{
if (!_disposed
&& token.IsValid
&& _candidate is { } candidate
&& candidate.Token == token)
{
PhysicsBody body = candidate.Body;
snapshot = new RuntimeLocalPlayerPhysicsCandidateSnapshot(
body.Position,
body.Orientation,
body.CellPosition.ObjCellId,
body.CellPosition.Frame.Origin,
body.State,
body.TransientState,
body.InWorld);
return true;
}
snapshot = default;
return false;
}
internal RuntimeLocalPlayerPhysicsPublicationOwnershipSnapshot
CaptureOwnership() => new(
IsBound: true,
_disposed,
_candidate is null ? 0 : 1,
_activation is null ? 0 : 1,
_nextPublicationId);
internal long ActivationDispatchFailureCount =>
_activationDispatchFailureCount;
internal void ResetSession()
{
ObjectDisposedException.ThrowIf(_disposed, this);
DiscardCurrent();
DiscardActivation();
}
public void Dispose()
{
if (_disposed)
return;
DiscardCurrent();
DiscardActivation();
_disposed = true;
}
private bool CanPrepare(
RuntimeEntityRecord record,
in RuntimeEntityPlacementToken placement,
in RuntimeSetPositionCommand command) =>
_activation is null
&& record.Key is { } key
&& key == placement.Entity
&& _entities.IsCurrent(record)
&& !record.DeleteAcceptedForTeardown
&& command.Kind is RuntimeSetPositionOperationKind.InitialLogin
or RuntimeSetPositionOperationKind.LocalAuthoritative
&& command.Physics.MovingEntityId == key.LocalEntityId
&& !_identity.IsDisposed
&& _identity.ServerGuid != 0u
&& _identity.ServerGuid == record.ServerGuid
&& record.PhysicsBody is null
&& _movement.Controller is null
&& record.PhysicsHost is null
&& record.RemoteMotion is null
&& record.Projectile is null
&& !record.PhysicsBodyAcquisitionInProgress
&& !record.RemoteMotionBindingInProgress
&& !record.ProjectileBindingInProgress
&& !record.RequiresRemotePlacementRuntime
&& _physics.SetPosition.IsExactPreparedPlacementCurrent(
record,
placement,
command);
private bool IsCurrent(Candidate candidate) =>
_activation is null
&& candidate.Controller.IsSealedPublicationCandidate
&& candidate.Controller.OwnsPhysicsBody(candidate.Body)
&& _entities.SessionLifetimeVersion
== candidate.Token.SessionGenerationAuthority
&& _entities.IsCurrent(candidate.Record)
&& candidate.Record.Key == candidate.Token.Entity
&& !_identity.IsDisposed
&& _identity.ServerGuid == candidate.Token.LocalPlayerServerGuid
&& _identity.ServerGuid == candidate.Record.ServerGuid
&& _identity.Revision == candidate.Token.LocalPlayerIdentityRevision
&& candidate.Record.PhysicsOwnershipEpoch
== candidate.Token.PhysicsOwnershipEpoch
&& candidate.Record.ObjectClockEpoch
== candidate.Token.ObjectClockEpoch
&& _movement.CanCommitRuntimeOwnedController(
candidate.Token.ControllerOwnershipEpoch,
expectedController: null)
&& candidate.Record.PhysicsBody is null
&& candidate.Record.PhysicsHost is null
&& candidate.Record.RemoteMotion is null
&& candidate.Record.Projectile is null
&& !candidate.Record.PhysicsBodyAcquisitionInProgress
&& !candidate.Record.RemoteMotionBindingInProgress
&& !candidate.Record.ProjectileBindingInProgress
&& !candidate.Record.RequiresRemotePlacementRuntime
&& !candidate.Record.DeleteAcceptedForTeardown
&& _physics.SetPosition.IsExactPreparedPlacementCurrent(
candidate.Record,
candidate.Token.Placement,
candidate.PlacementCommand);
private void DiscardCurrent()
{
Candidate? candidate = _candidate;
_candidate = null;
candidate?.Controller.DiscardRuntimeCandidate();
}
private bool IsActivationCurrent(Activation activation) =>
activation.Controller.IsRuntimeOwnedDormant
&& activation.Controller.OwnsPhysicsBody(activation.Body)
&& _entities.SessionLifetimeVersion
== activation.Token.SessionGenerationAuthority
&& _entities.IsCurrent(activation.Record)
&& activation.Record.Key == activation.Token.Entity
&& !_identity.IsDisposed
&& _identity.ServerGuid == activation.Token.LocalPlayerServerGuid
&& _identity.ServerGuid == activation.Record.ServerGuid
&& _identity.Revision == activation.Token.LocalPlayerIdentityRevision
&& activation.Record.PhysicsOwnershipEpoch
== activation.Token.PhysicsOwnershipEpoch
&& activation.Record.ObjectClockEpoch
== activation.Token.ObjectClockEpoch
&& _movement.CanCommitRuntimeOwnedController(
activation.Token.ControllerOwnershipEpoch,
activation.Controller)
&& ReferenceEquals(activation.Record.PhysicsBody, activation.Body)
&& activation.Record.PhysicsHost is null
&& activation.Record.RemoteMotion is null
&& activation.Record.Projectile is null
&& !activation.Record.PhysicsBodyAcquisitionInProgress
&& !activation.Record.RemoteMotionBindingInProgress
&& !activation.Record.ProjectileBindingInProgress
&& !activation.Record.RequiresRemotePlacementRuntime
&& !activation.Record.DeleteAcceptedForTeardown
&& _physics.SetPosition.IsDormantLocalActivationLeaseCurrent(
activation.Record,
activation.Body,
activation.Token.Placement,
activation.PlacementCommand);
private bool IsCommittedActivationSuffixCurrent(
Activation activation,
in RuntimeDormantSetPositionCommitReceipt receipt)
{
return activation.Token.ObjectClockEpoch != ulong.MaxValue
&& _entities.SessionLifetimeVersion
== activation.Token.SessionGenerationAuthority
&& _entities.IsCurrent(activation.Record)
&& activation.Record.Key == activation.Token.Entity
&& !_identity.IsDisposed
&& _identity.ServerGuid == activation.Token.LocalPlayerServerGuid
&& _identity.ServerGuid == activation.Record.ServerGuid
&& _identity.Revision
== activation.Token.LocalPlayerIdentityRevision
&& activation.Record.PhysicsOwnershipEpoch
== activation.Token.PhysicsOwnershipEpoch
&& activation.Record.ObjectClockEpoch
== activation.Token.ObjectClockEpoch + 1UL
&& _movement.ControllerOwnershipEpoch
== activation.Token.ControllerOwnershipEpoch
&& ReferenceEquals(_movement.Controller, activation.Controller)
&& activation.Controller.IsRuntimePublished
&& activation.Controller.OwnsPhysicsBody(activation.Body)
&& ReferenceEquals(
activation.Record.PhysicsBody,
activation.Body)
&& ReferenceEquals(
activation.Record.PhysicsHost,
activation.PhysicsHost)
&& activation.Record.RemoteMotion is null
&& activation.Record.Projectile is null
&& !activation.Record.DeleteAcceptedForTeardown
&& _physics.SetPosition.IsDormantLocalActivationCommitCurrent(
activation.Record,
activation.Body,
receipt);
}
private void DiscardActivation()
{
Activation? activation = _activation;
_activation = null;
if (activation is not null)
{
if (activation.PendingFinalCommit.Status
is not RuntimeDormantSetPositionCommitStatus.None)
{
_physics.SetPosition.RetireDormantLocalActivation(
activation.PendingFinalCommit,
collisionAlreadyDispatched: true);
}
_physics.SetPosition.RetireDormantLocalActivationToken(
activation.Record,
activation.Token.Placement);
}
if (activation is not null
&& _entities.IsCurrent(activation.Record)
&& ReferenceEquals(
activation.Record.PhysicsBody,
activation.Body))
{
_entities.SetPhysicsBody(activation.Record, null);
}
if (activation is not null
&& ReferenceEquals(_movement.Controller, activation.Controller))
{
_movement.Controller = null;
}
}
}