feat(runtime): own deferred set-position residence
This commit is contained in:
parent
e84a388e6f
commit
4c02ac4259
18 changed files with 5557 additions and 34 deletions
|
|
@ -140,3 +140,158 @@ collision-handler mapping, force-class policy, explicit shadow actions, null
|
|||
current-cell wakeup, ten-record scratch exhaustion, exact scatter ordering,
|
||||
failed-probe scratch lifetime, and deferred-scatter stop. The legacy public
|
||||
Resolve fixture remains unchanged until Slice 4B.
|
||||
|
||||
## Slice 4B1 — Runtime residence owner
|
||||
|
||||
Slice 4B1 adds the presentation-independent half of the cutover without
|
||||
changing a production graphical route yet. `RuntimeSetPositionState` accepts
|
||||
an exact entity/position token before graphical DAT preparation, consumes the
|
||||
immutable Core result, and commits body, contact, full cell, shadows, object
|
||||
clock, and Runtime spatial worksets before publishing one ordered placement
|
||||
delta. The delta carries the exact `RuntimeEntityKey`, session lifetime,
|
||||
position/spatial/placement versions, adjusted cell, collision generation, and
|
||||
optional portal-authority shape. A throwing or unavailable host does not roll
|
||||
simulation back: Runtime republishes the same projection token until the
|
||||
exact FIFO head is acknowledged. A newer operation changes an already-
|
||||
published token to `Discard` and increments its projection revision, so an
|
||||
acknowledgement of the previously observed Place/Withdraw cannot consume an
|
||||
unseen Discard. It is never silently forgotten. An unacknowledged lost-cell
|
||||
Withdraw transfers intact to a replacing accepted operation and remains the
|
||||
FIFO head before that replacement may publish Place.
|
||||
|
||||
The successful missing-cell path owns retail's residence shape:
|
||||
|
||||
```text
|
||||
SetPosition -> OK + DeferredCell
|
||||
retain adjusted Position and the same PhysicsBody/components
|
||||
clear only Active and suspend the object clock
|
||||
withdraw Runtime spatial worksets and shadow rows
|
||||
retain shadow registration and exact authored mover request
|
||||
append parentless root to (exact cell, collision generation)
|
||||
arm independent exact-key 25 s deadlines for root + direct children
|
||||
publish Withdraw
|
||||
|
||||
exact cell generation resident + Withdraw acknowledged
|
||||
re-run SetPosition with retained authored spheres and CurrentCellId=null
|
||||
atomically install complete result
|
||||
publish Place
|
||||
```
|
||||
|
||||
Lost-cell membership buckets use retail-shaped append plus swap-remove.
|
||||
Destruction deadlines use an exact-key hash plus a bounded indexed min-heap,
|
||||
the allocation-bounded modern equivalent of retail's hash +
|
||||
`PQueueArray<double>` priority owner. Rearm/removal updates the exact heap node;
|
||||
there are no stale tombstones. Only committed, current direct children from
|
||||
the parent-incarnation ordered CHILDLIST participate; unresolved or future
|
||||
relations cannot inherit a deadline. Parent, pickup, delete, GUID
|
||||
replacement, newer Position, reset, and disposal cancel the exact incarnation
|
||||
and use leave-world semantics rather than a wakeable lost entry. The dormant
|
||||
collision-retirement entry parks non-static parentless indoor roots and, for
|
||||
complete withdrawal, affected outdoor roots. It performs a complete preflight
|
||||
and rejects overlap with any active accepted/host-ack-pending placement before
|
||||
mutating one resident. It then installs every affected canonical lost
|
||||
residence and operation before publishing the first synchronous Withdraw, so
|
||||
an observer re-entering for a later root inherits that root's exact pending
|
||||
Withdraw instead of having its newly accepted placement cancelled by the
|
||||
retirement loop. 4B2 must quiesce that placement prefix before invoking the
|
||||
entry in the same transaction that installs host acknowledgements.
|
||||
|
||||
Runtime retains the last accepted prepared mover request, including exact
|
||||
off-center/two-sphere payloads, scale, flags, and step values. A cold resident
|
||||
with no prepared request still withdraws atomically but remains explicitly in
|
||||
`AwaitingPreparation`; it cannot wake through an invented empty-sphere shape.
|
||||
Preparation is cached only after Core accepts it as Committed or DeferredCell.
|
||||
A rejected/malformed preparation keeps the same accepted token retryable and
|
||||
cannot replace the last validated mover used by later collision retirement.
|
||||
Runtime's host boundary rejects only non-finite consumed frame/shape values;
|
||||
retail-valid oddities such as nonpositive authored scale remain untouched.
|
||||
Likewise, a non-deferred wake failure retains the withdrawn body, independent
|
||||
25-second lifetime, and exact operation: invalid arguments return to
|
||||
AwaitingPreparation and re-index for the next exact generation, while other
|
||||
world-placement failures also re-index. The last successful DeferredCell
|
||||
result and adjusted frame remain canonical across the failed attempt. No
|
||||
failed wake can leave a live entity withdrawn without a Runtime owner. The
|
||||
graphical/no-window cutover in 4B2 supplies that exact preparation token.
|
||||
|
||||
Retail `CPhysicsObj::SetPositionInternal` (`0x00515BD0`) calls
|
||||
`prepare_to_enter_world` (`0x00511FA0`) only when `this->cell == 0`.
|
||||
Consequently the physics `update_time` (`PhysicsBody.LastUpdateTime`) and
|
||||
active bit are reset only on the cellless-to-world edge. Ordinary same-cell or
|
||||
cross-cell in-world SetPosition preserves the already-consumed physics clock;
|
||||
entering the lost-cell residence also preserves it until the eventual
|
||||
cellless wake commit. Runtime pins both sides and does not inherit the older
|
||||
graphical teleport helper's unconditional timer reset.
|
||||
|
||||
The wake timestamp is in the Runtime simulation-time domain, never Unix/UTC:
|
||||
`GameRuntime` binds its instance `GameRuntimeClock` through the entity/physics
|
||||
owner, and RetryDeferred samples `SimulationTimeSeconds`. Standalone Runtime
|
||||
fixtures without a bound game clock retain the accepted command time. This is
|
||||
a Runtime dependency only; no App delegate enters the owner.
|
||||
|
||||
The canonical commit also installs every SetPosition-derived body invariant
|
||||
before host publication: Contact/OnWalkable/WaterContact, the current contact
|
||||
plane and slope `GroundNormal`, Sliding plus its normal, and the complete
|
||||
StationaryFall/Stop/Stuck encoding. Named retail
|
||||
`CPhysicsObj::SetPositionInternal(CTransition const*)` (`0x00515330`) copies
|
||||
only the transition's current contact plane/water flag, walkability, sliding
|
||||
normal/valid flag, and collision state (`0x005153E5–0x005154FE`). It does not
|
||||
publish `last_known_contact_plane` or the SpherePath walkable polygon on this
|
||||
path, so those ordinary-update-only fields are intentionally absent from the
|
||||
immutable SetPosition result and remain unchanged. A zero expected velocity
|
||||
version in host preparation preserves the nonzero version captured when the
|
||||
operation was accepted; an intervening Vector/Movement therefore suppresses
|
||||
only the stale collision-velocity response. A bodyless cancellation terminates
|
||||
without fabricating a PhysicsBody or a host Withdraw projection. The two time
|
||||
domains remain explicit: `PhysicsBody.LastUpdateTime` consumes the instance
|
||||
simulation clock, while `IRuntimeRemotePlacement.LastServerPositionTime`
|
||||
remains Unix-UTC receipt time because the remote stale-velocity owner ages it
|
||||
against `RuntimePhysicsState.UtcNowSeconds`. A deferred wake therefore cannot
|
||||
make fresh authoritative remote velocity appear years old. Runtime preparation
|
||||
also applies the existing retail `PositionFrameValidation` before Core or
|
||||
prepared-mover caching, and caps synchronous Scatter/RandomScatter work at 64
|
||||
attempts; this keeps valid authored retail request shapes while rejecting a
|
||||
hostile `uint.MaxValue` loop at the authority boundary.
|
||||
|
||||
Two boundaries intentionally remain open for 4B2:
|
||||
|
||||
- `RuntimePortalPlacementAuthority` validates immutable token shape only;
|
||||
4B2 must bind it to active `RuntimeWorldTransitState` generation, teleport
|
||||
sequence, destination, and host acknowledgement before reveal.
|
||||
- Runtime applies the canonical collision-report state but fails the handler
|
||||
return closed. Retail returns report/track success, not collision presence;
|
||||
the per-object report/tracking owner required for that boolean is not yet in
|
||||
Runtime, and the former environment/object-presence guess is forbidden.
|
||||
|
||||
AD-2 remains the explicit async adaptation: collision readiness can publish in
|
||||
a different frame from retail's blocking load. A failed wake is safely re-
|
||||
indexed to the next exact generation instead of inheriting retail's
|
||||
synchronous assumption. When older unbound survivors meet newer entities
|
||||
already indexed into that future generation, Runtime merges them into one
|
||||
bucket with the older survivor order first and retains one bucket-order entry.
|
||||
AP-1 and AD-1 remain open until 4B2 removes the legacy graphical/headless
|
||||
placement paths.
|
||||
|
||||
`RuntimeSetPositionStateTests` pins accepted-before-preparation ownership,
|
||||
portal-shape rejection, canonical-before-projection ordering, retry and
|
||||
reentrant discard, cross-landblock adjusted-cell park/wake, same-body
|
||||
identity, retained contact/water/sliding/velocity, exact generation gating,
|
||||
authored two-sphere retention, cold preparation, bounded priority-deadline
|
||||
rearm/cancel, zero-allocation empty ticks, independent ordered direct-child
|
||||
deadlines, actual collision-admission supersession/invalidation, missing exact
|
||||
indoor-cell generation rebind/wake, collision demotion/withdrawal preflight,
|
||||
failed-wake retry, malformed-preparation retry without cache poisoning,
|
||||
simulation-clock-domain wake, velocity-version preservation, derived body-bit
|
||||
writeback, immediate remote-velocity survival across the simulation/UTC clock
|
||||
boundary, invalid cell/frame/quaternion and extreme-scatter rejection before
|
||||
Core/caching, bodyless cancellation, newer Position/pickup/parent/delete, GUID
|
||||
reuse, reset, and complete index/node terminal convergence. Existing zero-
|
||||
allocation collision-generation gates remain unchanged on the no-deferred
|
||||
fast path.
|
||||
|
||||
The warmed immediate commit/ack route currently measures exactly **1,880
|
||||
managed bytes per operation** in the Release Runtime test host (1,000
|
||||
iterations after 64 warmups); the regression gate caps it at 2,048 bytes.
|
||||
This dormant-path result is an explicit 4B2 activation blocker rather than a
|
||||
claim of allocation-free production readiness: 4B2 must either pool/remove
|
||||
the operation and projection envelopes or record an approved measured budget
|
||||
before routing frame-frequency placement through this owner.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue