16 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.
- C — hydration create/materialize/landblock-recovery ownership and direct CreateObject/streaming cutover.
- D — ObjDesc/Parent/Pickup/ready/withdraw ownership and exact retained identity across leave-world/re-entry.
- 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.
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.
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.
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.