acdream/src/AcDream.Runtime/Physics/RuntimeSetPositionState.cs
Erik 6dc7ba51ee feat(physics): C4 route 4b-3 — remote teleport + cell-less through the canonical placement
Flips the last remote classification (SetPosition: teleport-advanced and
cell-less) onto 4b-1's RuntimeRemotePlacementDriveController, runs retail's
teleport_hook before the placement, and deletes the legacy remote-teleport
machinery. Contract: docs/research/2026-08-04-c4-route-4b-3-contract.md.

Retail: MoveOrTeleport @0x00516330's branch @0x00516386 -> teleport_hook
@0x005163EF -> SetFlags(0x1012) @0x00516414 -> SetPosition @0x00516420 ->
return 1 @0x00516438. The hook @0x00514ED0 runs BEFORE the placement and
regardless of its outcome. Retail places this branch unconditionally, at any
distance and any contact state (arg4 is read only @0x0051638E, after the
branch) — which is what retires AP-137's cell-less enqueue-vs-place delta.

D1 — the classifier's cell-less input is now the PRE-merge committed cell.
Retail's predicate is `this_1->cell == 0`, the BODY's own cell at
MoveOrTeleport entry (this_1 is assigned from this @0x00516334). acdream fed
the POST-merge canonical.FullCellId, which RefreshSnapshot ->
RefreshDerivedState -> SetFullCell has already stamped with the accepted wire
cell; a zero wire cell fails validation into RejectedData first. The shipped
remote cell-less predicate was therefore dead code, not merely different from
remotePlacementRequired. Threaded via a builder overload; route 1's overload
is untouched. The graphical !IsSpatiallyVisible arm of
projectionRequiresTeleportHook is deleted — a presentation predicate with no
retail analogue that fired the teleport machinery on a routine hot path.

Deleted: RemoteTeleportController (605), RemoteTeleportPlacement (85),
RemoteShadowPlacementSynchronizer (49), their 1,709 lines of tests, the
remotePlacementRequired predicate, the TeleportHookRequired plumbing, the
legacy pre-operation ConstrainTo fallback, and the player arm's legacy
!IsGrounded fallback. Net -2,030 lines.

Structural fix (two independent Opus reviews, round 1 FAIL/FAIL): three of the
four MAJORs were one defect — OnPosition carried two parallel inline copies of
the routing tail (player-guid, NPC-guid) that had drifted. Extracted
RunRemoteArmTail (3 call sites) and ApplyWireAirborneLeftoverBookkeeping (2),
both branches now share one implementation.

  A1  ToConstraintArm mapped AirborneSnap -> AirborneNoOperation, so the NPC
      arm armed ConstrainTo ZERO times for an out-of-contact wire-grounded
      creature — a regression this slice introduced while closing a
      structurally identical hole. Now maps to NearInterpolate; switch made
      total with a throwing default proven unreachable.
  R1  D2's write-nothing shape existed on the player arm only; NPC packets
      fell through and wrote the body. Retail makes no player/NPC distinction.
  R2  report_collision_end(this,1) @0x00514F31 was bound to
      ShadowObjects.Suspend, a port of a DIFFERENT retail function
      (remove_shadows_from_cells) that teleport_hook never calls. Now routes
      to RuntimeCollisionReportingState.LeaveWorld, which wraps the private
      ForceEnd in an admission-blocking transaction so a DoCollisionEnd
      callback cannot recreate the contact table.
  R3/A2 A teleported NPC synthesized ServerVelocity from the teleport distance
      (~1,000+ m/s) and planned a run cycle from it. Both the install and
      RemoteServerControlledVelocityCycle.Apply now gate on !isTeleportRoute.

BISECT HAZARD — A1's fix is correct only BECAUSE R1 landed. AirborneSnap is
reachable wire-airborne on the NPC arm only while D2's shape is missing there.
Reverting R1 alone silently inverts A1 into the opposite divergence: arming
where retail returns 0. Revert both or neither.

Also in the velocity hunk: the NPC block's two !IsPlayerGuid(update.Guid)
guards were dropped when it was wrapped in `if (!isTeleportRoute)`. Safe — all
five exit paths of the enclosing IsPlayerGuid block return, so the predicate is
unconditionally false below it — but it was unremarked by both reviews.

Register: AP-137 REWRITTEN (not deleted) to the surviving acdream-only
divergences — null classification during the login window and Rejected*
through UnroutedCatchUp keep a row. AD-42's RemoteTeleportController citation
retired; AP-136/AP-138 writer lists corrected to the two surviving non-Position
rebucket writers; AP-138 gains the teleport arm as a second producer of the
visible-without-collision residual (retirement path remains #309). AP-135 is
untouched and its two airborne bookkeeping writes are preserved on both arms.
AP-131 does not retire; #276 does not close.

Proof obligation 1: ParkCollisionResidents' overlap throw stays unreachable —
the teleport arm adds packets to the same TryBeginExclusiveAuthoredPlacement
one-operation-per-key machinery the far arm uses, opens no new operation shape,
and every DeferredCell outcome cancels synchronously with
restoreCancelledPark: true. The guarded property remains
HasOldPrefixPlacementDebt's stall, not a throw (4b-1's B2 caveat stands).

Correction to an earlier claim: LiveEntityPresentationController's
_activePlacementOwners was NOT write-never at HEAD —
remotePlacementRequired -> BeginPlacement -> Begin -> BeginAuthoritativePlacement
was a live writer chain. It becomes write-never BECAUSE this slice deletes that
chain, which is why deleting the dead half is behaviour-preserving.

Probe: ACDREAM_PROBE_REMOTE_TELEPORT=1 emits one [remote-teleport] line per
routed arm (guid, cause, hook-ran, placement status). TEMPORARY, strip with the
probe family.

Carried, disclosed not fixed: no dedicated bidirectional collision-partner test
for R2 (the wiring, not LeaveWorld itself, is what lacks coverage); the
stress test's teleport step drives hand-written field assignments rather than
the canonical arm; the per-packet runTeleportHook closure allocation (network
path, not the resolve path Slice I's 0 B discipline governs — file before
route 5 adds a fourth call site). B2: IRuntimeCollisionReportObserver has zero
production implementations, so retail's bidirectional DoCollisionEnd half still
reaches no gameplay consumer — this fix closes the wrong-function binding, not
that nobody listens.

Complete Release suite MEASURED at 11,013 passed / 4 skipped / 0 failed
(baseline 11,027/4/0; net -14 = ~33 deleted test cases against ~19 added).
Neither known flake fired (#302 PortalProjectionTests GC-allocation, #308
NakEmissionTests wall-clock).

STILL OWED: the two-client connected gate, which MUST use an NPC/creature
teleport target. Both round-1 MAJORs lived on the NPC arm and the velocity
cycle early-returns for 0x50xxxxxx guids, so a player target structurally
cannot observe A1, A2, or R3.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 16:00:10 +02:00

6191 lines
260 KiB
C#

using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using AcDream.Content;
using AcDream.Core.Items;
using AcDream.Core.Net.Messages;
using AcDream.Core.Physics;
using AcDream.Runtime.Entities;
using AcDream.Runtime.Gameplay;
namespace AcDream.Runtime.Physics;
internal enum RuntimeSetPositionOperationKind
{
InitialLogin,
LocalAuthoritative,
RemoteAuthoritative,
ProjectileAuthoritative,
}
internal enum RuntimeSetPositionStatus
{
Rejected,
DeferredCell,
CommittedHostAcknowledgementPending,
Committed,
Cancelled,
}
internal enum RuntimeEntityPlacementStage
{
AwaitingPreparation,
AwaitingWithdrawalAcknowledgement,
AwaitingCell,
QuiescenceHeld,
AwaitingFinalShadowPreparation,
AwaitingCommitAcknowledgement,
CancelledAwaitingAcknowledgement,
}
internal enum RuntimeEntityPlacementPreparationKind : byte
{
LegacyDirect,
AuthoredMover,
}
internal readonly record struct RuntimeEntityPlacementToken(
ulong SessionLifetimeVersion,
RuntimeEntityKey Entity,
ulong PositionAuthorityVersion,
ulong OperationId,
RuntimeEntityPlacementPreparationKind PreparationKind)
{
internal bool IsValid => OperationId != 0UL
&& Entity.LocalEntityId != 0u
&& PositionAuthorityVersion != 0UL;
}
public enum RuntimePlacementProjectionKind
{
Withdraw,
Place,
Discard,
/// <summary>
/// C0-1: the initial-create continuation executor's own FIFO drain has
/// finished for this entity (not itself a SetPosition operation - the
/// residence lease is already released by the time this publishes).
/// Published on the SAME ordered stream every Place/Withdraw/Discard
/// receipt uses so a host learns "this entity's placement committed and
/// its FIFO drained" through the one already-built observer seam,
/// instead of a second stream/queue. Acknowledge-only, like Discard -
/// see AcknowledgeProjection's dedicated branch.
/// </summary>
ExecutorCompleted,
/// <summary>
/// The <see cref="Withdraw"/> receipt a restorable park published has
/// been ROLLED BACK by <c>RestoreParkWithdrawal</c>: canonical residency,
/// <c>InWorld</c>, the transient bits, and the object clock are whole
/// again at the entity's committed cell, so every presentation
/// registration that <see cref="Withdraw"/> tore down must be re-installed
/// exactly as it stood.
///
/// <para>This exists because <c>RestoreParkWithdrawal</c> can only reach
/// CANONICAL state. The presentation half of a withdrawal (the graphical
/// bucket, the projection-visibility sinks, plugin world state/events, the
/// effect-pose registry, the local-player shadow) lives behind the host
/// sink, and its only mirror image is that sink's Place publication. Before
/// this receipt existed the rollback depended on a LATER <see cref="Place"/>
/// that a remote which stops moving never receives - ACE stops broadcasting
/// Positions for a stationary entity - leaving it simulated, collidable and
/// audible but invisible in the world and absent from the radar for the
/// rest of the session.</para>
///
/// <para>Acknowledge-only in Runtime, exactly like <see cref="Discard"/>
/// and <see cref="ExecutorCompleted"/>: it is published after the parked
/// operation has already been cancelled and retired, so there is no
/// operation to resume or commit against - see AcknowledgeProjection's
/// dedicated branch. A host must NEVER refuse it: a false return leaves it
/// at the FIFO head and wedges the whole ordered stream, which is strictly
/// worse than the invisibility it repairs.</para>
/// </summary>
WithdrawalRestored,
}
public readonly record struct RuntimePortalPlacementAuthority(
bool Present,
long RevealGeneration,
ushort TeleportSequence,
RuntimeWorldHostProjectionToken Projection)
{
internal bool IsEmpty => !Present
&& RevealGeneration == 0
&& TeleportSequence == 0
&& Projection == default;
internal bool IsValid => Present
&& RevealGeneration != 0
&& Projection.IsValid
&& Projection.Generation == RevealGeneration;
}
internal readonly record struct RuntimeSetPositionCommand(
PhysicsSetPositionRequest Physics,
RuntimeSetPositionOperationKind Kind,
double GameTime,
ulong ExpectedVelocityAuthorityVersion,
float ShadowWorldOffsetX = 0f,
float ShadowWorldOffsetY = 0f,
RuntimePortalPlacementAuthority Portal = default);
internal readonly record struct RuntimeCollisionGenerationAuthority(
uint LandblockId,
ulong Generation);
internal readonly record struct RuntimeCollisionPrefixQuiescenceToken(
ulong SessionLifetimeVersion,
uint LandblockPrefix,
ulong CollisionGeneration,
ulong OperationId)
{
// C3c-F3: presence is discriminated by OperationId (allocated from a
// monotonic counter starting at 1, so a default token always carries 0)
// and CollisionGeneration (generations also start at 1) — NOT by
// LandblockPrefix != 0. Prefix 0x00000000 is the legitimate prefix of
// landblock (0,0) (id 0x0000FFFF, Dereth's map corner); the old
// prefix-based term made every real corner-landblock token read as
// invalid, wedging TryGetCurrentQuiescence and every release path.
internal bool IsValid => (LandblockPrefix & 0xFFFFu) == 0u
&& CollisionGeneration != 0UL
&& OperationId != 0UL;
}
internal readonly record struct RuntimeCollisionPrefixMutationPermission(
RuntimeCollisionPrefixQuiescenceToken Quiescence,
ImmutableArray<RuntimePlacementProjectionToken> Withdrawals)
{
internal bool IsValid => Quiescence.IsValid;
}
internal readonly record struct RuntimeCollisionEvaluationAuthority(
ulong CollisionWorldAuthority,
ulong ShadowWorldAuthority,
ClientObjectTable? ObjectTable,
ulong ObjectTableBindingAuthority,
ulong ObjectTableAuthority,
ImmutableArray<RuntimeCollisionGenerationAuthority> Generations)
{
internal bool IsValid => CollisionWorldAuthority != 0UL
&& !Generations.IsDefault;
}
internal readonly record struct RuntimeDormantSetPositionEvaluation(
RuntimeEntityPlacementToken Placement,
RuntimeSetPositionCommand Command,
PhysicsSetPositionResult Result,
RuntimeCollisionEvaluationAuthority CollisionAuthority)
{
internal bool IsValid => Placement.IsValid
&& CollisionAuthority.IsValid;
}
internal enum RuntimeDormantSetPositionCommitStatus : byte
{
None,
AwaitingFinalShadowPreparation,
Committed,
DeferredCell,
RejectedPlacement,
RejectedAuthority,
}
internal sealed class PreparedDormantSetPositionCommit
{
internal required RuntimeDormantSetPositionEvaluation Evaluation
{ get; init; }
internal required RuntimeEntityKey Entity { get; init; }
internal required ulong OperationId { get; init; }
internal required ulong ExpectedProjectionSequence { get; init; }
internal required ShadowObjectRegistry.PreparedSetPositionShadowCommit?
Shadow { get; init; }
internal required RuntimeCollisionReportingState
.PreparedSetPositionCollisionBatch? Collision { get; init; }
internal required RuntimePlacementProjectionSnapshot Projection
{ get; init; }
internal required SortedDictionary<ulong, RuntimePlacementProjectionSnapshot>?
PendingProjection { get; init; }
internal required ulong DeferredCollisionGeneration { get; init; }
internal required List<RuntimeEntityKey>? DeferredBucket { get; init; }
internal required bool DeferredBucketIsNew { get; init; }
}
internal sealed class PreparedDormantActivationFinalCommit
{
internal required RuntimeEntityKey Entity { get; init; }
internal required ulong OperationId { get; init; }
internal required ulong ExpectedProjectionSequence { get; init; }
internal required ShadowObjectRegistry.PreparedSetPositionShadowCommit
Shadow { get; init; }
internal required RuntimePlacementProjectionSnapshot Projection
{ get; init; }
internal required SortedDictionary<ulong, RuntimePlacementProjectionSnapshot>
PendingProjection { get; init; }
}
internal readonly record struct RuntimeDormantSetPositionCommitReceipt(
RuntimeDormantSetPositionCommitStatus Status,
RuntimeEntityKey Entity,
ulong OperationId,
RuntimePlacementProjectionSnapshot Projection,
RuntimeCollisionReportingState.SetPositionCollisionBatchReceipt Collision,
ShadowObjectRegistry.SetPositionShadowCommitReceipt Shadow,
RuntimeCollisionEvaluationAuthority CollisionAuthority,
ulong SourceVectorAuthorityVersion,
bool HitGround,
bool LeaveGround)
{
internal bool IsCommitted => Status
is RuntimeDormantSetPositionCommitStatus.Committed;
}
public readonly record struct RuntimePlacementProjectionToken(
ulong Sequence,
ulong Revision,
RuntimeEntityKey Entity,
ulong PositionAuthorityVersion,
ulong SpatialAuthorityVersion,
ulong PlacementCommitVersion,
ulong SessionLifetimeVersion,
uint ExactCellId,
ulong CollisionGeneration,
RuntimePortalPlacementAuthority Portal)
{
internal bool IsValid => Sequence != 0
&& Entity.LocalEntityId != 0u
&& PositionAuthorityVersion != 0UL;
}
public readonly record struct RuntimePlacementProjectionSnapshot(
RuntimePlacementProjectionToken Token,
RuntimePlacementProjectionKind Kind,
Vector3 WorldPosition,
Quaternion Orientation,
Vector3 CellLocalPosition,
bool InContact,
bool OnWalkable);
internal readonly record struct RuntimeSetPositionOutcome(
RuntimeSetPositionStatus Status,
PhysicsSetPositionError Error,
PhysicsResidenceDisposition Residence,
uint ExactCellId,
RuntimePlacementProjectionToken Projection)
{
internal bool Accepted => Error == PhysicsSetPositionError.Ok;
}
internal readonly record struct RuntimePlacementCancellationReceipt(
RuntimePlacementProjectionSnapshot Projection)
{
internal bool IsValid => Projection.Kind
is RuntimePlacementProjectionKind.Discard
&& Projection.Token.IsValid;
}
internal readonly record struct RuntimeSetPositionOwnershipSnapshot(
int ActiveOperationCount,
int AwaitingPreparationCount,
int DeferredCellCount,
int PendingProjectionAcknowledgementCount,
int LostDeadlineCount,
int LostDeadlineNodeCount,
int LostDeadlineIndexCount,
int ExpiredLostCellCount,
int ExpiredLostCellIndexCount,
int DeferredBucketCount,
int DeferredBucketOrderCount,
int UnboundDeferredCellCount,
int UnboundDeferredCellOrderCount,
int PreparedMoverCount,
int MoverPreparationAuthorityCount,
int PlacementCompletionWatchCount,
int AcknowledgedPlacementCompletionCount,
int CollisionPrefixQuiescenceCount,
int PendingQuiescenceProjectionCount,
int PooledOperationCount,
int ParkedAwaitingSetupCollisionCount = 0,
int ParkedAwaitingWorldFrameCount = 0)
{
/// <summary>
/// #284: placements that could not be prepared on their last attempt and
/// are waiting for a later pump, by cause. Non-zero at a stable
/// checkpoint means work is stuck; the reason names where to look.
/// </summary>
internal int ParkedPlacementCount =>
ParkedAwaitingSetupCollisionCount + ParkedAwaitingWorldFrameCount;
internal bool IndexesConsistent =>
LostDeadlineCount == LostDeadlineNodeCount
&& LostDeadlineCount == LostDeadlineIndexCount
&& ExpiredLostCellCount == ExpiredLostCellIndexCount
&& DeferredBucketCount == DeferredBucketOrderCount
&& UnboundDeferredCellCount == UnboundDeferredCellOrderCount
&& MoverPreparationAuthorityCount <= ActiveOperationCount;
/// <summary>
/// F2: deliberately EXCLUDED from <see cref="IsConverged"/>.
/// <see cref="PooledOperationCount"/> is retained, idle Operation
/// capacity in the C2 object pool - legitimate to hold mid-session (that
/// is the entire point of pooling), so it must not make an otherwise
/// fully-drained, healthy session read as "not converged". Reset/dispose
/// tests assert it separately drops to zero
/// (OperationPoolClearsOnResetSession /
/// OperationPoolClearsOnDispose) instead of folding it into this gate.
/// </summary>
internal bool IsConverged => ActiveOperationCount == 0
&& AwaitingPreparationCount == 0
&& DeferredCellCount == 0
&& PendingProjectionAcknowledgementCount == 0
&& LostDeadlineCount == 0
&& LostDeadlineNodeCount == 0
&& LostDeadlineIndexCount == 0
&& ExpiredLostCellCount == 0
&& ExpiredLostCellIndexCount == 0
&& DeferredBucketCount == 0
&& DeferredBucketOrderCount == 0
&& UnboundDeferredCellCount == 0
&& UnboundDeferredCellOrderCount == 0
&& PreparedMoverCount == 0
&& MoverPreparationAuthorityCount == 0
&& PlacementCompletionWatchCount == 0
&& AcknowledgedPlacementCompletionCount == 0
&& CollisionPrefixQuiescenceCount == 0
&& PendingQuiescenceProjectionCount == 0;
}
/// <summary>
/// Presentation-independent owner of retail SetPosition residence. Runtime
/// commits the complete Core packet before publishing an immutable projection
/// token. A host can retry the exact token until acknowledged; no App delegate
/// is retained and no presentation callback can duplicate simulation state.
/// </summary>
internal sealed class RuntimeSetPositionState : IDisposable
{
// Retail accepts an unsigned num_tries and performs the attempts in one
// synchronous call. Runtime preparation is an authority boundary, so an
// untrusted uint.MaxValue must not turn that verbatim loop into a frame-
// thread denial of service. Authored retail callers use small counts;
// 64 preserves that shape while making the synchronous work finite.
private const uint MaxSynchronousScatterAttempts = 64u;
private readonly record struct CellGenerationKey(
uint CellId,
uint CollisionPrefix,
ulong CollisionGeneration);
private readonly record struct UnboundCellKey(
uint CellId,
uint CollisionPrefix);
private readonly record struct MoverPreparationAuthority(
ulong OperationId,
CreateObject.ServerPosition AcceptedPosition,
uint SetupTableId,
ulong PositionAuthorityVersion,
ulong VelocityAuthorityVersion,
ulong StateAuthorityVersion,
ulong VectorAuthorityVersion,
ulong ObjDescAuthorityVersion,
ulong CreateIntegrationVersion,
ulong PhysicsStateMutationVersion,
bool Prepared,
RuntimeSetPositionCommand PreparedCommand);
/// <summary>
/// C2: settable (not <c>init</c>/<c>required</c>) so <see cref="RentOperation"/>
/// / <see cref="RetireOperationToPool"/> can recycle instances via
/// <see cref="ResetAllFieldsToDefault"/> instead of allocating a fresh
/// object on every accepted placement. This was the single largest
/// contributor to the C2 allocation budget finding (see
/// docs/research/2026-07-31-canonical-set-position.md). Every
/// construction site (<c>BeginAcceptedPlacementCore</c>,
/// <c>CreateWithdrawalOperation</c>, <c>ParkDeferred</c>) still sets
/// every field it always set before; the only behavior change is that a
/// field left unset by a given site now comes from an explicit reset
/// instead of the CLR's implicit new-object default - the two are
/// identical in value.
/// </summary>
private sealed class Operation
{
internal RuntimeEntityRecord Record { get; set; } = null!;
internal PhysicsBody? Body { get; set; }
internal RuntimeEntityPlacementToken Token { get; set; }
internal RuntimeEntityKey Key { get; set; }
internal ulong PositionAuthorityVersion { get; set; }
internal ulong SessionLifetimeVersion { get; set; }
internal ulong SourceSpatialAuthorityVersion { get; set; }
internal ulong SourceVelocityAuthorityVersion { get; set; }
internal bool PreviousContact { get; set; }
internal bool PreviousOnWalkable { get; set; }
internal RuntimeSetPositionCommand Command { get; set; }
internal PhysicsSetPositionResult Result { get; set; }
internal ulong SpatialAuthorityVersion { get; set; }
internal ulong PlacementCommitVersion { get; set; }
internal uint ExactCellId { get; set; }
internal ulong CollisionGeneration { get; set; }
internal uint CollisionPrefix { get; set; }
internal bool WithdrawalAcknowledged { get; set; }
internal bool CollisionGenerationReady { get; set; }
internal bool CollisionQuiescenceHeld { get; set; }
internal ulong ProjectionSequence { get; set; }
internal bool WakeableLostCell { get; set; }
internal RuntimeEntityPlacementStage Stage { get; set; }
internal RuntimeSetPositionOperationKind Kind { get; set; }
internal RuntimePortalPlacementAuthority Portal { get; set; }
internal bool RequiresPreparation { get; set; }
internal bool Expired { get; set; }
internal List<RuntimeEntityKey>? LostFamilyKeys { get; set; }
internal bool InheritedLostDeadline { get; set; }
internal bool EnteringWorldFromCelllessResidence { get; set; }
internal bool DormantLocalActivation { get; set; }
/// <summary>
/// The entity state <see cref="ParkDeferred"/> overwrote, captured
/// BEFORE it snapped the body to the (unplaceable) destination and
/// ran <see cref="WithdrawCanonical"/>. <see cref="Forget"/> rolls
/// back to it when it cancels a wakeable park - see
/// <see cref="RestoreParkWithdrawal"/> for why the rollback target is
/// the PRE-PARK pose and never the destination.
/// </summary>
internal ParkWithdrawal ParkWithdrawal { get; set; }
/// <summary>
/// #284: why this operation's mover preparation is currently parked,
/// or <see cref="RuntimeSetPositionParkReason.None"/> when it is not.
/// Observability only - it never gates work.
/// </summary>
internal RuntimeSetPositionParkReason ParkReason { get; set; }
internal RuntimeSetPositionCommand? PreparedCommandAwaitingWithdrawalAck
{
get;
set;
}
/// <summary>
/// F3: pool-membership guard, not operation data. Set true by
/// <see cref="RetireOperationToPool"/> right before pushing; cleared
/// here (called from <see cref="RentOperation"/> right after
/// popping). Lets RetireOperationToPool detect and throw on a
/// double-retire - two retire calls for the same instance without an
/// intervening rent would otherwise silently duplicate it in the
/// pool stack.
/// </summary>
internal bool InPool { get; set; }
/// <summary>
/// C2/F4: the ONLY place every field is set to its inert default -
/// this is the completeness net that `required`/`init` used to
/// provide before pooling needed plain settable properties. Called
/// exactly once when an Operation is retired to the pool
/// (<see cref="RetireOperationToPool"/>), before it can be handed
/// back out by <see cref="RentOperation"/>. <see cref="Record"/> is
/// left null! only for the instant the instance sits in the pool -
/// every rent site immediately overwrites it before any other
/// member is read. A reflection-based test
/// (OperationResetAllFieldsToDefaultTouchesEveryDeclaredField) pins
/// that this method assigns every declared instance field of this
/// class by name - a newly added field fails that test until both
/// the reset and the test's expected-field list are updated.
/// </summary>
internal void ResetAllFieldsToDefault()
{
Record = null!;
Body = null;
Token = default;
Key = default;
PositionAuthorityVersion = 0UL;
SessionLifetimeVersion = 0UL;
SourceSpatialAuthorityVersion = 0UL;
SourceVelocityAuthorityVersion = 0UL;
PreviousContact = false;
PreviousOnWalkable = false;
Command = default;
Result = default;
SpatialAuthorityVersion = 0UL;
PlacementCommitVersion = 0UL;
ExactCellId = 0u;
CollisionGeneration = 0UL;
CollisionPrefix = 0u;
WithdrawalAcknowledged = false;
CollisionGenerationReady = false;
CollisionQuiescenceHeld = false;
ProjectionSequence = 0UL;
WakeableLostCell = false;
Stage = default;
Kind = default;
Portal = default;
RequiresPreparation = false;
Expired = false;
LostFamilyKeys = null;
InheritedLostDeadline = false;
EnteringWorldFromCelllessResidence = false;
DormantLocalActivation = false;
ParkReason = RuntimeSetPositionParkReason.None;
PreparedCommandAwaitingWithdrawalAck = null;
ParkWithdrawal = default;
InPool = false;
}
}
/// <summary>
/// The exact set of entity state <see cref="ParkDeferred"/> withdraws,
/// captured before it is overwritten so <see cref="Forget"/> can roll a
/// cancelled park back instead of stranding the entity.
/// </summary>
private readonly record struct ParkWithdrawal(
bool Captured,
bool InWorld,
TransientStateFlags TransientState,
bool ClockActive);
private sealed class CollisionPrefixQuiescence
{
internal required RuntimeCollisionPrefixQuiescenceToken Token
{ get; init; }
internal required bool IncludeOutdoorCells { get; init; }
internal required ulong ProjectionBarrierSequence { get; init; }
internal SortedDictionary<ulong, RuntimePlacementProjectionToken>
PendingWithdrawals { get; } = [];
internal SortedDictionary<ulong, RuntimePlacementProjectionToken>
PendingRestorePlacements { get; } = [];
internal List<RuntimePlacementProjectionToken> RetainedWithdrawals
{ get; } = [];
internal bool ResidentsParked { get; set; }
internal bool PermissionIssued { get; set; }
internal bool ReleaseInProgress { get; set; }
internal ulong ReleaseGeneration { get; set; }
internal bool ReleaseGenerationReady { get; set; }
}
/// <summary>
/// F1: captures the operation's PositionAuthorityVersion/
/// SpatialAuthorityVersion as PLAIN VALUES at construction time instead
/// of holding an <see cref="Operation"/> reference and reading its
/// fields lazily inside <see cref="IsCurrent"/>. <c>IsCurrent</c> can run
/// DURING the ground-edge HitGround/LeaveGround callbacks this guard is
/// built for - a synchronous cancel-then-begin (or begin-twice) chain
/// for the SAME entity can retire this exact Operation instance to the
/// pool and rent it right back out (LIFO) for a different logical
/// operation before this guard is asked whether it is still current. A
/// live Operation reference would then silently read the WRONG
/// operation's authority versions; these captured scalars cannot be
/// repurposed out from under it.
/// </summary>
private sealed class ContactCommitGuard(
RuntimeSetPositionState owner,
ulong positionAuthorityVersion,
ulong spatialAuthorityVersion,
RuntimeEntityRecord record,
PhysicsBody body,
ulong placementCommitVersion,
uint fullCellId)
{
internal bool IsCurrent() =>
owner.IsCanonicalPlacementCommitCurrent(
positionAuthorityVersion,
spatialAuthorityVersion,
record,
body,
placementCommitVersion,
fullCellId,
requireSpatialRoot: false);
}
private readonly RuntimePhysicsState _physics;
private readonly RuntimeEntityDirectory _entities;
private readonly Dictionary<RuntimeEntityKey, Operation> _operations = [];
private readonly Dictionary<CellGenerationKey, List<RuntimeEntityKey>>
_deferredByCellGeneration = [];
private SortedDictionary<ulong, RuntimePlacementProjectionSnapshot>
_pendingProjection = [];
private readonly List<CellGenerationKey> _deferredBucketOrder = [];
private readonly Dictionary<UnboundCellKey, List<RuntimeEntityKey>>
_unboundDeferredByCell = [];
private readonly List<UnboundCellKey> _unboundDeferredCellOrder = [];
private readonly Dictionary<RuntimeEntityKey, double> _lostDeadlines = [];
private readonly List<LostDeadlineEntry> _lostDeadlineNodes = [];
private readonly Dictionary<RuntimeEntityKey, int>
_lostDeadlineNodeIndex = [];
private readonly Dictionary<RuntimeEntityKey, PhysicsSetPositionRequest>
_preparedMovers = [];
private readonly Dictionary<RuntimeEntityKey, MoverPreparationAuthority>
_moverPreparationAuthorities = [];
private readonly HashSet<RuntimeEntityPlacementToken>
_placementCompletionWatches = [];
private readonly Dictionary<RuntimeEntityPlacementToken,
RuntimePlacementProjectionToken> _acknowledgedPlacementCompletions = [];
private readonly Dictionary<uint, CollisionPrefixQuiescence>
_collisionPrefixQuiescence = [];
private readonly LinkedList<RuntimeEntityKey> _expiredLostCells = [];
private readonly Dictionary<RuntimeEntityKey, LinkedListNode<RuntimeEntityKey>>
_expiredLostCellNodes = [];
private ulong _nextProjectionSequence;
private ulong _nextOperationId;
private ulong _nextCollisionPrefixQuiescenceOperationId;
private ulong _nextLostDeadlineSequence;
private RuntimeEntityObjectEventStream? _events;
private Action<RuntimeEntityKey, ulong>? _executorCompletionAcknowledged;
private bool _disposed;
private readonly record struct LostDeadlineEntry(
RuntimeEntityKey Key,
double Deadline,
ulong Sequence);
/// <summary>
/// C2: everything <see cref="HandleSetPositionCollisionsCallback"/> reads
/// to invoke <see cref="RuntimePhysicsState.HandleSetPositionCollisions"/>
/// on behalf of the in-flight <c>PhysicsEngine.SetPosition</c> call. A
/// plain per-call lambda closing over the live <see cref="Operation"/>
/// (and, at one call site, a local <c>canonicalCommand</c>) allocated a
/// fresh display class every accepted placement; this struct is pushed by
/// value onto <see cref="_collisionCallbackContexts"/> instead so the ONE
/// cached delegate below never needs a new closure. A stack (not a single
/// field) survives any theoretical nested/re-entrant SetPosition call at
/// the PhysicsEngine layer - <c>TransitionScratchArena.ActiveDepth</c>/
/// <c>Capacity</c> implies nesting is possible there even though
/// <see cref="RuntimePhysicsState.HandleSetPositionCollisions"/> itself
/// never calls back into this class.
/// </summary>
private readonly record struct CollisionCallbackContext(
RuntimeEntityRecord Record,
ulong PositionAuthorityVersion,
ulong SpatialAuthorityVersion,
ulong VelocityAuthorityVersion,
double GameTime,
bool PreviousContact,
bool PreviousOnWalkable);
private readonly Stack<CollisionCallbackContext> _collisionCallbackContexts
= new(4);
private readonly Func<PhysicsSetPositionCollisionReport, bool>
_handleSetPositionCollisionsCallback;
// C2: retired Operation instances wait here for reuse by
// BeginAcceptedPlacementCore instead of a fresh `new Operation` every
// accepted placement. Bounded so a pathological retirement/rent
// imbalance (e.g. many entities despawning with none spawning) cannot
// grow this into an unbounded retained cache - beyond the cap we simply
// let the retired instance become garbage, exactly like before pooling
// existed.
private const int MaxPooledOperations = 64;
private readonly Stack<Operation> _operationPool = new();
internal RuntimeSetPositionState(
RuntimePhysicsState physics,
RuntimeEntityDirectory entities)
{
_physics = physics ?? throw new ArgumentNullException(nameof(physics));
_entities = entities ?? throw new ArgumentNullException(nameof(entities));
_handleSetPositionCollisionsCallback =
HandleSetPositionCollisionsCallback;
}
/// <summary>
/// C2: the single cached delegate every accepted-placement SetPosition
/// call passes to <c>PhysicsEngine.SetPosition</c> in place of a fresh
/// per-call closure. Reads the innermost pushed
/// <see cref="CollisionCallbackContext"/> rather than capturing state
/// directly, so this delegate instance (created once in the
/// constructor) is reused for the lifetime of this owner.
/// </summary>
private bool HandleSetPositionCollisionsCallback(
PhysicsSetPositionCollisionReport report)
{
CollisionCallbackContext context = _collisionCallbackContexts.Peek();
return _physics.HandleSetPositionCollisions(
context.Record,
context.PositionAuthorityVersion,
context.SpatialAuthorityVersion,
context.VelocityAuthorityVersion,
context.GameTime,
context.PreviousContact,
context.PreviousOnWalkable,
report);
}
/// <summary>
/// C2: returns a pooled instance reset to inert defaults right here (NOT
/// at retirement - see <see cref="RetireOperationToPool"/> for why that
/// ordering matters), or allocates a fresh instance exactly as
/// <c>BeginAcceptedPlacementCore</c> did before pooling existed. Callers
/// MUST set every field they previously set via object-initializer
/// syntax - a rented instance's unset fields are the SAME defaults a
/// brand-new instance would have (see
/// <see cref="Operation.ResetAllFieldsToDefault"/>), never leftover
/// state from a prior use.
/// </summary>
private Operation RentOperation()
{
if (_operationPool.Count == 0)
return new Operation();
Operation pooled = _operationPool.Pop();
pooled.ResetAllFieldsToDefault();
return pooled;
}
/// <summary>
/// C2: the only place an Operation is retired to the pool - called the
/// instant one is removed from <see cref="_operations"/> for good.
/// Deliberately does NOT reset the instance here (that happens in
/// <see cref="RentOperation"/> instead, right before reuse): a reentrant
/// callback chain can retire the operation the OUTER frame is still
/// executing inside of and needs to keep reading.
///
/// <para>Round 3 correction: an earlier revision of this comment claimed
/// <c>IsCanonicalPlacementCommitCurrent</c> additionally compared the
/// operation's Token to detect exactly this recycling. That claim was
/// wrong and the check it described was reverted - retail's
/// SetPositionInternal settle is UNCONDITIONAL, so an in-flight
/// ground-edge commit for an entity a reentrant cancel-then-begin has
/// since displaced must still complete its physical settle (contact
/// transition, collision reports, shadow sync) - see
/// ReentrantGroundEdgePlacementCannotBeCancelledByDisplacedOperation. A
/// Token/identity gate on the settle path itself would incorrectly abort
/// that commit the moment the entity is displaced.</para>
///
/// <para>The ACTUAL safety mechanism, class-wide, is captured-token-vs-
/// fresh-lookup at every frame that holds an Operation reference across
/// a reentrancy point (a synchronous publish, a collision-report
/// dispatch that can reach an arbitrary
/// <c>IRuntimeCollisionReportObserver</c>, or a ground-edge HitGround/
/// LeaveGround callback): capture <c>operation.Token</c> (globally
/// unique - <c>checked(++_nextOperationId)</c> is never reissued) into a
/// local BEFORE the reentrancy point, then after it re-resolve via a
/// fresh <c>_operations.TryGetValue</c> and compare
/// <c>current.Token == capturedToken</c> - never
/// <c>ReferenceEquals</c>/<c>IsCurrent(Operation)</c> against the
/// original reference, which becomes a tautology once pooling can hand
/// that SAME physical instance back out for a different logical
/// operation. This identity gate belongs at publication/cancellation/
/// ownership decisions (see the token comparisons in
/// <c>BeginAcceptedPlacementCore</c>, <c>SubmitPreparedPlacementCore</c>,
/// <c>RetryDeferred</c>, and <c>CommitCanonical</c>'s own bookkeeping-
/// write gate), never inside the settle/currency layer itself.</para>
///
/// F3 reorders BeginAcceptedPlacementCore to rent only AFTER this method
/// retires the displaced operation - every field this class still needs
/// from a displaced operation is captured into a local before that
/// retire point (never read from the possibly-the-same, freshly-reset
/// instance after), so it is safe, and more efficient, for a single-
/// entity churn cycle to hand the SAME instance right back out as the
/// next operation (LIFO). <see cref="Operation.InPool"/> guards the one
/// invariant that ordering depends on: this method must never be called
/// twice for the same instance without an intervening
/// <see cref="RentOperation"/> in between - that would silently
/// duplicate the instance in <see cref="_operationPool"/>, so it throws
/// instead.
/// </summary>
private void RetireOperationToPool(Operation operation)
{
if (operation.InPool)
{
throw new InvalidOperationException(
"Operation was already retired to the pool - a double-retire " +
"without an intervening rent would duplicate it in the pool " +
"stack.");
}
if (_operationPool.Count >= MaxPooledOperations)
return;
operation.InPool = true;
_operationPool.Push(operation);
}
internal RuntimeSetPositionOwnershipSnapshot CaptureOwnership()
{
int deferred = 0;
int awaitingPreparation = 0;
int parkedAwaitingSetup = 0;
int parkedAwaitingWorldFrame = 0;
foreach (Operation operation in _operations.Values)
{
if (operation.Stage
is RuntimeEntityPlacementStage.AwaitingPreparation)
{
awaitingPreparation++;
}
if (operation.WakeableLostCell)
deferred++;
switch (operation.ParkReason)
{
case RuntimeSetPositionParkReason.AwaitingSetupCollision:
parkedAwaitingSetup++;
break;
case RuntimeSetPositionParkReason.AwaitingWorldFrame:
parkedAwaitingWorldFrame++;
break;
}
}
int pendingQuiescenceProjections = 0;
foreach (CollisionPrefixQuiescence quiescence
in _collisionPrefixQuiescence.Values)
{
pendingQuiescenceProjections +=
quiescence.PendingWithdrawals.Count
+ quiescence.PendingRestorePlacements.Count;
}
return new RuntimeSetPositionOwnershipSnapshot(
_operations.Count,
awaitingPreparation,
deferred,
_pendingProjection.Count,
_lostDeadlines.Count,
_lostDeadlineNodes.Count,
_lostDeadlineNodeIndex.Count,
_expiredLostCells.Count,
_expiredLostCellNodes.Count,
_deferredByCellGeneration.Count,
_deferredBucketOrder.Count,
_unboundDeferredByCell.Count,
_unboundDeferredCellOrder.Count,
_preparedMovers.Count,
_moverPreparationAuthorities.Count,
_placementCompletionWatches.Count,
_acknowledgedPlacementCompletions.Count,
_collisionPrefixQuiescence.Count,
pendingQuiescenceProjections,
_operationPool.Count,
parkedAwaitingSetup,
parkedAwaitingWorldFrame);
}
internal int PendingProjectionCount => _pendingProjection.Count;
internal bool CanBeginAuthoredPlacementSequence =>
_nextOperationId != ulong.MaxValue;
internal bool IsCollisionPrefixQuiescing(uint landblockId) =>
_collisionPrefixQuiescence.ContainsKey(
landblockId & 0xFFFF0000u);
internal RuntimeCollisionPrefixQuiescenceToken
BeginCollisionPrefixQuiescence(
uint landblockId,
ulong collisionGeneration,
bool includeOutdoorCells)
{
EnsureNotDisposed();
if (collisionGeneration == 0UL)
throw new ArgumentOutOfRangeException(nameof(collisionGeneration));
// C3c-F3: reject only the genuinely-absent landblock id (0). Prefix
// 0x00000000 is landblock (0,0) — the map corner — so a prefix == 0
// test can no longer stand in for "no landblock"; that sentinel
// collision crashed every collision publication whose streaming
// window reached the corner (connected-gate 20260802-135444).
if (landblockId == 0u)
throw new ArgumentOutOfRangeException(nameof(landblockId));
uint prefix = landblockId & 0xFFFF0000u;
if (_collisionPrefixQuiescence.TryGetValue(
prefix,
out CollisionPrefixQuiescence? active)
&& active.ReleaseInProgress)
{
throw new InvalidOperationException(
$"Collision quiescence 0x{prefix:X8}/{active.Token.OperationId} is releasing its retained residents.");
}
_collisionPrefixQuiescence.Remove(
prefix,
out CollisionPrefixQuiescence? superseded);
var token = new RuntimeCollisionPrefixQuiescenceToken(
_entities.SessionLifetimeVersion,
prefix,
collisionGeneration,
checked(++_nextCollisionPrefixQuiescenceOperationId));
var replacement = new CollisionPrefixQuiescence
{
Token = token,
IncludeOutdoorCells = includeOutdoorCells,
ProjectionBarrierSequence = superseded is null
? _nextProjectionSequence
: Math.Max(
_nextProjectionSequence,
superseded.ProjectionBarrierSequence),
ResidentsParked = superseded?.ResidentsParked ?? false,
};
if (superseded is not null)
{
foreach ((ulong sequence, RuntimePlacementProjectionToken pending)
in superseded.PendingWithdrawals)
replacement.PendingWithdrawals.Add(sequence, pending);
replacement.RetainedWithdrawals.AddRange(
superseded.RetainedWithdrawals);
}
_collisionPrefixQuiescence.Add(prefix, replacement);
if (superseded is not null)
{
RebindQuiescedDeferredOperations(
superseded.Token,
collisionGeneration,
ready: false);
}
_physics.AdvanceCollisionQuiescenceAuthority();
return token;
}
internal bool TryAcquireCollisionPrefixMutationPermission(
in RuntimeCollisionPrefixQuiescenceToken token,
out RuntimeCollisionPrefixMutationPermission permission)
{
EnsureNotDisposed();
permission = default;
if (!TryGetCurrentQuiescence(token, out CollisionPrefixQuiescence? state))
return false;
CollisionPrefixQuiescence current = state!;
if (HasPendingProjectionThrough(current.ProjectionBarrierSequence))
return false;
if (HasOldPrefixPlacementDebt(current))
return false;
if (!current.ResidentsParked)
{
ParkCollisionResidentsForQuiescence(current);
current.ResidentsParked = true;
return false;
}
else if (HasAffectedCollisionResident(
token.LandblockPrefix,
current.IncludeOutdoorCells))
{
ParkCollisionResidentsForQuiescence(current);
return false;
}
RemoveRetiredQuiescenceWithdrawals(current);
if (current.PendingWithdrawals.Count != 0
|| HasAffectedCollisionResident(
token.LandblockPrefix,
current.IncludeOutdoorCells)
|| HasOldPrefixPlacementDebt(current)
|| HasCollisionDispatchDebt())
{
return false;
}
current.PermissionIssued = true;
permission = new RuntimeCollisionPrefixMutationPermission(
current.Token,
current.RetainedWithdrawals.Count == 0
? default
: current.RetainedWithdrawals.ToImmutableArray());
return true;
}
internal bool IsCollisionPrefixMutationPermissionCurrent(
in RuntimeCollisionPrefixMutationPermission permission)
{
EnsureNotDisposed();
return permission.IsValid
&& TryGetCurrentQuiescence(
permission.Quiescence,
out CollisionPrefixQuiescence? state)
&& state!.PermissionIssued
&& state.PendingWithdrawals.Count == 0
&& !HasAffectedCollisionResident(
state.Token.LandblockPrefix,
state.IncludeOutdoorCells)
&& !HasOldPrefixPlacementDebt(state)
&& !HasCollisionDispatchDebt();
}
internal bool CancelCollisionPrefixQuiescence(
in RuntimeCollisionPrefixQuiescenceToken token,
ulong successorGeneration = 0UL,
bool successorReady = false)
{
EnsureNotDisposed();
if (!TryGetCurrentQuiescence(token, out CollisionPrefixQuiescence? state))
return false;
CollisionPrefixQuiescence current = state!;
if (!current.ResidentsParked
&& current.PendingWithdrawals.Count == 0
&& current.PendingRestorePlacements.Count == 0
&& !HasQuiescedDeferredOperations(token.LandblockPrefix))
{
bool removedBeforePark = _collisionPrefixQuiescence.Remove(
token.LandblockPrefix);
if (removedBeforePark)
_physics.AdvanceCollisionQuiescenceAuthority();
return removedBeforePark;
}
if (successorGeneration == 0UL)
return false;
return AdvanceCollisionPrefixRelease(
token,
successorGeneration,
successorReady,
requireMutationPermission: false);
}
internal bool CancelCollisionPrefixQuiescenceToUnavailable(
in RuntimeCollisionPrefixQuiescenceToken token)
{
EnsureNotDisposed();
return AdvanceCollisionPrefixRelease(
token,
generation: 0UL,
ready: false,
requireMutationPermission: false);
}
internal bool ReleaseCollisionPrefixAfterMutation(
in RuntimeCollisionPrefixQuiescenceToken token,
ulong activeGeneration,
bool ready)
{
EnsureNotDisposed();
return AdvanceCollisionPrefixRelease(
token,
activeGeneration,
ready,
requireMutationPermission: true);
}
private bool AdvanceCollisionPrefixRelease(
in RuntimeCollisionPrefixQuiescenceToken token,
ulong generation,
bool ready,
bool requireMutationPermission)
{
if ((generation == 0UL && ready)
|| !TryGetCurrentQuiescence(
token,
out CollisionPrefixQuiescence? state))
{
return false;
}
CollisionPrefixQuiescence current = state!;
if (current.PendingWithdrawals.Count != 0)
return false;
if (requireMutationPermission
&& !current.PermissionIssued
&& !current.ReleaseInProgress)
{
return false;
}
if (!current.ReleaseInProgress)
{
current.ReleaseInProgress = true;
current.ReleaseGeneration = generation;
current.ReleaseGenerationReady = ready;
current.PermissionIssued = false;
}
else if (current.ReleaseGeneration != generation
|| current.ReleaseGenerationReady != ready)
{
return false;
}
// A re-entrant/network placement may have joined the still-closed
// prefix after release started. Transfer every exact newcomer on each
// poll before deciding the barrier can open.
if (_operations.Count != 0)
{
RebindQuiescedDeferredOperations(
token,
ready ? generation : 0UL,
ready,
releaseUnavailable: !ready);
}
if (current.PendingRestorePlacements.Count != 0
|| HasQuiescedDeferredOperations(token.LandblockPrefix))
{
return false;
}
bool removed = _collisionPrefixQuiescence.Remove(
token.LandblockPrefix);
if (removed)
_physics.AdvanceCollisionQuiescenceAuthority();
return removed;
}
internal void BindEventStream(RuntimeEntityObjectEventStream events)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(events);
if (_events is not null)
throw new InvalidOperationException(
"The Runtime placement event stream is already bound.");
_events = events;
}
internal void RetryPendingProjections()
{
EnsureNotDisposed();
RuntimePlacementProjectionSnapshot[] snapshot =
_pendingProjection.Values.ToArray();
for (int index = 0; index < snapshot.Length; index++)
{
RuntimePlacementProjectionSnapshot projection = snapshot[index];
if (_pendingProjection.TryGetValue(
projection.Token.Sequence,
out RuntimePlacementProjectionSnapshot current)
&& current == projection)
{
PublishPlacement(projection);
}
}
}
/// <summary>
/// C0-1: publishes the initial-create continuation executor's own
/// completion (its FIFO drain has finished and its residence lease is
/// already released) on the SAME ordered receipt stream every
/// Place/Withdraw/Discard uses - the pinned contract forbids a second
/// stream/queue. This is NOT an Operation-backed receipt (the executor's
/// own placement operation, if any, already committed and was
/// acknowledged earlier in the drain - see
/// RuntimeInitialCreateContinuationExecutor.ExecuteCore's call site) so
/// the token is built the same way PublishProjection assembles one, but
/// from the CANONICAL record's current authority/version/cell facts
/// (self-consistent: nothing else can move them synchronously between
/// the executor's release and this publish) instead of a now-gone
/// Operation. AcknowledgeProjection's dedicated ExecutorCompleted branch
/// treats it exactly like Discard - acknowledge-only, no operation to
/// resume or commit against.
/// </summary>
internal RuntimePlacementProjectionToken PublishExecutorCompletion(
RuntimeEntityRecord record,
Action<RuntimePlacementProjectionToken>? beforePublish = null,
RuntimePortalPlacementAuthority portal = default)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
if (record.Key is not { } key)
return default;
PhysicsBody? body = record.PhysicsBody;
ulong sequence = checked(++_nextProjectionSequence);
var token = new RuntimePlacementProjectionToken(
sequence,
Revision: 1UL,
key,
record.PositionAuthorityVersion,
record.SpatialAuthorityVersion,
record.PlacementCommitVersion,
_entities.SessionLifetimeVersion,
record.FullCellId,
_physics.ExpectedCollisionGeneration(record.FullCellId),
portal);
var snapshot = new RuntimePlacementProjectionSnapshot(
token,
RuntimePlacementProjectionKind.ExecutorCompleted,
body?.Position ?? Vector3.Zero,
body?.Orientation ?? Quaternion.Identity,
body?.CellPosition.Frame.Origin ?? Vector3.Zero,
body?.InContact ?? false,
body?.OnWalkable ?? false);
_pendingProjection.Add(sequence, snapshot);
// F2: register-before-publish - beforePublish runs while the token is
// already in _pendingProjection but before PublishPlacement's
// synchronous observer dispatch, so a subscriber reading back the
// executor's correlation entry from inside its OWN OnPlacement
// callback always finds it.
beforePublish?.Invoke(token);
PublishPlacement(snapshot);
return token;
}
/// <summary>
/// Publishes the exact inverse of the <see cref="ParkDeferred"/>
/// withdrawal receipt whose CANONICAL half
/// <see cref="RestoreParkWithdrawal"/> just rolled back, on the SAME
/// ordered stream every Place/Withdraw/Discard receipt uses.
///
/// <para><b>Why a receipt rather than a wider rollback.</b>
/// <see cref="ParkDeferred"/>'s withdrawal has two halves. The canonical
/// half (<c>InWorld</c>, transient bits, object clock, residency, spatial
/// root) is Runtime-owned and <see cref="RestoreParkWithdrawal"/> restores
/// it directly. The PRESENTATION half was performed by the host sink that
/// consumed the Withdraw receipt - the graphical bucket, the projection
/// visibility sinks, plugin world state and events, the effect-pose
/// registry, the local-player shadow - and Runtime cannot and must not
/// reach any of it. Its one existing mirror image is the sink's own Place
/// publication, so the rollback names it the same way the teardown was
/// named: with an ordered receipt.</para>
///
/// <para><b>Why not simply route the restore's SetFullCell through
/// CommitCanonicalCell</b> so the graphical <c>CellCommitted</c> ->
/// <c>RebucketLiveEntity</c> recovery fires: measured, that recovery
/// restores the bucket, <c>IsSpatiallyProjected</c>,
/// <c>IsSpatiallyVisible</c> and the projection-visibility observers, but
/// it never touches the plugin world state, the world-event stream, or the
/// effect-pose registry - only the sink's Place publication does. It also
/// cannot fire at all in the shipped remote path, where the per-packet
/// prologue rebucket has already recommitted a NON-ZERO
/// <c>record.FullCellId</c> before the merge cancels the park, so the
/// restore's residency arm is skipped and there is no cell edge to
/// commit.</para>
///
/// <para>NOT Operation-backed: the parked operation was removed and
/// retired by <c>CancelCoreDeferred</c> before this runs, so the token is
/// assembled from the canonical record's current facts exactly the way
/// <see cref="PublishExecutorCompletion"/> assembles one, and
/// <see cref="AcknowledgeProjection"/> consumes it through the same
/// acknowledge-only branch.</para>
///
/// <para>Ordering is the stream's, not ours: the cancelled park's own
/// Discard still sits at a LOWER sequence when this publishes, so the
/// synchronous dispatch below is a no-op and the host's per-frame
/// <c>RetryPending</c> pump delivers this receipt immediately after that
/// Discard drains. If the same packet then commits or re-parks the entity,
/// its Place/Withdraw lands at a HIGHER sequence and supersedes this
/// restoration in canonical order.</para>
/// </summary>
private void PublishWithdrawalRestoration(RuntimeEntityRecord record)
{
if (record.Key is not { } key)
return;
PhysicsBody? body = record.PhysicsBody;
ulong sequence = checked(++_nextProjectionSequence);
var token = new RuntimePlacementProjectionToken(
sequence,
Revision: 1UL,
key,
record.PositionAuthorityVersion,
record.SpatialAuthorityVersion,
record.PlacementCommitVersion,
_entities.SessionLifetimeVersion,
record.FullCellId,
_physics.ExpectedCollisionGeneration(record.FullCellId),
Portal: default);
var snapshot = new RuntimePlacementProjectionSnapshot(
token,
RuntimePlacementProjectionKind.WithdrawalRestored,
body?.Position ?? Vector3.Zero,
body?.Orientation ?? Quaternion.Identity,
body?.CellPosition.Frame.Origin ?? Vector3.Zero,
body?.InContact ?? false,
body?.OnWalkable ?? false);
_pendingProjection.Add(sequence, snapshot);
PublishPlacement(snapshot);
}
/// <summary>
/// F2: binds the ONE notification fired when a Kind ExecutorCompleted
/// receipt is acknowledged (mirrors
/// RuntimeInitialCreateResidenceState.BindRetirementNotification's
/// existing one-bound-delegate shape). The executor uses this to reap
/// its own token-to-receipt correlation entry exactly when the receipt
/// it correlates is consumed - never before (a host might still be
/// mid-retry) and never left dangling after (unbounded per-completed-
/// entity retention).
/// </summary>
internal void BindExecutorCompletionAcknowledgement(
Action<RuntimeEntityKey, ulong> acknowledged)
{
ArgumentNullException.ThrowIfNull(acknowledged);
if (_executorCompletionAcknowledged is not null)
{
throw new InvalidOperationException(
"The executor-completion acknowledgement notification is already bound.");
}
_executorCompletionAcknowledged = acknowledged;
}
internal void ResetSession()
{
EnsureNotDisposed();
ClearOwnedState();
}
internal RuntimeSetPositionOutcome Apply(
RuntimeEntityRecord record,
ulong expectedPositionAuthorityVersion,
in RuntimeSetPositionCommand command)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
RuntimeEntityPlacementToken token = BeginAcceptedPlacementCore(
record,
expectedPositionAuthorityVersion,
command.Kind,
command.Portal,
captureMoverPreparationAuthority: false);
if (!token.IsValid)
{
return Rejected(command.Physics);
}
return SubmitPreparedPlacementCore(
token,
command,
allowDirectUnsealed: true);
}
internal RuntimeEntityPlacementToken BeginAcceptedPlacement(
RuntimeEntityRecord record,
ulong expectedPositionAuthorityVersion,
RuntimeSetPositionOperationKind kind,
RuntimePortalPlacementAuthority portal = default) =>
BeginAcceptedPlacementCore(
record,
expectedPositionAuthorityVersion,
kind,
portal,
captureMoverPreparationAuthority: false);
internal RuntimeEntityPlacementToken BeginAuthoredPlacement(
RuntimeEntityRecord record,
ulong expectedPositionAuthorityVersion,
RuntimeSetPositionOperationKind kind,
RuntimePortalPlacementAuthority portal = default) =>
BeginAcceptedPlacementCore(
record,
expectedPositionAuthorityVersion,
kind,
portal,
captureMoverPreparationAuthority: true);
internal bool IsPlacementCurrent(
in RuntimeEntityPlacementToken token)
{
EnsureNotDisposed();
// Round 3 audit: safe - fresh lookup + Token check on the SAME line
// immediately precede IsCurrent, nothing reentrant in between.
return token.IsValid
&& _operations.TryGetValue(token.Entity, out Operation? operation)
&& operation.Token == token
&& IsCurrent(operation);
}
/// <summary>
/// Reserves the exact acknowledgement edge for a higher-level Runtime
/// transaction. Ordinary SetPosition operations retain no completion
/// history; only explicitly watched tokens survive operation retirement.
/// </summary>
internal bool WatchPlacementCompletion(
in RuntimeEntityPlacementToken token)
{
EnsureNotDisposed();
return IsPlacementCurrent(token)
&& _placementCompletionWatches.Add(token);
}
internal bool IsPlacementCompletionTracked(
in RuntimeEntityPlacementToken token)
{
EnsureNotDisposed();
return token.IsValid
&& (IsPlacementCurrent(token)
&& _placementCompletionWatches.Contains(token)
|| _acknowledgedPlacementCompletions.ContainsKey(token));
}
internal bool TryPeekAcknowledgedPlacement(
in RuntimeEntityPlacementToken token,
out RuntimePlacementProjectionToken projection)
{
EnsureNotDisposed();
if (token.IsValid
&& _acknowledgedPlacementCompletions.TryGetValue(
token,
out projection))
{
return true;
}
projection = default;
return false;
}
internal bool ConsumeAcknowledgedPlacement(
in RuntimeEntityPlacementToken token,
in RuntimePlacementProjectionToken expected)
{
EnsureNotDisposed();
return token.IsValid
&& _acknowledgedPlacementCompletions.TryGetValue(
token,
out RuntimePlacementProjectionToken current)
&& current == expected
&& _acknowledgedPlacementCompletions.Remove(token);
}
internal void ForgetPlacementCompletion(
in RuntimeEntityPlacementToken token)
{
EnsureNotDisposed();
ForgetPlacementCompletionCore(token);
}
/// <summary>
/// <paramref name="restoreCancelledPark"/> — see <see cref="Forget"/>. It
/// defaults to false so every shipped caller keeps its exact prior
/// behaviour; only a caller that is genuinely CANCELLING a placement
/// intent (rather than withdrawing the entity from the world) opts in.
/// </summary>
internal RuntimePlacementCancellationReceipt ForgetExactPlacement(
in RuntimeEntityPlacementToken token,
bool restoreCancelledPark = false)
{
EnsureNotDisposed();
ForgetPlacementCompletionCore(token);
if (!token.IsValid
|| !_operations.TryGetValue(token.Entity, out Operation? operation)
|| operation.Token != token)
{
return default;
}
// Round 3: `token` is this call's own parameter, verified fresh
// against `_operations` immediately above with nothing reentrant in
// between - passing it straight through is equivalent to (and safer
// than) re-deriving it from `operation`.
return CancelCore(
token.Entity,
token,
restoreCancelledPark: restoreCancelledPark);
}
internal RuntimeEntityPlacementToken TryBeginExclusiveAuthoredPlacement(
RuntimeEntityRecord record,
ulong expectedPositionAuthorityVersion,
RuntimeSetPositionOperationKind kind,
RuntimePortalPlacementAuthority portal = default)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
// B2 dependency (C4 route 4b-2): the `_operations.ContainsKey`
// refusal is what makes an INHERITED park impossible for any
// operation begun here, which is in turn what lets
// RuntimeRemotePlacementDriveController document a pre-engine
// Rejected as unreachable on its far-snap path (the
// WakeableLostCell-only `with` rewrite in
// SubmitPreparedPlacementCore cannot apply). Loosening it to admit a
// second concurrent operation invalidates that argument.
if (record.Key is not { } key
|| _operations.ContainsKey(key)
|| HasRetainedCompletion(key))
{
return default;
}
return BeginAcceptedPlacementCore(
record,
expectedPositionAuthorityVersion,
kind,
portal,
captureMoverPreparationAuthority: true);
}
internal void PrepareDormantLocalActivationOwnership(
RuntimeEntityRecord record,
PhysicsBody body,
in RuntimeEntityPlacementToken token)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
ArgumentNullException.ThrowIfNull(body);
// Round 3 audit: safe - fresh lookup + Token check earlier in this
// SAME guard clause precede IsCurrent, nothing reentrant in between.
if (!token.IsValid
|| record.Key != token.Entity
|| !_operations.TryGetValue(token.Entity, out Operation? operation)
|| operation.Token != token
|| operation.Stage is not RuntimeEntityPlacementStage
.AwaitingPreparation
|| !ReferenceEquals(operation.Record, record)
// B2 dependency (C4 route 4b-2): this `is not null` is what makes
// DormantLocalActivation and "the record has a body" mutually
// exclusive, which is the step
// RuntimeRemotePlacementDriveController's pre-engine-Rejected
// argument uses to dismiss the AwaitingCell stage divergence
// between PrepareMover and SubmitPreparedPlacementCore.
|| record.PhysicsBody is not null
|| !IsCurrent(operation)
|| body.InWorld
|| (body.TransientState & TransientStateFlags.Active) != 0)
{
throw new InvalidOperationException(
"Dormant local activation must bind to the exact current placement owner.");
}
operation.Body = body;
operation.DormantLocalActivation = true;
}
private RuntimeEntityPlacementToken BeginAcceptedPlacementCore(
RuntimeEntityRecord record,
ulong expectedPositionAuthorityVersion,
RuntimeSetPositionOperationKind kind,
RuntimePortalPlacementAuthority portal,
bool captureMoverPreparationAuthority)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
CreateObject.ServerPosition? acceptedPosition =
record.Snapshot.Physics?.Position ?? record.Snapshot.Position;
if (record.Key is not { } key
|| !_entities.IsCurrent(record)
|| HasRetainedCompletion(key)
|| record.PositionAuthorityVersion
!= expectedPositionAuthorityVersion
|| (captureMoverPreparationAuthority
&& acceptedPosition is null)
|| !(portal.IsEmpty
|| (portal.IsValid
&& kind is RuntimeSetPositionOperationKind
.LocalAuthoritative
&& acceptedPosition is { } portalPosition
&& portal.Projection.DestinationCell
== portalPosition.LandblockId)))
{
return default;
}
var token = new RuntimeEntityPlacementToken(
_entities.SessionLifetimeVersion,
key,
expectedPositionAuthorityVersion,
checked(++_nextOperationId),
captureMoverPreparationAuthority
? RuntimeEntityPlacementPreparationKind.AuthoredMover
: RuntimeEntityPlacementPreparationKind.LegacyDirect);
List<RuntimeEntityKey>? inheritedLostFamily = null;
RuntimePlacementProjectionSnapshot? inheritedWithdrawal = null;
bool inheritedWithdrawalAcknowledged = false;
// F3: captured into locals (rather than re-read from `displaced`
// after CancelCoreDeferred below) because `replacement` is
// deliberately rented AFTER that retire - see the no-self-aliasing
// note below and RetireOperationToPool's doc comment. Reading every
// scalar this method still needs before the retire point keeps this
// correct regardless of which physical instance `replacement` ends
// up being.
PhysicsSetPositionResult inheritedResult = default;
uint inheritedExactCellId = 0u;
ulong inheritedCollisionGeneration = 0UL;
if (_operations.TryGetValue(key, out Operation? displaced)
&& (displaced.WakeableLostCell
|| displaced.InheritedLostDeadline))
{
inheritedLostFamily = displaced.LostFamilyKeys;
displaced.LostFamilyKeys = null;
inheritedWithdrawalAcknowledged =
displaced.WithdrawalAcknowledged;
inheritedResult = displaced.Result;
inheritedExactCellId = displaced.ExactCellId;
inheritedCollisionGeneration = displaced.CollisionGeneration;
if (displaced.ProjectionSequence != 0UL
&& _pendingProjection.TryGetValue(
displaced.ProjectionSequence,
out RuntimePlacementProjectionSnapshot pendingWithdrawal)
&& pendingWithdrawal.Kind
is RuntimePlacementProjectionKind.Withdraw)
{
inheritedWithdrawal = pendingWithdrawal;
displaced.ProjectionSequence = 0UL;
}
}
_ = CancelCoreDeferred(
key,
cancelLostFamily: false,
preserveLostFamily: inheritedLostFamily is not null,
out RuntimePlacementProjectionSnapshot? discard);
// F3: rent only AFTER the retire above (not before, as the C2
// landing originally had it). Every field this method needs from a
// displaced operation was already captured into the locals above,
// so it is both SAFE and efficient for a single-entity churn cycle
// to hand that exact instance right back out here (the pool is
// LIFO) instead of allocating or drawing a different pooled
// instance - a fresh RentOperation() call always starts from
// `ResetAllFieldsToDefault`'s inert state regardless of which
// instance it returns.
Operation replacement = RentOperation();
replacement.Record = record;
replacement.Token = token;
replacement.Key = key;
replacement.PositionAuthorityVersion = expectedPositionAuthorityVersion;
replacement.SessionLifetimeVersion = _entities.SessionLifetimeVersion;
replacement.SourceSpatialAuthorityVersion =
record.SpatialAuthorityVersion;
replacement.SourceVelocityAuthorityVersion =
record.VelocityAuthorityVersion;
replacement.PreviousContact = record.PhysicsBody?.InContact ?? false;
replacement.PreviousOnWalkable =
record.PhysicsBody?.OnWalkable ?? false;
replacement.Command = default;
replacement.Result = default;
replacement.SpatialAuthorityVersion = record.SpatialAuthorityVersion;
replacement.PlacementCommitVersion = record.PlacementCommitVersion;
replacement.Stage = RuntimeEntityPlacementStage.AwaitingPreparation;
replacement.Kind = kind;
replacement.Portal = portal;
replacement.LostFamilyKeys = inheritedLostFamily;
replacement.InheritedLostDeadline = inheritedLostFamily is not null;
replacement.WithdrawalAcknowledged = inheritedWithdrawalAcknowledged;
if (inheritedWithdrawal is { } retainedWithdrawal)
{
replacement.ProjectionSequence =
retainedWithdrawal.Token.Sequence;
replacement.Result = inheritedResult;
replacement.ExactCellId = inheritedExactCellId;
replacement.CollisionGeneration = inheritedCollisionGeneration;
}
_operations[key] = replacement;
if (captureMoverPreparationAuthority)
{
_moverPreparationAuthorities[key] = CapturePreparationAuthority(
replacement,
acceptedPosition!.Value,
prepared: false);
}
if (discard is { } cancelled)
PublishPlacement(cancelled);
// F3: deliberately does NOT use `IsCurrent(replacement)` here.
// `PublishPlacement` above can synchronously notify a subscriber
// that reentrantly calls BeginAcceptedPlacement for the SAME entity
// (see ReentrantBeginDuringDiscardCannotBeOverwrittenByOuterBegin) -
// that reentrant call retires `replacement` and, per this method's
// rent-after-retire ordering, can rent it right back out (LIFO) for
// the INNER operation. `replacement` (the physical object) would
// then read as the inner operation's Key/Token, and comparing it
// against itself via `_operations.TryGetValue(replacement.Key, ...)
// && ReferenceEquals(current, replacement)` is a tautology - it
// would report "still current" even though THIS (outer) Begin
// invocation was clearly superseded. `token` was captured fresh at
// the top of this call, before any reentrancy could touch it, so
// comparing it against whatever now actually owns the key correctly
// answers "is my own invocation still canonical" regardless of
// what happened to `replacement` in between.
return _operations.TryGetValue(key, out Operation? currentOperation)
&& currentOperation.Token == token
? token
: default;
}
private bool HasRetainedCompletion(RuntimeEntityKey key)
{
foreach (RuntimeEntityPlacementToken token
in _acknowledgedPlacementCompletions.Keys)
{
if (token.Entity == key)
return true;
}
return false;
}
internal RuntimeSetPositionMoverPreparationStatus PrepareMover(
in RuntimeEntityPlacementToken token,
in RuntimeSetPositionMoverPreparation preparation,
out RuntimeSetPositionCommand command)
{
EnsureNotDisposed();
command = default;
// Round 3 audit: safe - fresh lookup + Token check earlier in this
// SAME guard clause precede IsCurrent, nothing reentrant in between.
//
// B2 dependency (C4 route 4b-2): this guard clause SHADOWS
// SubmitPreparedPlacementCore's entry validation one call later, and
// RuntimeRemotePlacementDriveController's far-snap default arm
// documents a pre-engine `Rejected` as unreachable BECAUSE of that
// shadowing - every term dropped from here re-surfaces there as a
// non-storing Rejected instead of a storing RejectedAuthority. The
// one term it deliberately does NOT shadow is the null-body test;
// that caller's own entry check covers it, and says so.
if (!token.IsValid
|| !_operations.TryGetValue(token.Entity, out Operation? operation)
|| operation.Token != token
|| operation.Stage is not (
RuntimeEntityPlacementStage.AwaitingPreparation
or RuntimeEntityPlacementStage.AwaitingCell)
|| operation.Stage is RuntimeEntityPlacementStage.AwaitingCell
&& (!operation.DormantLocalActivation
|| !operation.WakeableLostCell)
|| !IsCurrent(operation)
|| !_moverPreparationAuthorities.TryGetValue(
token.Entity,
out MoverPreparationAuthority authority)
|| authority.OperationId != token.OperationId
|| !IsPreparationAuthorityCurrent(operation, authority))
{
return RuntimeSetPositionMoverPreparationStatus.RejectedAuthority;
}
if (!preparation.Setup.IsResolved)
{
return Park(
operation,
RuntimeSetPositionMoverPreparationStatus
.RetrySetupUnavailable);
}
RuntimeSetPositionMoverPreparation effectivePreparation = preparation;
if (preparation.ResolveWorldOffsetFromRuntimeFrame)
{
// CreateObject/Position origins are local to their authored
// landblock. Resolve them through Runtime's accepted world frame,
// which is initialized by the local-player Create and advanced
// only by authoritative teleport transitions. This is available
// before streaming publishes the target collision generation, so
// remote admission cannot starve world loading while still using
// the exact same coordinate frame that generation will publish.
if (!_physics.TryGetWorldFrameOffset(
authority.AcceptedPosition.LandblockId,
out float worldOffsetX,
out float worldOffsetY))
{
// #284: the frame is published once, by the accepted
// local-player Create, and is never withdrawn inside a
// session. If that Create has already been observed, waiting
// is not a wait - no later pump can ever supply the frame, so
// parking here would retry forever in silence. Surface the
// contradiction instead, exactly as 01f4791e made a violated
// receipt-ledger invariant terminal rather than resumable.
_physics.ThrowIfWorldFrameUnreachable(
authority.AcceptedPosition.LandblockId);
return Park(
operation,
RuntimeSetPositionMoverPreparationStatus
.RetryWorldFrameUnavailable);
}
effectivePreparation = preparation with
{
ShadowWorldOffsetX = worldOffsetX,
ShadowWorldOffsetY = worldOffsetY,
};
}
if (!RuntimeSetPositionMoverPreparer.TryBuild(
operation.Record,
authority.AcceptedPosition,
authority.SetupTableId,
operation.Kind,
operation.Portal,
authority.VelocityAuthorityVersion,
effectivePreparation,
out command)
|| !IsStructurallyValid(command.Physics))
{
command = default;
return RuntimeSetPositionMoverPreparationStatus.InvalidData;
}
_moverPreparationAuthorities[token.Entity] = authority with
{
Prepared = true,
PreparedCommand = command,
};
operation.ParkReason = RuntimeSetPositionParkReason.None;
return RuntimeSetPositionMoverPreparationStatus.Prepared;
}
/// <summary>
/// #284: records why this operation could not be prepared, so parked work
/// is visible in <see cref="CaptureOwnership"/> by cause rather than only
/// as a downstream symptom. Retains the reason on the operation until the
/// preparation succeeds or the operation is retired.
/// </summary>
private static RuntimeSetPositionMoverPreparationStatus Park(
Operation operation,
RuntimeSetPositionMoverPreparationStatus status)
{
operation.ParkReason = status.ParkReason();
return status;
}
/// <summary>
/// C0-3: chains the exact-Setup mover pipeline end-to-end for an
/// authored placement (initial-Create or any other authored-mover
/// operation) whose route performs SetPosition - PrepareMover /
/// RuntimeSetPositionMoverPreparer.TryBuild /
/// IPreparedCollisionSource.ReadSetupCollision already exist piecewise
/// (inventory gap a); this is the missing wiring, not a behavior change.
/// Reads the CANONICAL Setup table id from the record via
/// <see cref="CanonicalSetupTableId"/> - the SAME field
/// <see cref="CapturePreparationAuthority"/> already trusts - rather than
/// a caller-supplied id, so this can never be pointed at the wrong
/// Setup. A record with no authored Setup at all (id 0) takes retail's
/// genuine "no Setup" dummy-sphere path
/// (<see cref="RuntimeSetPositionMoverSetup.ResolvedAbsent"/>) instead of
/// reading anything; a record WITH an id but an unavailable/corrupt
/// asynchronous read yields <see cref="RuntimeSetPositionMoverPreparationStatus.RetrySetupUnavailable"/>
/// so the caller retries once the prepared-collision package lands,
/// mirroring <see cref="RuntimeSetPositionMoverSetup"/>'s own
/// doc-comment distinction between "not arrived yet" and "resolved
/// absent". Dormant: internal, no production caller - a residence
/// lease's own <c>Placement</c>/<c>Route.OperationKind</c>/
/// <c>Route.SetPositionFlags</c> are exactly the token/kind/flags this
/// takes.
/// </summary>
internal RuntimeSetPositionMoverPreparationStatus
TryPrepareAndSubmitAuthoredPlacement(
RuntimeEntityRecord record,
in RuntimeEntityPlacementToken token,
RuntimeSetPositionOperationKind operationKind,
PhysicsSetPositionFlags flags,
IPreparedCollisionSource collisionSource,
double gameTime,
out RuntimeSetPositionOutcome outcome,
PhysicsPlacementClass placementClass = PhysicsPlacementClass.Ordinary,
RuntimePortalPlacementAuthority portal = default,
Vector3 line = default,
float scatterRadiusX = 0f,
float scatterRadiusY = 0f,
uint scatterAttempts = 0u,
float shadowWorldOffsetX = 0f,
float shadowWorldOffsetY = 0f,
bool resolveWorldOffsetFromRuntimeFrame = false)
{
outcome = default;
RuntimeSetPositionMoverPreparationStatus status =
TryPrepareAuthoredMover(
record,
token,
operationKind,
flags,
collisionSource,
gameTime,
out RuntimeSetPositionCommand command,
placementClass,
portal,
line,
scatterRadiusX,
scatterRadiusY,
scatterAttempts,
shadowWorldOffsetX,
shadowWorldOffsetY,
resolveWorldOffsetFromRuntimeFrame);
if (status != RuntimeSetPositionMoverPreparationStatus.Prepared)
return status;
outcome = SubmitPreparedPlacement(token, command);
return RuntimeSetPositionMoverPreparationStatus.Prepared;
}
/// <summary>
/// C3a: the exact-Setup-read + <see cref="PrepareMover"/> half of
/// <see cref="TryPrepareAndSubmitAuthoredPlacement"/>, extracted (pure
/// refactor, byte-identical behavior for the existing caller above) so
/// the dormant local-player first-entry conductor
/// (<c>AcDream.Runtime.Gameplay.RuntimeLocalPlayerFirstEntryState</c>)
/// can obtain a prepared <see cref="RuntimeSetPositionCommand"/> WITHOUT
/// the trailing <see cref="SubmitPreparedPlacement"/> call. Submission
/// through the ordinary tail is exactly what an operation with
/// <c>DormantLocalActivation</c> set must never receive — see
/// <see cref="RetryDeferred"/>'s "must never bypass that path through the
/// ordinary remote CommitCanonical tail" comment; the dormant chain's own
/// Evaluate/Commit/FinalizeActivation methods are the sole substitute for
/// submission on that path.
/// </summary>
internal RuntimeSetPositionMoverPreparationStatus TryPrepareAuthoredMover(
RuntimeEntityRecord record,
in RuntimeEntityPlacementToken token,
RuntimeSetPositionOperationKind operationKind,
PhysicsSetPositionFlags flags,
IPreparedCollisionSource collisionSource,
double gameTime,
out RuntimeSetPositionCommand command,
PhysicsPlacementClass placementClass = PhysicsPlacementClass.Ordinary,
RuntimePortalPlacementAuthority portal = default,
Vector3 line = default,
float scatterRadiusX = 0f,
float scatterRadiusY = 0f,
uint scatterAttempts = 0u,
float shadowWorldOffsetX = 0f,
float shadowWorldOffsetY = 0f,
bool resolveWorldOffsetFromRuntimeFrame = false)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
ArgumentNullException.ThrowIfNull(collisionSource);
command = default;
uint setupTableId = CanonicalSetupTableId(record);
RuntimeSetPositionMoverSetup setup;
if (setupTableId == 0u)
{
setup = RuntimeSetPositionMoverSetup.ResolvedAbsent;
}
else
{
PreparedCollisionReadResult<FlatSetupCollision> read =
collisionSource.ReadSetupCollision(setupTableId);
if (read.Status != PreparedAssetReadStatus.Loaded
|| read.Data is null)
{
return RuntimeSetPositionMoverPreparationStatus
.RetrySetupUnavailable;
}
setup = RuntimeSetPositionMoverSetup.Resolved(
setupTableId, read.Data);
}
var preparation = new RuntimeSetPositionMoverPreparation(
setup,
operationKind,
gameTime,
placementClass,
flags,
line,
scatterRadiusX,
scatterRadiusY,
scatterAttempts,
shadowWorldOffsetX,
shadowWorldOffsetY,
portal,
resolveWorldOffsetFromRuntimeFrame);
return PrepareMover(token, preparation, out command);
}
internal bool IsExactPreparedPlacementCurrent(
RuntimeEntityRecord record,
in RuntimeEntityPlacementToken token,
in RuntimeSetPositionCommand command)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
// Round 3 audit: safe - fresh lookup + Token check earlier in this
// SAME return expression precede IsCurrent, nothing reentrant in
// between.
return token.IsValid
&& token.Entity == record.Key
&& _operations.TryGetValue(token.Entity, out Operation? operation)
&& ReferenceEquals(operation.Record, record)
&& operation.Token == token
&& operation.Stage
is RuntimeEntityPlacementStage.AwaitingPreparation
&& IsCurrent(operation)
&& _moverPreparationAuthorities.TryGetValue(
token.Entity,
out MoverPreparationAuthority authority)
&& authority.OperationId == token.OperationId
&& authority.Prepared
&& authority.PreparedCommand == command
&& IsPreparationAuthorityCurrent(operation, authority);
}
/// <summary>
/// Evaluates the exact authored local-player placement without mutating
/// the canonical dormant body or any Runtime ownership index. Core's
/// SetPosition transaction is pure; collision reporting is deliberately
/// omitted until the later atomic activation commit.
/// </summary>
internal bool TryEvaluateDormantLocalActivation(
RuntimeEntityRecord record,
PhysicsBody body,
in RuntimeEntityPlacementToken token,
in RuntimeSetPositionCommand command,
out RuntimeDormantSetPositionEvaluation evaluation)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
ArgumentNullException.ThrowIfNull(body);
evaluation = default;
if (!IsExactDormantLocalActivationCurrent(
record,
body,
token,
command,
out _)
&& !TryRearmDeferredDormantLocalActivation(
record,
body,
token,
command))
{
return false;
}
if (!IsExactDormantLocalActivationCurrent(
record,
body,
token,
command,
out Operation? operation))
{
return false;
}
PhysicsSetPositionRequest canonicalRequest = command.Physics with
{
MoverPhysicsState = record.FinalPhysicsState,
MovingEntityId = token.Entity.LocalEntityId,
CurrentCellId = null,
};
if (!IsStructurallyValid(canonicalRequest))
return false;
var canonicalCommand = command with { Physics = canonicalRequest };
ulong collisionWorldAuthority = _physics.CollisionWorldAuthority;
ulong shadowWorldAuthority = _physics.ShadowWorldAuthority;
ClientObjectTable? objectTable = _physics.ObjectTable;
ulong objectTableBindingAuthority =
_physics.ObjectTableBindingAuthority;
ulong objectTableAuthority = objectTable?.MutationRevision ?? 0UL;
// Round 3 audit: safe - `handleCollisions: null` means this call
// never invokes HandleSetPositionCollisions/HandleReports/
// ReportEnvironment (no collision-report observer can be reached),
// and this dormant-activation path never calls CommitCanonical (so
// no ground-edge HitGround/LeaveGround dispatch either) - there is
// no reentrancy point between `operation` being obtained above and
// the ReferenceEquals check below.
PhysicsSetPositionResult result = _physics.Engine.SetPosition(
canonicalRequest,
handleCollisions: null);
if (!IsExactDormantLocalActivationCurrent(
record,
body,
token,
command,
out Operation? current)
|| !ReferenceEquals(current, operation))
{
return false;
}
if (!_physics.TrySealCollisionEvaluationAuthority(
result,
collisionWorldAuthority,
shadowWorldAuthority,
objectTable,
objectTableBindingAuthority,
objectTableAuthority,
out RuntimeCollisionEvaluationAuthority collisionAuthority))
{
return false;
}
evaluation = new RuntimeDormantSetPositionEvaluation(
token,
canonicalCommand,
result,
collisionAuthority);
return true;
}
internal bool IsDormantLocalEvaluationCurrent(
RuntimeEntityRecord record,
PhysicsBody body,
in RuntimeDormantSetPositionEvaluation evaluation) =>
evaluation.IsValid
&& IsExactDormantLocalActivationCurrent(
record,
body,
evaluation.Placement,
evaluation.Command,
out _,
allowCanonicalCommand: true)
&& _physics.IsCollisionEvaluationAuthorityCurrent(
evaluation.CollisionAuthority);
internal bool IsDormantLocalActivationLeaseCurrent(
RuntimeEntityRecord record,
PhysicsBody body,
in RuntimeEntityPlacementToken token,
in RuntimeSetPositionCommand command) =>
IsExactDormantLocalActivationCurrent(
record,
body,
token,
command,
out _,
allowDeferredLease: true);
internal bool IsDormantLocalActivationAwaitingCell(
RuntimeEntityRecord record,
PhysicsBody body,
in RuntimeEntityPlacementToken token,
in RuntimeSetPositionCommand command)
{
return IsExactDormantLocalActivationCurrent(
record,
body,
token,
command,
out Operation? operation,
allowDeferredLease: true)
&& operation is not null
&& operation.Stage is RuntimeEntityPlacementStage.AwaitingCell
&& operation.DormantLocalActivation
&& operation.WakeableLostCell;
}
/// <summary>
/// C3c-F2: the identity check below is against
/// <see cref="RuntimePhysicsState.CollisionGenerationAuthority"/> — the
/// generation the collision world currently HOLDS — not against
/// <c>ExpectedCollisionGeneration</c>, which means two different things
/// at the two ends of this wait. At park time (this class's own
/// <c>TryPrepareDormantLocalActivationCommit</c>) an admission for the
/// destination landblock is in flight, so Expected == that admission's
/// generation G and the lease correctly parks against G. The wake that
/// sets <c>CollisionGenerationReady</c> is
/// <c>CommitCollisionGeneration(lb, G, ready)</c>, and the very next
/// statement in RuntimePhysicsState retires the admission
/// (AdvanceCommittedActivation) while leaving the committed generation at
/// G — from that instant Expected returns G+1, a generation that does not
/// exist and may never be begun. Comparing the parked G against Expected
/// therefore refused every login rearm forever (the connected-gate
/// DeferredCell wedge: controller never published, world never visible).
/// The committed-authority comparison keeps every staleness guarantee: a
/// superseding BeginCollisionAdmission or a CancelCollisionGeneration
/// moves the authority off G and this lease still refuses to rearm.
///
/// <para>
/// The trailing
/// <see cref="RuntimePhysicsState.IsCollisionEvaluationPrefixAdmissible"/>
/// term is the second half of the same C3c-F2 defect and is what the live
/// probe caught: the collision-generation commit reenters the host's
/// first-entry pump BEFORE its own admission is retired
/// (RuntimePhysicsState.cs:2503 commits the generation, :2552-2558 retires
/// the admission). Rearming inside that window moves the lease out of
/// AwaitingCell and the very next evaluation fails
/// <c>TrySealCollisionEvaluationAuthority</c> on the still-registered
/// admission — at which point EvaluateActivation can no longer report
/// DeferredCell (the operation is no longer AwaitingCell) and returns
/// RejectedAuthority, which is TERMINAL for the conductor. Refusing the
/// rearm until the prefix is evaluable keeps the lease parked and
/// retryable, exactly as the remote wake path already does with
/// <c>TryGetBlockingQuiescence</c> (:4069-4095).
/// </para>
/// </summary>
private bool TryRearmDeferredDormantLocalActivation(
RuntimeEntityRecord record,
PhysicsBody body,
in RuntimeEntityPlacementToken token,
in RuntimeSetPositionCommand command)
{
if (!IsExactDormantLocalActivationCurrent(
record,
body,
token,
command,
out Operation? operation,
allowDeferredLease: true)
|| operation is null
|| operation.Stage is not RuntimeEntityPlacementStage.AwaitingCell
|| !operation.DormantLocalActivation
|| !operation.WakeableLostCell
|| !operation.CollisionGenerationReady
|| operation.ProjectionSequence != 0UL
|| operation.CollisionGeneration != _physics
.CollisionGenerationAuthority(operation.ExactCellId)
|| !_physics.Engine.IsSpawnCellReady(operation.ExactCellId)
|| !_physics.IsCollisionEvaluationPrefixAdmissible(
operation.ExactCellId))
{
return false;
}
UnindexDeferred(operation);
operation.WakeableLostCell = false;
operation.CollisionGenerationReady = false;
operation.Stage = RuntimeEntityPlacementStage.AwaitingPreparation;
return true;
}
internal bool TryPrepareDormantLocalActivationCommit(
RuntimeEntityRecord record,
PhysicsBody body,
in RuntimeDormantSetPositionEvaluation evaluation,
bool provenShapeless,
out PreparedDormantSetPositionCommit? prepared)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
ArgumentNullException.ThrowIfNull(body);
prepared = null;
if (!IsDormantLocalEvaluationCurrent(record, body, evaluation)
|| !IsExactDormantLocalActivationCurrent(
record,
body,
evaluation.Placement,
evaluation.Command,
out Operation? operation,
allowCanonicalCommand: true)
|| operation is null)
{
return false;
}
PhysicsSetPositionResult result = evaluation.Result;
ShadowObjectRegistry.PreparedSetPositionShadowCommit? shadow = null;
RuntimeCollisionReportingState.PreparedSetPositionCollisionBatch?
collision = null;
RuntimePlacementProjectionSnapshot projection = default;
SortedDictionary<ulong, RuntimePlacementProjectionSnapshot>?
pendingProjection = null;
ulong deferredCollisionGeneration = 0UL;
List<RuntimeEntityKey>? deferredBucket = null;
bool deferredBucketIsNew = false;
if (!result.IsDeferred)
{
if (!_physics.CollisionReports.TryPrepareSetPositionBatch(
record,
body,
evaluation.Command.GameTime,
result.IsCommitted && operation.PreviousContact,
result.IsCommitted && operation.PreviousOnWalkable,
result.IsCommitted && result.OnWalkable,
result.CollidedWithEnvironment,
result.CollidedObjectIds,
out collision)
|| collision is null)
{
return false;
}
}
if (result.IsDeferred)
{
deferredCollisionGeneration = _physics
.ExpectedCollisionGeneration(result.CellId);
_preparedMovers.EnsureCapacity(_preparedMovers.Count + 1);
if (result.CellId != 0u && deferredCollisionGeneration != 0UL)
{
var bucketKey = new CellGenerationKey(
result.CellId,
result.CellId & 0xFFFF0000u,
deferredCollisionGeneration);
if (_deferredByCellGeneration.TryGetValue(
bucketKey,
out deferredBucket))
{
deferredBucket.EnsureCapacity(deferredBucket.Count + 1);
}
else
{
deferredBucket = [operation.Key];
deferredBucketIsNew = true;
_deferredByCellGeneration.EnsureCapacity(
_deferredByCellGeneration.Count + 1);
_deferredBucketOrder.EnsureCapacity(
_deferredBucketOrder.Count + 1);
}
}
if (!_physics.Engine.ShadowObjects.TryPrepareSetPosition(
operation.Key.LocalEntityId,
result.Position,
result.Orientation,
result.CellId,
evaluation.Command.ShadowWorldOffsetX,
evaluation.Command.ShadowWorldOffsetY,
PhysicsShadowCommitAction.Preserve,
ImmutableArray<uint>.Empty,
provenShapeless,
suspendOwner: true,
out shadow)
|| shadow is null)
{
return false;
}
}
ulong expectedProjectionSequence = _nextProjectionSequence;
if (result.IsCommitted)
{
_ = checked(record.ObjectClockEpoch + 1UL);
_ = checked(record.PlacementCommitVersion + 1UL);
if (record.FullCellId != result.CellId)
_ = checked(record.SpatialAuthorityVersion + 1UL);
if (!_physics.TryPrepareSpatialRootAdmission(record))
return false;
ulong sequence = checked(expectedProjectionSequence + 1UL);
ulong spatial = record.SpatialAuthorityVersion
+ (record.FullCellId == result.CellId ? 0UL : 1UL);
ulong placement = checked(record.PlacementCommitVersion + 1UL);
var token = new RuntimePlacementProjectionToken(
sequence,
Revision: 1UL,
operation.Key,
operation.PositionAuthorityVersion,
spatial,
placement,
operation.SessionLifetimeVersion,
result.CellId,
operation.CollisionGeneration,
evaluation.Command.Portal);
projection = new RuntimePlacementProjectionSnapshot(
token,
RuntimePlacementProjectionKind.Place,
result.Position,
result.Orientation,
result.CellLocalPosition,
result.InContact,
result.OnWalkable);
pendingProjection = new SortedDictionary<
ulong,
RuntimePlacementProjectionSnapshot>(_pendingProjection)
{
[sequence] = projection,
};
}
prepared = new PreparedDormantSetPositionCommit
{
Evaluation = evaluation,
Entity = operation.Key,
OperationId = operation.Token.OperationId,
ExpectedProjectionSequence = expectedProjectionSequence,
Shadow = shadow,
Collision = collision,
Projection = projection,
PendingProjection = pendingProjection,
DeferredCollisionGeneration = deferredCollisionGeneration,
DeferredBucket = deferredBucket,
DeferredBucketIsNew = deferredBucketIsNew,
};
return IsPreparedDormantCommitCurrent(record, body, prepared);
}
internal bool TryApplyDormantLocalActivationCommit(
RuntimeEntityRecord record,
PhysicsBody body,
PlayerMovementController controller,
EntityPhysicsHost physicsHost,
PreparedDormantSetPositionCommit prepared,
out RuntimeDormantSetPositionCommitReceipt receipt)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
ArgumentNullException.ThrowIfNull(body);
ArgumentNullException.ThrowIfNull(controller);
ArgumentNullException.ThrowIfNull(physicsHost);
ArgumentNullException.ThrowIfNull(prepared);
receipt = default;
if (!IsPreparedDormantCommitCurrent(record, body, prepared)
|| !_operations.TryGetValue(
prepared.Entity,
out Operation? operation))
{
return false;
}
PhysicsSetPositionResult result = prepared.Evaluation.Result;
operation.Body = body;
operation.DormantLocalActivation = true;
if (result.IsDeferred)
{
if (prepared.Shadow is null
|| !_physics.Engine.ShadowObjects.TryApplySetPosition(
prepared.Shadow,
out ShadowObjectRegistry.SetPositionShadowCommitReceipt
deferredShadowReceipt))
{
return false;
}
body.Orientation = result.Orientation;
body.StageDormantCellFrame(
result.CellId,
result.Position,
result.CellLocalPosition);
body.InWorld = false;
body.TransientState &= ~TransientStateFlags.Active;
operation.Result = result;
operation.ExactCellId = result.CellId;
operation.WakeableLostCell = true;
operation.CollisionGeneration = prepared
.DeferredCollisionGeneration;
operation.CollisionPrefix = result.CellId & 0xFFFF0000u;
operation.CollisionGenerationReady = false;
operation.Stage = RuntimeEntityPlacementStage.AwaitingCell;
_preparedMovers[operation.Key] = prepared.Evaluation.Command.Physics;
if (prepared.DeferredBucket is { } deferredBucket)
{
var bucketKey = new CellGenerationKey(
result.CellId,
operation.CollisionPrefix,
prepared.DeferredCollisionGeneration);
if (prepared.DeferredBucketIsNew)
{
_deferredByCellGeneration.Add(bucketKey, deferredBucket);
_deferredBucketOrder.Add(bucketKey);
}
else if (!deferredBucket.Contains(operation.Key))
{
deferredBucket.Add(operation.Key);
}
}
receipt = new RuntimeDormantSetPositionCommitReceipt(
RuntimeDormantSetPositionCommitStatus.DeferredCell,
operation.Key,
operation.Token.OperationId,
default,
default,
deferredShadowReceipt,
prepared.Evaluation.CollisionAuthority,
operation.Record.VectorAuthorityVersion,
HitGround: false,
LeaveGround: false);
return true;
}
if (prepared.Collision is null
|| !_physics.CollisionReports.TryInstallSetPositionBatch(
prepared.Collision,
out RuntimeCollisionReportingState
.SetPositionCollisionBatchReceipt collisionReceipt))
{
return false;
}
if (!result.IsCommitted)
{
operation.Result = result;
receipt = new RuntimeDormantSetPositionCommitReceipt(
RuntimeDormantSetPositionCommitStatus.RejectedPlacement,
operation.Key,
operation.Token.OperationId,
default,
collisionReceipt,
default,
prepared.Evaluation.CollisionAuthority,
operation.Record.VectorAuthorityVersion,
HitGround: false,
LeaveGround: false);
return true;
}
bool previousOnWalkable = operation.PreviousOnWalkable;
bool hitGround = !previousOnWalkable
&& result.InContact
&& result.OnWalkable;
bool leaveGround = previousOnWalkable
&& !(result.InContact && result.OnWalkable);
UnindexDeferred(operation);
body.Orientation = result.Orientation;
body.StageDormantCellFrame(
result.CellId,
result.Position,
result.CellLocalPosition);
body.LastUpdateTime = prepared.Evaluation.Command.GameTime;
body.ContactPlaneValid = result.InContact;
body.ContactPlane = result.ContactPlane;
body.ContactPlaneCellId = result.ContactPlaneCellId;
body.ContactPlaneIsWater = result.ContactPlaneIsWater;
if (result.InContact)
body.GroundNormal = result.ContactPlane.Normal;
_ = PhysicsObjUpdate.CommitSetPositionContactPrefix(
body,
result.InContact,
result.OnWalkable,
previousOnWalkable);
operation.Result = result;
operation.ExactCellId = result.CellId;
operation.WakeableLostCell = false;
operation.CollisionGenerationReady = false;
operation.EnteringWorldFromCelllessResidence = false;
operation.Stage = RuntimeEntityPlacementStage
.AwaitingFinalShadowPreparation;
receipt = new RuntimeDormantSetPositionCommitReceipt(
RuntimeDormantSetPositionCommitStatus
.AwaitingFinalShadowPreparation,
operation.Key,
operation.Token.OperationId,
prepared.Projection,
collisionReceipt,
default,
prepared.Evaluation.CollisionAuthority,
operation.Record.VectorAuthorityVersion,
hitGround,
leaveGround);
return true;
}
internal SetPositionCollisionBatchDispatchResult
DispatchDormantLocalActivationCollision(
in RuntimeDormantSetPositionCommitReceipt receipt)
{
if (receipt.Status
is RuntimeDormantSetPositionCommitStatus.DeferredCell
or RuntimeDormantSetPositionCommitStatus.RejectedAuthority)
{
return new(
SetPositionCollisionBatchDispatchStatus.RejectedReceipt,
Reported: false);
}
SetPositionCollisionBatchDispatchResult dispatch = _physics
.CollisionReports.DispatchSetPositionBatchResult(receipt.Collision);
bool reported = dispatch.Reported;
// Round 3 audit: safe - fresh lookup + Token.OperationId check
// earlier in this SAME guard clause precede IsCurrent, nothing
// reentrant in between. This dormant-activation family has zero
// production callers and never routes through CommitCanonical's
// ground-edge callback or the live collision-report dispatch that
// can reach an arbitrary observer.
if (receipt.Status
is RuntimeDormantSetPositionCommitStatus.RejectedPlacement
&& _operations.TryGetValue(receipt.Entity, out Operation? operation)
&& operation.Token.OperationId == receipt.OperationId
&& IsCurrent(operation)
&& !operation.Result.IsCommitted
&& !operation.Result.IsDeferred)
{
operation.Result = operation.Result with
{
Error = reported
? PhysicsSetPositionError.Collided
: PhysicsSetPositionError.NoValidPosition,
CollisionHandlerResult = reported,
};
}
return dispatch;
}
internal bool IsDormantLocalActivationPrephaseCurrent(
RuntimeEntityRecord record,
PhysicsBody body,
in RuntimeDormantSetPositionCommitReceipt receipt)
{
// Round 3 audit: safe - fresh lookup + Token.OperationId check
// earlier in this SAME return expression precede IsCurrent, nothing
// reentrant in between; this dormant family has zero production
// callers.
return receipt.Status is RuntimeDormantSetPositionCommitStatus
.AwaitingFinalShadowPreparation
&& _operations.TryGetValue(receipt.Entity, out Operation? operation)
&& operation.Token.OperationId == receipt.OperationId
&& operation.Stage is RuntimeEntityPlacementStage
.AwaitingFinalShadowPreparation
&& operation.DormantLocalActivation
&& IsCurrent(operation)
&& ReferenceEquals(operation.Record, record)
&& ReferenceEquals(record.PhysicsBody, body)
&& !body.InWorld
&& (body.TransientState & TransientStateFlags.Active) == 0
&& record.PhysicsHost is null
&& record.RemoteMotion is null
&& record.Projectile is null
&& !_physics.IsSpatialRoot(record)
&& _moverPreparationAuthorities.TryGetValue(
receipt.Entity,
out MoverPreparationAuthority authority)
&& authority.OperationId == receipt.OperationId
&& authority.Prepared
&& record.PositionAuthorityVersion
== authority.PositionAuthorityVersion
&& record.ObjDescAuthorityVersion
== authority.ObjDescAuthorityVersion
&& record.CreateIntegrationVersion
== authority.CreateIntegrationVersion
&& CanonicalSetupTableId(record) == authority.SetupTableId;
}
internal bool IsDormantLocalActivationResponseCurrent(
RuntimeEntityRecord record,
PhysicsBody body,
in RuntimeDormantSetPositionCommitReceipt receipt)
{
if (receipt.Status is RuntimeDormantSetPositionCommitStatus
.AwaitingFinalShadowPreparation)
return IsDormantLocalActivationPrephaseCurrent(record, body, receipt);
// Round 3 audit: safe - fresh lookup + Token.OperationId check
// earlier in this SAME return expression precede IsCurrent, nothing
// reentrant in between; this dormant family has zero production
// callers.
return receipt.Status is RuntimeDormantSetPositionCommitStatus
.RejectedPlacement
&& _operations.TryGetValue(receipt.Entity, out Operation? operation)
&& operation.Token.OperationId == receipt.OperationId
&& operation.DormantLocalActivation
&& IsCurrent(operation)
&& ReferenceEquals(operation.Record, record)
&& ReferenceEquals(record.PhysicsBody, body)
&& !operation.Result.IsCommitted
&& !operation.Result.IsDeferred
&& !body.InWorld
&& (body.TransientState & TransientStateFlags.Active) == 0
&& record.PhysicsHost is null
&& record.RemoteMotion is null
&& record.Projectile is null
&& !_physics.IsSpatialRoot(record);
}
internal bool CommitDormantLocalActivationPostGround(
RuntimeEntityRecord record,
PhysicsBody body,
in RuntimeDormantSetPositionCommitReceipt receipt)
{
if (!IsDormantLocalActivationPrephaseCurrent(record, body, receipt))
return false;
PhysicsObjUpdate.CommitSetPositionPostGround(body);
PhysicsSetPositionResult result = _operations[receipt.Entity].Result;
body.SlidingNormal = result.SlidingNormal;
if (result.SlidingNormalValid)
body.TransientState |= TransientStateFlags.Sliding;
else
body.TransientState &= ~TransientStateFlags.Sliding;
return IsDormantLocalActivationPrephaseCurrent(record, body, receipt);
}
internal bool CommitDormantLocalActivationPostCollision(
RuntimeEntityRecord record,
PhysicsBody body,
in RuntimeDormantSetPositionCommitReceipt receipt)
{
// Round 3 audit: safe - fresh lookup + Token.OperationId check
// immediately precede IsCurrent, nothing reentrant in between; this
// dormant family has zero production callers. Nothing between here
// and the final `IsCurrent(operation)` below invokes anything
// reentrant either (IsVelocityCurrent/HandleAllCollisions/
// CommitStationaryBits are pure PhysicsObjUpdate calls on `body`,
// and the nested IsDormantLocalActivationPrephaseCurrent call is
// itself a fresh-lookup check), so the SAME verified `operation`
// reference remains valid through the final check.
if (!_operations.TryGetValue(receipt.Entity, out Operation? operation)
|| operation.Token.OperationId != receipt.OperationId
|| !IsCurrent(operation)
|| !ReferenceEquals(operation.Record, record)
|| !ReferenceEquals(record.PhysicsBody, body))
{
return false;
}
if (receipt.Status is RuntimeDormantSetPositionCommitStatus
.AwaitingFinalShadowPreparation
&& !IsDormantLocalActivationPrephaseCurrent(record, body, receipt))
{
return false;
}
PhysicsSetPositionResult result = operation.Result;
body.FramesStationaryFall = result.FramesStationaryFall;
if (IsVelocityCurrent(operation))
{
PhysicsObjUpdate.HandleAllCollisions(
body,
result.CollisionNormalValid,
result.CollisionNormal,
operation.PreviousContact,
operation.PreviousOnWalkable,
body.OnWalkable);
}
CommitStationaryBits(body, result.FramesStationaryFall);
return IsCurrent(operation);
}
internal bool TryPrepareDormantLocalActivationFinalCommit(
RuntimeEntityRecord record,
PhysicsBody body,
in RuntimeDormantSetPositionCommitReceipt receipt,
bool provenShapeless,
out PreparedDormantActivationFinalCommit? prepared)
{
prepared = null;
if (!IsDormantLocalActivationPrephaseCurrent(record, body, receipt)
|| !_operations.TryGetValue(receipt.Entity, out Operation? operation))
{
return false;
}
PhysicsSetPositionResult result = operation.Result;
if (!_physics.Engine.ShadowObjects.TryPrepareSetPosition(
operation.Key.LocalEntityId,
result.Position,
result.Orientation,
result.CellId,
operation.Command.ShadowWorldOffsetX,
operation.Command.ShadowWorldOffsetY,
result.ShadowAction,
result.CrossCellIds,
provenShapeless,
suspendOwner: false,
out ShadowObjectRegistry.PreparedSetPositionShadowCommit? shadow)
|| shadow is null
|| _nextProjectionSequence + 1UL
!= receipt.Projection.Token.Sequence)
{
return false;
}
var pending = new SortedDictionary<
ulong,
RuntimePlacementProjectionSnapshot>(_pendingProjection)
{
[receipt.Projection.Token.Sequence] = receipt.Projection,
};
prepared = new PreparedDormantActivationFinalCommit
{
Entity = receipt.Entity,
OperationId = receipt.OperationId,
ExpectedProjectionSequence = _nextProjectionSequence,
Shadow = shadow,
Projection = receipt.Projection,
PendingProjection = pending,
};
bool current = IsDormantLocalActivationPrephaseCurrent(
record, body, receipt);
bool shadowCurrent = _physics.Engine.ShadowObjects
.IsPreparedSetPositionCurrent(shadow);
return current && shadowCurrent;
}
internal bool TryApplyDormantLocalActivationFinalCommit(
RuntimeEntityRecord record,
PhysicsBody body,
PlayerMovementController controller,
EntityPhysicsHost physicsHost,
in RuntimeDormantSetPositionCommitReceipt prephase,
PreparedDormantActivationFinalCommit prepared,
out RuntimeDormantSetPositionCommitReceipt committed)
{
committed = default;
if (prepared.Entity != prephase.Entity
|| prepared.OperationId != prephase.OperationId
|| prepared.ExpectedProjectionSequence != _nextProjectionSequence
|| prepared.Projection != prephase.Projection
|| !IsDormantLocalActivationPrephaseCurrent(record, body, prephase)
|| !_physics.Engine.ShadowObjects.TryApplySetPosition(
prepared.Shadow,
out ShadowObjectRegistry.SetPositionShadowCommitReceipt shadow))
{
return false;
}
Operation operation = _operations[prephase.Entity];
PhysicsSetPositionResult result = operation.Result;
if (record.FullCellId != result.CellId)
{
_entities.SetFullCell(record, result.CellId,
(result.CellId & 0xFFFF0000u) | 0xFFFFu);
}
operation.SpatialAuthorityVersion = record.SpatialAuthorityVersion;
_entities.AdvancePlacementCommit(record);
operation.PlacementCommitVersion = record.PlacementCommitVersion;
body.InWorld = true;
bool isStatic = (record.FinalPhysicsState & PhysicsStateFlags.Static) != 0;
if (!isStatic)
body.TransientState |= TransientStateFlags.Active;
_entities.SetPhysicsHost(record, physicsHost);
controller.CommitRuntimeActivationFrame();
_physics.Engine.UpdatePlayerCurrCell(result.CellId);
_physics.AcknowledgeSpatialProjection(record, spatial: true);
_entities.ResetObjectClockForEnterWorld(record, isStatic);
operation.Stage = RuntimeEntityPlacementStage.AwaitingCommitAcknowledgement;
operation.ProjectionSequence = prepared.Projection.Token.Sequence;
_pendingProjection = prepared.PendingProjection;
_nextProjectionSequence = prepared.Projection.Token.Sequence;
CancelLostFamilyDeadlines(operation);
controller.ActivateRuntimePublication();
committed = prephase with
{
Status = RuntimeDormantSetPositionCommitStatus.Committed,
Shadow = shadow,
};
return true;
}
internal void DispatchDormantLocalActivationShadow(
in RuntimeDormantSetPositionCommitReceipt receipt)
{
if (receipt.Status is not (
RuntimeDormantSetPositionCommitStatus.Committed
or RuntimeDormantSetPositionCommitStatus.DeferredCell))
return;
_physics.Engine.ShadowObjects.DispatchSetPositionCommit(receipt.Shadow);
}
internal void DispatchDormantLocalActivationPlacement(
in RuntimeDormantSetPositionCommitReceipt receipt)
{
if (!receipt.IsCommitted)
return;
PublishPlacement(receipt.Projection);
}
internal void DiscardDormantLocalActivationDispatches(
in RuntimeDormantSetPositionCommitReceipt receipt,
bool collisionAlreadyDispatched)
{
if (!collisionAlreadyDispatched)
_physics.CollisionReports.DiscardSetPositionBatch(receipt.Collision);
_physics.Engine.ShadowObjects.DiscardSetPositionCommit(receipt.Shadow);
}
internal void RetireDormantLocalActivation(
in RuntimeDormantSetPositionCommitReceipt receipt,
bool collisionAlreadyDispatched)
{
DiscardDormantLocalActivationDispatches(
receipt,
collisionAlreadyDispatched);
_physics.CollisionReports.RetireSetPositionBatchOwner(
receipt.Collision);
if (_operations.TryGetValue(receipt.Entity, out Operation? operation)
&& operation.Token.OperationId == receipt.OperationId)
{
// Round 3: `operation.Token` is read from the fresh lookup
// immediately above, with nothing reentrant in between - safe
// to pass straight through as the captured token.
_ = CancelCore(receipt.Entity, operation.Token);
}
}
internal void RetireDormantLocalActivationToken(
RuntimeEntityRecord record,
in RuntimeEntityPlacementToken token)
{
if (!token.IsValid
|| record.Key != token.Entity
|| !_operations.TryGetValue(token.Entity, out Operation? operation)
|| operation.Token != token
|| !ReferenceEquals(operation.Record, record))
{
return;
}
// Round 3: `token` is this call's own parameter, verified fresh
// against `_operations` immediately above with nothing reentrant in
// between.
_ = CancelCore(token.Entity, token);
}
internal bool IsDormantLocalActivationCommitCurrent(
RuntimeEntityRecord record,
PhysicsBody body,
in RuntimeDormantSetPositionCommitReceipt receipt)
{
// Round 3 audit: safe - fresh lookup + Stage/ProjectionSequence
// check earlier in this SAME guard clause precede IsCurrent,
// nothing reentrant in between.
if (!receipt.IsCommitted
|| !receipt.Projection.Token.IsValid
|| record.Key != receipt.Projection.Token.Entity
|| !ReferenceEquals(record.PhysicsBody, body)
|| !_pendingProjection.TryGetValue(
receipt.Projection.Token.Sequence,
out RuntimePlacementProjectionSnapshot pending)
|| pending != receipt.Projection
|| !_operations.TryGetValue(
receipt.Projection.Token.Entity,
out Operation? operation)
|| operation.Stage is not RuntimeEntityPlacementStage
.AwaitingCommitAcknowledgement
|| operation.ProjectionSequence
!= receipt.Projection.Token.Sequence
|| !IsCurrent(operation)
|| !body.InWorld
|| !_physics.IsSpatialRoot(record))
{
return false;
}
return true;
}
internal bool TryCaptureDormantLocalActivationResult(
in RuntimeEntityPlacementToken token,
out PhysicsSetPositionResult result)
{
if (!_disposed
&& token.IsValid
&& _operations.TryGetValue(token.Entity, out Operation? operation)
&& operation.Token == token)
{
result = operation.Result;
return true;
}
result = default;
return false;
}
private bool IsPreparedDormantCommitCurrent(
RuntimeEntityRecord record,
PhysicsBody body,
PreparedDormantSetPositionCommit prepared)
{
if (_nextProjectionSequence != prepared.ExpectedProjectionSequence
|| !IsDormantLocalEvaluationCurrent(
record,
body,
prepared.Evaluation)
|| !_operations.TryGetValue(
prepared.Entity,
out Operation? operation)
|| operation.Token.OperationId != prepared.OperationId)
{
return false;
}
if (prepared.Collision is not null
&& !_physics.CollisionReports.IsPreparedSetPositionBatchCurrent(
prepared.Collision))
return false;
return prepared.Shadow is null
|| _physics.Engine.ShadowObjects.IsPreparedSetPositionCurrent(
prepared.Shadow);
}
private static void CommitStationaryBits(
PhysicsBody body,
int framesStationaryFall)
{
body.TransientState &= ~(TransientStateFlags.StationaryFall
| TransientStateFlags.StationaryStop
| TransientStateFlags.StationaryStuck);
body.TransientState |= framesStationaryFall switch
{
1 => TransientStateFlags.StationaryFall,
2 => TransientStateFlags.StationaryStop,
3 => TransientStateFlags.StationaryStuck,
_ => TransientStateFlags.None,
};
}
internal RuntimeSetPositionOutcome SubmitPreparedPlacement(
in RuntimeEntityPlacementToken token,
in RuntimeSetPositionCommand command) =>
SubmitPreparedPlacementCore(
token,
command,
allowDirectUnsealed: token.PreparationKind
is RuntimeEntityPlacementPreparationKind.LegacyDirect);
private RuntimeSetPositionOutcome SubmitPreparedPlacementCore(
in RuntimeEntityPlacementToken token,
in RuntimeSetPositionCommand command,
bool allowDirectUnsealed)
{
EnsureNotDisposed();
Operation? operation = null;
bool ownsToken = token.IsValid
&& _operations.TryGetValue(token.Entity, out operation)
&& operation.Token == token;
MoverPreparationAuthority exactAuthority = default;
bool hasPreparationAuthority = token.IsValid
&& _moverPreparationAuthorities.TryGetValue(
token.Entity,
out exactAuthority)
&& exactAuthority.OperationId == token.OperationId;
// Round 3 audit: safe - `ownsToken` (fresh lookup + Token check)
// was just computed above with nothing reentrant in between; this
// is the function's own entry validation, before any of its
// internal reentrancy points (the SetPosition/CommitCanonical calls
// further down, which ARE converted to IsCurrentByToken).
if (!ownsToken
|| operation is null
|| operation.Stage
is not RuntimeEntityPlacementStage.AwaitingPreparation
|| !IsCurrent(operation)
|| operation.Record.PhysicsBody is not { } body
|| !double.IsFinite(command.GameTime)
|| command.Kind != operation.Kind
|| command.Portal != operation.Portal
|| (hasPreparationAuthority
? !exactAuthority.Prepared
|| exactAuthority.PreparedCommand != command
|| !IsPreparationAuthorityCurrent(
operation,
exactAuthority)
: !allowDirectUnsealed)
|| (command.ExpectedVelocityAuthorityVersion != 0UL
&& operation.Record.VelocityAuthorityVersion
!= command.ExpectedVelocityAuthorityVersion))
{
// Preparation is an accepted-operation input, not the operation
// itself. A malformed or temporarily incomplete preparation must
// remain retryable under the exact token and cannot discard a
// withdrawn resident or its last validated mover shape.
return Rejected(command.Physics);
}
operation.Body = body;
operation.EnteringWorldFromCelllessResidence |=
!body.InWorld || operation.Record.FullCellId == 0u;
if (command.ExpectedVelocityAuthorityVersion != 0UL)
{
operation.SourceVelocityAuthorityVersion =
command.ExpectedVelocityAuthorityVersion;
}
operation.PreviousContact = body.InContact;
operation.PreviousOnWalkable = body.OnWalkable;
var canonicalRequest = command.Physics with
{
Position = operation.WakeableLostCell
? operation.Result.Position
: command.Physics.Position,
Orientation = operation.WakeableLostCell
? operation.Result.Orientation
: command.Physics.Orientation,
CellId = operation.WakeableLostCell
? operation.ExactCellId
: command.Physics.CellId,
CellLocalPosition = operation.WakeableLostCell
? operation.Result.CellLocalPosition
: command.Physics.CellLocalPosition,
MoverPhysicsState = operation.Record.FinalPhysicsState,
MovingEntityId = operation.Key.LocalEntityId,
CurrentCellId = operation.WakeableLostCell
? null
: body.InWorld
&& operation.Record.FullCellId != 0u
? operation.Record.FullCellId
: null,
};
var canonicalCommand = command with { Physics = canonicalRequest };
operation.Command = canonicalCommand;
if (hasPreparationAuthority)
{
_moverPreparationAuthorities[token.Entity] = exactAuthority with
{
PreparedCommand = canonicalCommand,
};
}
if (operation.InheritedLostDeadline
&& !operation.WithdrawalAcknowledged
&& operation.ProjectionSequence != 0UL)
{
operation.PreparedCommandAwaitingWithdrawalAck =
canonicalCommand;
operation.Stage = RuntimeEntityPlacementStage
.AwaitingWithdrawalAcknowledgement;
return Outcome(
RuntimeSetPositionStatus.DeferredCell,
operation.Result,
_pendingProjection.TryGetValue(
operation.ProjectionSequence,
out RuntimePlacementProjectionSnapshot pending)
? pending.Token
: default);
}
if (operation.WakeableLostCell)
{
operation.RequiresPreparation = false;
operation.Stage = RuntimeEntityPlacementStage.AwaitingCell;
if (operation.WithdrawalAcknowledged
&& operation.CollisionGenerationReady
&& operation.ProjectionSequence == 0UL)
{
RetryDeferred(operation);
}
return Outcome(
RuntimeSetPositionStatus.DeferredCell,
operation.Result,
operation.ProjectionSequence != 0UL
&& _pendingProjection.TryGetValue(
operation.ProjectionSequence,
out RuntimePlacementProjectionSnapshot pending)
? pending.Token
: default);
}
if (!IsStructurallyValid(canonicalRequest))
{
PhysicsSetPositionResult invalid = InvalidResult(canonicalRequest);
operation.Result = invalid;
operation.RequiresPreparation = true;
operation.Stage = RuntimeEntityPlacementStage.AwaitingPreparation;
return Outcome(RuntimeSetPositionStatus.Rejected, invalid, default);
}
if (TryGetBlockingQuiescence(
canonicalRequest,
out CollisionPrefixQuiescence? quiescence))
{
var deferred = new PhysicsSetPositionResult(
PhysicsSetPositionError.Ok,
PhysicsResidenceDisposition.DeferredCell,
canonicalRequest.Position,
canonicalRequest.Orientation,
canonicalRequest.CellId,
canonicalRequest.CellLocalPosition,
InContact: operation.PreviousContact,
OnWalkable: operation.PreviousOnWalkable,
ContactPlane: body.ContactPlane,
ContactPlaneCellId: body.ContactPlaneCellId,
ContactPlaneIsWater: body.ContactPlaneIsWater,
SlidingNormalValid: body.SlidingNormal != Vector3.Zero,
SlidingNormal: body.SlidingNormal,
FramesStationaryFall: body.FramesStationaryFall,
CrossCellIds: ImmutableArray<uint>.Empty,
CollidedObjectIds: ImmutableArray<uint>.Empty,
QueriedCellIds: ImmutableArray<uint>.Empty);
operation.Result = deferred;
operation.RequiresPreparation = false;
operation.ExactCellId = deferred.CellId;
_preparedMovers[operation.Key] = canonicalRequest;
return ParkDeferred(
operation,
deferred,
collisionGenerationOverride:
quiescence!.Token.CollisionGeneration,
collisionPrefixOverride:
quiescence.Token.LandblockPrefix,
// A quiescence park is a momentarily-unavailable destination,
// not a world going away, so it is eligible for the rollback.
// ParkDeferred is what decides whether the cell it would
// restore into is itself quiescing.
restorableOnCancel: true);
}
PhysicsSetPositionResult result;
_collisionCallbackContexts.Push(new CollisionCallbackContext(
operation.Record,
operation.PositionAuthorityVersion,
operation.SourceSpatialAuthorityVersion,
operation.SourceVelocityAuthorityVersion,
canonicalCommand.GameTime,
operation.PreviousContact,
operation.PreviousOnWalkable));
try
{
result = _physics.Engine.SetPosition(
canonicalRequest,
_handleSetPositionCollisionsCallback);
}
finally
{
_collisionCallbackContexts.Pop();
}
// Round 3: `_physics.Engine.SetPosition` above can reenter this class
// - its collision-report callback can reach an arbitrary
// IRuntimeCollisionReportObserver subscriber that calls back into
// Begin/Cancel for this (or any) entity, which can retire-then-rent
// (LIFO) this exact `operation` instance for a different logical
// operation. `token` (the function parameter, captured before any
// of this ran) proves identity by value instead of trusting
// `operation`'s live fields.
if (!IsCurrentByToken(token.Entity, token, out operation))
return Outcome(RuntimeSetPositionStatus.Cancelled, result, default);
if (result.IsSuccessful
&& TryGetBlockingQuiescence(
result,
out CollisionPrefixQuiescence? queriedQuiescence))
{
PhysicsSetPositionResult held = result with
{
Residence = PhysicsResidenceDisposition.DeferredCell,
};
operation.Result = held;
operation.RequiresPreparation = false;
operation.ExactCellId = held.CellId;
_preparedMovers[operation.Key] = canonicalRequest;
return ParkDeferred(
operation,
held,
collisionGenerationOverride:
queriedQuiescence!.Token.CollisionGeneration,
collisionPrefixOverride:
queriedQuiescence.Token.LandblockPrefix,
// Same reason as the pre-sweep park above, plus the swept
// footprint: ResultTouchesPrefix scans every QueriedCellIds
// entry, and that set spans NEIGHBOUR landblocks.
restorableOnCancel: true);
}
operation.Result = result;
if (!result.IsSuccessful)
{
operation.RequiresPreparation = true;
operation.Stage = RuntimeEntityPlacementStage.AwaitingPreparation;
return Outcome(RuntimeSetPositionStatus.Rejected, result, default);
}
// Round 3: same reentrancy hazard as the check right after the
// SetPosition call above - re-verify by token rather than trusting
// `operation` across the collision-report dispatch.
if (!IsCurrentByToken(token.Entity, token, out operation))
return Outcome(RuntimeSetPositionStatus.Cancelled, result, default);
operation.RequiresPreparation = false;
operation.ExactCellId = result.CellId;
_preparedMovers[operation.Key] = canonicalRequest;
if (result.IsDeferred)
// The plain restorable park: the destination is not placeable
// right now. The only NON-restorable caller is the retirement
// park - see ParkDeferred's restorableOnCancel doc.
return ParkDeferred(operation, result, restorableOnCancel: true);
if (!CommitCanonical(operation, result))
{
// Round 3: CommitCanonical's own ground-edge callback and
// collision-report dispatch can reenter this class, so
// `operation` may already be stale here even though it was
// just re-verified before the call. `token` (this function's
// own parameter, untouched since entry) is the safe capture.
PublishCancellation(CancelCore(token.Entity, token));
return Outcome(RuntimeSetPositionStatus.Cancelled, result, default);
}
// F1: CommitCanonical can succeed (fully applying the physical
// settle - contact transition, collision reports, shadow sync) for
// an operation a reentrant ground-edge callback has since displaced
// - retail lets that physical commit land regardless (see
// ReentrantGroundEdgePlacementCannotBeCancelledByDisplacedOperation).
// But THIS caller's own operation is no longer canonical, so it must
// still report Cancelled rather than publish a Place projection
// nothing will ever acknowledge again. `token` (the parameter,
// captured before any of this ran) is compared against a fresh
// lookup instead of trusting `operation`'s live fields, which may
// already reflect whatever displaced it.
if (!_operations.TryGetValue(token.Entity, out Operation? stillOwns)
|| stillOwns.Token != token)
{
return Outcome(RuntimeSetPositionStatus.Cancelled, result, default);
}
operation.Stage = RuntimeEntityPlacementStage
.AwaitingCommitAcknowledgement;
RuntimePlacementProjectionToken projection = PublishProjection(
operation,
RuntimePlacementProjectionKind.Place,
result);
return Outcome(
RuntimeSetPositionStatus.CommittedHostAcknowledgementPending,
result,
projection);
}
/// <summary>
/// C2: zero-allocation replacement for the LINQ
/// <c>_pendingProjection.First()</c> pattern used at every call site
/// below. <c>Enumerable.First&lt;TSource&gt;</c> takes an
/// <c>IEnumerable&lt;TSource&gt;</c> parameter, so calling it on a
/// <see cref="SortedDictionary{TKey, TValue}"/> dispatches through the
/// interface-typed <c>IEnumerable&lt;KeyValuePair&lt;TKey,
/// TValue&gt;&gt;.GetEnumerator()</c>, which BOXES the dictionary's
/// normally-struct <c>Enumerator</c> - this was the entire measured C2
/// acknowledgement-path residual (120 B/op). A plain <c>foreach</c> on
/// the concrete <see cref="SortedDictionary{TKey, TValue}"/> field type
/// resolves to its public non-interface, struct-returning
/// <c>GetEnumerator()</c> instead and never boxes. Every call site below
/// already checks <c>_pendingProjection.Count != 0</c> immediately
/// before calling this (short-circuiting `||`/`&amp;&amp;`), exactly
/// mirroring the precondition LINQ's <c>First()</c> relied on - the
/// throw path is unreachable in current usage, kept only so a future
/// caller that skips the guard fails loudly instead of silently, same as
/// LINQ's own contract would have.
/// </summary>
private KeyValuePair<ulong, RuntimePlacementProjectionSnapshot>
FirstPendingProjection()
{
foreach (KeyValuePair<ulong, RuntimePlacementProjectionSnapshot> entry
in _pendingProjection)
{
return entry;
}
throw new InvalidOperationException(
"FirstPendingProjection requires at least one pending entry.");
}
internal bool TryPeekProjection(
out RuntimePlacementProjectionSnapshot projection)
{
EnsureNotDisposed();
if (_pendingProjection.Count == 0)
{
projection = default;
return false;
}
projection = FirstPendingProjection().Value;
return true;
}
internal bool AcknowledgeProjection(
in RuntimePlacementProjectionToken token)
{
EnsureNotDisposed();
if (!token.IsValid
|| _pendingProjection.Count == 0
|| FirstPendingProjection().Key != token.Sequence
|| !_pendingProjection.TryGetValue(
token.Sequence,
out RuntimePlacementProjectionSnapshot pending)
|| pending.Token != token)
{
return false;
}
if (pending.Kind is RuntimePlacementProjectionKind.Discard
or RuntimePlacementProjectionKind.ExecutorCompleted
or RuntimePlacementProjectionKind.WithdrawalRestored)
{
// C0-1: an ExecutorCompleted receipt is never Operation-backed
// (see PublishExecutorCompletion) - there is nothing to resume or
// commit against, exactly like Discard. A WithdrawalRestored
// receipt is published from RestoreParkWithdrawal, AFTER
// CancelCoreDeferred already removed and retired the parked
// operation (see PublishWithdrawalRestoration), so it is never
// Operation-backed either.
_pendingProjection.Remove(token.Sequence);
RetireQuiescenceProjectionSequence(token.Sequence);
if (pending.Kind is RuntimePlacementProjectionKind.ExecutorCompleted)
{
// F2: notify the executor so it can reap its own
// token-to-receipt correlation entry now - not before (a
// host might still be mid-retry against this exact
// unacknowledged receipt) and not left dangling after.
_executorCompletionAcknowledged?.Invoke(
token.Entity,
token.Sequence);
}
return true;
}
// Round 3 audit: safe - fresh lookup + ProjectionSequence check
// immediately precede IsCurrent, nothing reentrant in between (this
// is AcknowledgeProjection's own entry validation).
if (!_operations.TryGetValue(
token.Entity,
out Operation? operation)
|| operation.ProjectionSequence != token.Sequence
|| !IsCurrent(operation)
|| operation.SpatialAuthorityVersion
!= token.SpatialAuthorityVersion)
{
return false;
}
_pendingProjection.Remove(token.Sequence);
RetireQuiescenceProjectionSequence(token.Sequence);
operation.ProjectionSequence = 0UL;
if (pending.Kind is RuntimePlacementProjectionKind.Place)
{
if (_placementCompletionWatches.Remove(operation.Token))
{
_acknowledgedPlacementCompletions.Add(
operation.Token,
pending.Token);
}
operation.Stage = RuntimeEntityPlacementStage.AwaitingCommitAcknowledgement;
_moverPreparationAuthorities.Remove(operation.Key);
bool removed = _operations.Remove(operation.Key);
if (removed)
RetireOperationToPool(operation);
return removed;
}
if (!operation.WakeableLostCell
&& !operation.InheritedLostDeadline)
{
_moverPreparationAuthorities.Remove(operation.Key);
bool removed = _operations.Remove(operation.Key);
if (removed)
RetireOperationToPool(operation);
return removed;
}
operation.WithdrawalAcknowledged = true;
operation.Stage = operation.RequiresPreparation
|| operation.InheritedLostDeadline
? RuntimeEntityPlacementStage.AwaitingPreparation
: operation.CollisionQuiescenceHeld
? RuntimeEntityPlacementStage.QuiescenceHeld
: RuntimeEntityPlacementStage.AwaitingCell;
if (operation.PreparedCommandAwaitingWithdrawalAck is { } prepared)
{
operation.PreparedCommandAwaitingWithdrawalAck = null;
operation.Stage = RuntimeEntityPlacementStage.AwaitingPreparation;
_ = SubmitPreparedPlacement(operation.Token, prepared);
return true;
}
if (operation.CollisionGenerationReady)
RetryDeferred(operation);
return true;
}
/// <summary>
/// Runs retail's 25-second lost-cell destruction timer. Expired exact
/// incarnation keys are consumed by the entity-lifetime owner; no host
/// callback or GUID-only deletion can cross a replacement generation.
/// </summary>
internal void TickLostCellDeadlines()
{
EnsureNotDisposed();
if (_lostDeadlineNodes.Count == 0)
return;
double now = _physics.MonotonicNowSeconds;
while (_lostDeadlineNodes.Count != 0)
{
LostDeadlineEntry entry = _lostDeadlineNodes[0];
if (entry.Deadline > now)
break;
RemoveLostDeadlineNodeAt(0);
if (!_lostDeadlines.Remove(entry.Key))
throw new InvalidOperationException(
"The lost-cell deadline index diverged from its exact key owner.");
if (_operations.TryGetValue(
entry.Key,
out Operation? operation))
operation.Expired = true;
if (_entities.TryGetByLocalId(
entry.Key.LocalEntityId,
out RuntimeEntityRecord record)
&& record.Key == entry.Key)
{
if (!_expiredLostCellNodes.ContainsKey(entry.Key))
{
LinkedListNode<RuntimeEntityKey> node =
_expiredLostCells.AddLast(entry.Key);
_expiredLostCellNodes.Add(entry.Key, node);
}
}
}
}
internal bool TryDequeueExpiredLostCell(out RuntimeEntityKey key)
{
EnsureNotDisposed();
if (_expiredLostCells.First is not { } first)
{
key = default;
return false;
}
key = first.Value;
_expiredLostCells.RemoveFirst();
_expiredLostCellNodes.Remove(key);
return true;
}
internal bool Cancel(RuntimeEntityRecord record, bool publishWithdrawal)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
if (record.Key is not { } key)
return false;
bool removed = CancelCoreDeferred(
key,
cancelLostFamily: false,
preserveLostFamily: false,
out RuntimePlacementProjectionSnapshot? discard);
if (!publishWithdrawal || !_entities.IsCurrent(record))
{
if (discard is { } cancelled)
PublishPlacement(cancelled);
return removed;
}
LeaveWorldCanonical(record);
if (record.PhysicsBody is null)
{
if (discard is { } cancelledBodyless)
PublishPlacement(cancelledBodyless);
return removed;
}
var operation = CreateWithdrawalOperation(record, key);
_operations[key] = operation;
// Round 3: `operation.Token` is captured HERE, before
// PublishPlacement below can synchronously reenter this class - a
// subscriber reacting to the withdrawal-of-the-old-operation
// notification can call Begin/Cancel for this SAME entity, which
// (per RetireOperationToPool's doc comment) can retire-then-rent
// (LIFO) this exact `operation` instance for a brand-new logical
// operation before the checks below run. Comparing
// `ReferenceEquals`/`IsCurrent(operation)` against the stale
// reference afterward would be a tautology - it would report "still
// current" and then publish a Withdraw projection carrying the
// NEWER operation's state under the OLD operation's identity.
RuntimeEntityPlacementToken capturedToken = operation.Token;
if (discard is { } cancelledOld)
PublishPlacement(cancelledOld);
if (!IsCurrentByToken(key, capturedToken, out operation))
return true;
_ = PublishProjection(
operation,
RuntimePlacementProjectionKind.Withdraw,
operation.Result);
return true;
}
/// <summary>
/// Cancelling a wakeable lost-cell park ROLLS THE ENTITY BACK. Without
/// that, <see cref="ParkDeferred"/>'s withdrawal (<c>body.InWorld =
/// false</c>, object clock suspended, <see cref="WithdrawCanonical"/>
/// clearing canonical residency) outlived the operation that was the only
/// thing able to wake it: <see cref="CancelCoreDeferred"/> removes the
/// operation and restores none of that, so the entity was left invisible
/// AND intangible for the rest of the session. The producing sequence is
/// mundane - the accepted-Position merge
/// (<c>RuntimeEntityObjectLifetime.TryApplyPosition</c>) calls this on
/// EVERY accepted Position, so packet N parked and packet N+1 destroyed
/// the park ~150 ms later, before any collision-generation wake could
/// fire.
///
/// <para>This also closes the same hole on route 2's shipped
/// <c>DeferredCell</c> path, which was masked only by its re-issue funnel
/// - correct for a one-shot ForcePosition, absent for a repeated remote
/// stream.</para>
/// </summary>
/// <summary>
/// <paramref name="restoreCancelledPark"/> distinguishes a CANCELLATION
/// from a WITHDRAWAL, and defaults to false so every shipped caller keeps
/// its exact prior behaviour.
///
/// <para>Only a cancellation may roll a park back. Most callers of this
/// method are withdrawal transactions - pickup, parent attach, explicit
/// withdrawal, position-channel teardown - which deliberately take the
/// entity OUT of the world and then hand-roll their own partial
/// re-withdrawal. Rolling a park back underneath one of those would set
/// <c>body.InWorld = true</c> and re-register the entity in
/// <c>_spatialRoots</c>, neither of which their cleanup undoes (it only
/// zeroes the clock and <c>FullCellId</c>) - leaving e.g. a picked-up item
/// simultaneously in inventory AND an <c>InWorld</c> cell-less spatial root
/// handed to the <c>CPhysics::UseTime</c> workset by
/// <c>CopySpatialRootsTo</c>, which filters only on key and
/// <c>IsCurrent</c>.</para>
///
/// <para>The rollback exists because <see cref="ParkDeferred"/>'s
/// withdrawal otherwise outlives the operation that was the only thing
/// able to wake it: <see cref="CancelCoreDeferred"/> restores neither
/// <c>InWorld</c>, the object clock, nor canonical residency, so the entity
/// was left invisible AND intangible for the rest of the session. The
/// accepted-Position merge produced that every ~150 ms - packet N parked,
/// packet N+1 destroyed the park before any collision-generation wake could
/// fire. It closes the same hole on route 2's shipped <c>DeferredCell</c>
/// path, which was masked only by its re-issue funnel.</para>
/// </summary>
internal RuntimePlacementCancellationReceipt Forget(
RuntimeEntityRecord record,
bool releasePreparedMover = false,
bool restoreCancelledPark = false)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
RuntimePlacementCancellationReceipt receipt = default;
if (record.Key is { } key)
{
// Captured before CancelCore, which retires the operation to the
// pool and resets every field on it.
ParkWithdrawal withdrawal =
restoreCancelledPark
&& _operations.TryGetValue(key, out Operation? parked)
&& parked.WakeableLostCell
&& ReferenceEquals(parked.Record, record)
? parked.ParkWithdrawal
: default;
receipt = CancelCore(key);
if (releasePreparedMover)
_preparedMovers.Remove(key);
if (withdrawal.Captured)
RestoreParkWithdrawal(record, withdrawal);
}
return receipt;
}
/// <summary>
/// Undoes <see cref="ParkDeferred"/>'s WITHDRAWAL - <c>InWorld</c>, the
/// transient-state bits, the object clock, and canonical residency - so a
/// cancelled park cannot leave the entity invisible and intangible with
/// nothing able to wake it.
///
/// <para><b>Presentation is rolled back too, through
/// <see cref="PublishWithdrawalRestoration"/>.</b> The canonical half
/// below is only one half of what <see cref="ParkDeferred"/>'s Withdraw
/// receipt removed; the host sink that consumed that receipt also dropped
/// the graphical bucket, the projection-visibility sinks, plugin world
/// state/events, the effect-pose registry and the local-player shadow, and
/// nothing but that sink's Place publication re-installs them. Relying on
/// a LATER Place was the defect: a remote that parks on its final Position
/// and then stops moving never receives one (ACE stops broadcasting for a
/// stationary entity), so it stayed simulated, collidable, audible - and
/// invisible in both the world and the radar for the rest of the session.
/// The restoration receipt is published exactly when the entity ends this
/// method canonically whole, so the two halves can never disagree.</para>
///
/// <para>Residency specifically is re-tested against the live quiescence
/// map HERE as well as at park time, because this runs on a later packet
/// for a retained park - see the inline comment for the window. The
/// <c>InWorld</c>/transient/clock half is restored unconditionally: it is
/// per-entity simulation state, not a claim on any landblock's collision
/// generation, so it cannot block a retirement.</para>
///
/// <para><b>The committed pose is deliberately left alone.</b>
/// <see cref="ParkDeferred"/> snaps the body to the destination before
/// withdrawing, which is precisely retail's lost-cell behaviour:
/// <c>CPhysicsObj::SetPositionInternal</c> @0x00515BD0 calls
/// <c>store_position</c> @0x00515CE2 on the no-cell branch and returns
/// <c>OK_SPE</c>. Retail commits the destination pose and never rolls it
/// back, and route 2's shipped tests pin the same contract by capturing
/// the pose AFTER the park and asserting it survives the cancel. Residency
/// is therefore restored at the body's committed cell, keeping residency
/// and pose consistent, rather than at the stale pre-park cell.</para>
///
/// <para>Re-entering at a destination whose collision is not yet published
/// cannot re-arm <see cref="ParkCollisionResidents"/>'s overlap throw:
/// that throw fires only for a spatial root still holding an ACTIVE
/// operation, and the cancel this restore follows has already retired the
/// operation. An ordinary retirement re-parks the entity through the
/// normal path instead.</para>
///
/// <para><b>Residual divergence, measured against retail rather than
/// labelled retail-shaped.</b> Retail would keep the object hidden and
/// re-show it on cell load - a lost registration is removed ONLY by
/// <c>CObjectMaint::InitObjCell</c> @0x00508260, which drains the lost
/// list and calls <c>CPhysicsObj::reenter_visibility</c> @0x00508296
/// (@0x00516250). We instead re-show it immediately at the committed
/// destination pose, uncollidable until its landblock publishes. For a
/// remote at 5-10 Hz the next packet supersedes within ~150 ms; a remote
/// that teleports into a non-resident landblock and then STOPS MOVING
/// holds that state, because ACE stops broadcasting for a stationary
/// entity. The retail-faithful end state is a park that SURVIVES
/// cancellation, blocked on re-deciding the newer-Position-cancels-the-park
/// invariant pinned by
/// <c>NewerPositionPickupAndParentEachCancelExactLostOperation</c> and on
/// teardown convergence. See the divergence register row and its issue.</para>
///
/// <para>The shadow-object suspension <see cref="WithdrawCanonical"/>
/// applied is NOT lifted here: <c>ShadowObjectRegistry.Suspend</c> drops
/// the owner's cell rows and only a real placement dispatch
/// (<c>ReplacePositionRows</c>) rebuilds them, so un-suspending would mean
/// re-running a placement re-entrantly from inside a cancel. The entity is
/// restored visible and simulated and rejoins the collision broadphase on
/// its next placement - recorded with the divergence above, not papered
/// over.</para>
/// </summary>
private void RestoreParkWithdrawal(
RuntimeEntityRecord record,
in ParkWithdrawal withdrawal)
{
if (!_entities.IsCurrent(record))
return;
uint residentCellId = 0u;
if (record.PhysicsBody is { } body)
{
body.InWorld = withdrawal.InWorld;
body.TransientState = withdrawal.TransientState;
residentCellId = body.CellPosition.ObjCellId;
}
if (withdrawal.ClockActive)
_entities.ResumeObjectClock(record);
// Round 4 (D6): the park-time decision in ParkDeferred is a SNAPSHOT,
// and for a RETAINED park it can be stale by the time this runs. The
// far snap's park is cancelled synchronously (SubmitAndResolve's
// DeferredCell arm), so its window is nanoseconds - but route 2's
// park is retained (AwaitingCommitWake) and this restore lands on the
// NEXT packet's merge-time Forget, ~150 ms later at ACE's 5-10 Hz.
// Streaming opens a quiescence per landblock mutation, so a prefix
// that was clean when the park was taken can be quiescing now.
// Re-testing here is what makes AP-136's claim - "the rollback never
// re-admits a spatial root into a retiring prefix" - exact at the
// moment residency is actually written, instead of true only as of
// when the park was taken. The `!= 0u` test ahead of it is also the
// C3c-F3 sentinel guard ParkDeferred applies: AdjustToOutside zeroes
// the cell id on map-edge failure, and prefix 0x00000000 is the
// legitimate corner landblock.
bool residencyRestored = false;
if (residentCellId != 0u
&& !IsCollisionPrefixQuiescing(residentCellId)
&& record.FullCellId == 0u)
{
_entities.SetFullCell(
record,
residentCellId,
(residentCellId & 0xFFFF0000u) | 0xFFFFu);
_physics.AcknowledgeSpatialProjection(record, spatial: true);
residencyRestored = true;
}
// The presentation rollback is gated on the entity actually ENDING
// this method canonically whole, not on `residencyRestored` alone.
// Those are different facts: in the shipped graphical remote path the
// per-packet prologue rebucket (LiveEntityNetworkUpdateController ->
// LiveEntityRuntime.RebucketLiveEntity) has already recommitted a
// non-zero FullCellId and re-acknowledged the spatial root BEFORE the
// merge cancels the park, so the arm above is correctly skipped while
// the entity is nonetheless whole and must be shown again. The
// converse - a quiescing prefix refusing residency (AP-136) - leaves
// FullCellId at zero, and the entity stays presentation-withdrawn to
// match, exactly as it stays canonically withdrawn.
bool canonicallyWhole = record.FullCellId != 0u
&& record.PhysicsBody is { InWorld: true };
if (canonicallyWhole)
PublishWithdrawalRestoration(record);
// Issue #309's connected-gate confirmation signal; see the [park]
// line's own comment in ParkDeferred.
if (PhysicsDiagnostics.ProbeParkEnabled)
{
Console.WriteLine(FormattableString.Invariant(
$"[park-restore] guid=0x{record.ServerGuid:X8} restoreCell=0x{residentCellId:X8} inWorld={withdrawal.InWorld} residency={residencyRestored} presentation={canonicallyWhole}"));
}
}
internal void LeaveWorld(RuntimeEntityRecord record)
{
EnsureNotDisposed();
ArgumentNullException.ThrowIfNull(record);
RuntimePlacementCancellationReceipt receipt = record.Key is { } key
? CancelCore(key)
: default;
if (_entities.IsCurrent(record))
LeaveWorldCanonical(record);
PublishCancellation(receipt);
}
internal bool IsDeferred(RuntimeEntityRecord record) =>
record.Key is { } key
&& _operations.TryGetValue(key, out Operation? operation)
&& ReferenceEquals(operation.Record, record)
&& operation.WakeableLostCell;
internal bool TryGetPreparedMoverSphereCount(
RuntimeEntityRecord record,
out int sphereCount)
{
EnsureNotDisposed();
if (record.Key is { } key
&& _preparedMovers.TryGetValue(
key,
out PhysicsSetPositionRequest request))
{
sphereCount = request.Spheres.Length;
return true;
}
sphereCount = 0;
return false;
}
internal bool TryGetAwaitingPreparationToken(
RuntimeEntityRecord record,
out RuntimeEntityPlacementToken token)
{
EnsureNotDisposed();
if (record.Key is { } key
&& _operations.TryGetValue(key, out Operation? operation)
&& ReferenceEquals(operation.Record, record)
&& operation.RequiresPreparation)
{
token = operation.Token;
return true;
}
token = default;
return false;
}
internal void ParkCollisionResidents(
uint landblockId,
bool includeOutdoorCells)
{
EnsureNotDisposed();
uint prefix = landblockId & 0xFFFF0000u;
var roots = new List<RuntimeEntityRecord>();
_physics.CopySpatialRootsTo(roots);
RuntimeEntityRecord[] affected = roots
.Where(record => IsAffectedCollisionResident(
record,
prefix,
includeOutdoorCells))
.ToArray();
for (int index = 0; index < affected.Length; index++)
{
if (affected[index].Key is { } key
&& _operations.ContainsKey(key))
{
throw new InvalidOperationException(
$"Collision retirement for 0x{prefix:X8} cannot overlap active placement for 0x{affected[index].ServerGuid:X8}/{affected[index].Incarnation}.");
}
}
// Close every exact collision-report owner before the first force-end
// callback can re-enter. The prefix admission barrier is already in
// place for transactional callers, so a callback cannot evaluate a
// new placement against the retiring rows.
_physics.CollisionReports.LeaveWorldBatch(affected);
var stagedWithdrawals = new List<RuntimePlacementProjectionSnapshot>(
roots.Count);
for (int index = 0; index < roots.Count; index++)
{
RuntimeEntityRecord record = roots[index];
uint cellId = record.FullCellId;
if (!IsAffectedCollisionResident(
record,
prefix,
includeOutdoorCells)
|| record.Key is not { } key
|| record.PhysicsBody is not { } body
|| _operations.ContainsKey(key)
|| !affected.Any(candidate =>
ReferenceEquals(candidate, record)
&& candidate.Key == key))
{
continue;
}
bool hasPrepared = _preparedMovers.TryGetValue(
key,
out PhysicsSetPositionRequest prepared);
var request = (hasPrepared
? prepared
: new PhysicsSetPositionRequest(
body.Position,
body.Orientation,
cellId,
body.CellPosition.Frame.Origin,
ImmutableArray<FlatCollisionSphere>.Empty,
1f,
0f,
0f)) with
{
Position = body.Position,
Orientation = body.Orientation,
CellId = cellId,
CellLocalPosition = body.CellPosition.Frame.Origin,
MoverPhysicsState = record.FinalPhysicsState,
MovingEntityId = key.LocalEntityId,
CurrentCellId = null,
};
var result = new PhysicsSetPositionResult(
PhysicsSetPositionError.Ok,
PhysicsResidenceDisposition.DeferredCell,
body.Position,
body.Orientation,
cellId,
body.CellPosition.Frame.Origin,
InContact: body.InContact,
OnWalkable: body.OnWalkable,
ContactPlane: body.ContactPlane,
ContactPlaneCellId: body.ContactPlaneCellId,
ContactPlaneIsWater: body.ContactPlaneIsWater,
SlidingNormalValid: body.SlidingNormal != Vector3.Zero,
SlidingNormal: body.SlidingNormal,
FramesStationaryFall: body.FramesStationaryFall,
CrossCellIds: ImmutableArray<uint>.Empty,
CollidedObjectIds: ImmutableArray<uint>.Empty);
var command = new RuntimeSetPositionCommand(
request,
RuntimeSetPositionOperationKind.RemoteAuthoritative,
body.LastUpdateTime,
record.VelocityAuthorityVersion);
// F4: routed through RentOperation() (rather than a fresh
// `new Operation { ... }`) so every construction flows one path
// - see ResetAllFieldsToDefault's completeness-net doc comment.
// No key/displaced-operation collision is possible here: the
// loop above already skips this record when
// `_operations.ContainsKey(key)`.
Operation operation = RentOperation();
operation.Record = record;
operation.Body = body;
operation.Token = new RuntimeEntityPlacementToken(
_entities.SessionLifetimeVersion,
key,
record.PositionAuthorityVersion,
checked(++_nextOperationId),
RuntimeEntityPlacementPreparationKind.AuthoredMover);
operation.Key = key;
operation.PositionAuthorityVersion = record.PositionAuthorityVersion;
operation.SessionLifetimeVersion = _entities.SessionLifetimeVersion;
operation.SourceSpatialAuthorityVersion =
record.SpatialAuthorityVersion;
operation.SourceVelocityAuthorityVersion =
record.VelocityAuthorityVersion;
operation.PreviousContact = body.InContact;
operation.PreviousOnWalkable = body.OnWalkable;
operation.Command = command;
operation.Result = result;
operation.SpatialAuthorityVersion = record.SpatialAuthorityVersion;
operation.PlacementCommitVersion = record.PlacementCommitVersion;
operation.ExactCellId = cellId;
operation.Stage = RuntimeEntityPlacementStage.AwaitingPreparation;
operation.Kind = RuntimeSetPositionOperationKind.RemoteAuthoritative;
operation.Portal = default;
operation.RequiresPreparation = !hasPrepared;
_operations.Add(key, operation);
_moverPreparationAuthorities[key] = CapturePreparationAuthority(
operation,
ServerPositionFrom(
cellId,
body.CellPosition.Frame.Origin,
body.Orientation),
prepared: hasPrepared,
command);
CollisionPrefixQuiescence? quiescence =
_collisionPrefixQuiescence.GetValueOrDefault(prefix);
// C3c-F3: pass the overrides through as genuinely optional —
// `quiescence?.` yields null (absent) with no quiescence and the
// token's exact values (present, prefix 0x00000000 included)
// with one. The old `?? 0u` collapse made a corner-landblock
// quiescence indistinguishable from "no quiescence".
RuntimeSetPositionOutcome parked = ParkDeferred(
operation,
result,
publishImmediately: false,
collisionGenerationOverride:
quiescence?.Token.CollisionGeneration,
collisionPrefixOverride:
quiescence?.Token.LandblockPrefix,
// Stated, not inherited from the parameter default: a
// RETIREMENT park withdraws the entity because its own world
// is going away, which is the one shape AP-136's reason
// covers exactly. Round 3 (m5) - the blanket doc that used to
// guard a forgetful caller here is gone.
restorableOnCancel: false);
if (_pendingProjection.TryGetValue(
parked.Projection.Sequence,
out RuntimePlacementProjectionSnapshot staged))
{
stagedWithdrawals.Add(staged);
}
if (operation.RequiresPreparation)
{
operation.Stage = RuntimeEntityPlacementStage
.AwaitingPreparation;
}
}
// Canonical residence and operation ownership for every affected root
// must be installed before a synchronous host observer can re-enter.
// A callback may legitimately replace or cancel a later root; publish
// only the exact snapshot that is still pending when its turn arrives.
for (int index = 0; index < stagedWithdrawals.Count; index++)
{
RuntimePlacementProjectionSnapshot staged =
stagedWithdrawals[index];
if (_pendingProjection.TryGetValue(
staged.Token.Sequence,
out RuntimePlacementProjectionSnapshot current)
&& current == staged)
{
PublishPlacement(staged);
}
}
}
private bool IsAffectedCollisionResident(
RuntimeEntityRecord record,
uint prefix,
bool includeOutdoorCells)
{
uint cellId = record.FullCellId;
bool exactResidence = (cellId & 0xFFFF0000u) == prefix
&& (includeOutdoorCells || (cellId & 0xFFFFu) >= 0x0100u);
return exactResidence
&& record.Key is not null
&& _entities.IsCurrent(record)
&& record.PhysicsBody is not null
&& _physics.IsSpatialRoot(record)
&& (record.FinalPhysicsState & PhysicsStateFlags.Static) == 0
&& !_entities.ParentAttachments.HasCommittedParent(
record.ServerGuid);
}
private void ParkCollisionResidentsForQuiescence(
CollisionPrefixQuiescence state)
{
if (!TryGetCurrentQuiescence(state.Token, out CollisionPrefixQuiescence? current)
|| !ReferenceEquals(current, state))
{
return;
}
ParkCollisionResidents(
state.Token.LandblockPrefix,
state.IncludeOutdoorCells);
}
private bool HasAffectedCollisionResident(
uint prefix,
bool includeOutdoorCells)
{
if (_physics.SpatialRootCount == 0)
return false;
var roots = new List<RuntimeEntityRecord>();
_physics.CopySpatialRootsTo(roots);
for (int index = 0; index < roots.Count; index++)
{
if (IsAffectedCollisionResident(
roots[index],
prefix,
includeOutdoorCells))
{
return true;
}
}
return false;
}
private bool TryGetCurrentQuiescence(
in RuntimeCollisionPrefixQuiescenceToken token,
out CollisionPrefixQuiescence? state)
{
if (token.IsValid
&& token.SessionLifetimeVersion == _entities.SessionLifetimeVersion
&& _collisionPrefixQuiescence.TryGetValue(
token.LandblockPrefix,
out state)
&& state.Token == token)
{
return true;
}
state = null;
return false;
}
private bool HasPendingProjectionThrough(ulong barrierSequence) =>
barrierSequence != 0UL
&& _pendingProjection.Count != 0
&& FirstPendingProjection().Key <= barrierSequence;
private bool HasCollisionDispatchDebt()
{
RuntimeCollisionReportingOwnershipSnapshot reports =
_physics.CollisionReports.CaptureOwnership();
return reports.PendingReportCount != 0
|| reports.LeavingOwnerCount != 0
|| reports.AdmissionBlockedOwnerCount != 0
|| reports.PendingSetPositionDispatchCount != 0
|| reports.IsDispatching
|| _physics.Engine.ShadowObjects
.PendingSetPositionDispatchCount != 0;
}
private bool HasOldPrefixPlacementDebt(CollisionPrefixQuiescence state)
{
uint prefix = state.Token.LandblockPrefix;
foreach (Operation operation in _operations.Values)
{
if (operation.WakeableLostCell || operation.DormantLocalActivation)
continue;
if (PlacementTouchesPrefix(operation.Command.Physics, prefix)
|| ResultTouchesPrefix(operation.Result, prefix)
|| _moverPreparationAuthorities.TryGetValue(
operation.Key,
out MoverPreparationAuthority preparation)
&& preparation.OperationId
== operation.Token.OperationId
&& (preparation.AcceptedPosition.LandblockId
& 0xFFFF0000u) == prefix
|| IsAffectedCollisionResident(
operation.Record,
prefix,
state.IncludeOutdoorCells))
{
return true;
}
}
return false;
}
private static bool PlacementTouchesPrefix(
in PhysicsSetPositionRequest request,
uint prefix) =>
(request.CellId & 0xFFFF0000u) == prefix
|| request.CurrentCellId is uint current
&& (current & 0xFFFF0000u) == prefix;
private static bool ResultTouchesPrefix(
in PhysicsSetPositionResult result,
uint prefix)
{
if ((result.CellId & 0xFFFF0000u) == prefix)
return true;
if (!result.QueriedCellIds.IsDefaultOrEmpty)
{
foreach (uint cellId in result.QueriedCellIds)
{
if ((cellId & 0xFFFF0000u) == prefix)
return true;
}
}
return false;
}
private bool TryGetBlockingQuiescence(
in PhysicsSetPositionRequest request,
out CollisionPrefixQuiescence? state)
{
state = null;
foreach (CollisionPrefixQuiescence candidate
in _collisionPrefixQuiescence.Values)
{
if (PlacementTouchesPrefix(
request,
candidate.Token.LandblockPrefix)
&& (state is null
|| candidate.Token.OperationId
< state.Token.OperationId))
{
state = candidate;
}
}
return state is not null;
}
private bool TryGetBlockingQuiescence(
in PhysicsSetPositionResult result,
out CollisionPrefixQuiescence? state,
in RuntimeCollisionPrefixQuiescenceToken excluded = default)
{
state = null;
foreach (CollisionPrefixQuiescence candidate
in _collisionPrefixQuiescence.Values)
{
if (excluded.IsValid && candidate.Token == excluded)
continue;
if (ResultTouchesPrefix(
result,
candidate.Token.LandblockPrefix)
&& (state is null
|| candidate.Token.OperationId
< state.Token.OperationId))
{
state = candidate;
}
}
return state is not null;
}
private void TrackQuiescenceWithdrawal(
Operation operation,
in RuntimePlacementProjectionSnapshot snapshot)
{
if (snapshot.Kind is not RuntimePlacementProjectionKind.Withdraw
|| !_collisionPrefixQuiescence.TryGetValue(
operation.CollisionPrefix,
out CollisionPrefixQuiescence? state)
|| snapshot.Token.CollisionGeneration
!= state.Token.CollisionGeneration)
{
return;
}
state.PendingWithdrawals[snapshot.Token.Sequence] = snapshot.Token;
state.RetainedWithdrawals.Add(snapshot.Token);
state.PermissionIssued = false;
}
private void TrackQuiescenceRestorePlacement(
Operation operation,
in RuntimePlacementProjectionSnapshot snapshot)
{
if (snapshot.Kind is not RuntimePlacementProjectionKind.Place
|| !_collisionPrefixQuiescence.TryGetValue(
operation.CollisionPrefix,
out CollisionPrefixQuiescence? state)
|| !state.ReleaseInProgress
|| !state.ReleaseGenerationReady)
{
return;
}
state.PendingRestorePlacements[snapshot.Token.Sequence] =
snapshot.Token;
}
private void RetireQuiescenceProjectionSequence(ulong sequence)
{
foreach (CollisionPrefixQuiescence state
in _collisionPrefixQuiescence.Values)
{
if (state.PendingWithdrawals.TryGetValue(
sequence,
out _))
{
state.PendingWithdrawals.Remove(sequence);
state.PermissionIssued = false;
return;
}
if (state.PendingRestorePlacements.Remove(sequence))
return;
}
}
private void RemoveRetiredQuiescenceWithdrawals(
CollisionPrefixQuiescence state)
{
if (state.PendingWithdrawals.Count == 0)
return;
ulong[] stale = state.PendingWithdrawals
.Where(pair => !_pendingProjection.ContainsKey(pair.Key))
.Select(pair => pair.Key)
.ToArray();
for (int index = 0; index < stale.Length; index++)
state.PendingWithdrawals.Remove(stale[index]);
}
private void RebindQuiescedDeferredOperations(
in RuntimeCollisionPrefixQuiescenceToken token,
ulong successorGeneration,
bool ready,
bool releaseUnavailable = false)
{
// Round 3: snapshot (Key, Token) PAIRS, not Operation references.
// This loop's own RetryDeferred call below can reenter this class
// (CommitCanonical's ground-edge callbacks, or an arbitrary
// collision-report observer reentrantly calling Begin/Cancel) and
// retire-then-rent (LIFO) a LATER array entry's physical instance
// for a brand-new operation before this loop ever reaches it - a
// stale `Operation` reference captured once at the top (the
// pre-round-3 `.ToArray()` shape) would then silently read/mutate
// the wrong logical operation. Re-resolving by captured Token at
// the top of every iteration (before touching any field) detects
// that instead.
var snapshot =
new List<(RuntimeEntityKey Key, RuntimeEntityPlacementToken Token)>(
_operations.Count);
foreach (Operation existing in _operations.Values)
snapshot.Add((existing.Key, existing.Token));
foreach ((RuntimeEntityKey key, RuntimeEntityPlacementToken capturedToken)
in snapshot)
{
if (!IsCurrentByToken(key, capturedToken, out Operation? operation))
continue;
bool unavailableAfterReadyCommit = ready
&& operation.CollisionQuiescenceHeld
&& operation.CollisionGeneration == 0UL
&& operation.CollisionPrefix == token.LandblockPrefix;
if (!operation.WakeableLostCell
|| !operation.CollisionQuiescenceHeld
|| operation.CollisionPrefix != token.LandblockPrefix
|| (operation.CollisionGeneration
!= token.CollisionGeneration
&& !unavailableAfterReadyCommit))
{
continue;
}
UnindexDeferred(operation);
ulong reboundGeneration = releaseUnavailable
|| unavailableAfterReadyCommit
? 0UL
: successorGeneration;
operation.CollisionGeneration = reboundGeneration;
operation.CollisionGenerationReady = ready
&& reboundGeneration != 0UL;
if (releaseUnavailable || unavailableAfterReadyCommit)
{
operation.CollisionQuiescenceHeld = false;
operation.Stage = operation.RequiresPreparation
? RuntimeEntityPlacementStage.AwaitingPreparation
: RuntimeEntityPlacementStage.AwaitingCell;
}
if (reboundGeneration != 0UL)
IndexDeferred(operation);
else
IndexUnboundDeferred(operation);
if (operation.CollisionGenerationReady
&& operation.WithdrawalAcknowledged)
{
RetryDeferred(operation);
}
}
}
private bool HasQuiescedDeferredOperations(uint prefix)
{
foreach (Operation operation in _operations.Values)
{
if (operation.WakeableLostCell
&& operation.CollisionQuiescenceHeld
&& operation.CollisionPrefix == prefix)
{
return true;
}
}
return false;
}
internal void BeginCollisionGeneration(uint landblockId, ulong generation)
{
EnsureNotDisposed();
if (generation == 0UL)
throw new ArgumentOutOfRangeException(nameof(generation));
uint prefix = landblockId & 0xFFFF0000u;
for (int index = 0; index < _unboundDeferredCellOrder.Count;)
{
UnboundCellKey unboundKey = _unboundDeferredCellOrder[index];
if (unboundKey.CollisionPrefix != prefix
|| !_unboundDeferredByCell.Remove(
unboundKey,
out List<RuntimeEntityKey>? retained))
{
index++;
continue;
}
_unboundDeferredCellOrder.RemoveAt(index);
var bucket = new CellGenerationKey(
unboundKey.CellId,
unboundKey.CollisionPrefix,
generation);
var rebound = new List<RuntimeEntityKey>(retained.Count);
for (int entityIndex = 0;
entityIndex < retained.Count;
entityIndex++)
{
RuntimeEntityKey entity = retained[entityIndex];
if (_operations.TryGetValue(entity, out Operation? operation)
&& operation.WakeableLostCell
&& operation.ExactCellId == unboundKey.CellId
&& operation.CollisionPrefix == prefix
&& operation.CollisionGeneration == 0UL)
{
operation.CollisionGeneration = generation;
rebound.Add(entity);
}
}
if (rebound.Count != 0)
{
if (_deferredByCellGeneration.TryGetValue(
bucket,
out List<RuntimeEntityKey>? futureBound))
{
// The unbound survivors entered lost residence before
// entities indexed directly into this future generation.
// Preserve both append orders while restoring that age.
var merged = new List<RuntimeEntityKey>(
rebound.Count + futureBound.Count);
merged.AddRange(rebound);
merged.AddRange(futureBound);
_deferredByCellGeneration[bucket] = merged;
}
else
{
_deferredByCellGeneration.Add(bucket, rebound);
_deferredBucketOrder.Add(bucket);
}
}
}
foreach (Operation operation in _operations.Values)
{
if (!operation.WakeableLostCell
|| operation.CollisionGeneration != 0UL
|| operation.CollisionPrefix != prefix)
{
continue;
}
operation.CollisionGeneration = generation;
IndexDeferred(operation);
}
}
internal void CancelCollisionGeneration(uint landblockId, ulong generation)
{
EnsureNotDisposed();
if (_deferredBucketOrder.Count == 0)
return;
uint prefix = landblockId & 0xFFFF0000u;
CellGenerationKey[] matching = _deferredBucketOrder
.Where(key => key.CollisionGeneration == generation
&& key.CollisionPrefix == prefix)
.ToArray();
for (int index = 0; index < matching.Length; index++)
{
UnbindDeferredBucket(matching[index]);
}
}
internal void CommitCollisionGeneration(
uint landblockId,
ulong generation,
bool ready)
{
EnsureNotDisposed();
if (!ready || _deferredBucketOrder.Count == 0)
return;
uint prefix = landblockId & 0xFFFF0000u;
var cells = new List<CellGenerationKey>();
for (int index = 0; index < _deferredBucketOrder.Count; index++)
{
CellGenerationKey key = _deferredBucketOrder[index];
if (key.CollisionGeneration == generation
&& key.CollisionPrefix == prefix)
{
cells.Add(key);
}
}
foreach (CellGenerationKey cell in cells)
{
if (!_deferredByCellGeneration.TryGetValue(
cell,
out List<RuntimeEntityKey>? indexed))
{
continue;
}
RuntimeEntityKey[] exact = indexed.ToArray();
if (!_physics.Engine.IsSpawnCellReady(cell.CellId))
{
UnbindDeferredBucket(cell);
continue;
}
RemoveDeferredBucket(cell);
// Round 3 audit: safe - `exact` snapshots KEYS (RuntimeEntityKey
// values), never Operation references, so nothing here can go
// stale the way a snapshotted-reference loop
// (RebindQuiescedDeferredOperations, before its round-3 fix)
// could. Every iteration re-resolves `operation` via a fresh
// `_operations.TryGetValue` and re-validates the exact
// WakeableLostCell/ExactCellId/CollisionPrefix/
// CollisionGeneration shape before acting - a reentrant
// cancel-then-begin from an earlier iteration's RetryDeferred
// call (itself converted to IsCurrentByToken) is either not
// found at all or correctly rejected by this shape check for
// any later iteration touching the same or a different entity.
foreach (RuntimeEntityKey entity in exact)
{
if (!_operations.TryGetValue(
entity,
out Operation? operation)
|| !operation.WakeableLostCell
|| operation.ExactCellId != cell.CellId
|| operation.CollisionPrefix != prefix
|| operation.CollisionGeneration != generation)
{
continue;
}
operation.CollisionGenerationReady = true;
if (operation.WithdrawalAcknowledged)
RetryDeferred(operation);
}
}
}
public void Dispose()
{
if (_disposed)
return;
ClearOwnedState();
_events = null;
_disposed = true;
}
private void ClearOwnedState()
{
_operations.Clear();
_deferredByCellGeneration.Clear();
_deferredBucketOrder.Clear();
_unboundDeferredByCell.Clear();
_unboundDeferredCellOrder.Clear();
_lostDeadlines.Clear();
_lostDeadlineNodes.Clear();
_lostDeadlineNodeIndex.Clear();
_preparedMovers.Clear();
_moverPreparationAuthorities.Clear();
_placementCompletionWatches.Clear();
_acknowledgedPlacementCompletions.Clear();
_collisionPrefixQuiescence.Clear();
_pendingProjection.Clear();
_expiredLostCells.Clear();
_expiredLostCellNodes.Clear();
// F2: the C2 object pool retains full previous-generation entity
// graphs (Record -> Snapshot/PhysicsBody/clock/host references)
// through every pooled instance until it is rented and reset. Both
// callers of this method (ResetSession and Dispose) end the session
// those graphs belonged to, so nothing can still be mid-rent across
// this clear - unlike RetireOperationToPool/RentOperation, which
// must worry about a reentrant frame still executing inside a
// ground-edge callback, a session clear cannot be reentered from
// inside itself.
_operationPool.Clear();
}
/// <summary>
/// C3c-F3: the quiescence-override pair is nullable — null means "no
/// quiescence holds this park", a present value means "parked under that
/// quiescence's exact prefix/generation". Nullable uint is the chosen
/// has-prefix representation for the whole chain because the previous
/// 0-sentinel collided with landblock (0,0)'s legitimate prefix
/// 0x00000000: a corner-landblock quiescence override read as "absent",
/// so <see cref="Operation.CollisionQuiescenceHeld"/> derived false and
/// the parked operation skipped the QuiescenceHeld stage entirely.
///
/// <para>
/// <paramref name="restorableOnCancel"/> is the caller's HALF of the
/// opt-in into <see cref="Forget"/>'s rollback: "this park is a
/// momentarily-unavailable destination, not a world going away". It is
/// true for the plain "destination is not placeable right now" park and
/// for <see cref="SubmitPreparedPlacementCore"/>'s two collision-prefix
/// QUIESCENCE parks; it is false for a retirement park
/// (<see cref="ParkCollisionResidents"/>), which withdraws the entity
/// precisely because its own world is being retired.
/// </para>
///
/// <para>
/// The OTHER half is decided here, after <see cref="PhysicsBody.SnapToCell"/>
/// has committed the parked pose, and it is the only test AP-136's stated
/// reason actually needs: the rollback restores canonical residency at
/// <c>body.CellPosition.ObjCellId</c>
/// (<see cref="RestoreParkWithdrawal"/>), so it is safe exactly when THAT
/// cell's prefix is not itself quiescing
/// (<see cref="IsCollisionPrefixQuiescing"/> — the pre-flight's own
/// predicate). Deciding it here rather than at the call sites is what
/// makes the claim true rather than approximately true, for two
/// independent reasons (C4 route 4b-2, round-3 correction A1):
/// </para>
/// <list type="number">
/// <item><description>A blocking-quiescence token is the MINIMUM-
/// <c>OperationId</c> match, not the only live one —
/// <c>_collisionPrefixQuiescence</c> is a per-prefix dictionary and a
/// streaming recentre opens one per landblock mutation. Comparing the
/// restore cell against that single token proves nothing about the
/// others, so it could answer "safe" for a destination that is itself
/// retiring. (Round 4 bounded the reach rather than asserting it. On a
/// FIRST submit it is unreachable, and provably so: the pre-engine check
/// can match at most the request's own prefix and its
/// <c>CurrentCellId</c>, which are the same prefix there, so its token IS
/// the restore cell's; and the post-sweep check runs only once the
/// pre-engine check has proven the destination prefix is NOT quiescing,
/// so its token can never be. What is NOT ruled out is a RETAINED
/// operation whose <c>CurrentCellId</c> has since been moved to another
/// landblock by a non-Position rebucket — see the arm's own scoping
/// below — with concurrent quiescences on both prefixes. That shape is
/// unmeasured, and it is exactly the shape the far arm's pre-flight
/// refuses on the only route that has one. Testing the live map here
/// makes the decision free of the question rather than dependent on
/// it.)</description></item>
/// <item><description>The restore cell is not the caller's
/// <c>result.CellId</c>. <see cref="PhysicsBody.StageDormantCellFrame"/>
/// runs <see cref="AcDream.Core.Physics.LandDefs.AdjustToOutside"/> for
/// any outdoor cell, whose own contract says the re-derived id may belong
/// to a NEIGHBOUR landblock. Only the post-snap value is the value the
/// rollback will use. This is the reachable half, and it is pinned by
/// <c>QuiescingOwnPrefix_SeamCrossingParkIsRestoredAtTheReDerivedNeighbourCell</c>:
/// a wire (cell, position) pair whose position lies past its own named
/// block's seam is exactly the pair #107's re-derivation exists to
/// distrust, and the entity is stranded without this.</description></item>
/// </list>
///
/// <para>
/// AP-136's blanket "no quiescence park is restorable" was over-broad
/// because <see cref="TryGetBlockingQuiescence"/> also fires on prefixes a
/// placement merely TOUCHES — chiefly any <c>QueriedCellIds</c> entry
/// (a NEIGHBOUR the sweep reached across a seam;
/// <c>CellTransit.AddOutsideCell</c> has no same-block filter), and the
/// request's <c>CurrentCellId</c>.
/// </para>
///
/// <para>
/// <b>What <c>CurrentCellId</c> names, scoped to the submit (round 4,
/// D5).</b> On the FIRST submit of an accepted Position it names the
/// DESTINATION, not a departed source: both accepted-Position callers
/// commit the accepted wire cell to <c>record.FullCellId</c> ahead of the
/// drive (route 2 through the merge, the graphical remote path through
/// <c>LiveEntityRuntime.RebucketLiveEntity</c>), and this request field is
/// read from that same record field. It is NOT invariant for a RETAINED
/// operation: both drives re-submit from their own cadence pump with no
/// fresh merge in between (<c>SubmitAndResolve</c> re-reads the record as
/// it then stands). The surviving non-Position rebucket writers (C4
/// route 4b-3 deleted the third, <c>RemoteTeleportController</c>'s
/// rollback) are the projection materializer
/// (<c>DatLiveEntityProjectionMaterializer</c>) and the equipped-child
/// renderer (<c>EquippedChildRenderController.TickChild</c>).
/// <c>RuntimeRemotePlacementDriveController</c>'s
/// <c>CanAttemptDestination</c> doc states this correctly; treat the arm
/// as live, not as dead code.
/// </para>
///
/// <para>
/// In those touched-prefix
/// shapes the retiring prefix is not the one residency is restored into,
/// so the rollback pins nothing, while leaving the park non-restorable
/// stranded the entity (<c>InWorld = false</c>, clock suspended,
/// <c>FullCellId = 0</c>) with the only operation able to wake it
/// destroyed by its own next accepted Position.
/// </para>
/// </summary>
private RuntimeSetPositionOutcome ParkDeferred(
Operation operation,
in PhysicsSetPositionResult result,
bool publishImmediately = true,
ulong? collisionGenerationOverride = null,
uint? collisionPrefixOverride = null,
bool restorableOnCancel = false)
{
PhysicsBody body = operation.Body!;
// Read BEFORE the withdrawal below clears them - and before the
// SnapToCell, which sets InWorld = true itself. Only the WITHDRAWAL
// is captured, never the pose: the SnapToCell deliberately commits
// the destination pose and that commit stands, exactly as retail's
// store_position @0x00515CE2 commits it on the lost-cell branch and
// never un-commits it.
bool priorInWorld = body.InWorld;
TransientStateFlags priorTransientState = body.TransientState;
bool priorClockActive = operation.Record.ObjectClock.IsActive;
body.Orientation = result.Orientation;
body.SnapToCell(
result.CellId,
result.Position,
result.CellLocalPosition);
// The restorable decision reads the POST-snap cell, because that is
// the cell RestoreParkWithdrawal will restore residency into - see
// this method's own doc for why the caller's result.CellId and a
// single blocking-quiescence token are both the wrong inputs.
//
// C3c-F3 sentinel guard (round 4, N1): cell id 0 is
// AdjustToOutside's map-edge FAILURE sentinel
// (LandDefs.AdjustToOutside's `cellId = 0u; return false` tail), and
// prefix 0x00000000 is simultaneously the LEGITIMATE corner landblock
// (0,0) - which is exactly why BeginCollisionPrefixQuiescence rejects
// landblock id 0 rather than treating it as "absent". So the
// quiescence map must never be consulted with the sentinel: a corner
// landblock quiescing would otherwise make every map-edge failure
// read as "restoring into a retiring prefix". A sentinel cell has no
// residency to re-admit anywhere - RestoreParkWithdrawal applies the
// same `!= 0u` test before it restores residency at all - so the
// decision falls back to the caller's half alone.
uint parkedCellId = body.CellPosition.ObjCellId;
operation.ParkWithdrawal = new ParkWithdrawal(
Captured: restorableOnCancel
&& (parkedCellId == 0u
|| !IsCollisionPrefixQuiescing(parkedCellId)),
InWorld: priorInWorld,
TransientState: priorTransientState,
ClockActive: priorClockActive);
// Issue #309's connected-gate confirmation signal. Off by default;
// one line per park, nothing at all for a committing placement.
if (PhysicsDiagnostics.ProbeParkEnabled)
{
string parkCause = collisionPrefixOverride is uint blockedPrefix
? FormattableString.Invariant($"quiescence:0x{blockedPrefix:X8}")
: "unplaceable";
Console.WriteLine(FormattableString.Invariant(
$"[park] guid=0x{operation.Record.ServerGuid:X8} cause={parkCause} resultCell=0x{result.CellId:X8} restoreCell=0x{parkedCellId:X8} eligible={restorableOnCancel} captured={operation.ParkWithdrawal.Captured}"));
}
body.InWorld = false;
body.TransientState &= ~TransientStateFlags.Active;
if (operation.Record.RemoteMotion is IRuntimeRemotePlacement remote)
{
remote.LastServerPosition = result.Position;
// Remote-motion stale-age bookkeeping is in Unix-time seconds
// (RuntimeRemotePhysicsUpdater and the retained App network
// updater both consume this field in that clock domain). The
// placement command's GameTime is the instance simulation clock
// used only by PhysicsBody.LastUpdateTime. Mixing the two after
// a deferred wake makes a fresh server velocity look decades old.
remote.LastServerPositionTime = _physics.UtcNowSeconds;
remote.LastShadowSyncPosition = Vector3.Zero;
remote.LastShadowSyncOrientation = Quaternion.Zero;
}
WithdrawCanonical(operation.Record);
_entities.SuspendObjectClock(operation.Record);
operation.SpatialAuthorityVersion =
operation.Record.SpatialAuthorityVersion;
_entities.AdvancePlacementCommit(operation.Record);
operation.PlacementCommitVersion =
operation.Record.PlacementCommitVersion;
operation.ExactCellId = result.CellId;
operation.WakeableLostCell = true;
operation.EnteringWorldFromCelllessResidence = true;
ArmLostFamilyDeadlines(operation);
operation.CollisionGeneration = collisionGenerationOverride
?? _physics.ExpectedCollisionGeneration(result.CellId);
operation.CollisionPrefix = collisionPrefixOverride
?? result.CellId & 0xFFFF0000u;
operation.CollisionQuiescenceHeld = collisionPrefixOverride.HasValue;
operation.Command = operation.Command with
{
Physics = operation.Command.Physics with
{
Position = result.Position,
Orientation = result.Orientation,
CellId = result.CellId,
CellLocalPosition = result.CellLocalPosition,
CurrentCellId = null,
},
};
if (_moverPreparationAuthorities.ContainsKey(operation.Key))
{
RebindPreparedCommand(operation);
}
else
{
_moverPreparationAuthorities[operation.Key] =
CapturePreparationAuthority(
operation,
ServerPositionFrom(
result.CellId,
result.CellLocalPosition,
result.Orientation),
prepared: true,
operation.Command);
}
IndexDeferred(operation);
operation.Stage = operation.RequiresPreparation
? RuntimeEntityPlacementStage.AwaitingPreparation
: operation.CollisionQuiescenceHeld
? RuntimeEntityPlacementStage.QuiescenceHeld
: RuntimeEntityPlacementStage.AwaitingWithdrawalAcknowledgement;
RuntimePlacementProjectionToken projection = PublishProjection(
operation,
RuntimePlacementProjectionKind.Withdraw,
result,
publishImmediately);
return Outcome(
RuntimeSetPositionStatus.DeferredCell,
result,
projection);
}
/// <summary>
/// Round 3 audit: the entry <see cref="IsCurrent(Operation)"/> check
/// below is safe (not converted to <see cref="IsCurrentByToken"/>)
/// because every one of this method's 4 call sites passes an
/// <paramref name="operation"/> reference obtained via a fresh
/// <c>_operations</c> lookup (or an <see cref="IsCurrentByToken"/> call)
/// with NOTHING reentrant executed between that lookup and this call -
/// <c>AcknowledgeProjection</c> and <c>SubmitPreparedPlacementCore</c>
/// call it immediately after their own entry validation, the
/// exact-cell-ready loop re-resolves by key every iteration and rejects
/// a repurposed operation via its WakeableLostCell/ExactCellId/
/// CollisionPrefix/CollisionGeneration shape, and
/// <c>RebindQuiescedDeferredOperations</c> was converted in round 3 to
/// call <see cref="IsCurrentByToken"/> immediately before this method.
/// </summary>
private void RetryDeferred(Operation operation)
{
// The local-player activation lease owns its dormant body/controller
// and must re-enter through the same sealed evaluation/commit path.
// A collision-generation wake only marks readiness; it must never
// bypass that path through the ordinary remote CommitCanonical tail.
if (operation.DormantLocalActivation)
return;
if (!IsCurrent(operation)
|| !operation.WakeableLostCell
|| operation.RequiresPreparation
|| operation.Expired
|| !operation.WithdrawalAcknowledged
|| !operation.CollisionGenerationReady
|| operation.ProjectionSequence != 0UL)
{
return;
}
if (!IsDeferredWakePreparationCurrent(operation))
return;
// F1: hoisted before the ground-edge-callback-bearing
// CommitCanonical call below (same reasoning as
// SubmitPreparedPlacementCore's `token` parameter) - lets the
// post-CommitCanonical check confirm THIS operation is still
// canonical without trusting `operation`'s live fields, which a
// reentrant cancel-then-begin during the callback may have already
// repurposed.
RuntimeEntityPlacementToken operationToken = operation.Token;
RuntimeCollisionPrefixQuiescenceToken restoringQuiescence = default;
if (TryGetBlockingQuiescence(
operation.Command.Physics,
out CollisionPrefixQuiescence? blocking))
{
if (blocking!.ReleaseInProgress
&& blocking.ReleaseGenerationReady
&& operation.CollisionQuiescenceHeld
&& operation.CollisionPrefix
== blocking.Token.LandblockPrefix)
{
// The selected collision generation is active. Keep the
// admission barrier closed while this exact parked operation
// restores and its Place receipt drains.
restoringQuiescence = blocking.Token;
}
else
{
UnindexDeferred(operation);
operation.CollisionPrefix = blocking.Token.LandblockPrefix;
operation.CollisionGeneration = blocking.Token.CollisionGeneration;
operation.CollisionGenerationReady = false;
operation.CollisionQuiescenceHeld = true;
operation.Stage = RuntimeEntityPlacementStage.QuiescenceHeld;
IndexDeferred(operation);
return;
}
}
UnindexDeferred(operation);
operation.CollisionQuiescenceHeld = false;
operation.Command = operation.Command with
{
GameTime = _physics.PlacementSimulationTime(
operation.Command.GameTime),
};
RebindPreparedCommand(operation);
PhysicsSetPositionResult result;
if (IsStructurallyValid(operation.Command.Physics))
{
_collisionCallbackContexts.Push(new CollisionCallbackContext(
operation.Record,
operation.PositionAuthorityVersion,
operation.SpatialAuthorityVersion,
operation.SourceVelocityAuthorityVersion,
operation.Command.GameTime,
operation.PreviousContact,
operation.PreviousOnWalkable));
try
{
result = _physics.Engine.SetPosition(
operation.Command.Physics,
_handleSetPositionCollisionsCallback);
}
finally
{
_collisionCallbackContexts.Pop();
}
}
else
{
result = InvalidResult(operation.Command.Physics);
}
operation.CollisionGenerationReady = false;
// Round 3: same reentrancy hazard as SubmitPreparedPlacementCore's
// post-SetPosition checks - the collision-report callback above can
// reach an arbitrary observer that calls back into Begin/Cancel and
// retires-then-rents (LIFO) this exact instance. `operationToken`
// was hoisted before the SetPosition call. (`operation` is a plain
// non-nullable parameter here, not a nullable local like
// SubmitPreparedPlacementCore's - route through a temporary so the
// NotNullWhen-proven reference can be assigned back to it.)
if (!IsCurrentByToken(
operationToken.Entity,
operationToken,
out Operation? refreshed))
{
return;
}
operation = refreshed;
if (result.IsSuccessful
&& TryGetBlockingQuiescence(
result,
out CollisionPrefixQuiescence? queriedQuiescence,
restoringQuiescence))
{
PhysicsSetPositionResult held = result with
{
Residence = PhysicsResidenceDisposition.DeferredCell,
};
operation.Result = held;
operation.ExactCellId = held.CellId;
operation.CollisionPrefix =
queriedQuiescence!.Token.LandblockPrefix;
operation.CollisionGeneration =
queriedQuiescence.Token.CollisionGeneration;
operation.CollisionQuiescenceHeld = true;
operation.Stage = RuntimeEntityPlacementStage.QuiescenceHeld;
_preparedMovers[operation.Key] = operation.Command.Physics;
IndexDeferred(operation);
return;
}
if (result.IsDeferred)
{
operation.Result = result;
operation.ExactCellId = result.CellId;
_preparedMovers[operation.Key] = operation.Command.Physics;
operation.CollisionPrefix = result.CellId & 0xFFFF0000u;
operation.CollisionGeneration = _physics
.ExpectedCollisionGeneration(result.CellId);
IndexDeferred(operation);
return;
}
if (!result.IsSuccessful)
{
if (result.Error is PhysicsSetPositionError.InvalidArguments)
{
operation.RequiresPreparation = true;
operation.Stage = RuntimeEntityPlacementStage
.AwaitingPreparation;
operation.CollisionPrefix = operation.ExactCellId
& 0xFFFF0000u;
operation.CollisionGeneration = _physics
.ExpectedCollisionGeneration(operation.ExactCellId);
IndexDeferred(operation);
}
else
{
operation.Stage = RuntimeEntityPlacementStage.AwaitingCell;
operation.CollisionPrefix = operation.ExactCellId
& 0xFFFF0000u;
operation.CollisionGeneration = _physics
.ExpectedCollisionGeneration(operation.ExactCellId);
IndexDeferred(operation);
}
return;
}
// Round 3: nothing reentrant runs between here and the previous
// token check (only quiescence/deferred bookkeeping branches, all
// of which return before reaching this point) - re-verifying by
// token again anyway keeps this in lockstep with the same pattern
// used everywhere else in this method, and `operation` is already
// the freshly-verified reference from that check.
if (!IsCurrentByToken(
operationToken.Entity,
operationToken,
out Operation? stillCurrent))
{
return;
}
operation = stillCurrent;
_preparedMovers[operation.Key] = operation.Command.Physics;
if (!CommitCanonical(operation, result))
{
// Round 3: CommitCanonical's own ground-edge callback and
// collision-report dispatch can reenter this class, so
// `operation` may already be stale here even though it was
// just re-verified before the call.
PublishCancellation(CancelCore(operationToken.Entity, operationToken));
return;
}
// F1: CommitCanonical can succeed (fully applying the physical
// settle) for an operation a reentrant ground-edge callback has
// since displaced - retail lets that physical commit land
// regardless (see
// ReentrantGroundEdgePlacementCannotBeCancelledByDisplacedOperation).
// But if THIS operation is no longer canonical, publishing a Place
// projection for it is wrong - nothing will ever acknowledge it
// again, and `operation`'s own fields may already reflect whatever
// displaced it. `operationToken` (hoisted before the callback) is
// compared against a fresh lookup rather than trusting `operation`
// itself.
if (!_operations.TryGetValue(
operationToken.Entity,
out Operation? stillOwns)
|| stillOwns.Token != operationToken)
{
return;
}
operation.Stage = RuntimeEntityPlacementStage
.AwaitingCommitAcknowledgement;
_ = PublishProjection(
operation,
RuntimePlacementProjectionKind.Place,
result);
}
private bool CommitCanonical(
Operation operation,
in PhysicsSetPositionResult result)
{
// Round 3 audit: safe - this is the function's own entry
// validation; every caller (SubmitPreparedPlacementCore,
// RetryDeferred) passes an `operation` obtained via
// IsCurrentByToken/IsCurrent immediately before calling
// CommitCanonical, with nothing reentrant in between.
if (!result.IsCommitted || !IsCurrent(operation))
return false;
RuntimeEntityRecord record = operation.Record;
PhysicsBody body = operation.Body!;
// F1: every operation-derived scalar this method still needs AFTER
// invoking the ground-edge HitGround/LeaveGround callbacks below is
// captured into a local HERE, before those callbacks run - retail's
// own savedTransientState pattern (pseudo-C 283952 stacks the exact
// same bits before handle_all_collisions). A synchronous ground-edge
// chain that cancels then begins (or begins twice) for the SAME
// entity can retire this exact `operation` instance to the pool and
// rent it right back out (LIFO) for a DIFFERENT logical operation -
// reading `operation`'s live fields after that point would silently
// observe the wrong operation's state. The SETTLE below (contact
// transition, collision reports, shadow sync, and the currency
// checks gating them) deliberately does NOT hoist/compare the
// operation's Token: retail intentionally lets an in-flight
// ground-edge commit for a DISPLACED operation still complete (see
// IsCanonicalPlacementCommitCurrent's doc comment and
// ReentrantGroundEdgePlacementCannotBeCancelledByDisplacedOperation).
// `operationToken` is hoisted anyway - not for the settle, but for
// the Runtime-owned BOOKKEEPING writes at the very end of this
// method (Round 3 addendum A1), which must land on the operation
// THIS frame actually started with, never a nested cancel-then-
// begin's freshly-begun operation that happens to share the key and
// pass the record-state checks (a bare Begin never advances
// PlacementCommitVersion, so the settle-layer checks cannot detect
// that repurposing - only Token identity can).
RuntimeEntityPlacementToken operationToken = operation.Token;
RuntimeEntityKey operationKey = operation.Key;
ulong positionAuthorityVersion = operation.PositionAuthorityVersion;
ulong sourceVelocityAuthorityVersion =
operation.SourceVelocityAuthorityVersion;
double commandGameTime = operation.Command.GameTime;
bool previousContact = operation.PreviousContact;
bool previousOnWalkable = operation.PreviousOnWalkable;
float shadowWorldOffsetX = operation.Command.ShadowWorldOffsetX;
float shadowWorldOffsetY = operation.Command.ShadowWorldOffsetY;
body.Orientation = result.Orientation;
body.SnapToCell(
result.CellId,
result.Position,
result.CellLocalPosition);
bool isStatic = (record.FinalPhysicsState & PhysicsStateFlags.Static) != 0;
if (operation.EnteringWorldFromCelllessResidence)
{
body.LastUpdateTime = commandGameTime;
_entities.ResetObjectClockForEnterWorld(record, isStatic);
}
if (operation.EnteringWorldFromCelllessResidence && !isStatic)
body.TransientState |= TransientStateFlags.Active;
body.ContactPlaneValid = result.InContact;
body.ContactPlane = result.ContactPlane;
body.ContactPlaneCellId = result.ContactPlaneCellId;
body.ContactPlaneIsWater = result.ContactPlaneIsWater;
if (result.InContact)
body.GroundNormal = result.ContactPlane.Normal;
body.SlidingNormal = result.SlidingNormal;
if (result.SlidingNormalValid)
body.TransientState |= TransientStateFlags.Sliding;
else
body.TransientState &= ~TransientStateFlags.Sliding;
IRuntimeRemotePlacement? remote =
record.RemoteMotion as IRuntimeRemotePlacement;
if (record.FullCellId != result.CellId)
{
_entities.SetFullCell(
record,
result.CellId,
(result.CellId & 0xFFFF0000u) | 0xFFFFu);
}
operation.SpatialAuthorityVersion = record.SpatialAuthorityVersion;
ulong spatialAuthorityVersion = record.SpatialAuthorityVersion;
_entities.AdvancePlacementCommit(record);
operation.PlacementCommitVersion = record.PlacementCommitVersion;
ulong canonicalCommitVersion = record.PlacementCommitVersion;
if (remote is not null)
{
remote.CellId = result.CellId;
remote.LastServerPosition = result.Position;
remote.LastServerPositionTime = _physics.UtcNowSeconds;
remote.LastShadowSyncPosition = result.Position;
remote.LastShadowSyncOrientation = result.Orientation;
}
uint committedCellId = result.CellId;
bool collidedWithEnvironment = result.CollidedWithEnvironment;
System.Collections.Immutable.ImmutableArray<uint> collidedObjectIds =
result.CollidedObjectIds;
if (!IsCanonicalPlacementCommitCurrent(
positionAuthorityVersion,
spatialAuthorityVersion,
record,
body,
canonicalCommitVersion,
committedCellId,
requireSpatialRoot: false))
return false;
bool contactCommitted;
if (remote is null)
{
contactCommitted = PhysicsObjUpdate.CommitSetPositionContactTransition(
body,
result.InContact,
result.OnWalkable,
previousOnWalkable);
}
else
{
var guard = new ContactCommitGuard(
this,
positionAuthorityVersion,
spatialAuthorityVersion,
record,
body,
canonicalCommitVersion,
committedCellId);
contactCommitted = PhysicsObjUpdate.CommitSetPositionContactTransition(
body,
result.InContact,
result.OnWalkable,
previousOnWalkable,
remote.HitGround,
remote.LeaveGround,
guard.IsCurrent);
}
if (!contactCommitted
|| !IsCanonicalPlacementCommitCurrent(
positionAuthorityVersion,
spatialAuthorityVersion,
record,
body,
canonicalCommitVersion,
committedCellId,
requireSpatialRoot: false))
{
return false;
}
bool reportingCurrent = !IsCollisionReportingEligible(record, body)
|| _physics.HandleSetPositionCollisionReports(
record,
positionAuthorityVersion,
spatialAuthorityVersion,
commandGameTime,
previousContact,
previousOnWalkable,
collidedWithEnvironment,
collidedObjectIds,
out _);
if (!reportingCurrent
|| !IsCanonicalPlacementCommitCurrent(
positionAuthorityVersion,
spatialAuthorityVersion,
record,
body,
canonicalCommitVersion,
committedCellId,
requireSpatialRoot: false))
return false;
body.FramesStationaryFall = result.FramesStationaryFall;
if (IsVelocityCurrent(sourceVelocityAuthorityVersion, record))
{
PhysicsObjUpdate.HandleAllCollisions(
body,
result.CollisionNormalValid,
result.CollisionNormal,
previousContact,
previousOnWalkable,
body.OnWalkable);
}
body.TransientState &= ~(TransientStateFlags.StationaryFall
| TransientStateFlags.StationaryStop
| TransientStateFlags.StationaryStuck);
body.TransientState |= result.FramesStationaryFall switch
{
1 => TransientStateFlags.StationaryFall,
2 => TransientStateFlags.StationaryStop,
3 => TransientStateFlags.StationaryStuck,
_ => TransientStateFlags.None,
};
if (remote is not null)
remote.Airborne = !body.OnWalkable;
if (!IsCanonicalPlacementCommitCurrent(
positionAuthorityVersion,
spatialAuthorityVersion,
record,
body,
canonicalCommitVersion,
committedCellId,
requireSpatialRoot: false))
return false;
_physics.Engine.ShadowObjects.CommitSetPosition(
operationKey.LocalEntityId,
result.Position,
result.Orientation,
result.CellId,
shadowWorldOffsetX,
shadowWorldOffsetY,
result.ShadowAction,
result.CrossCellIds);
_physics.AcknowledgeSpatialProjection(record, spatial: true);
// A1 (round 3 addendum): unlike the settle above, these are
// Runtime's OWN bookkeeping for which logical operation this settle
// belongs to - a nested cancel-then-begin (reachable via either the
// ground-edge callbacks above OR an arbitrary collision-report
// observer reentrantly calling Begin/Cancel from inside
// HandleSetPositionCollisionReports) can recycle `operation` for a
// brand-new operation that stages at AwaitingPreparation without
// ever advancing PlacementCommitVersion - invisible to the
// record-state checks above. Re-resolve by the token captured
// before any callback ran and only write if it is still the exact
// instance; skipping the writes (rather than failing the whole
// commit) matches retail's already-unconditional physical settle -
// only the ownership bookkeeping is conditional.
if (_operations.TryGetValue(operationKey, out Operation? currentOperation)
&& currentOperation.Token == operationToken)
{
currentOperation.ExactCellId = result.CellId;
currentOperation.Result = result;
currentOperation.WakeableLostCell = false;
currentOperation.EnteringWorldFromCelllessResidence = false;
CancelLostFamilyDeadlines(currentOperation);
}
return IsCanonicalPlacementCommitCurrent(
positionAuthorityVersion,
spatialAuthorityVersion,
record,
body,
canonicalCommitVersion,
committedCellId,
requireSpatialRoot: true);
}
/// <summary>
/// F1: takes the operation's authority versions as explicit VALUES
/// (captured by the caller before invoking the ground-edge HitGround/
/// LeaveGround callbacks) rather than reading them live off an
/// <see cref="Operation"/> reference that a reentrant cancel-then-begin
/// (or begin-twice) chain may have already retired and repurposed for a
/// DIFFERENT logical operation. Deliberately does NOT also compare the
/// operation's Token/identity: retail intentionally lets an in-flight
/// ground-edge commit for a DISPLACED operation still complete (its
/// physical contact-transition/shadow-sync settle even though a newer
/// operation now owns future placement authority for this entity - see
/// ReentrantGroundEdgePlacementCannotBeCancelledByDisplacedOperation).
/// Adding an identity check here would incorrectly abort that commit the
/// moment the entity is displaced, which is exactly the behavior that
/// test pins as wrong. The self-aliasing hazard a Token comparison would
/// otherwise guard against is real, but belongs at the call sites that
/// need "is this SPECIFIC Begin invocation still canonical" (see the
/// local-token comparison at the end of
/// <c>BeginAcceptedPlacementCore</c>), not here.
/// </summary>
private bool IsCanonicalPlacementCommitCurrent(
ulong positionAuthorityVersion,
ulong spatialAuthorityVersion,
RuntimeEntityRecord record,
PhysicsBody body,
ulong placementCommitVersion,
uint fullCellId,
bool requireSpatialRoot) =>
_entities.IsCurrent(record)
&& ReferenceEquals(record.PhysicsBody, body)
&& record.PositionAuthorityVersion == positionAuthorityVersion
&& record.SpatialAuthorityVersion == spatialAuthorityVersion
&& record.PlacementCommitVersion == placementCommitVersion
&& record.FullCellId == fullCellId
&& (!requireSpatialRoot || _physics.IsSpatialRoot(record));
private bool IsCollisionReportingEligible(
RuntimeEntityRecord record,
PhysicsBody body) =>
_entities.IsCurrent(record)
&& ReferenceEquals(record.PhysicsBody, body)
&& body.InWorld
&& (body.State & PhysicsStateFlags.Hidden) == 0;
private void WithdrawCanonical(RuntimeEntityRecord record)
{
_physics.CollisionReports.LeaveWorld(record);
_physics.RemoveSpatialProjection(record);
if (record.Key is { } key)
_physics.Engine.ShadowObjects.Suspend(key.LocalEntityId);
if (record.FullCellId != 0u)
_entities.SetFullCell(record, 0u, 0u);
}
private void LeaveWorldCanonical(RuntimeEntityRecord record)
{
WithdrawCanonical(record);
if (record.PhysicsBody is not { } body)
{
_entities.SuspendObjectClock(record);
_entities.AdvancePlacementCommit(record);
return;
}
body.SnapToCell(
0u,
body.Position,
body.CellPosition.Frame.Origin);
body.InWorld = false;
body.TransientState = TransientStateFlags.None;
body.ContactPlaneValid = false;
body.ContactPlaneCellId = 0u;
body.ContactPlaneIsWater = false;
body.SlidingNormal = Vector3.Zero;
body.FramesStationaryFall = 0;
body.calc_acceleration();
if (record.RemoteMotion is IRuntimeRemotePlacement remote)
remote.CellId = 0u;
_entities.SuspendObjectClock(record);
_entities.AdvancePlacementCommit(record);
}
private RuntimePlacementProjectionToken PublishProjection(
Operation operation,
RuntimePlacementProjectionKind kind,
in PhysicsSetPositionResult result,
bool publishImmediately = true)
{
if (operation.ProjectionSequence != 0UL)
_pendingProjection.Remove(operation.ProjectionSequence);
ulong sequence = checked(++_nextProjectionSequence);
var token = new RuntimePlacementProjectionToken(
sequence,
Revision: 1UL,
operation.Key,
operation.PositionAuthorityVersion,
operation.SpatialAuthorityVersion,
operation.PlacementCommitVersion,
operation.SessionLifetimeVersion,
operation.ExactCellId,
operation.CollisionGeneration,
operation.Command.Portal);
var snapshot = new RuntimePlacementProjectionSnapshot(
token,
kind,
result.Position,
result.Orientation,
result.CellLocalPosition,
result.InContact,
result.OnWalkable);
operation.ProjectionSequence = sequence;
_pendingProjection.Add(sequence, snapshot);
TrackQuiescenceWithdrawal(operation, snapshot);
TrackQuiescenceRestorePlacement(operation, snapshot);
if (publishImmediately)
PublishPlacement(snapshot);
return token;
}
private Operation CreateWithdrawalOperation(
RuntimeEntityRecord record,
RuntimeEntityKey key)
{
PhysicsBody body = record.PhysicsBody
?? throw new InvalidOperationException(
"A withdrawal projection requires the canonical PhysicsBody.");
var physics = new PhysicsSetPositionRequest(
body.Position,
body.Orientation,
body.CellPosition.ObjCellId,
body.CellPosition.Frame.Origin,
ImmutableArray<FlatCollisionSphere>.Empty,
1f,
0f,
0f);
var result = new PhysicsSetPositionResult(
PhysicsSetPositionError.Ok,
PhysicsResidenceDisposition.DeferredCell,
body.Position,
body.Orientation,
body.CellPosition.ObjCellId,
body.CellPosition.Frame.Origin,
CrossCellIds: ImmutableArray<uint>.Empty,
CollidedObjectIds: ImmutableArray<uint>.Empty);
// F4: routed through RentOperation() (rather than a fresh
// `new Operation { ... }`) so every construction flows one path -
// see ResetAllFieldsToDefault's completeness-net doc comment. The
// sole caller (Cancel) always runs CancelCoreDeferred against this
// same key first, so there is no displaced-operation state left to
// read here.
Operation operation = RentOperation();
operation.Record = record;
operation.Body = body;
operation.Token = new RuntimeEntityPlacementToken(
_entities.SessionLifetimeVersion,
key,
record.PositionAuthorityVersion,
checked(++_nextOperationId),
RuntimeEntityPlacementPreparationKind.LegacyDirect);
operation.Key = key;
operation.PositionAuthorityVersion = record.PositionAuthorityVersion;
operation.SessionLifetimeVersion = _entities.SessionLifetimeVersion;
operation.SourceSpatialAuthorityVersion = record.SpatialAuthorityVersion;
operation.SourceVelocityAuthorityVersion = record.VelocityAuthorityVersion;
operation.PreviousContact = body.InContact;
operation.PreviousOnWalkable = body.OnWalkable;
operation.Command = new RuntimeSetPositionCommand(
physics,
RuntimeSetPositionOperationKind.RemoteAuthoritative,
body.LastUpdateTime,
record.VelocityAuthorityVersion,
ShadowWorldOffsetX: 0f,
ShadowWorldOffsetY: 0f);
operation.Result = result;
operation.SpatialAuthorityVersion = record.SpatialAuthorityVersion;
operation.PlacementCommitVersion = record.PlacementCommitVersion;
operation.ExactCellId = result.CellId;
operation.WakeableLostCell = false;
operation.Stage = RuntimeEntityPlacementStage
.AwaitingWithdrawalAcknowledgement;
operation.Kind = RuntimeSetPositionOperationKind.RemoteAuthoritative;
operation.Portal = default;
return operation;
}
/// <summary>
/// Reference-identity currency check. SAFE ONLY when no reentrancy
/// point (a synchronous publish, a collision-report dispatch reaching
/// an arbitrary <c>IRuntimeCollisionReportObserver</c>, or a
/// ground-edge HitGround/LeaveGround callback) has intervened between
/// `operation` being obtained/last verified and this call - every
/// call site is audited and either (a) has no such reentrancy point in
/// between (commented at the call site), or (b) has been converted to
/// <see cref="IsCurrentByToken"/> instead. See
/// <see cref="RetireOperationToPool"/>'s doc comment for why
/// <c>ReferenceEquals</c> becomes a tautology once pooling can hand
/// the SAME physical instance back out for a different logical
/// operation at the same key.
/// </summary>
private bool IsCurrent(Operation operation) =>
_operations.TryGetValue(operation.Key, out Operation? current)
&& ReferenceEquals(current, operation)
&& IsOperationStateConsistent(operation);
/// <summary>
/// Round 3: the consistency half of <see cref="IsCurrent(Operation)"/>,
/// factored out so <see cref="IsCurrentByToken"/> can reuse the exact
/// same checks after establishing identity via Token (safe under
/// pooling) instead of <c>ReferenceEquals</c> (unsafe under pooling -
/// see <see cref="RetireOperationToPool"/>'s doc comment).
/// </summary>
private bool IsOperationStateConsistent(Operation operation) =>
_entities.SessionLifetimeVersion == operation.SessionLifetimeVersion
&& _entities.IsCurrent(operation.Record)
&& operation.Record.Key == operation.Key
&& (operation.Body is null
|| ReferenceEquals(operation.Record.PhysicsBody, operation.Body))
&& operation.Record.PositionAuthorityVersion
== operation.PositionAuthorityVersion
&& operation.Record.SpatialAuthorityVersion
== operation.SpatialAuthorityVersion
&& operation.Record.PlacementCommitVersion
== operation.PlacementCommitVersion;
/// <summary>
/// Round 3: the class-wide replacement for
/// <c>ReferenceEquals</c>/<see cref="IsCurrent(Operation)"/> at any frame
/// that holds an Operation reference across a reentrancy point (a
/// synchronous publish, a collision-report dispatch that can reach an
/// arbitrary <c>IRuntimeCollisionReportObserver</c>, or a ground-edge
/// HitGround/LeaveGround callback). <paramref name="capturedToken"/>
/// MUST be read from the operation (or already be the caller's own
/// token parameter) BEFORE that reentrancy point - reading it fresh off
/// a possibly-already-repurposed reference here would be exactly as
/// tautological as the <c>ReferenceEquals</c> check this replaces (see
/// <see cref="RetireOperationToPool"/>'s doc comment for the full
/// hazard: a reentrant cancel-then-begin can retire-then-rent the SAME
/// physical instance for a DIFFERENT logical operation, LIFO). On
/// success, returns the FRESHLY resolved Operation so the caller
/// continues with a reference proven current at THIS instant, never
/// the possibly-stale one it held before the reentrancy point.
/// </summary>
private bool IsCurrentByToken(
RuntimeEntityKey key,
in RuntimeEntityPlacementToken capturedToken,
[NotNullWhen(true)] out Operation? operation)
{
if (_operations.TryGetValue(key, out Operation? current)
&& current.Token == capturedToken
&& IsOperationStateConsistent(current))
{
operation = current;
return true;
}
operation = null;
return false;
}
private bool IsExactDormantLocalActivationCurrent(
RuntimeEntityRecord record,
PhysicsBody body,
in RuntimeEntityPlacementToken token,
in RuntimeSetPositionCommand command,
out Operation? operation,
bool allowCanonicalCommand = false,
bool allowDeferredLease = false)
{
operation = null;
// Round 3 audit: safe - fresh lookup + Token check earlier in this
// SAME guard clause (below) precede IsCurrent, nothing reentrant in
// between; this dormant family has zero production callers.
if (!token.IsValid
|| token.Entity != record.Key
|| token.PreparationKind
is not RuntimeEntityPlacementPreparationKind.AuthoredMover
|| command.Kind is not (RuntimeSetPositionOperationKind.InitialLogin
or RuntimeSetPositionOperationKind.LocalAuthoritative)
|| command.Portal != default
&& !command.Portal.IsValid
|| !_operations.TryGetValue(token.Entity, out operation)
|| operation.Token != token
|| operation.Stage
is not RuntimeEntityPlacementStage.AwaitingPreparation
&& !(allowDeferredLease
&& operation.DormantLocalActivation
&& (operation.Stage
is RuntimeEntityPlacementStage.AwaitingCell
&& operation.WakeableLostCell
|| operation.Stage is RuntimeEntityPlacementStage
.AwaitingFinalShadowPreparation)
&& operation.ProjectionSequence == 0UL)
|| !ReferenceEquals(operation.Record, record)
|| !IsCurrent(operation)
|| !ReferenceEquals(record.PhysicsBody, body)
|| body.InWorld
|| (body.TransientState & TransientStateFlags.Active) != 0
|| record.PhysicsHost is not null
|| record.RemoteMotion is not null
|| record.Projectile is not null
|| record.PhysicsBodyAcquisitionInProgress
|| record.RemoteMotionBindingInProgress
|| record.ProjectileBindingInProgress
|| record.RequiresRemotePlacementRuntime
|| record.DeleteAcceptedForTeardown
|| _physics.IsSpatialRoot(record)
|| !_moverPreparationAuthorities.TryGetValue(
token.Entity,
out MoverPreparationAuthority authority)
|| authority.OperationId != token.OperationId
|| !authority.Prepared
|| !IsPreparationAuthorityCurrent(operation, authority))
{
operation = null;
return false;
}
if (authority.PreparedCommand == command)
return true;
if (!allowCanonicalCommand)
return false;
RuntimeSetPositionCommand authored = authority.PreparedCommand;
return authored with
{
Physics = authored.Physics with
{
MoverPhysicsState = record.FinalPhysicsState,
MovingEntityId = token.Entity.LocalEntityId,
CurrentCellId = null,
},
} == command;
}
private bool IsVelocityCurrent(Operation operation) =>
IsVelocityCurrent(
operation.SourceVelocityAuthorityVersion,
operation.Record);
/// <summary>
/// F1: overload taking the hoisted scalar directly, for callers (like
/// <c>CommitCanonical</c>) that must not re-read a live
/// <see cref="Operation"/> after a ground-edge callback may have retired
/// and repurposed it.
/// </summary>
private static bool IsVelocityCurrent(
ulong sourceVelocityAuthorityVersion,
RuntimeEntityRecord record) =>
sourceVelocityAuthorityVersion == 0UL
|| record.VelocityAuthorityVersion == sourceVelocityAuthorityVersion;
private static MoverPreparationAuthority CapturePreparationAuthority(
Operation operation,
in CreateObject.ServerPosition acceptedPosition,
bool prepared,
in RuntimeSetPositionCommand preparedCommand = default) => new(
operation.Token.OperationId,
acceptedPosition,
CanonicalSetupTableId(operation.Record),
operation.Record.PositionAuthorityVersion,
operation.Record.VelocityAuthorityVersion,
operation.Record.StateAuthorityVersion,
operation.Record.VectorAuthorityVersion,
operation.Record.ObjDescAuthorityVersion,
operation.Record.CreateIntegrationVersion,
operation.Record.PhysicsStateMutationVersion,
prepared,
preparedCommand);
private static uint CanonicalSetupTableId(RuntimeEntityRecord record) =>
record.Snapshot.Physics?.SetupTableId
?? record.Snapshot.SetupTableId
?? 0u;
private static CreateObject.ServerPosition ServerPositionFrom(
uint cellId,
Vector3 cellLocal,
Quaternion orientation) => new(
cellId,
cellLocal.X,
cellLocal.Y,
cellLocal.Z,
orientation.W,
orientation.X,
orientation.Y,
orientation.Z);
/// <summary>
/// B2 dependency (C4 route 4b-2): all SEVEN version dimensions below are
/// load-bearing for <c>RuntimeRemotePlacementDriveController</c>'s
/// documented invariant that a PRE-engine <c>Rejected</c> can never reach
/// its far-snap default arm — it relies on <see cref="PrepareMover"/>
/// catching every authority divergence one call earlier, as
/// <c>RejectedAuthority</c> (which STORES), rather than
/// <see cref="SubmitPreparedPlacementCore"/> catching it as
/// <c>Rejected</c> (which does not). Dropping a dimension here silently
/// moves that shape to the non-storing arm.
/// </summary>
private static bool IsPreparationAuthorityCurrent(
Operation operation,
in MoverPreparationAuthority authority) =>
operation.Record.PositionAuthorityVersion
== authority.PositionAuthorityVersion
&& operation.Record.VelocityAuthorityVersion
== authority.VelocityAuthorityVersion
&& operation.Record.StateAuthorityVersion
== authority.StateAuthorityVersion
&& operation.Record.VectorAuthorityVersion
== authority.VectorAuthorityVersion
&& operation.Record.ObjDescAuthorityVersion
== authority.ObjDescAuthorityVersion
&& operation.Record.CreateIntegrationVersion
== authority.CreateIntegrationVersion
&& operation.Record.PhysicsStateMutationVersion
== authority.PhysicsStateMutationVersion;
private void RebindPreparedCommand(Operation operation)
{
if (_moverPreparationAuthorities.TryGetValue(
operation.Key,
out MoverPreparationAuthority authority)
&& authority.OperationId == operation.Token.OperationId
&& authority.Prepared)
{
_moverPreparationAuthorities[operation.Key] = authority with
{
PreparedCommand = operation.Command,
};
}
}
private bool IsDeferredWakePreparationCurrent(Operation operation)
{
if (_moverPreparationAuthorities.TryGetValue(
operation.Key,
out MoverPreparationAuthority authority)
&& authority.OperationId == operation.Token.OperationId
&& authority.Prepared
&& authority.PreparedCommand == operation.Command
&& IsPreparationAuthorityCurrent(operation, authority))
{
return true;
}
operation.SourceVelocityAuthorityVersion =
operation.Record.VelocityAuthorityVersion;
operation.RequiresPreparation = true;
operation.Stage = RuntimeEntityPlacementStage.AwaitingPreparation;
operation.PreparedCommandAwaitingWithdrawalAck = null;
_moverPreparationAuthorities[operation.Key] =
CapturePreparationAuthority(
operation,
ServerPositionFrom(
operation.ExactCellId,
operation.Result.CellLocalPosition,
operation.Result.Orientation),
prepared: false);
return false;
}
internal void PublishCancellation(
in RuntimePlacementCancellationReceipt receipt)
{
if (!receipt.IsValid)
return;
RuntimePlacementProjectionSnapshot projection = receipt.Projection;
if (_pendingProjection.TryGetValue(
projection.Token.Sequence,
out RuntimePlacementProjectionSnapshot current)
&& current == projection)
{
PublishPlacement(projection);
}
}
private RuntimePlacementCancellationReceipt CancelCore(
RuntimeEntityKey key)
{
_ = CancelCoreDeferred(
key,
cancelLostFamily: false,
preserveLostFamily: false,
out RuntimePlacementProjectionSnapshot? discard);
return discard is { } projection
? new RuntimePlacementCancellationReceipt(projection)
: default;
}
private bool CancelCoreDeferred(
RuntimeEntityKey key,
bool cancelLostFamily,
bool preserveLostFamily,
out RuntimePlacementProjectionSnapshot? discard)
{
discard = null;
if (!preserveLostFamily)
CancelExactLostKey(key);
if (!_operations.Remove(key, out Operation? operation))
return false;
ForgetPlacementCompletionCore(operation.Token);
_moverPreparationAuthorities.Remove(key);
UnindexDeferred(operation);
if (!preserveLostFamily && cancelLostFamily)
CancelLostFamilyDeadlines(operation);
if (operation.ProjectionSequence != 0UL
&& _pendingProjection.TryGetValue(
operation.ProjectionSequence,
out RuntimePlacementProjectionSnapshot pending))
{
RuntimePlacementProjectionSnapshot cancelled = pending with
{
Token = pending.Token with
{
Revision = checked(pending.Token.Revision + 1UL),
},
Kind = RuntimePlacementProjectionKind.Discard,
};
_pendingProjection[operation.ProjectionSequence] = cancelled;
if (pending.Kind is RuntimePlacementProjectionKind.Withdraw)
{
foreach (CollisionPrefixQuiescence state
in _collisionPrefixQuiescence.Values)
{
if (state.PendingWithdrawals.ContainsKey(
operation.ProjectionSequence))
{
state.PendingWithdrawals[
operation.ProjectionSequence] = cancelled.Token;
for (int retainedIndex = 0;
retainedIndex < state.RetainedWithdrawals.Count;
retainedIndex++)
{
if (state.RetainedWithdrawals[retainedIndex].Sequence
== operation.ProjectionSequence)
{
state.RetainedWithdrawals[retainedIndex] =
cancelled.Token;
break;
}
}
break;
}
}
}
operation.Stage = RuntimeEntityPlacementStage
.CancelledAwaitingAcknowledgement;
discard = cancelled;
}
// C2: `operation` was just removed from `_operations` above - see
// RetireOperationToPool's doc comment for why every caller (this one
// included) is safe to hand it back here, even the discard-pending
// case (AcknowledgeProjection's Discard branch never looks the
// operation back up by key).
RetireOperationToPool(operation);
return true;
}
/// <summary>
/// Round 3: takes the entity key plus a Token CAPTURED BY THE CALLER
/// (before any reentrancy point the caller passed through) instead of
/// an <see cref="Operation"/> reference. The <c>ReferenceEquals</c>
/// check this replaced was exactly the shape the round 3 architecture
/// review flagged: safe before pooling (an Operation instance was never
/// reused), silently tautological after (a reentrant cancel-then-begin
/// can retire-then-rent the SAME instance for a DIFFERENT logical
/// operation, so `expected` and the freshly-looked-up `current` could be
/// the same reference while representing different operations) - with
/// the worse outcome that this method would then cancel the NEWER
/// operation instead of correctly no-op'ing. See
/// <see cref="RetireOperationToPool"/>'s doc comment for the full
/// hazard and <see cref="IsCurrentByToken"/> for the equivalent
/// conversion applied to plain currency checks.
/// </summary>
private RuntimePlacementCancellationReceipt CancelCore(
RuntimeEntityKey key,
in RuntimeEntityPlacementToken expectedToken,
bool preserveLostFamily = false,
bool restoreCancelledPark = false)
{
if (!_operations.TryGetValue(key, out Operation? current)
|| current.Token != expectedToken)
{
return default;
}
// Opt-in only - see Forget's doc comment for why a withdrawal must
// never roll a park back. This overload is the path route 2's
// controller and route 4b's remote controller cancel through
// (ForgetExactPlacement); they opt in, the initial-create residence
// and continuation executors deliberately do not.
RuntimeEntityRecord parkedRecord = current.Record;
ParkWithdrawal withdrawal =
restoreCancelledPark && current.WakeableLostCell
? current.ParkWithdrawal
: default;
_ = CancelCoreDeferred(
key,
cancelLostFamily: false,
preserveLostFamily,
out RuntimePlacementProjectionSnapshot? discard);
if (withdrawal.Captured)
RestoreParkWithdrawal(parkedRecord, withdrawal);
return discard is { } projection
? new RuntimePlacementCancellationReceipt(projection)
: default;
}
private void ForgetPlacementCompletionCore(
in RuntimeEntityPlacementToken token)
{
if (!token.IsValid)
return;
_placementCompletionWatches.Remove(token);
_acknowledgedPlacementCompletions.Remove(token);
}
private void IndexDeferred(Operation operation)
{
if (operation.ExactCellId == 0u
|| operation.CollisionGeneration == 0UL)
{
return;
}
var bucket = new CellGenerationKey(
operation.ExactCellId,
operation.CollisionPrefix,
operation.CollisionGeneration);
if (!_deferredByCellGeneration.TryGetValue(
bucket,
out List<RuntimeEntityKey>? entities))
{
entities = [];
_deferredByCellGeneration.Add(bucket, entities);
_deferredBucketOrder.Add(bucket);
}
if (!entities.Contains(operation.Key))
entities.Add(operation.Key);
}
private void IndexUnboundDeferred(Operation operation)
{
if (operation.ExactCellId == 0u)
return;
var key = new UnboundCellKey(
operation.ExactCellId,
operation.CollisionPrefix);
if (!_unboundDeferredByCell.TryGetValue(
key,
out List<RuntimeEntityKey>? entities))
{
entities = [];
_unboundDeferredByCell.Add(key, entities);
_unboundDeferredCellOrder.Add(key);
}
if (!entities.Contains(operation.Key))
entities.Add(operation.Key);
}
private void UnindexDeferred(Operation operation)
{
if (operation.ExactCellId == 0u)
{
return;
}
if (operation.CollisionGeneration == 0UL)
{
var key = new UnboundCellKey(
operation.ExactCellId,
operation.CollisionPrefix);
if (_unboundDeferredByCell.TryGetValue(
key,
out List<RuntimeEntityKey>? unbound))
{
int unboundIndex = unbound.IndexOf(operation.Key);
if (unboundIndex >= 0)
{
int last = unbound.Count - 1;
unbound[unboundIndex] = unbound[last];
unbound.RemoveAt(last);
}
if (unbound.Count == 0)
{
_unboundDeferredByCell.Remove(key);
_unboundDeferredCellOrder.Remove(key);
}
}
return;
}
var bucket = new CellGenerationKey(
operation.ExactCellId,
operation.CollisionPrefix,
operation.CollisionGeneration);
if (_deferredByCellGeneration.TryGetValue(
bucket,
out List<RuntimeEntityKey>? entities))
{
int index = entities.IndexOf(operation.Key);
if (index >= 0)
{
int last = entities.Count - 1;
entities[index] = entities[last];
entities.RemoveAt(last);
}
if (entities.Count == 0)
RemoveDeferredBucket(bucket);
}
}
private void UnbindDeferredBucket(CellGenerationKey bucket)
{
if (!_deferredByCellGeneration.TryGetValue(
bucket,
out List<RuntimeEntityKey>? entities))
{
return;
}
RemoveDeferredBucket(bucket);
var unboundKey = new UnboundCellKey(
bucket.CellId,
bucket.CollisionPrefix);
if (!_unboundDeferredByCell.TryGetValue(
unboundKey,
out List<RuntimeEntityKey>? unbound))
{
unbound = [];
_unboundDeferredByCell.Add(unboundKey, unbound);
_unboundDeferredCellOrder.Add(unboundKey);
}
for (int index = 0; index < entities.Count; index++)
{
RuntimeEntityKey key = entities[index];
if (!_operations.TryGetValue(key, out Operation? operation)
|| !operation.WakeableLostCell
|| operation.ExactCellId != bucket.CellId
|| operation.CollisionPrefix != bucket.CollisionPrefix
|| operation.CollisionGeneration != bucket.CollisionGeneration)
{
continue;
}
operation.CollisionGeneration = 0UL;
operation.CollisionGenerationReady = false;
if (!unbound.Contains(key))
unbound.Add(key);
}
if (unbound.Count == 0)
{
_unboundDeferredByCell.Remove(unboundKey);
_unboundDeferredCellOrder.Remove(unboundKey);
}
}
private void RemoveDeferredBucket(CellGenerationKey bucket)
{
_deferredByCellGeneration.Remove(bucket);
int index = _deferredBucketOrder.IndexOf(bucket);
if (index < 0)
return;
int last = _deferredBucketOrder.Count - 1;
_deferredBucketOrder[index] = _deferredBucketOrder[last];
_deferredBucketOrder.RemoveAt(last);
}
private static RuntimeSetPositionOutcome Outcome(
RuntimeSetPositionStatus status,
in PhysicsSetPositionResult result,
in RuntimePlacementProjectionToken projection) => new(
status,
result.Error,
result.Residence,
result.CellId,
projection);
private static RuntimeSetPositionOutcome Rejected(
in PhysicsSetPositionRequest request) => new(
RuntimeSetPositionStatus.Rejected,
PhysicsSetPositionError.InvalidArguments,
PhysicsResidenceDisposition.Unchanged,
request.CellId,
default);
private static PhysicsSetPositionResult InvalidResult(
in PhysicsSetPositionRequest request) => new(
PhysicsSetPositionError.InvalidArguments,
PhysicsResidenceDisposition.Unchanged,
request.Position,
request.Orientation,
request.CellId,
request.CellLocalPosition,
CrossCellIds: ImmutableArray<uint>.Empty,
CollidedObjectIds: ImmutableArray<uint>.Empty);
private static bool IsStructurallyValid(
in PhysicsSetPositionRequest request)
{
static bool Finite(Vector3 value) => float.IsFinite(value.X)
&& float.IsFinite(value.Y)
&& float.IsFinite(value.Z);
// The wire/runtime frame is retail Position::IsValid composed with
// Frame::IsValid: valid inbound cell plus the exact unit-quaternion
// tolerance. This must run before Core or prepared-mover caching.
if (!PositionFrameValidation.IsValid(
request.CellId,
request.CellLocalPosition,
request.Orientation)
|| !Finite(request.Position)
|| !Finite(request.CellLocalPosition)
|| !float.IsFinite(request.StepUpHeight)
|| !float.IsFinite(request.StepDownHeight))
{
return false;
}
if (!request.Spheres.IsDefaultOrEmpty)
{
if (!float.IsFinite(request.Scale))
return false;
int count = Math.Min(request.Spheres.Length, 2);
for (int index = 0; index < count; index++)
{
FlatCollisionSphere sphere = request.Spheres[index];
if (!Finite(sphere.Origin) || !float.IsFinite(sphere.Radius))
return false;
}
}
if (request.Flags.HasFlag(PhysicsSetPositionFlags.Line)
&& !Finite(request.Line))
{
return false;
}
bool scatter = request.Flags.HasFlag(PhysicsSetPositionFlags.Scatter)
|| request.Flags.HasFlag(PhysicsSetPositionFlags.RandomScatter);
if (scatter
&& (!float.IsFinite(request.ScatterRadiusX)
|| !float.IsFinite(request.ScatterRadiusY)
|| request.ScatterAttempts > MaxSynchronousScatterAttempts))
{
return false;
}
return true;
}
private void PublishPlacement(
in RuntimePlacementProjectionSnapshot projection) =>
_events?.PublishPlacement(projection);
private void ArmLostFamilyDeadlines(Operation operation)
{
RuntimeEntityRecord root = operation.Record;
CancelLostFamilyDeadlines(operation);
double deadline = _physics.MonotonicNowSeconds + 25d;
operation.LostFamilyKeys ??= [];
if (root.Key is { } rootKey)
{
operation.LostFamilyKeys.Add(rootKey);
ArmLostDeadline(rootKey, deadline);
}
IReadOnlyList<uint> children = _entities.ParentAttachments
.ChildrenAttachedToParent(root.ServerGuid, root.Incarnation);
for (int index = 0; index < children.Count; index++)
{
if (_entities.TryGetActive(
children[index],
out RuntimeEntityRecord child)
&& child.Key is { } childKey)
{
operation.LostFamilyKeys.Add(childKey);
ArmLostDeadline(childKey, deadline);
}
}
}
private void CancelLostFamilyDeadlines(Operation operation)
{
if (operation.Record.Key is { } rootKey)
{
RemoveLostDeadline(rootKey);
RemoveExpiredLostCell(rootKey);
}
IReadOnlyList<uint> currentChildren = _entities.ParentAttachments
.ChildrenAttachedToParent(
operation.Record.ServerGuid,
operation.Record.Incarnation);
for (int index = 0; index < currentChildren.Count; index++)
{
if (_entities.TryGetActive(
currentChildren[index],
out RuntimeEntityRecord child)
&& child.Key is { } key)
{
RemoveLostDeadline(key);
RemoveExpiredLostCell(key);
}
}
operation.LostFamilyKeys?.Clear();
}
private void CancelExactLostKey(RuntimeEntityKey key)
{
RemoveLostDeadline(key);
RemoveExpiredLostCell(key);
foreach (Operation operation in _operations.Values)
operation.LostFamilyKeys?.Remove(key);
}
private void RemoveExpiredLostCell(RuntimeEntityKey key)
{
if (!_expiredLostCellNodes.Remove(
key,
out LinkedListNode<RuntimeEntityKey>? node))
{
return;
}
_expiredLostCells.Remove(node);
}
private void ArmLostDeadline(RuntimeEntityKey key, double deadline)
{
RemoveLostDeadlineNode(key);
_lostDeadlines[key] = deadline;
int index = _lostDeadlineNodes.Count;
_lostDeadlineNodes.Add(new LostDeadlineEntry(
key,
deadline,
checked(++_nextLostDeadlineSequence)));
_lostDeadlineNodeIndex.Add(key, index);
BubbleLostDeadlineUp(index);
}
private void RemoveLostDeadline(RuntimeEntityKey key)
{
_lostDeadlines.Remove(key);
RemoveLostDeadlineNode(key);
}
private static bool IsEarlier(
in LostDeadlineEntry candidate,
in LostDeadlineEntry current) =>
candidate.Deadline < current.Deadline
|| (candidate.Deadline == current.Deadline
&& candidate.Sequence < current.Sequence);
private void BubbleLostDeadlineUp(int index)
{
while (index > 0)
{
int parent = (index - 1) / 2;
if (!IsEarlier(
_lostDeadlineNodes[index],
_lostDeadlineNodes[parent]))
break;
SwapLostDeadlineNodes(index, parent);
index = parent;
}
}
private void BubbleLostDeadlineDown(int index)
{
while (true)
{
int left = checked(index * 2 + 1);
if (left >= _lostDeadlineNodes.Count)
return;
int right = left + 1;
int earlier = right < _lostDeadlineNodes.Count
&& IsEarlier(
_lostDeadlineNodes[right],
_lostDeadlineNodes[left])
? right
: left;
if (!IsEarlier(
_lostDeadlineNodes[earlier],
_lostDeadlineNodes[index]))
return;
SwapLostDeadlineNodes(index, earlier);
index = earlier;
}
}
private void SwapLostDeadlineNodes(int first, int second)
{
LostDeadlineEntry temporary = _lostDeadlineNodes[first];
_lostDeadlineNodes[first] = _lostDeadlineNodes[second];
_lostDeadlineNodes[second] = temporary;
_lostDeadlineNodeIndex[_lostDeadlineNodes[first].Key] = first;
_lostDeadlineNodeIndex[_lostDeadlineNodes[second].Key] = second;
}
private void RemoveLostDeadlineNode(RuntimeEntityKey key)
{
if (_lostDeadlineNodeIndex.TryGetValue(key, out int index))
RemoveLostDeadlineNodeAt(index);
}
private void RemoveLostDeadlineNodeAt(int index)
{
LostDeadlineEntry removed = _lostDeadlineNodes[index];
_lostDeadlineNodeIndex.Remove(removed.Key);
int last = _lostDeadlineNodes.Count - 1;
if (index != last)
{
LostDeadlineEntry moved = _lostDeadlineNodes[last];
_lostDeadlineNodes[index] = moved;
_lostDeadlineNodeIndex[moved.Key] = index;
}
_lostDeadlineNodes.RemoveAt(last);
if (index >= _lostDeadlineNodes.Count)
return;
int parent = index == 0 ? -1 : (index - 1) / 2;
if (parent >= 0
&& IsEarlier(
_lostDeadlineNodes[index],
_lostDeadlineNodes[parent]))
{
BubbleLostDeadlineUp(index);
}
else
{
BubbleLostDeadlineDown(index);
}
}
private void EnsureNotDisposed() =>
ObjectDisposedException.ThrowIf(_disposed, this);
}