acdream/docs/plans/2026-07-21-gamewindow-slice-4-live-entity-integration.md

20 KiB

GameWindow Slice 4 — live-entity App integration

Status: Active 2026-07-21. Parent program: docs/architecture/code-structure.md, Slice 4. Baseline: ed9dc366; GameWindow.cs is 14,310 lines, 274 fields, and 190 methods before this slice. Release baseline: 6,714 passed / 5 skipped. Behavior rule: Preserve the accepted live-object identity, packet FIFO, independent timestamp authorities, render/physics/effect lifetime, and connected R6 behavior while moving their App integration to focused owners. Correct only proven retail-conformance defects with an explicit oracle and test; do not hide them inside a mechanical extraction.

Progress ledger:

  • A — canonical seams: LiveWorldOriginState, single-bind runtime-component lifecycle bridge, extracted RemoteMotion, and canonical physics-host ownership. Landed in d68c83d1, 5882b308, and fcb66198. The final exact-record host checkpoint passed three clean reviews plus 6,743 Release tests / 5 skipped on 2026-07-21.
  • B — pure appearance/projection helpers and controller-level characterization tests. Landed in 69a2ca0c. Exact appearance/collision replacement, default-pose resolution, local-shadow ownership, and recursive retained projection withdrawal passed three clean reviews plus 6,799 Release tests / 5 skipped on 2026-07-21.
  • C — hydration create/materialize/landblock-recovery ownership and direct CreateObject/streaming cutover. Landed in d10c5f2d; 6,854 Release tests passed / 5 skipped after three clean retail, architecture, and adversarial re-reviews on 2026-07-21.
  • D — ObjDesc/Parent/Pickup/ready/withdraw ownership and exact retained identity across leave-world/re-entry. Landed in fe551496; 6,877 Release tests passed / 5 skipped after three clean retail, architecture, and adversarial re-reviews on 2026-07-21.
  • E — Delete/prune and retryable exact-incarnation teardown ownership.
  • F — Position/Vector/State/Movement controller, same-generation CreateObject tail, independent authority gates, and direct inbound cutover.
  • G — GameWindow cleanup, three-agent review cycle, full Release suite, connected gates, documentation, and durable memory closeout.

1. Outcome and non-goals

This slice creates two cooperating App owners:

  • LiveEntityHydrationController owns CreateObject, ObjDesc, Parent, Pickup, Delete/prune, DAT-backed appearance hydration, first materialization, landblock rehydration, ready publication, projection withdrawal, and exact App-component teardown over LiveEntityRuntime.
  • LiveEntityNetworkUpdateController owns accepted Position, Vector, State, and Movement routing into the existing motion, physics, projectile, presentation, and teleport owners. It also consumes the same-generation CreateObject update tail without reconstructing the entity.

LiveEntityRuntime remains the only owner of server GUID ↔ local identity, incarnation, accepted snapshots, independent authority versions, spatial worksets, and teardown tombstones. Neither new controller may contain a GUID dictionary or cache an incarnation outside the runtime record it is currently validating.

This is not a new entity model, physics algorithm, renderer, packet decoder, or DAT reader. It does not retire the documented future-packet, visibility-PVS, or null-parent-queue divergences. It does not redesign the accepted update thread or RetailInboundEventDispatcher FIFO.

2. Retail and shipped oracles

The extraction is pinned to:

  • SmartBox::HandleCreateObject @ 0x00454C80;
  • ACCObjectMaint::CreateObject @ 0x00558870;
  • SmartBox::ProcessObjectNetBlobs @ 0x00454B20 and QueueBlobForObject @ 0x00451B90;
  • SmartBox::HandleReceivedPosition @ 0x00453FD0;
  • SmartBox::DoPickupEvent @ 0x00452240 and DoParentEvent @ 0x00452290;
  • SmartBox::HandleDeleteObject @ 0x00451EA0;
  • CPhysicsObj::set_description @ 0x00514F40;
  • CPhysicsObj::set_state @ 0x00514DD0;
  • CPhysicsObj::change_cell @ 0x00513390;
  • CPhysicsObj::exit_world @ 0x00514E60 and leave_world @ 0x005155A0;
  • 2026-07-13-retail-projectile-vfx-pseudocode.md;
  • 2026-07-18-retail-object-liveness-and-mesh-reclamation-pseudocode.md;
  • 2026-07-19-r6-update-object-order-pseudocode.md;
  • ACE and Holtburger object-update handlers as interpretation and protocol cross-checks, never as replacements for the named-retail ordering.

The following rules are load-bearing:

  1. One logical object exists per accepted INSTANCE_TS. Equal generation mutates it; newer generation tears down and replaces it; older generation is ignored using retail's wrap-safe comparison, including the 0x8000 boundary.
  2. A fresh CreateObject constructs, describes, attaches, enters world, then replays queued blobs. An equal-generation CreateObject applies ObjDesc, Parent or Position/Pickup, Movement, State, Vector, then WeenieDesc without recreating the object.
  3. Position, Movement, State, Vector, ObjDesc, Teleport, ForcePosition, ServerControlledMove, and Instance authorities remain independent. After every reentrant callback, the exact record and relevant authority version are revalidated.
  4. Movement consumes strict MOVEMENT_TS before it can discover a stale server-controlled timestamp; equality on the latter is accepted.
  5. Parent, Pickup, and Position share POSITION_TS. Pickup unparents and leaves world; a later fresh Position unparents and restores the same object identity/resources.
  6. leave_world is not deletion. It clears cell/shadow/contact/transient presentation while retaining PartArray, movement, animation, scripts, effects, timestamps, and identity. Logical destruction alone performs exit_world manager cleanup.
  7. Inbound processing is one FIFO. Nested heterogeneous packets wait until the active packet reaches its complete tail.

3. Architecture and interfaces

3.1 Shared origin state

LiveWorldOriginState owns the session-scoped world center currently spread across _liveCenterX, _liveCenterY, and _liveCenterKnown:

bool IsKnown { get; }
double CenterX { get; }
double CenterY { get; }
bool TryInitialize(double worldX, double worldY);
void Recenter(double worldX, double worldY);
void Reset();

Hydration, accepted Position/teleport, streaming, and render consumers share this state directly. No GameWindow callback conceals origin mutation.

3.2 Runtime component lifecycle

Introduce:

interface ILiveEntityRuntimeComponentLifecycle
{
    void TearDown(LiveEntityRecord exactRecord);
}

DeferredLiveEntityRuntimeComponentLifecycle is a composition-only, single-assignment bridge. Construction order is fixed:

  1. construct the unbound bridge;
  2. construct LiveEntityRuntime with the bridge;
  3. construct effect, projectile, presentation, child, and related owners;
  4. construct hydration;
  5. bind the bridge exactly once to hydration;
  6. construct and bind the network-update sink;
  7. only then permit a live session to start.

Calling before bind fails fast; second bind is rejected. This removes the circular GameWindow teardown façade without making runtime mutation optional. The existing CompositeLiveEntityResourceLifecycle remains the sole logical mesh/script registration transaction; hydration does not become a second resource owner.

3.3 Canonical runtime components

Move RemoteMotion out of GameWindow into AcDream.App.Physics without semantic changes. Store physics-host resolution on the exact LiveEntityRecord (or an explicit runtime-owned component index) rather than the duplicate _physicsHosts GUID dictionary. Local-player host publication uses the same focused owner, not a second identity table. Preserve the full-cell binding and remote-placement contract.

3.4 Hydration API

The controller surface is narrow and event-shaped:

void OnCreate(WorldSession.EntitySpawn spawn);
void OnObjDesc(ObjDescEvent.Parsed update);
void OnDelete(DeleteObject.Parsed update);
void OnPrune(LiveEntityPruneCandidate candidate);
void OnPickup(PickupEvent.Parsed update);
void OnParent(ParentEvent.Parsed update);
bool TryAcceptParentForRender(ParentEvent.Parsed update);
void OnLandblockLoaded(uint landblockId);
bool EnsureWorldOriginAndRecover(
    LiveEntityRecord expected,
    ulong positionAuthorityVersion,
    WorldSession.EntitySpawn acceptedSpawn);
void OnEntityReady(uint guid);
bool WithdrawWorldProjection(uint guid);

Hydration receives focused concrete collaborators/ports: runtime and object table, the sole DatCollection and shared DAT lock, physics data cache, spawn/animation/collision builders, spatial state/origin/streaming, and the existing effect/projectile/child/presentation/light owners. It must not receive a generic GameWindow context or a bundle of callbacks to old substantial methods.

ObjDesc mutates the captured exact entity. Acquire-before-publish rollback and post-callback incarnation checks preserve local ID, body, motion, physics host, effect owner, and parent state. Parent-on-spawn may reenter; the canonical snapshot is reread afterward. A materialized object only rebuckets; a pending, never-materialized object hydrates once. Landblock load never replays create-time logical resource activation.

3.5 Network-update API

The network owner accepts Position, Vector, State, Movement, and the equal- generation CreateObject tail. It resolves through LiveEntityRuntime, captures the relevant authority version, calls existing focused runtime owners, and revalidates exact record plus authority after every callback.

Hydration calls a once-bound ILiveEntityNetworkUpdateSink for the same-generation tail. Network position recovery calls EnsureWorldOriginAndRecover; no substantial dispatch returns to GameWindow. Local ForcePosition, teleport presentation, projectile corrections, shadow updates, movement animation, and static/headless branches retain their shipped ordering.

3.6 Direct composition

At slice exit these callbacks point directly to the new owners:

  • session Create/Delete/Pickup/Parent/ObjDesc/Position/Vector/State/Movement;
  • streaming landblock-loaded rehydration;
  • liveness prune;
  • equipped-child parent acceptance and entity-ready replay;
  • runtime exact-component teardown.

GameWindow keeps controller construction plus narrow frame calls. The old handler, hydration, collision-registration, appearance-rebind, ready, leave-world, and teardown method bodies must be absent, not retained as one-line façades.

4. Commit sequence and gates

A — canonical seams

  • Add and test LiveWorldOriginState.
  • Add and test the fail-fast, single-bind lifecycle bridge.
  • Extract RemoteMotion mechanically; retarget all 51 App-test references.
  • Canonicalize physics-host ownership and remove _physicsHosts only after resolution/teardown/local-player tests prove equivalence.
  • Run App remote-motion, runtime, physics-host, session-reset, and structural suites; full Release build/test; three-agent review and re-review.

B — presentation helpers and characterization

  • Extract AppearanceUpdateState, appearance rebind, default-pose, and collision-build helpers behind focused App types.
  • Preserve the exact DAT lock and existing extracted WorldBuilder pipeline.
  • Add controller-harness fakes that require no Silk/GL context.
  • Characterize current leave-world failure ordering rather than silently redesigning it.
  • Run appearance, animation, spawn-adapter, collision, resource-lifecycle, and new characterization suites; full Release build/test; review cycle.

Completed in 69a2ca0c. The checkpoint also pinned the retail add_child / set_parent / leave_world boundary required by C and D: parent timestamps are staged before validation, accepted relationships are committed one at a time, and world withdrawal recursively removes the exact parent-first projection subtree while retaining logical identity and retry ownership. Release build completed with zero warnings and errors; 6,799 tests passed with five intentional skips; retail, architecture, and adversarial re-reviews were clean.

C — create and materialization

  • Implement hydration CreateObject registration, first materialization, pending deferral, landblock recovery, and ready publication.
  • Preserve prior-incarnation cleanup failure aggregation and rollback.
  • Route session CreateObject and streaming callbacks directly.
  • Tests: loaded create order; pending→loaded; materialized rebucket; same/ older/new/wrapped generations; nested callback replacement; registration failure/retry; no duplicate mesh/script/effect activation.
  • Full Release build/test; review cycle.

Completed in d10c5f2d. LiveEntityHydrationController now owns the exact CreateObject registration transaction, world-origin bootstrap, pending deferral, first DAT projection materialization, landblock recovery, and the ready/PES replay boundary. Same-generation CreateObject supersession carries a monotonic integration version and a persistent retry obligation, so an older reentrant materialization cannot publish or erase the newer canonical snapshot. Parent and pickup creates complete through their retail cell-less paths, while interrupted initial hydration reuses the same animation sequencer and completed owners retain their exact phase and callback queues. Session CreateObject and streaming callbacks route directly to the extracted owner; the old GameWindow bodies are gone. Release build completed with zero warnings and errors; 6,854 tests passed with five intentional skips; retail, architecture, and adversarial re-reviews were clean.

D — appearance, parenting, pickup, withdrawal

  • Move ObjDesc, Parent, Pickup, child-ready, collision registration, and projection withdrawal.
  • Tests: identity/component preservation; acquire failure rollback; stale or reentrant ObjDesc; parent-before-create canonical reread; Pickup/Parent leave-world; Position re-entry with unchanged local ID/resources.
  • Bind child callbacks directly and remove their GameWindow façades.
  • Full Release build/test; review cycle.

Completed in fe551496. LiveEntityHydrationController now owns accepted ObjDesc, Parent, Pickup, child-ready, and exact leave-world/re-entry routing. ObjDesc carries an independent authority/retry transaction and reports success only when the current visual projection is published; delayed landblock or Position recovery therefore refreshes the player paperdoll exactly once. Attached objects re-realize through the equipped-child owner without requiring a world Position, retain their local identity/resources, and restore their complete descendant chain synchronously. Ready publication pins the exact create, Position, ObjDesc, projection-mutation, projection-kind, spatial, and entity authorities across every callback. The retail absent AnimationFrame default is placement zero. Release build completed with zero warnings and errors; 6,877 tests passed with five intentional skips; retail, architecture, and adversarial re-reviews were clean.

E — delete and exact teardown

  • Move Delete/prune, teardown-plan construction, leave-world component cleanup, and retry tombstone behavior.
  • Bind runtime bridge and liveness directly.
  • Tests: unknown/stale/current Delete; callback deletion; dual failure; teardown retry; same-GUID newer generation during old teardown; reset convergence; no surviving renderer/collision/script/effect/light owner.
  • Full Release build/test; review cycle.

Completed in f38822c4. LiveEntityRuntimeTeardownController now owns the retryable App-component half of retail CObjectMaint::DeleteObject and keeps the stable cleanup plan on the exact record tombstone. Hydration rejects the local player before every lookup or side effect, gates remote Delete by the exact Instance timestamp, discards only unknown-owner pending effects, and routes the 25-second prune through the same transaction. Successful cleanup steps never replay after a failure; a same-GUID replacement cannot be mutated by the old incarnation's delayed cleanup. The derived remote stop-observation state also has a focused session owner instead of a loose GameWindow dictionary. Full Release validation passed 6,891 tests with five intentional skips and no errors; all three corrected-diff re-reviews were clean.

F — network-update owner

  • Move Movement, Vector, State, and Position routing plus the equal-generation CreateObject tail.
  • Preserve FIFO and independent authorities; test stale, equal, wrap, nested, and callback-invalidated updates for every channel.
  • Preserve ForcePosition, server-controlled move, teleport, projectile, shadow, static, airborne, autonomous, animated, and headless branches.
  • Route session callbacks directly and remove old GameWindow handlers.
  • Full Release build/test; review cycle.

G — closeout

  • Structural tests prove both controllers lack identity dictionaries and GameWindow lacks every moved field/type/method/body.
  • Run all live-runtime, object-table, parent/attachment, appearance/animation, effect/light/projectile, remote-motion/physics, inbound FIFO, liveness, stress, session-reset, and router suites.
  • Run dotnet build AcDream.slnx -c Release and full Release tests.
  • Run the connected R6 route and graceful reconnect gate, then user visual checks for inventory/equip/parenting, death/corpse, and portals when available.
  • Update architecture, roadmap, milestones, issues/divergence register, this ledger, AGENTS.md/CLAUDE.md when current-state pointers change, and durable GameWindow/live-runtime memory.

5. Adversarial acceptance matrix

Automated acceptance includes:

  • equal/old/new/wrapped INSTANCE_TS, including 0x8000;
  • full same-generation call trace and WeenieDesc tail ordering;
  • nested heterogeneous FIFO and exact authority invalidation;
  • fresh loaded create and pending→loaded without replay;
  • loaded→loaded rebucket and loaded↔pending oscillation;
  • ObjDesc identity/body/motion/host/effect/parent preservation;
  • Parent/Pickup→cell-less→Position re-entry with unchanged local ID;
  • unknown/stale/current Delete, callback delete, GUID reuse, and retry;
  • state side-effect order and movement/ForcePosition timestamp order;
  • projectile and remote-position corrections across landblocks;
  • bridge unbound/second-bind failures;
  • session reset with zero surviving live owners;
  • 96-owner and repeated-recall stress with no resource growth;
  • source/reflection ownership gates.

Connected acceptance includes:

  • capped login and populated radar/world;
  • remote creature motion and target/status projection;
  • wield/dewield, bow/wand/melee switching, ammo parenting, inventory pickup;
  • open and loot a corpse after approach;
  • kill/death/corpse lifetime;
  • recall and portal travel across landblocks, revisit, graceful close, and fresh-process reconnect;
  • uncapped post-reconnect performance checkpoint.

6. Review discipline

Every ownership commit receives three independent read-only reviews:

  1. retail conformance — symbols, ordering, timestamps, and documented divergences;
  2. architecture/integration — identity ownership, dependency direction, update-thread rules, lifecycle symmetry, and GameWindow reduction;
  3. adversarial testing — malformed/stale packets, callback reentrancy, registration failure, GUID reuse, landblock churn, reset, and leaks.

The primary agent reproduces and fixes confirmed findings, reruns focused and full gates, and requests re-review until no actionable finding remains. No subagent writes the implementation.

7. Explicit carried divergences

Slice 4 preserves, rather than disguises:

  • AD-32 future-generation non-effect packet dropping;
  • AP-65 picked-up data-only weenie retention;
  • AP-69 approximate 384-unit visibility envelope;
  • TS-32 missing complete child-before-parent null-object queue;
  • the equal-generation PES-table refresh and VectorUpdate airborne/state adaptations recorded during Slice 4 planning.

These remain visible in the divergence register and are not evidence that the ownership extraction itself is incomplete.