442 lines
22 KiB
Markdown
442 lines
22 KiB
Markdown
# GameWindow Slice 4 — live-entity App integration
|
|
|
|
**Status:** Complete 2026-07-21.
|
|
**Parent program:** [`docs/architecture/code-structure.md`](../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:**
|
|
|
|
- [x] 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.
|
|
- [x] 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.
|
|
- [x] 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.
|
|
- [x] 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.
|
|
- [x] E — Delete/prune and retryable exact-incarnation teardown ownership.
|
|
- [x] F — Position/Vector/State/Movement controller, same-generation CreateObject
|
|
tail, independent authority gates, and direct inbound cutover.
|
|
- [x] 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`](../research/2026-07-13-retail-projectile-vfx-pseudocode.md);
|
|
- [`2026-07-18-retail-object-liveness-and-mesh-reclamation-pseudocode.md`](../research/2026-07-18-retail-object-liveness-and-mesh-reclamation-pseudocode.md);
|
|
- [`2026-07-19-r6-update-object-order-pseudocode.md`](../research/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`:
|
|
|
|
```csharp
|
|
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:
|
|
|
|
```csharp
|
|
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:
|
|
|
|
```csharp
|
|
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.
|
|
|
|
Completed in `aa90c646`. `LiveEntityNetworkUpdateController` now owns accepted
|
|
Position, Vector, State, and Movement routing;
|
|
`LiveEntitySameGenerationUpdateRouter` owns the retail equal-generation
|
|
CreateObject tail. `LiveEntityInboundAuthorityGate` pins the exact record,
|
|
independent channel authority, and velocity authority before any reentrant App
|
|
callback. `LiveEntityMotionRuntimeController` owns the shared physics-host,
|
|
Setup, MoveTo/Sticky, Hidden-target, and server-controlled-cycle policy behind
|
|
a once-bound construction bridge. ForcePosition preserves retail's
|
|
blip-then-immediate-F7B1 order and stamps the exact Position snapshot serialized
|
|
on the wire. Focused tests cover stale/equal/wrapped timestamps, callback
|
|
replacement, GUID reuse, projectile/body/remote Vector precedence, mixed
|
|
same-generation routing, bridge binding, and the exact 56-byte autonomous
|
|
position payload. All three corrected-diff re-reviews were clean.
|
|
|
|
### 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.
|
|
|
|
Completed 2026-07-21. `GameWindow` fell from the Slice-3 baseline of 14,310
|
|
lines to 10,301 lines; its top-level field and method declarations are now 267
|
|
and 163. Release build completed with zero warnings/errors and the full suite
|
|
passed 6,940 tests with five intentional skips. The 310-second connected R6
|
|
route passed login, Caul/Sawato/Rynthid/Aerlinthe/Sawato-revisit/Holtburg/
|
|
Caul-return materialization, turn sampling, three locomotion/jump/combat
|
|
exercises, and graceful close. Live-server population churn, previously known
|
|
missing DAT VFX diagnostics, and empty world-edge landblocks remained warnings,
|
|
not lifecycle failures. Slice 5 is the next structural owner boundary.
|
|
|
|
## 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.
|