19 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, extractedRemoteMotion, and canonical physics-host ownership. Landed ind68c83d1,5882b308, andfcb66198. 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 —
GameWindowcleanup, 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:
LiveEntityHydrationControllerowns CreateObject, ObjDesc, Parent, Pickup, Delete/prune, DAT-backed appearance hydration, first materialization, landblock rehydration, ready publication, projection withdrawal, and exact App-component teardown overLiveEntityRuntime.LiveEntityNetworkUpdateControllerowns 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 @ 0x00454B20andQueueBlobForObject @ 0x00451B90;SmartBox::HandleReceivedPosition @ 0x00453FD0;SmartBox::DoPickupEvent @ 0x00452240andDoParentEvent @ 0x00452290;SmartBox::HandleDeleteObject @ 0x00451EA0;CPhysicsObj::set_description @ 0x00514F40;CPhysicsObj::set_state @ 0x00514DD0;CPhysicsObj::change_cell @ 0x00513390;CPhysicsObj::exit_world @ 0x00514E60andleave_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:
- 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 the0x8000boundary. - 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.
- 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.
- Movement consumes strict
MOVEMENT_TSbefore it can discover a stale server-controlled timestamp; equality on the latter is accepted. - Parent, Pickup, and Position share
POSITION_TS. Pickup unparents and leaves world; a later fresh Position unparents and restores the same object identity/resources. leave_worldis not deletion. It clears cell/shadow/contact/transient presentation while retaining PartArray, movement, animation, scripts, effects, timestamps, and identity. Logical destruction alone performsexit_worldmanager cleanup.- 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:
- construct the unbound bridge;
- construct
LiveEntityRuntimewith the bridge; - construct effect, projectile, presentation, child, and related owners;
- construct hydration;
- bind the bridge exactly once to hydration;
- construct and bind the network-update sink;
- 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
RemoteMotionmechanically; retarget all 51 App-test references. - Canonicalize physics-host ownership and remove
_physicsHostsonly 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.
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
GameWindowlacks 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 Releaseand 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.mdwhen current-state pointers change, and durable GameWindow/live-runtime memory.
5. Adversarial acceptance matrix
Automated acceptance includes:
- equal/old/new/wrapped
INSTANCE_TS, including0x8000; - 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:
- retail conformance — symbols, ordering, timestamps, and documented divergences;
- architecture/integration — identity ownership, dependency direction, update-thread rules, lifecycle symmetry, and GameWindow reduction;
- 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.