Move the sole PhysicsEngine, production cache, collision admissions, canonical bodies and hosts, remote components, ordinary/remote worksets, simulation, cell commits, and shadow synchronization under RuntimeEntityObjectLifetime. Keep App as the prepared-asset, animation-input, and render-projection adapter while preserving the named-retail update and collision order. Add exact-incarnation, object-clock, callback-reentrancy, GUID-reuse, two-runtime isolation, source ownership, collision publication, and graphical projection coverage. Release build and the complete 8,588-test solution pass. Co-authored-by: Codex <noreply@openai.com>
200 lines
8.8 KiB
Markdown
200 lines
8.8 KiB
Markdown
# Slice J5.5 — per-session physics and remote-simulation ownership
|
|
|
|
Date: 2026-07-26
|
|
Scope: ownership relocation only; no retail algorithm or gameplay-policy change
|
|
|
|
## Objective
|
|
|
|
Make one `AcDream.Runtime` instance own one complete mutable physics world:
|
|
|
|
- one `PhysicsEngine`, its transition-scratch arena, and its shadow registry;
|
|
- one production `PhysicsDataCache`/cell graph;
|
|
- canonical physics bodies and physics hosts;
|
|
- canonical remote movement/interpolation state;
|
|
- loaded/cell-backed ordinary and remote update worksets.
|
|
|
|
App remains responsible for DAT/package preparation, streaming policy, animation
|
|
pose production, render projection, effects, meshes, debug drawing, and UI. It
|
|
publishes immutable prepared collision records and animation-root inputs to the
|
|
Runtime owner, then applies committed Runtime snapshots to graphical objects.
|
|
|
|
This is the J5.5 boundary from
|
|
`docs/plans/2026-07-26-modern-runtime-slice-j5.md`. Projectile component
|
|
ownership and prediction remain explicitly deferred to J5.6.
|
|
|
|
## Named-retail oracle
|
|
|
|
Primary source:
|
|
`docs/research/named-retail/acclient_2013_pseudo_c.txt`.
|
|
|
|
- `CPhysics::UseTime` `0x00509950`
|
|
- `CPhysicsObj::UpdatePositionInternal` `0x00512C30`
|
|
- `CPhysicsObj::transition` `0x00512DC0`
|
|
- `CPhysicsObj::SetPositionInternal(CTransition const*)` `0x00515330`
|
|
- `CPhysicsObj::UpdateObjectInternal` `0x005156B0`
|
|
- `CPhysicsObj::update_object` `0x00515D10`
|
|
- `CPhysicsObj::MoveOrTeleport` `0x00516330`
|
|
- `CPhysicsObj::add_shadows_to_cells` `0x00514AE0`
|
|
|
|
The complete translated control flow is already pinned in
|
|
`docs/research/2026-07-19-r6-update-object-order-pseudocode.md`. The current
|
|
Core/App implementation was cross-checked there and in the R6/physics digest
|
|
against ACE's `PhysicsObj` interpretation and the extracted WorldBuilder
|
|
collision/content pipeline. J5.5 reuses that port unchanged.
|
|
|
|
## Preserved pseudocode
|
|
|
|
```text
|
|
for each ordinary object in the active object table:
|
|
elapsed = current physics time - object update time
|
|
apply retail epsilon / stale-quantum / subdivision gates
|
|
|
|
if object is Active:
|
|
if not Hidden:
|
|
advance PartArray and obtain the complete root-motion Frame
|
|
apply PositionManager correction to that Frame
|
|
compose the candidate position and orientation
|
|
if not Hidden:
|
|
integrate acceleration, velocity, and omega
|
|
drain object animation hooks
|
|
|
|
if the candidate frame moved:
|
|
run Transition against the object's current full cell
|
|
commit accepted frame, contact state, and full cell
|
|
update the object's collision shadows
|
|
|
|
DetectionManager.CheckDetection
|
|
TargetManager.HandleTargetting
|
|
MovementManager.UseTime
|
|
PartArray.HandleMovement
|
|
PositionManager.UseTime
|
|
|
|
ParticleManager.UpdateParticles
|
|
ScriptManager.UpdateScripts
|
|
```
|
|
|
|
The App/Runtime seam may split pose production from simulation, but it must not
|
|
change this observable ordering. In particular:
|
|
|
|
- root motion and the position-manager delta are complete before collision;
|
|
- the transition's swept full cell is canonical;
|
|
- a Hidden object is not the same as an inactive or deleted object;
|
|
- exact record/incarnation, authority version, and object-clock epoch are
|
|
revalidated after every callback;
|
|
- remote shadows follow the committed body frame, never a raw server sample;
|
|
- `CellGraph.CurrCell` remains local-player-only state.
|
|
|
|
## Baseline ownership gap
|
|
|
|
The canonical `RuntimeEntityRecord` already owns `PhysicsBody`,
|
|
`IPhysicsObjHost`, full cell, final physics state, accepted authority versions,
|
|
and `RetailObjectQuantumClock`. The remaining duplicate boundary is:
|
|
|
|
- `GameWindow` constructs the session `PhysicsEngine` and production
|
|
`PhysicsDataCache`;
|
|
- App `LiveEntityRecord` stores the remote-motion component;
|
|
- App `LiveEntityRuntime` stores remote and ordinary spatial workset indexes;
|
|
- App updaters both mutate canonical simulation and project `WorldEntity`;
|
|
- App streaming mutates the engine directly.
|
|
|
|
That baseline shape prevented a no-window Runtime from owning the same
|
|
simulation graph and made two simultaneous sessions harder to prove isolated.
|
|
J5.5 retires this gap.
|
|
|
|
## Target ownership
|
|
|
|
`RuntimeEntityObjectLifetime` constructs one `RuntimePhysicsState` beside its
|
|
entity directory. `RuntimePhysicsState` owns:
|
|
|
|
- the exact `PhysicsEngine` and production cache;
|
|
- remote components and physics hosts stored on `RuntimeEntityRecord`;
|
|
- keyed ordinary/remote worksets containing exact `RuntimeEntityKey` values;
|
|
- typed collision admission/withdrawal receipts;
|
|
- simulation commits and immutable presentation snapshots;
|
|
- reset/disposal convergence and an ownership ledger.
|
|
|
|
App acknowledgements contain no gameplay policy:
|
|
|
|
```text
|
|
prepared collision publication -> Runtime typed admission -> receipt
|
|
render spatial visibility edge -> Runtime workset acknowledgement
|
|
animated root Frame -> Runtime remote/ordinary tick
|
|
Runtime committed snapshot -> App WorldEntity/rebucket/pose projection
|
|
```
|
|
|
|
The immutable prepared collision payload may originate in App streaming. The
|
|
engine, transition scratch, cell graph, body, shadow registry, interpolation,
|
|
manager state, and workset are never shared across Runtime instances.
|
|
|
|
## Implemented boundary
|
|
|
|
- `RuntimeEntityObjectLifetime` constructs and disposes exactly one
|
|
`RuntimePhysicsState`.
|
|
- `RuntimePhysicsState` constructs the production `PhysicsDataCache` and the
|
|
sole `PhysicsEngine`, including its ten-deep reusable transition scratch and
|
|
shadow registry. App borrows both objects and cannot construct alternatives.
|
|
- `RuntimeEntityRecord` owns the canonical `PhysicsBody`, `RemoteMotion`,
|
|
`EntityPhysicsHost`, full cell, object clock, and exact-incarnation binding
|
|
guards.
|
|
- `RuntimePhysicsState` owns keyed ordinary/remote worksets, body acquisition,
|
|
host installation/rebinding/lookup, remote component binding, and typed
|
|
canonical cell commits.
|
|
- `RuntimeRemotePhysicsUpdater` and `RuntimeOrdinaryPhysicsUpdater` contain the
|
|
unchanged presentation-free retail simulation. Their App adapters supply
|
|
DAT-derived shape/animation inputs and project immutable pose snapshots only.
|
|
- `LandblockPhysicsPublisher` publishes the prepared collision root through a
|
|
generation-scoped `RuntimeCollisionAdmission`; demotion and withdrawal cross
|
|
the same typed Runtime boundary.
|
|
- Runtime cell commits synchronously publish
|
|
`RuntimePhysicsCellCommit`. The graphical subscriber revalidates the exact
|
|
record and spatial-authority version before rebucketing the render
|
|
projection.
|
|
- Two Runtime instances own distinct engines, caches, cell graphs, scratch
|
|
arenas, shadow registries, components, hosts, bodies, and worksets.
|
|
|
|
No retail algorithm, constant, order, packet, or gameplay policy changed, and
|
|
this ownership relocation introduces no retail-divergence row.
|
|
|
|
## Staged implementation boundary
|
|
|
|
1. Construct engine/cache under `RuntimePhysicsState`; make App borrow them.
|
|
2. Move presentation-free `RemoteMotion` and `EntityPhysicsHost` types into
|
|
Runtime and store the remote component on `RuntimeEntityRecord`.
|
|
3. Move remote/ordinary keyed worksets and their visibility acknowledgements
|
|
into `RuntimePhysicsState`.
|
|
4. Split remote/ordinary update into Runtime simulation commits and App
|
|
presentation acknowledgements without changing update order.
|
|
5. Replace direct streaming mutation with typed Runtime
|
|
admission/withdrawal receipts.
|
|
6. Remove App simulation mirrors and prove reset/two-instance isolation.
|
|
|
|
Each intermediate state must build and retain exact behavior. The production
|
|
commit remains independently revertible as the single J5.5 ownership unit.
|
|
|
|
## Acceptance evidence
|
|
|
|
- existing flat-collision conformance corpus remains bit-identical;
|
|
- reused versus fresh transition scratch stays equivalent and allocation-free;
|
|
- local and remote position/cell/orientation fixtures remain exact;
|
|
- crowd, doors, stairs, cell seams, Hidden, teleport, delete, and GUID-reuse
|
|
fixtures pass;
|
|
- two Runtime instances have distinct engine, cache, scratch, shadows, bodies,
|
|
hosts, remote components, and worksets;
|
|
- App production source cannot construct a `PhysicsEngine`,
|
|
`PhysicsDataCache`, canonical remote component, or simulation workset;
|
|
- Release build, focused Runtime/App suites, complete Release suite, connected
|
|
lifecycle/reconnect, and the canonical movement route pass.
|
|
|
|
Automated gate on the J5.5 production tree:
|
|
|
|
- Release solution build: zero warnings and zero errors.
|
|
- Core collision/physics suite: 3,273 passed / 2 skipped.
|
|
- Runtime suite: 314 passed.
|
|
- App suite: 3,718 passed / 3 skipped.
|
|
- Complete solution: 8,588 passed / 5 skipped.
|
|
- Source ownership guards prove App does not construct a `PhysicsEngine` or
|
|
production cache, does not contain the remote/ordinary transition solver,
|
|
and cannot directly admit/remove streamed landblock collision.
|
|
|
|
Connected lifecycle/reconnect and the canonical movement/collision route are
|
|
the exact-binary post-commit gate.
|