using System.Numerics; using AcDream.Content; using AcDream.Core.Net.Messages; using AcDream.Core.Physics; using AcDream.Runtime.Entities; using AcDream.Runtime.Physics; namespace AcDream.Runtime.Session; /// /// C4 route 4b-1: per-entity remote-placement service-window predicate. A /// host implements this over whatever collision-publication residency it /// actually tracks — GpuWorldState.IsNearTier for the graphical host, /// HeadlessCollisionNeighborhood's explicit implementation (backed by /// its private IsCollisionCurrentlyPublished — NOT /// , /// which is a pure geometry test over the requested 3x3 window and answers a /// different question: "can this landblock EVER collision-publish", not "is /// it collision-published right now" — B1 review fix) for headless — so /// can /// ask, BEFORE attempting any canonical SetPosition, whether the accepted /// destination is one this host can actually place a remote into right now. /// /// /// Headless is not a live consumer, stated plainly (C4 route 4b-2, review /// fix). The headless implementation above exists and is exact, but /// NOTHING in AcDream.Headless constructs a /// : the graphical /// composition root (SessionPlayerComposition) is the only /// construction site, and /// RuntimeLiveEntitySessionController.OnPositionUpdated returns early /// for every non-local GUID before any remote routing could occur. Route /// 4b-2's contract item 6 ("both hosts drive the identical Runtime entry /// point, or the divergence is stated plainly rather than satisfied /// vacuously") is therefore satisfied by THIS statement, not by a shared /// caller. The far snap is a graphical-host-only path until a headless /// remote-motion consumer exists. /// /// public interface IRuntimeRemotePlacementServiceWindow { /// /// True when 's collision is currently /// published by this host, so a canonical SetPosition into it is worth /// attempting rather than certain to park (see /// docs/research/2026-08-04-c4-route-4b-1-contract.md's "central /// decision"). may be a full cell id — the /// implementation canonicalizes to the containing landblock. /// /// /// C4 route 4b-2 delta review: this answer is an OPTIMISATION only. It /// cannot be a correctness gate — see /// 's /// CanAttemptDestination for the two Core predicates that are /// strictly broader than any pre-flight, one of which reads a sweep /// footprint that does not exist until the sweep has run. /// /// bool IsWithinServiceWindow(uint landblockId); } /// /// Typed yields for /// . /// /// /// The partition this enum exists to express (C4 route 4b-2, delta review /// MAJOR A). Retail's CPhysicsObj::SetPositionInternal @0x00515BD0 /// has exactly two shapes, and the earlier three-value enum could not tell /// them apart: /// /// /// Stores. AdjustPosition yielded no /// transition @0x00515C1D, so the resolve never ran: /// prepare_to_leave_visibility @0x00515CDA, /// store_position(this, arg2) @0x00515CE2, /// CObjectMaint::GotoLostCell @0x00515CF2, transient-state clear /// @0x00515CF7, return 0 @0x00515D07. The object MOVES to the accepted /// destination. /// Does not store. The resolve DID run and refused: /// CheckPositionInternal == 0 @0x00515C85 → /// handle_all_collisions @0x00515CC2 → /// return ((eax_14 - eax_14) & 2) + 2 @0x00515CD5 (2 or 4), and /// sphere_path.curr_cell == 0 @0x00515C8F → return 3 /// @0x00515CB2. Both leave the object where it was. /// /// /// /// is the single predicate that reads this partition; every value below /// states which side it falls on and WHY, so a new value cannot be added /// without deciding. /// /// internal enum RuntimeRemotePlacementExecutionStatus : byte { /// /// Out of this route's scope: not a disposition this controller owns /// (), /// no canonical body, or no incarnation key. Stores — nothing ran. /// /// /// The three sub-cases are not symmetric, and round 3 (correction m4) /// states each. Not owned stores the accepted destination like any /// other never-ran outcome. No canonical body stores nothing: /// there is nowhere to write, which /// /// tests directly rather than inferring from this value. No /// incarnation key, with a body DOES write, and that is correct on /// retail's partition — nothing ran, so the pose must advance — but it is /// unreachable in production regardless: the far arm requires an /// already-classified route, and /// RuntimeAcceptedPositionRouteRequests.TryBuild refuses to build /// one for a record whose Key is null, so no caller can hold a /// route for a keyless record. /// /// NotApplicable, /// /// The central decision (see the class doc on /// ): the pre-flight /// declined to attempt this destination at all, so no operation was ever /// begun and the canonical resolve never ran. /// /// /// Stores. This is exactly retail's no-transition branch — "no cell /// for it here", never "do not move". See /// . /// /// Refused, /// /// /// refused, or this controller retained a preparation retry. /// /// /// Round 3 (correction m2) — the producers this route can actually reach, /// not the two the earlier text named. The Begin refuses when the entity /// already holds an active operation (a concurrent placement authority — /// portal, teleport, another host route), when it holds a RETAINED /// COMPLETION that has not been acknowledged yet /// (HasRetainedCompletion — ordinary right after a /// far snap whose projection sink declined), or /// when the record is no longer the current incarnation /// (!IsCurrent). Its remaining refusals cannot fire from here: /// the expected position-authority version is read off the same record /// one statement earlier, and the accepted destination was already /// required non-null by the pre-flight. This controller adds the fourth /// producer: a retryable preparation status /// (RetrySetupUnavailable/RetryWorldFrameUnavailable). /// /// /// /// Stores in every one of those shapes: all four are decided /// before _physics.Engine.SetPosition is called for THIS packet, /// and retail never waits for an asset before committing the pose. /// ( /// re-validates currency itself, so the !IsCurrent producer cannot /// write through a superseded record.) /// /// Contention, /// /// Preparation refused TERMINALLY, before anything was submitted: /// RuntimeSetPositionMoverPreparationStatus.RejectedAuthority (the /// operation/authority pair went stale between Begin and prepare) or /// InvalidData (the accepted frame fails /// PositionFrameValidation, or the prepared mover could not be /// built). /// /// /// Stores. The engine was never called — this is the same /// "placement never executed" state as , reached one /// stage later. Kept distinct from /// because that one is the opposite side of the partition. /// /// RejectedPreparation, /// The canonical SetPosition committed synchronously. /// Does not store: the committed pose IS the settled pose, and it /// is already on the canonical body. Committed, /// /// Core parked the placement (RuntimeSetPositionStatus.DeferredCell) /// and this controller cancelled-and-restored it immediately rather than /// retaining a watch — no park survives this controller. /// /// /// Does not store. ParkDeferred has ALREADY performed /// retail's store_position: it snaps the body to the parked result /// before withdrawing (and RestoreParkWithdrawal deliberately /// leaves that pose alone). For the pre-sweep quiescence park that result /// is the accepted destination; for the post-sweep one it is the /// COLLISION-SETTLED spherePath.CurPos, and writing the raw /// destination over it would undo the settle (delta review N2). The two /// DeferredCell returns that park nothing /// (InheritedLostDeadline, WakeableLostCell) are /// unreachable here: TryBeginExclusiveAuthoredPlacement refuses /// whenever an operation already exists for the key, so neither flag can /// be inherited, and this controller's own retained entries are /// preparation retries that have not parked. /// /// Deferred, /// /// The canonical placement EXECUTED and did not commit: /// RuntimeSetPositionStatus.Rejected (the engine's own sweep /// refused the destination — PhysicsEngine.SetPosition returned a /// non-Ok error, acdream's port of @0x00515CD5/@0x00515CB2) or /// Cancelled (authority was displaced after the engine ran, which /// includes the case where CommitCanonical had already SETTLED the /// body). /// /// /// Does not store. Retail's matching returns (2/3/4) leave the /// object where it was, and the Cancelled-after-commit shape has a /// freshly settled pose (contact plane, step-down) that a raw destination /// write would destroy. /// /// /// /// Round 3 (correction B2): "EXECUTED" is a reachability property of the /// producers this route can reach, not a structural guarantee Core /// enforces. RuntimeSetPositionStatus.Rejected has two other, /// PRE-engine producers in SubmitPreparedPlacementCore, both /// unreachable through this controller; the default: arm of /// /// enumerates exactly what each depends on, and why the failure direction /// if one is ever broken is the safe one. /// /// RejectedByPlacement, } internal static class RuntimeRemotePlacementExecutionStatusExtensions { /// /// True when retail's store_position @0x00515CE2 is what this /// outcome corresponds to: the canonical placement never reached the /// engine, so nothing has committed a pose to the body and the remote /// would otherwise be frozen at a superseded one. See the enum's own doc /// for the retail partition and for why each value falls where it does. /// /// /// Written as an exhaustive switch rather than a set test so adding a /// value is a compile-time decision, not a silent default. /// /// internal static bool StoresAcceptedDestination( this RuntimeRemotePlacementExecutionStatus status) => status switch { RuntimeRemotePlacementExecutionStatus.NotApplicable => true, RuntimeRemotePlacementExecutionStatus.Refused => true, RuntimeRemotePlacementExecutionStatus.Contention => true, RuntimeRemotePlacementExecutionStatus.RejectedPreparation => true, RuntimeRemotePlacementExecutionStatus.Committed => false, RuntimeRemotePlacementExecutionStatus.Deferred => false, RuntimeRemotePlacementExecutionStatus.RejectedByPlacement => false, _ => throw new ArgumentOutOfRangeException(nameof(status)), }; } /// /// C4 route 4b-1: the Runtime-owned, per-entity accepted-Position execution /// seam for a remote whose classification is SetPosition (teleport / /// cell-less — 4b-3's eventual disposition) or SetPositionSimple (far /// snap, >=96 m — 4b-2's). Route 4a's /// already owns the two /// dispositions that perform no SetPosition at all /// (NoPositionOperation/Interpolate); this controller is the /// architectural sibling for the remaining two, built from route 2's /// controller shape with two deliberate omissions and one deliberate /// generalization: /// /// /// No ack. Retail's remote arm has no /// SendPositionEventHandleReceivedPosition @0x00453FD0 calls /// it only on the local-player FORCE_POSITION branch. There is nothing here /// resembling route 2's PositionEventOwed/SendPositionEvent /// pair. The separate question 4b-1's review left open is now settled /// (C4 route 4b-2 review fix): the SetPositionStruct flag /// SEND_POSITION_EVENT_SPF = 0x1000 — which /// CPhysicsObj::SetPositionSimple @0x005162B0 sets as part of /// 0x1012 @0x005162C4 and which therefore reaches /// TryPrepareAndSubmitAuthoredPlacement here — is never read. /// The commit path CPhysicsObj::SetPositionInternal /// @0x00515330-@0x00515593 takes only this and the CTransition /// and never sees the struct; the flag-reading overload @0x00515BD0 tests /// only bit 5 (DONOTCREATECELLS_SPF = 0x20) @0x00515BF8/@0x00515C6C; /// and no site anywhere in the decomp tests bit 12 of a /// SetPositionStruct. It is a carried, inert flag, entirely distinct /// from CommandInterpreter::SendPositionEvent @0x006B4770 (dispatched /// from @0x00454091, the local-player branch 4b-1 already /// cleared). /// No re-issue funnel. Route 2 re-issues a dead /// operation because a ForcePosition is a one-shot correction ACE never /// repeats. A remote Position is a REPEATED stream — re-issuing packet N /// after N+1 has already merged would apply a pose the newer packet already /// superseded. When this controller's own tracked operation dies for any /// reason (superseded, torn down, forgotten by the entity's next accepted /// Position), it is simply dropped: the next packet supplies the current /// truth on its own. /// Per-entity, not per-session. Route 2's /// _pending is a single slot because the local player is the only /// entity that route ever touches. Remotes are N entities, so /// is a per-key map and every entry is independent — /// route 2's single-owner invariant (Begin refuses a second live entry for /// the SAME key) is unchanged, just re-derived per entity instead of /// globally. /// /// /// /// The central decision — avoid the PARK where it is cheap to, never the /// tracking. /// 's DeferredCell park /// withdraws the entity from the world (ParkDeferred sets /// body.InWorld = false, suspends the object clock, and publishes a /// Withdraw) — and RuntimeEntityObjectLifetime.TryApplyPosition /// calls RuntimeSetPositionState.Forget on EVERY subsequent accepted /// Position for that same entity, regardless of disposition. Because ACE /// broadcasts a remote's Position every 100-150 ms — almost always faster /// than the collision-generation wake this park would need to resolve on its /// own — any DeferredCell park opened here would be cancelled by the /// entity's own next packet long before it could wake. /// Correcting this paragraph's earlier claim (4b-1's review ordered it /// and it shipped uncorrected): that cancellation no longer strands the /// entity "invisible AND intangible for the rest of the session". /// passes restoreCancelledPark: true, and /// RuntimeSetPositionState.RestoreParkWithdrawal rolls /// InWorld, the object clock, and canonical residency back — the /// AP-136 behaviour 634bc551 landed. The park is still worth avoiding /// (a restored park re-shows the entity where retail keeps it hidden until /// cell load, which is precisely what AP-136 records), so /// stays — but it is an OPTIMISATION, not a /// correctness mechanism, and it is never the reason a remote stops /// tracking the server (see /// 's store_position /// fallback). /// checks it BEFORE calling /// , /// and if Core still returns DeferredCell despite the guard passing, /// the operation is cancelled immediately rather than retained, so the /// ledger still converges even though the guard's invariant did not hold for /// that one packet. /// /// /// /// Why a pre-flight structurally cannot be the correctness mechanism (C4 /// route 4b-2, delta review MAJOR B/C). A tier/residency-backed service /// window (the graphical host's GpuWorldState.IsNearTier, headless's /// collision-published check) is co-extensive with collision PUBLICATION in /// both directions — verified by reading both tier-writer call sites /// (promotion cannot read Near before collision commits) and the retirement /// call site (the tier flips to Far as the FIRST, synchronous step of /// retirement, strictly before collision-side withdrawal). It is NOT /// co-extensive with a live in-place collision-prefix MUTATION, which is why /// also reads Core's own /// . But even /// that pair only tests ONE prefix — the DESTINATION's — while Core's park /// predicates are broader: ResultTouchesPrefix scans every /// QueriedCellIds entry, a sweep footprint that provably spans /// NEIGHBOUR landblocks (CellTransit.AddOutsideCell re-derives the /// block id from the global lcoord and has no same-block filter). The sweep /// footprint does not exist until the sweep has run, so no pre-flight can /// close that half. The correctness mechanism is therefore at the source: /// SubmitPreparedPlacementCore's two quiescence parks are RESTORABLE, /// and ParkDeferred decides whether the rollback is safe by testing /// the cell it will actually restore into — after the snap, against EVERY /// live quiescence — so the rollback re-admits nothing into ANY quiescing /// prefix, which is the only thing AP-136's blanket non-restorable scoping /// was protecting. This guard merely shrinks the reachable set. Recorded as /// AP-138(2). /// /// /// /// One instance per host session route, constructed once per host process /// and reused across reconnects exactly like /// and /// — /// / assert the same /// "session reset precedes a new route" ordering and clear any tracked /// entries left by a torn-down session. /// /// internal sealed class RuntimeRemotePlacementDriveController { private sealed class Pending { internal required RuntimeEntityRecord Record { get; init; } internal required RuntimeEntityPlacementToken Token { get; init; } internal required RuntimeAuthoritativePositionRoute Route { get; init; } } private readonly RuntimeEntityObjectLifetime _entityObjects; private readonly IGameRuntimeClock _clock; private readonly IPreparedCollisionSource _collisionSource; private readonly IRuntimeRemotePlacementServiceWindow _serviceWindow; /// /// Per-entity preparation-retry map (bounded to the two retryable /// reasons — Setup /// or world-frame data not resolved yet, NEITHER of which withdraws the /// entity). A DeferredCell outcome never enters this map — see the /// class doc's central decision. /// private readonly Dictionary _pending = []; /// /// B4 review fix: per-entity tokens whose /// outcome was CommittedHostAcknowledgementPending and were STILL /// live (not synchronously consumed-and-acknowledged by the production /// placement-projection subscription inside that same call) the instant /// returned Committed. Without this, /// the ledger went blind the moment Committed was returned, hiding /// exactly the declined-sink class the FIFO retry mechanism exists for. /// Pruned lazily (self-healing) on every read — see /// — never gates any /// placement decision itself; Core's own _operations map remains /// the sole authority TryBeginExclusiveAuthoredPlacement consults. /// private readonly Dictionary _awaitingAcknowledgement = []; private readonly List _driveScratch = []; /// /// C2-1 review fix (delta round): dedicated reusable scratch list for /// 's self-heal removal /// pass — kept separate from (owned by /// ) so a ledger read reached while Advance /// is mid-iteration can never corrupt its scratch buffer. /// private readonly List _awaitingAcknowledgementScratch = []; /// /// R9 review fix: 's own removal buffer, /// kept separate from (owned by /// ) for the same reason /// is. /// private readonly List _pendingScratch = []; private bool _driving; private object? _routeOwner; internal RuntimeRemotePlacementDriveController( RuntimeEntityObjectLifetime entityObjects, IGameRuntimeClock clock, IPreparedCollisionSource collisionSource, IRuntimeRemotePlacementServiceWindow serviceWindow) { _entityObjects = entityObjects ?? throw new ArgumentNullException(nameof(entityObjects)); _clock = clock ?? throw new ArgumentNullException(nameof(clock)); _collisionSource = collisionSource ?? throw new ArgumentNullException(nameof(collisionSource)); _serviceWindow = serviceWindow ?? throw new ArgumentNullException(nameof(serviceWindow)); _entityObjects.RegisterRemotePlacementDriveOwnership( CountLivePending); // B4 review fix: a second, independent registration — multiple // registrations sum (RegisterRemotePlacementDriveOwnership's own doc // comment) — so the awaiting-acknowledgement dimension is visible in // the SAME ledger without changing what _pending itself reports. _entityObjects.RegisterRemotePlacementDriveOwnership( CountLiveAwaitingAcknowledgement); } /// /// Preparation-stage retries only (see 's own doc). /// Deliberately does NOT include — /// that dimension is reported to the lifetime's ownership ledger via the /// constructor's second RegisterRemotePlacementDriveOwnership call /// (B4 review fix) and has no separate test-visible counter of its own. /// Raw, unhealed: this is the map's literal size. The ownership ledger /// reads instead, which prunes entries Core /// has already retired (R9 review fix). /// internal int PendingCount => _pending.Count; /// /// True when route 4b owns this classification for a remote — the two /// dispositions route 4a's /// does NOT already handle. Everything else (Interpolate, /// NoPositionOperation, RejectedAuthority, /// RejectedData, AwaitFreshPosition) is out of scope here. /// B6 review fix: Disposition alone is not exact — the classifier /// (RuntimeAuthoritativePositionRouteClassifier.cs) assigns /// SetPosition/SetPositionSimple at several independent /// call sites (:256, :332, :355, :403, :459) and derives /// OperationKind separately (:560-575) — the SAME disposition /// covers the LOCAL PLAYER's FORCE_POSITION/teleport branches /// (RuntimeSetPositionOperationKind.LocalAuthoritative). /// is a parameter separate from the entity /// record at every call site, so a mismatched pair is expressible; /// gating on OperationKind narrows to remotes AND the local /// player's own initial Create — OperationKind's own switch /// (:559-570) maps InitialLogin to the LOCAL PLAYER's Create /// ONLY; a REMOTE top-level Create maps to RemoteAuthoritative /// exactly like a remote accepted Position does (correcting this /// comment's earlier, wrong claim that all initial Creates map to /// InitialLogin). /// /// C2-4 review fix (delta round): so OperationKind alone still /// does not exclude a remote top-level Create — ClassifyCreate /// (:254-273) emits SetPosition + RemoteAuthoritative + /// InitialCreateFlags (Placement|Slide) for one, while /// ClassifyAcceptedPosition's remote branches (:401-416, /// :454-472) always carry AuthoritativeTeleportFlags /// (Teleport|Slide|SendPositionEvent) for the SAME disposition/ /// OperationKind pair. The Teleport bit is the exact /// discriminator retail's own flag choice provides — Create asks for /// placement collision, an accepted Position asks for a teleport /// resolve — so requiring it here excludes Creates (route 4b-1 is a /// POSITION-only route; the first-entry conductor owns every Create) /// without excluding either remote Position shape. /// /// /// C4 route 5 (D-P3): widened to admit /// ProjectileAuthoritative alongside RemoteAuthoritative — /// a live missile's teleport/cell-less and far accepted-Position /// dispositions are disposition-identical to a remote's (the classifier /// never branches on kind past LocalPlayer), and route 5's /// is the sibling seam over /// this SAME shared core ( + /// ) — never a second pending /// map, never a sibling controller. OwnsFarSnap and /// OwnsTeleportPlacement are deliberately NOT widened: both remote /// arm methods (/ /// ) require and throw without a /// RemoteMotion, which a projectile never has. /// /// internal static bool OwnsPlacement(RuntimeAuthoritativePositionRoute route) => route.OperationKind is RuntimeSetPositionOperationKind.RemoteAuthoritative or RuntimeSetPositionOperationKind.ProjectileAuthoritative && route.Disposition is RuntimeAuthoritativePositionDisposition.SetPosition or RuntimeAuthoritativePositionDisposition.SetPositionSimple && (route.SetPositionFlags & PhysicsSetPositionFlags.Teleport) != 0; /// /// Mirrors and /// : this /// controller outlives its session routes, so the "session reset /// precedes a new route" ordering is asserted, not assumed. /// internal void AttachRoute(object route) { ArgumentNullException.ThrowIfNull(route); if (_routeOwner is not null && !ReferenceEquals(_routeOwner, route)) { throw new InvalidOperationException( "A remote placement drive controller serves one session " + "route at a time; the prior route must be disposed " + "(session reset precedes a new route) before a " + "replacement attaches."); } _routeOwner = route; } /// /// Route-scoped teardown: abandons every tracked entry, but ONLY when /// is the attached owner. /// /// /// C2-1 review fix (delta round) — the prior version of this method (and /// this comment) was wrong: it cleared and /// as if they were pure /// bookkeeping, citing /// as the mirror. That is the WRONG sibling — first-entry's tracked /// entries have an INDEPENDENT owner (the residence lease) that survives /// route teardown on its own, so clearing first-entry's local map merely /// stops WATCHING an operation something else still owns. These two maps /// have no such owner: EVERY entry holds a Core operation THIS /// controller alone began — at /// AwaitingPreparation (already begun via /// TryBeginExclusiveAuthoredPlacement), /// at AwaitingCommitAcknowledgement with a published Place. /// Clearing the local dictionary without cancelling the Core operation /// left it live forever, pinning its landblock prefix /// (HasOldPrefixPlacementDebt) — docs/ISSUES.md #310's unbounded /// streaming-stall hazard, now reachable from an ordinary reconnect/ /// session-reset instead of only a stuck asset retry. The correct mirror /// is route 2's RuntimeAcceptedPositionDriveController.DetachRoute /// → AbandonPending, which this now matches: cancel every live /// operation (, restoreCancelledPark: true /// — these are cancellations of an abandoned placement INTENT, not /// withdrawals, so any park rolls back rather than stranding the body) /// before clearing the local maps. /// /// internal void DetachRoute(object route) { ArgumentNullException.ThrowIfNull(route); if (!ReferenceEquals(_routeOwner, route)) return; _routeOwner = null; RuntimeSetPositionState setPosition = _entityObjects.Physics.SetPosition; if (_pending.Count != 0) { Pending[] abandoned = [.. _pending.Values]; _pending.Clear(); foreach (Pending entry in abandoned) { setPosition.ForgetPlacementCompletion(entry.Token); CancelToken(setPosition, entry.Token); } } if (_awaitingAcknowledgement.Count != 0) { RuntimeEntityPlacementToken[] abandoned = [.. _awaitingAcknowledgement.Values]; _awaitingAcknowledgement.Clear(); foreach (RuntimeEntityPlacementToken token in abandoned) { setPosition.ForgetPlacementCompletion(token); CancelToken(setPosition, token); } } } /// /// Executes an already-classified remote accepted Position against the /// canonical Runtime SetPosition owner. 's /// Snapshot and PositionAuthorityVersion must already reflect the merge /// performed — /// this method never re-merges the wire frame, and /// must already be the result of /// /// for the SAME packet (the shared classification builder every remote /// caller uses — never re-derived here). /// internal RuntimeRemotePlacementExecutionStatus TryExecuteAcceptedRemotePosition( RuntimeEntityRecord record, in RuntimeAuthoritativePositionRoute route) { ArgumentNullException.ThrowIfNull(record); if (!OwnsPlacement(route) || record.PhysicsBody is null || record.Key is not { } key) { return RuntimeRemotePlacementExecutionStatus.NotApplicable; } RuntimeSetPositionState setPosition = _entityObjects.Physics.SetPosition; // A retained preparation retry whose operation died some other way // (superseded, torn down, generation change, or simply forgotten by // an unrelated accepted Position for this same entity) must not // block a fresh Begin for THIS packet — self-heal rather than report // a Contention nothing is actually contending. if (_pending.TryGetValue(key, out Pending? stale) && !setPosition.IsPlacementCurrent(stale.Token)) { _pending.Remove(key); } CreateObject.ServerPosition? destination = record.Snapshot.Physics?.Position ?? record.Snapshot.Position; if (destination is not { } accepted || !CanAttemptDestination(setPosition, accepted.LandblockId)) { // The central decision: skip a placement this host already knows // will only park and be cancelled again. An OPTIMISATION — see // CanAttemptDestination for the two Core predicates it cannot // reproduce and where correctness actually lives — and the body // still advances, because Refused is on the storing side of // retail's partition. return RuntimeRemotePlacementExecutionStatus.Refused; } RuntimeEntityPlacementToken token = setPosition.TryBeginExclusiveAuthoredPlacement( record, record.PositionAuthorityVersion, route.OperationKind); if (!token.IsValid) return RuntimeRemotePlacementExecutionStatus.Contention; return SubmitAndResolve(record, token, route); } /// /// C4 route 4b-2: retail's far branch, end to end, for one remote whose /// accepted Position already classified to /// . This is the /// route's FIRST production caller of /// . /// /// /// 005163c1 position_manager = this_1->position_manager; /// 005163c9 if (position_manager != 0) /// 005163cb PositionManager::StopInterpolating(position_manager); /// 005163d9 CPhysicsObj::SetPositionSimple(this_1, arg2, 1); /// 005163e8 return 1; /// /// /// /// The ORDER is load-bearing and is why this lives here rather than being /// assembled by a caller: StopInterpolating runs strictly BEFORE /// the placement (@0x005163CB before @0x005163D9). acdream's /// InterpolationManager queue is the analogue — a stale near /// waypoint surviving a far snap would immediately drag the freshly /// placed body back toward it on the next per-tick catch-up. The /// classifier's own StopInterpolating flag /// (RuntimeAuthoritativePositionRouteClassifier.ClassifyAcceptedPosition's /// remote tail, StopInterpolating: !nearby) is what gates it, so /// the retail condition is read from the route rather than restated. /// /// /// /// The destination is NOT a parameter: it is read from the canonical /// merged snapshot by and /// resolved through Runtime's own accepted world frame /// (resolveWorldOffsetFromRuntimeFrame: true). A caller's /// separately-derived world position is not a second input — #283 proved /// by measurement that App's streaming origin and Runtime's world frame /// cannot disagree, and LiveWorldOriginState.EnsureAgreesWithRuntimeFrame /// is terminal if they ever do. /// /// /// /// ConstrainTo is deliberately NOT armed here. /// SmartBox::HandleReceivedPosition owns retail's single arming /// site (@0x00454272) for all three nonzero-returning branches; acdream's /// analogue is /// , /// called once by the caller after the routing block. Arming inside this /// method would be the second site the route 4b scoping forbids. /// /// /// /// The store_position fallback (C4 route 4b-2 review fix — the /// one root defect). Every outcome for which the canonical placement /// never reached the engine /// () /// still advances the body to the accepted destination pose, through /// . Without it a refused, /// contended, or preparation-rejected far snap left the body at its stale /// pose with the interpolation queue ALREADY cleared by the /// StopInterpolating above — a frozen remote that the next 5-10 Hz /// packet simply reproduces, because nothing about the refusal reason /// changes at packet cadence. /// /// /// This is retail, not a symptom patch. /// CPhysicsObj::SetPositionInternal @0x00515BD0 takes the /// no-transition branch @0x00515C1D whenever AdjustPosition /// resolves no cell, and that branch commits the destination pose — /// prepare_to_leave_visibility @0x00515CDA, /// store_position(this, arg2) @0x00515CE2, /// CObjectMaint::GotoLostCell @0x00515CF2 — and returns 0 /// (success) @0x00515D07. "This host cannot resolve a cell for the /// destination right now" is exactly that state; retail moves the object /// and hides it pending cell load, and never leaves it standing at a /// superseded pose. The deleted legacy far block also always tracked. /// /// /// The other half of retail's partition is honoured too (delta review /// MAJOR A — correcting this comment's earlier claim that no non-commit /// outcome could represent it). Retail's failure returns that do NOT /// store — curr_cell == 0 @0x00515C8F/@0x00515CB2 and the blocked /// CheckPositionInternal @0x00515C85/@0x00515CD5 — are reached /// AFTER the resolve ran, and acdream CAN represent that: /// /// is returned when PhysicsEngine.SetPosition itself refused, or /// when authority was displaced after it ran (including after /// CommitCanonical had already settled the body). Those do not /// store, so a destination the engine's own sweep refuses no longer /// teleports the canonical body into it, and a just-settled pose is never /// overwritten. The residual is recorded as AP-138. /// /// internal RuntimeRemotePlacementExecutionStatus ApplyAcceptedRemoteFarSnap( RuntimeEntityRecord record, RemoteMotion remote, in RuntimeAuthoritativePositionRoute route) { ArgumentNullException.ThrowIfNull(record); ArgumentNullException.ThrowIfNull(remote); if (!RuntimeRemoteFarSnapPosition.OwnsFarSnap(route)) { throw new ArgumentException( "Only a remote far-snap classification (SetPositionSimple, " + "RemoteAuthoritative, Teleport-flagged) may be applied " + "through the far-snap arm; the caller must select the arm " + "with RuntimeRemoteFarSnapPosition.ResolveArm.", nameof(route)); } if (route.StopInterpolating) remote.Interp.Clear(); RuntimeRemotePlacementExecutionStatus status = TryExecuteAcceptedRemotePosition(record, route); if (status.StoresAcceptedDestination()) StoreAcceptedDestinationPose(record); return status; } /// /// C4 route 4b-3: retail's teleport/cell-less branch, end to end, for one /// remote whose accepted Position already classified to /// . /// /// /// 00516386 if (newer_event(TELEPORT_TS) || this_1->cell == 0) /// 005163ef CPhysicsObj::teleport_hook(this_1, edx_2); /// 00516414 SetPositionStruct::SetFlags(&var_64, 0x1012); /// 00516420 CPhysicsObj::SetPosition(this_1, &var_64); /// 00516438 return 1; /// /// /// /// The teleport hook is the CALLER's responsibility (D3) — it must run /// BEFORE this method, regardless of what the placement then yields, /// exactly like retail's ordering. This method does not clear the /// interpolation queue itself: unlike the far arm, the classifier's /// teleport branch carries StopInterpolating: false on purpose — /// retail's clear for THIS branch lives inside teleport_hook's /// PositionManager::StopInterpolating @0x00514EFD, not in /// MoveOrTeleport itself. /// /// /// /// The store_position fallback (invariant 1) is identical to the /// far arm's: every outcome for which the canonical placement never /// reached the engine /// () /// still advances the body to the accepted destination pose. Retail /// discards SetPosition's error and returns 1 unconditionally /// @0x00516438 — the placement's outcome never changes whether the /// packet "succeeded". /// /// internal RuntimeRemotePlacementExecutionStatus ApplyAcceptedRemoteTeleport( RuntimeEntityRecord record, RemoteMotion remote, in RuntimeAuthoritativePositionRoute route) { ArgumentNullException.ThrowIfNull(record); ArgumentNullException.ThrowIfNull(remote); if (!RuntimeRemoteTeleportPosition.OwnsTeleportPlacement(route)) { throw new ArgumentException( "Only a remote teleport/cell-less classification (SetPosition, " + "RemoteAuthoritative, Teleport-flagged) may be applied " + "through the teleport arm; the caller must select the arm " + "with RuntimeRemoteTeleportPosition.OwnsTeleportPlacement.", nameof(route)); } RuntimeRemotePlacementExecutionStatus status = TryExecuteAcceptedRemotePosition(record, route); if (status.StoresAcceptedDestination()) StoreAcceptedDestinationPose(record); return status; } /// /// C4 route 5 (D-P2): the projectile arm over this SAME shared core. A /// live missile carries no , so /// / /// are not reusable — both require one and throw without it. This is the /// sibling seam the D-P2 design pins: same /// + /// core, same /// / ledgers, /// no second pending map, no sibling controller (trap T9). /// /// /// Returns for every disposition this route does /// not own: Interpolate (near, in contact) and /// NoPositionOperation (airborne) are pinned NO-OPS — retail would /// lazily build interpolation/leash machinery for a manager-less missile /// (@0x005163AF / @0x00454272-@0x00510523), which acdream deliberately /// does not construct for a ballistic body (the register row this route /// adds); RejectedAuthority/RejectedData and an ownership /// mismatch are SWALLOWED — write nothing, never fall through to the /// remote tail (trap T5). A caller must not fall back to any remote arm /// when this returns . /// /// /// /// No velocity write (D-P5). Retail's MoveOrTeleport /// @0x00516330 never references its velocity argument in the decompiled /// body, and a byte-level disassembly of the PDB-paired binary /// (@0x00516330-@0x00516438) confirms no instruction anywhere in the /// function reads that argument's stack slot. This seam commits no /// velocity from the Position packet at all — the Vector channel /// () /// remains the sole velocity authority for a missile. /// /// /// /// No constraint leash armed (D-P4). Unlike the remote arms, this /// method never calls TryArmConstraintAfterOperation — the /// classifier's projectile routes still carry /// ConstrainPhase.AfterPositionOperation (kind-blind), but this arm /// deliberately does not consume it, matching the pinned divergence. /// /// /// /// Teleport hook reduction (D-P4). Of retail's six /// teleport_hook @0x00514ED0 actions, five are structurally absent /// for a manager-less missile (no MovementManager/ /// PositionManager/TargetManager). The sixth, /// report_collision_end(this, 1) @0x00514F31-@0x00514620, applies /// to any object with a collision table and runs BEFORE the placement — /// ported here as RuntimeCollisionReportingState.LeaveWorld (the /// exact force-end seam the 4b-3 round-2 review validated against the /// same retail address). /// /// /// /// Prediction is invalidated once per packet, before any body write on /// this route (placement or the store fallback) — mirroring /// RuntimeProjectilePhysicsUpdater's existing invalidate-before- /// write ordering — so an in-flight split quantum straddling this packet /// aborts at Complete rather than clobbering a canonical /// placement. The no-op dispositions invalidate nothing: the body is /// untouched, so a straddling quantum completing over them is correct. /// /// internal RuntimeRemotePlacementExecutionStatus? ApplyAcceptedProjectilePosition( RuntimeEntityRecord record, in RuntimeAuthoritativePositionRoute route) { ArgumentNullException.ThrowIfNull(record); if (route.OperationKind is not RuntimeSetPositionOperationKind.ProjectileAuthoritative || record.Projectile is not RuntimeProjectile projectile || record.PhysicsBody is not { } body || !ReferenceEquals(body, projectile.Body)) { return null; } // A6 fix (review round): captured BEFORE the placement dispatch, // mirroring the deleted tail's `bool wasInWorld = body.InWorld;` // ordering — TryExecuteAcceptedRemotePosition's canonical commit // calls body.SnapToCell, which sets InWorld = true, so reading this // AFTER the dispatch (as the first cut of this seam did) makes the // re-activation branch below permanently dead on every committed // outcome. bool wasInWorld = body.InWorld; RuntimeRemotePlacementExecutionStatus status; switch (route.Disposition) { case RuntimeAuthoritativePositionDisposition.SetPosition: _entityObjects.Physics.CollisionReports.LeaveWorld(record); projectile.InvalidatePrediction(); status = TryExecuteAcceptedRemotePosition(record, route); break; case RuntimeAuthoritativePositionDisposition.SetPositionSimple: // B1/B2 fix (round-2 review): retail's far branch runs // `StopInterpolating` @0x005163C9-@0x005163CB whenever // `position_manager != 0` — the SAME guard the remote far // arm ports as `ApplyAcceptedRemoteFarSnap`'s // `if (route.StopInterpolating) remote.Interp.Clear();`. A // bare missile has no RemoteMotion so this is structurally // inert, but the ADOPTED-BODY case (TryBind's shared-body // branch: an ordinary remote whose Missile bit was set by a // later State packet) carries a live Interp queue the far // branch must clear too — the teleport hook only covers the // SetPosition disposition. if (route.StopInterpolating && record.RemoteMotion is RemoteMotion adoptedFar) { adoptedFar.Interp.Clear(); } projectile.InvalidatePrediction(); status = TryExecuteAcceptedRemotePosition(record, route); break; default: // Interpolate / NoPositionOperation: pinned no-op (D-P4). // RejectedAuthority / RejectedData: swallow (T5) — the // shared authority gate already rejected an invalid payload // upstream; there is nothing left to route. return null; } if (status.StoresAcceptedDestination()) StoreAcceptedDestinationPose(record); if (status is not RuntimeRemotePlacementExecutionStatus.Deferred and not RuntimeRemotePlacementExecutionStatus.RejectedByPlacement) { // Invariant 2: presentation advances on every committed/stored // outcome only — Deferred/RejectedByPlacement leave the body at // its prior (already-synced) pose. SyncProjectilePresentation(record, projectile, body, wasInWorld); } return status; } /// /// C4 route 5 (REVISED after the review round — A6/A7/A8): the /// J5.6-owned post-commit lifecycle tail (InWorld/Activate/shadow-sync /// on spatial+visible, suspend on spatial+hidden, deactivate+suspend on /// non-spatial), reduced from the deleted /// RuntimeProjectilePhysicsUpdater.ApplyAuthoritativePosition /// tail (former :390-422) to this controller's own seam — /// is the caller's pre-dispatch capture /// (A6: reading body.InWorld here, after the canonical commit's /// own SnapToCell already forced it true, made the re-activation /// branch permanently dead); supplies the same /// clock source the deleted method took as an explicit /// currentTime parameter; the world-frame offset comes from /// (the same /// source uses) instead of an /// App-supplied live-center pair. /// private void SyncProjectilePresentation( RuntimeEntityRecord record, RuntimeProjectile projectile, PhysicsBody body, bool wasInWorld) { if (!_entityObjects.Entities.IsCurrent(record) || !ReferenceEquals(record.Projectile, projectile) || !ReferenceEquals(record.PhysicsBody, body)) { return; } RuntimePhysicsState physics = _entityObjects.Physics; bool spatial = physics.IsSpatialProjectile(record, projectile); bool hidden = (record.FinalPhysicsState & PhysicsStateFlags.Hidden) != 0; uint localId = record.LocalEntityId ?? 0u; if (spatial && !hidden) { if (!wasInWorld) { body.LastUpdateTime = _clock.SimulationTimeSeconds; if ((body.State & PhysicsStateFlags.Static) == 0) body.TransientState |= TransientStateFlags.Active; } body.InWorld = true; // A8 fix: #284's policy ("a frame that can never arrive is // terminal, never silent") applies here exactly as it does to // StoreAcceptedDestinationPose. A false result during the // legitimate pre-local-player-Create window silently skips the // publish (self-heals once the frame arrives); a false result // AFTER that window is a genuinely stuck frame, and // ThrowIfWorldFrameUnreachable escalates it instead of leaving // the shadow silently stale forever. if (physics.TryGetWorldFrameOffset( record.FullCellId, out float offsetX, out float offsetY)) { physics.Engine.ShadowObjects.UpdatePosition( localId, body.Position, body.Orientation, offsetX, offsetY, record.FullCellId, seedCellId: record.FullCellId); } else { physics.ThrowIfWorldFrameUnreachable(record.FullCellId); } } else if (spatial) { body.InWorld = true; // A7 fix: retail's hidden-branch clock consumption — restored, // matching ProjectileController.TryBind's equivalent branch // ("consume the hidden clock so UnHide cannot replay a time // backlog"). body.LastUpdateTime = _clock.SimulationTimeSeconds; physics.Engine.ShadowObjects.Suspend(localId); } else { body.InWorld = false; body.TransientState &= ~TransientStateFlags.Active; physics.Engine.ShadowObjects.Suspend(localId); } } /// /// Retail CPhysicsObj::store_position @0x00515CE2, reached from /// SetPositionInternal's no-resolvable-cell branch @0x00515C1D. /// Commits the SAME accepted destination /// reads — the canonical /// merged snapshot, resolved through Runtime's own accepted world frame, /// which is the exact pair /// RuntimeSetPositionMoverPreparer.TryBuild composes for a /// committed placement (cellLocal + ShadowWorldOffset in X/Y, the /// authored Z, the authored quaternion). A caller's separately-derived /// wire pose is deliberately not an input here either, for the same /// reason the committed path does not take one. /// /// /// Currency is re-validated first (delta review MAJOR D). /// publishes its cancellation receipt /// SYNCHRONOUSLY, and the production placement-projection sink can delete /// or replace this incarnation from inside that publish — so by the time /// control returns to the record /// may no longer be the canonical one for its GUID. Writing a pose /// through a superseded incarnation is the exact class the R5 fix /// introduced the rule for, and /// RuntimeSetPositionState.RestoreParkWithdrawal already guards the /// same way. The App-side re-validation happens only after this seam /// returns, which is too late. /// /// /// /// The write target is the CANONICAL body (delta review N5). /// Retail's store_position(this, arg2) writes the CPhysicsObj's own /// position, and acdream's canonical CPhysicsObj is /// . /// RemoteMotion.Body IS that instance in production, by two /// independent routes: RuntimePhysicsState.GetOrCreateRemoteMotion /// passes record.PhysicsBody into the constructor, and when the /// record has no body yet SetRemoteMotion ADOPTS the component's /// private one as canonical (InitializeNewPhysicsBody + /// SetPhysicsBody). So the divergent pair is not constructible /// through the production seam and this change moves no production /// behaviour — it removes the ability to write a pose into a body the /// canonical record does not own, which is what /// 's /// no-body producer would otherwise permit for a caller-supplied /// component. Reading the record directly makes "there is no canonical /// body" and "there is nothing to store into" the same test. /// /// /// /// Returns false only when there is nothing to write, or nowhere to write /// it: no canonical body, no accepted destination on the snapshot, a /// superseded incarnation, or no Runtime world frame yet. The last case /// reuses Core's own #284 policy — /// makes a /// frame that can never arrive terminal rather than silent — so the only /// surviving false there is the genuine pre-local-player-Create window, /// which the far arm cannot reach anyway: the classifier needs a live /// player_distance to emit SetPositionSimple at all, and /// that requires the local movement controller to exist. /// /// private bool StoreAcceptedDestinationPose(RuntimeEntityRecord record) { if (!_entityObjects.Entities.IsCurrent(record) || record.PhysicsBody is not { } body) { return false; } CreateObject.ServerPosition? destination = record.Snapshot.Physics?.Position ?? record.Snapshot.Position; if (destination is not { } accepted) return false; if (!_entityObjects.Physics.TryGetWorldFrameOffset( accepted.LandblockId, out float worldOffsetX, out float worldOffsetY)) { _entityObjects.Physics.ThrowIfWorldFrameUnreachable( accepted.LandblockId); return false; } body.Position = new Vector3( accepted.PositionX + worldOffsetX, accepted.PositionY + worldOffsetY, accepted.PositionZ); body.Orientation = new Quaternion( accepted.RotationX, accepted.RotationY, accepted.RotationZ, accepted.RotationW); return true; } /// /// Host cadence pump: retries a preparation-only retry status /// (RetrySetupUnavailable/RetryWorldFrameUnavailable) by /// re-calling the SAME prepare+submit pair, exactly like /// 's own continuation /// completion. Bounded, non-allocating iteration mirrors /// 's _driveScratch /// template. Safe to call from any host cadence point; a no-op when /// nothing is pending. /// internal void Advance() { if (_driving || _pending.Count == 0) return; _driving = true; try { _driveScratch.Clear(); foreach (RuntimeEntityKey key in _pending.Keys) _driveScratch.Add(key); RuntimeSetPositionState setPosition = _entityObjects.Physics.SetPosition; foreach (RuntimeEntityKey key in _driveScratch) { if (!_pending.TryGetValue(key, out Pending? pending)) continue; if (!setPosition.IsPlacementCurrent(pending.Token)) { // Forgotten by some other accepted Position for this // same entity before this retry resolved. No re-issue // funnel for remotes: the next packet supplies current // truth on its own. _pending.Remove(key); continue; } _pending.Remove(key); // R3 fix (review round): a retained retry can belong to a // projectile operation exactly as it can belong to a // remote's — this is the SAME shared _pending map (trap T9: // no second map), and pending.Route carries the OperationKind // that was classified when the retry was first parked. // Neither invariant this route pins (prediction invalidated // before every body write; presentation advances on every // committed/stored outcome) may hold on the direct arm only. // Real nullable locals (not a stored bool) so the compiler // can track definite assignment through the branches below. RuntimeProjectile? pendingProjectile = null; PhysicsBody? pendingBody = null; if (pending.Route.OperationKind is RuntimeSetPositionOperationKind.ProjectileAuthoritative && pending.Record.Projectile is RuntimeProjectile candidateProjectile && pending.Record.PhysicsBody is { } candidateBody && ReferenceEquals(candidateBody, candidateProjectile.Body)) { pendingProjectile = candidateProjectile; pendingBody = candidateBody; } bool pendingWasInWorld = pendingBody?.InWorld ?? false; // B3 review fix: a retry can sit retained across many host // cadence pumps (bounded only by how long the asset stayed // unavailable) while its destination's collision publication // retires out from under it. Re-check the SAME pre-flight the // entry point uses BEFORE resubmitting — dropping (and // cancelling the already-begun token) rather than resubmitting // matches the entry point's own Refused semantics: no // operation survives and the next packet supplies current // truth on its own. Without this re-check a destination that // fell out of the window would just keep coming back // Contention forever (the asset source has not changed), never // converging even though the window already knows better. // // Delta review N1: this path is the entry point's Refused // semantics, so it must ALSO be the entry point's // store_position — correcting this comment's earlier claim // that "the entity keeps its last committed pose". A retained // retry whose destination leaves the window is exactly the // freeze the fallback exists to prevent, one cadence pump // later; the pre-flight is an optimisation here for the same // reason it is one at the entry point, and it may never be the // reason a remote stops tracking. CreateObject.ServerPosition? destination = pending.Record.Snapshot.Physics?.Position ?? pending.Record.Snapshot.Position; RuntimeRemotePlacementExecutionStatus retryStatus; if (destination is not { } accepted || !CanAttemptDestination( setPosition, accepted.LandblockId)) { CancelToken(setPosition, pending.Token); pendingProjectile?.InvalidatePrediction(); StoreAcceptedDestinationPose(pending.Record); retryStatus = RuntimeRemotePlacementExecutionStatus.Refused; } else { // B5 fix (round-2 review): invalidating BEFORE this call // unconditionally was wrong when SubmitAndResolve itself // re-parks (returns Contention) — that outcome writes // NOTHING (no store, no commit), so invalidating for it // violates invariant 4's "the no-op dispositions // invalidate nothing" on this arm specifically (unlike // the entry point, where StoresAcceptedDestination() // treats Contention as a storing outcome via the // caller's own StoreAcceptedDestinationPose — this retry // arm does not store on a re-parked Contention, matching // the pre-existing residual A3/round-1 already named). // Invalidating AFTER the call instead of before is safe // here: this method is single-threaded and synchronous, // so a write performed inside SubmitAndResolve and the // very next statement's invalidate are never observably // separated by a quantum's Complete call. retryStatus = SubmitAndResolve( pending.Record, pending.Token, pending.Route); if (retryStatus is not RuntimeRemotePlacementExecutionStatus.Contention) { pendingProjectile?.InvalidatePrediction(); } } if (pendingProjectile is { } confirmedProjectile && pendingBody is { } confirmedBody && retryStatus is not RuntimeRemotePlacementExecutionStatus.Deferred and not RuntimeRemotePlacementExecutionStatus.RejectedByPlacement) { SyncProjectilePresentation( pending.Record, confirmedProjectile, confirmedBody, pendingWasInWorld); } } } finally { _driving = false; } } private RuntimeRemotePlacementExecutionStatus SubmitAndResolve( RuntimeEntityRecord record, in RuntimeEntityPlacementToken token, in RuntimeAuthoritativePositionRoute route) { RuntimeSetPositionState setPosition = _entityObjects.Physics.SetPosition; RuntimeSetPositionMoverPreparationStatus status = setPosition.TryPrepareAndSubmitAuthoredPlacement( record, token, route.OperationKind, route.SetPositionFlags, _collisionSource, _clock.SimulationTimeSeconds, out RuntimeSetPositionOutcome outcome, resolveWorldOffsetFromRuntimeFrame: true); if (status != RuntimeSetPositionMoverPreparationStatus.Prepared) { if (status.IsRetryable()) { _pending[token.Entity] = new Pending { Record = record, Token = token, Route = route, }; return RuntimeRemotePlacementExecutionStatus.Contention; } // Preparation refused TERMINALLY (RejectedAuthority/InvalidData). // Nothing was submitted, so the engine never ran — this is the // STORING side of retail's partition, one stage later than the // pre-flight Refused. Delta review MAJOR A. CancelToken(setPosition, token); return RuntimeRemotePlacementExecutionStatus.RejectedPreparation; } switch (outcome.Status) { case RuntimeSetPositionStatus.CommittedHostAcknowledgementPending: // No ack for remotes. The production placement-projection // subscription (shared infrastructure, not owned here) has // already applied-and-acknowledged the Place receipt // synchronously inside the SetPosition call above, if it was // going to — exactly like route 2's own commit branch, minus // the ack call route 2 makes for the local player. B4 review // fix: when the sink declined instead (host not ready — the // exact scenario the FIFO retry mechanism exists for), the // operation is STILL LIVE in Core's _operations map until // some later AcknowledgeProjection retires it. Track it so // the ledger can see that class of outstanding operation // instead of going blind the instant this method returns. if (setPosition.IsPlacementCurrent(token)) _awaitingAcknowledgement[token.Entity] = token; return RuntimeRemotePlacementExecutionStatus.Committed; case RuntimeSetPositionStatus.DeferredCell: // Central decision: the pre-flight passed but Core still // parked the destination — the residual the class doc's // central-decision paragraph explains, now that the pre-flight // is explicitly only an optimisation (it tests the DESTINATION // prefix; Core's own post-sweep predicate also matches the // whole swept footprint, which spans neighbouring landblocks // and does not exist until the sweep has run). Cancel // immediately rather than // retain a watch: no re-issue, no park survives this // controller, and CancelToken's restoreCancelledPark rolls the // withdrawal back at the destination cell. // // ParkDeferred has already performed retail's store_position — // it snaps the body to the parked result before withdrawing, // and RestoreParkWithdrawal deliberately leaves that pose // alone — so the fallback must NOT fire here. For the // post-sweep park that result is the collision-SETTLED // position and a raw destination write would undo the settle // (delta review N2). CancelToken(setPosition, token); return RuntimeRemotePlacementExecutionStatus.Deferred; default: // Rejected/Cancelled. Correcting this comment's earlier claim // that "the body never moved" (delta review MAJOR A — it was // the claim that made the fallback fire here): the statuses // that reach this arm are returned AFTER // _physics.Engine.SetPosition ran. Rejected is the engine's // own sweep refusing the destination (retail @0x00515CD5 / // @0x00515CB2, neither of which stores), and Cancelled // includes the shape where CommitCanonical already SETTLED // the body and only the projection ownership was displaced. // Neither may be overwritten with the raw accepted // destination. // // Round 3 (correction B2) — that is a REACHABILITY claim, not // a structural one, so state what it rests on. Core's // SubmitPreparedPlacementCore has three Rejected producers // and only the post-engine one (`!result.IsSuccessful` after // the SetPosition call) can reach here. Its two PRE-engine // producers are unreachable through this controller because // each is shadowed by a check PrepareMover already made, with // nothing reentrant in between: // * the entry validation's identity/authority terms (token // ownership, stage, preparation authority) re-test what // PrepareMover's own guard clause tested one call // earlier, and IsPreparationAuthorityCurrent catches // all seven of its version dimensions there first — as // RejectedAuthority, i.e. RejectedPreparation, which // DOES store. The one stage divergence PrepareMover // admits and SubmitPreparedPlacementCore refuses is // AwaitingCell, which additionally requires // DormantLocalActivation — forbidden for a record that // has a body, and this route requires one. Its remaining // terms (finite GameTime, matching Kind/Portal, the exact // PreparedCommand, the velocity-version echo) are // satisfied by construction: TryPrepareAndSubmitAuthored- // Placement submits the very command PrepareMover just // stored, built from the same operation, with nothing in // between. // * the NULL-BODY term is the one entry-validation test // PrepareMover does NOT shadow (round 4, D3 — its guard // clause has no body test at all). This route's own // entry check does: TryExecuteAcceptedRemotePosition's // `record.PhysicsBody is null → NotApplicable` above. // The only two writers that CLEAR it are entity teardown // (RuntimeEntityObjectLifetime's canonical leave-world // tail) and local-player activation retirement, and each // retires the operation as part of the same transaction — // so a body lost in between surfaces as Cancelled, not // as a pre-engine Rejected. // * !IsStructurallyValid(canonicalRequest) re-tests the // command PrepareMover just validated. The `with` between // them only replaces fields IsStructurallyValid reads // when WakeableLostCell is set, which requires an // inherited park — and TryBeginExclusiveAuthoredPlacement // refuses whenever an operation already exists for the // key, so nothing can be inherited here. // If a future change breaks one of those, the failure lands // on the SAFE side: a pre-engine Rejected filed here does not // store, so the body holds a stale pose for ONE packet (no // operation is retained — CancelToken runs below — so the // next 5-10 Hz packet starts clean). The opposite mistake, // storing after the engine refused, teleports the canonical // body into a destination the sweep just declined. That // asymmetry is why this stays a documented invariant rather // than a stage flag threaded out of Core: the flag would // change the shared placement contract three shipped routes // depend on, to make the already-safe direction slightly // safer. CancelToken(setPosition, token); return RuntimeRemotePlacementExecutionStatus.RejectedByPlacement; } } /// /// R9 review fix — the same self-healing read /// already performed, for /// . Both maps are keyed by /// (guid + incarnation), so a reused GUID /// produces a NEW key and cannot displace a dead incarnation's entry by /// itself. drops such entries, but it early-returns /// whenever nothing is pending and is a host cadence call the ledger has /// no right to assume ran; without this the count converged only at /// , i.e. never in-session — contract item 7's /// GUID-reuse/incarnation dimension. /// /// /// Removal is gated on !IsPlacementCurrent, so this can only ever /// drop entries Core has ALREADY retired. It never cancels anything and /// therefore cannot hide the live-operation leak /// 's own review fix exists to prevent. The /// disposal guard matches its sibling's, for the same /// post-Dispose() CaptureOwnership() contract. /// /// private int CountLivePending() { if (_pending.Count == 0) return 0; if (_entityObjects.Physics.IsDisposed) return _pending.Count; RuntimeSetPositionState setPosition = _entityObjects.Physics.SetPosition; _pendingScratch.Clear(); foreach ((RuntimeEntityKey key, Pending entry) in _pending) { if (!setPosition.IsPlacementCurrent(entry.Token)) _pendingScratch.Add(key); } foreach (RuntimeEntityKey key in _pendingScratch) _pending.Remove(key); return _pending.Count; } /// /// Self-healing read: prunes every /// entry whose token Core no longer considers current (the ack already /// landed through whatever path — the synchronous in-call apply, a later /// FIFO retry, or Runtime's own session-reset/generation-change teardown /// clearing the operation outright) before returning the live count. /// This is what lets the constructor's second /// RegisterRemotePlacementDriveOwnership registration converge to /// zero (B4 review fix) without this controller needing a separate /// periodic pump for this one dictionary — every ownership-snapshot read /// (including the exact convergence checks teardown/reset/generation /// change assert) sees the truth as of that read. /// /// /// C2-1 review fix (delta round), disposal safety: IsPlacementCurrent's /// first statement is EnsureNotDisposed, which THROWS once /// is disposed. A post-Dispose() /// CaptureOwnership() read is the designed contract /// (GameWindowLifetime.DisposeGameRuntime: runtime.Dispose(); /// runtime.CaptureOwnership();), so this — the first ledger provider /// to reach into another disposable subsystem — must survive it. When /// is already true, Core /// itself is gone; there is nothing left to ask, so this returns /// whatever count is STILL in the local map rather than calling into the /// disposed state. A healthy teardown already cancelled and cleared /// every entry via before disposal, so this /// branch reports 0 in the healthy path and a genuine nonzero leak /// otherwise — never an exception either way. /// /// /// C2-1 review fix (delta round), allocation: reuses /// instead of a per-call /// List<RuntimeEntityKey>, mirroring 's /// own template. /// /// private int CountLiveAwaitingAcknowledgement() { if (_awaitingAcknowledgement.Count == 0) return 0; if (_entityObjects.Physics.IsDisposed) return _awaitingAcknowledgement.Count; RuntimeSetPositionState setPosition = _entityObjects.Physics.SetPosition; _awaitingAcknowledgementScratch.Clear(); foreach ((RuntimeEntityKey key, RuntimeEntityPlacementToken token) in _awaitingAcknowledgement) { if (!setPosition.IsPlacementCurrent(token)) _awaitingAcknowledgementScratch.Add(key); } foreach (RuntimeEntityKey key in _awaitingAcknowledgementScratch) _awaitingAcknowledgement.Remove(key); return _awaitingAcknowledgement.Count; } /// /// An OPTIMISATION, never the correctness mechanism: can this host place a /// remote into RIGHT NOW without paying for /// a park that will only be cancelled again? /// /// /// Deliberately NOT complete, and it cannot be (C4 route 4b-2, delta /// review MAJOR B/C — correcting this comment's earlier "the complete /// pre-flight" framing). This tests ONE prefix, the destination's. /// Core's own park predicates are broader in two independent ways that no /// pre-flight can reproduce: /// /// /// PlacementTouchesPrefix also matches the /// request's CurrentCellId. Round 3 — the earlier text called /// that "the SOURCE landblock the remote is snapping OUT of" and "the /// likelier shape"; that is not what production supplies. /// CurrentCellId is read from record.FullCellId, and both /// accepted-Position callers commit the accepted WIRE cell to that field /// before this seam is reached — the graphical remote path through /// LiveEntityRuntime.RebucketLiveEntity → /// RuntimeEntityObjectLifetime.CommitRebucket in its shared /// prologue, route 2 through the merge itself. So on the FIRST submit /// this arm names the DESTINATION, and it is the destination prefix — the /// one this pre-flight DOES see — that it matches. Measured, not argued. /// Scoped deliberately (round 4, D5): that is a property of the first /// submit only. A RETAINED operation re-submits from a cadence pump with /// no fresh merge, so see the paragraph below for /// what the arm can name by then — the arm is live, not dead /// code. /// ResultTouchesPrefix scans every /// QueriedCellIds entry, and that sweep footprint provably spans /// NEIGHBOUR landblocks (CellTransit.AddOutsideCell re-derives the /// block id from the global lcoord and states outright that there is no /// same-block filter). The footprint does not EXIST until the sweep has /// run. /// /// /// re-reads this predicate and is subject to the /// same two gaps, plus a third: a non-Position rebucket (the projection /// materializer DatLiveEntityProjectionMaterializer — C4 route /// 4b-3 deleted the second shipped writer, RemoteTeleportController's /// rollback, and C4 route 7 D4 demoted the third, /// EquippedChildRenderController.TickChild, to a presentation- /// only bucket move that no longer touches record.FullCellId — /// Runtime's own D1/D2 propagation is the child's canonical writer now) /// can move record.FullCellId to a THIRD landblock between the /// retained submit and the retry. The remaining writer is /// harmless for the same reason (delta review N3). That reason is the /// paragraph below — NOT, as the round-2 text claimed, that re-reading /// record.CurrentCellId here would "re-derive a private Core /// predicate outside Core": this method already calls Core's own /// internal , /// so that objection was simply false (round-3 correction A5). /// /// /// Correctness lives at the source instead. /// SubmitPreparedPlacementCore's two quiescence parks are opted /// into ParkDeferred's rollback, and ParkDeferred then /// restores only when the cell it will actually restore into — /// body.CellPosition.ObjCellId, read AFTER the snap and tested /// against EVERY live quiescence — is not itself quiescing. /// Corrected round 4 (D5): the earlier text said "every shape this /// predicate cannot see is a merely-swept NEIGHBOUR", which contradicts /// the third-landblock rebucket shape named ten lines above. The right /// statement is weaker and does not need the enumeration: whatever the /// blocking prefix turns out to be, the rollback is decided against the /// RESTORE cell rather than against that prefix, so it re-admits nothing /// into any quiescing prefix and AP-136's reason for the blanket /// non-restorable scoping (a spatial root re-entering the prefix that is /// trying to quiesce) cannot apply. This predicate therefore only /// shrinks the reachable set, and the DeferredCell case in /// handles whatever still reaches Core. /// Recorded as AP-138(2). /// /// /// Two other properties DEPEND on this pre-flight staying here /// (round-3 correction A5). Do not delete it as redundant. First, /// N3's "a retained retry can no longer strand" argument: a retry whose /// destination has begun quiescing since the submit is refused HERE and /// takes the window-drop store_position, /// rather than reaching Core and opening a park into a prefix whose own /// restore is (correctly) declined. Second, the destination-quiescing /// shape is the one case where ParkDeferred would refuse to /// restore, so refusing ahead of it is what keeps that shape off the /// remote path entirely; without this call it becomes reachable and the /// remote is left withdrawn until a later packet commits. /// /// private bool CanAttemptDestination( RuntimeSetPositionState setPosition, uint landblockId) => _serviceWindow.IsWithinServiceWindow(landblockId) && !setPosition.IsCollisionPrefixQuiescing(landblockId); private static void CancelToken( RuntimeSetPositionState setPosition, in RuntimeEntityPlacementToken token) { // Cancellation, not withdrawal: this controller abandons a placement // intent while the remote stays in the world, so a DeferredCell park // must roll back rather than strand the entity invisible and // intangible (RuntimeSetPositionState.Forget). RuntimePlacementCancellationReceipt cancellation = setPosition.ForgetExactPlacement( token, restoreCancelledPark: true); if (cancellation.IsValid) setPosition.PublishCancellation(cancellation); } }