docs(architecture): close GameWindow slice 5
This commit is contained in:
parent
4a205a3e56
commit
d4ecac1da3
7 changed files with 70 additions and 43 deletions
|
|
@ -1,7 +1,7 @@
|
|||
# acdream — code structure & extraction sequence
|
||||
|
||||
**Status:** Living document. Created 2026-05-16; implementation reconciliation
|
||||
completed 2026-07-21; Slices 1–4 landed the same day. This is the active
|
||||
completed 2026-07-21; Slices 1–5 landed the same day. This is the active
|
||||
structural program before new M4 subsystems enter the App layer.
|
||||
**Purpose:** Describe the desired structural state of the App layer,
|
||||
explain the rules we've adopted, and lay out the safe extraction
|
||||
|
|
@ -27,7 +27,7 @@ after Slice 1 14,912 lines / 278 fields / 191 method
|
|||
after Slice 2 14,546 lines / 277 fields / 190 methods
|
||||
after Slice 3 14,310 lines / 274 fields / 190 methods
|
||||
after Slice 4 10,301 lines / 267 fields / 163 methods
|
||||
after Slice 5G 8,793 lines (field/method closeout in H)
|
||||
after Slice 5 closeout 8,811 lines / 247 fields / 153 methods
|
||||
```
|
||||
|
||||
`GameWindow` is the single object that:
|
||||
|
|
@ -400,7 +400,7 @@ useful ordering seam, but its ownership status is **partial**.
|
|||
| World reveal | **Complete** | `WorldRevealCoordinator` owns login/portal readiness and reveal lifetime (`a4ef5788`). The accepted deterministic lifecycle trace did not change after extraction. |
|
||||
| Retained gameplay UI | **Mostly complete feature ownership** | `RetailUiRuntime` and focused panel/controllers own layout and behavior. `GameWindow.OnLoad` still performs substantial service composition, which is allowed until the final composition cleanup. |
|
||||
| Selection/interaction | **Complete** | `WorldSelectionQuery` owns read-only picking/classification/range queries; `SelectionInteractionController` owns selection intent, Use/PickUp transport, exact-incarnation queues, and auto-walk deferral; `ItemInteractionController` owns ItemHolder policy plus the shared retail inventory-request transaction. `GameWindow` retains construction and narrow lifecycle forwarding only. |
|
||||
| Landblock presentation | **Complete; closeout active** | `LandblockBuildFactory` owns the captured-origin DAT transaction; concrete render/physics/DAT-static publishers and `LandblockPresentationPipeline` own publication and exact retryable retirement. `StreamingOriginRecenterCoordinator` serializes old-window retirement with teleport/session origin lifetimes. `GameWindow` retains construction and one pipeline field only (`c79d0a49`). |
|
||||
| Landblock presentation | **Complete** | `LandblockBuildFactory` owns the captured-origin DAT transaction; concrete render/physics/DAT-static publishers and `LandblockPresentationPipeline` own publication and exact retryable retirement. `StreamingOriginRecenterCoordinator` serializes old-window retirement with teleport/session origin lifetimes. `GameWindow` retains construction and one pipeline field only (`c79d0a49`, closeout `4a205a3e`). |
|
||||
| Render-frame orchestration | **Not extracted** | `OnRender` plus its portal/PView/alpha/particle helpers still own the draw graph and frame-local scratch state. There is no `RenderFrameOrchestrator` yet. |
|
||||
| Unified `GameEntity` | **Deferred target** | `LiveEntityRuntime` already supplies the critical canonical owner. Full type aggregation is a separate high-risk migration and is not required to make `GameWindow` thin. |
|
||||
|
||||
|
|
@ -547,15 +547,19 @@ Slice 5 checkpoints A–G are complete. The pipeline owns the serialized worker
|
|||
build, concrete render/physics/static publication, and retryable Near/full
|
||||
retirement. The direct cutover deleted the legacy apply/facade/scratch body and
|
||||
added one retained shared-origin lifetime transaction for teleport, logout,
|
||||
and fast relogin. `GameWindow.cs` is 8,793 raw lines and no longer owns
|
||||
landblock build/apply/retirement behavior. Deterministic and connected closeout
|
||||
is active in H.
|
||||
and fast relogin. `GameWindow.cs` was 8,793 raw lines at checkpoint G and no
|
||||
longer owns landblock build/apply/retirement behavior. H then corrected native
|
||||
shutdown ordering so live-session reset converges before the streamer and
|
||||
other reset dependencies are disposed. The final measurement is 8,811 raw
|
||||
lines / 247 fields / 153 methods. The complete Release suite (7,054 pass / 5
|
||||
skip), the 311-second capped/reconnect lifecycle gate, and the synchronized
|
||||
394-second nine-stop resource soak all pass (`4a205a3e`).
|
||||
|
||||
#### Slice 5 — extract landblock presentation — CHECKPOINTS A–G COMPLETE
|
||||
#### Slice 5 — extract landblock presentation — COMPLETE
|
||||
|
||||
Detailed execution ledger:
|
||||
[`docs/plans/2026-07-21-gamewindow-slice-5-landblock-presentation.md`](../plans/2026-07-21-gamewindow-slice-5-landblock-presentation.md)
|
||||
(active).
|
||||
(complete).
|
||||
|
||||
Create `LandblockPresentationPipeline` around the existing immutable
|
||||
`LandblockBuild` transaction. It owns DAT build context, scenery/EnvCell
|
||||
|
|
@ -565,8 +569,8 @@ what is resident; `GpuWorldState` continues owning spatial buckets.
|
|||
|
||||
Tests pin loaded/pending/demoted/unloaded symmetry, stale build generations,
|
||||
resource pin/release balance, collision footprints across landblock seams, and
|
||||
first-login bootstrap replacement. Run the deterministic world-lifecycle gate
|
||||
and the seven-destination resource soak.
|
||||
first-login bootstrap replacement. The deterministic world-lifecycle gate and
|
||||
nine-destination resource soak pass.
|
||||
|
||||
#### Slice 6 — extract update-frame orchestration
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ accepted-divergence entries (#96, #49, #50).
|
|||
|---|---|---|---|---|---|
|
||||
| AD-38 | Outgoing teleport viewports retire when retail's quantized animation level exceeds the last captured visible level 1022 (index 96), suppressing levels 1023/1024 up to 20.2 ms before retail's literal `elapsed >= 1.0` state edge. Incoming fades retain the exact timer. | `src/AcDream.Core/World/TeleportAnimSequencer.cs` (`OutgoingViewportReachedTerminalProjection`) | An uncapped 2000 FPS pass can publish the finite tunnel at levels 1023/1024 even though the paired 2013 retail capture switches viewports after 1022. The table-level cutover preserves the captured visible viewport ordering without throttling the application. | Exit sound, viewport replacement, and logout tunnel entry can occur at most two easing-table quanta (about 20.2 ms) earlier than retail's logical timer. | `UIGlobals::GetAnimLevel @ 0x004EE540`; `gmSmartBoxUI::UseTime @ 0x004D6E30`; paired retail/acdream captures documented in `docs/research/2026-07-15-retail-portal-space-pseudocode.md` |
|
||||
| AD-1 | Lost-cell machinery replaced by recoverable outdoor demote (**#107** safety net) + outdoor-restore `max(terrainZ, z)` under-terrain lift; retail goes `GotoLostCell` | `src/AcDream.Core/Physics/PhysicsEngine.cs:553` (+ :808) | acdream has no lost-cell state machine; outdoor landcell is the recoverable equivalent; the #107 auto-entry hold should make the demote branch unreachable | Gap in the hold → player committed to outdoor terrain inside/under a building (fake-grounded spawn, fall-through); a legit below-heightmap server restore is silently lifted — upward warp vs server | `GotoLostCell` pc:283418; `SetPositionInternal` 0x00515bd0, pc:283892-283945 |
|
||||
| AD-2 | Async readiness gates replace retail's synchronous destination cell load. **#229 refinement (2026-07-20):** login and F751 portal-space exit now share `WorldRevealReadinessBarrier`, so neither path can expose the normal viewport until the same render-publication, composite-texture, and collision domains converge. A hydratable indoor claim requires its owning Near-tier static/EnvCell mesh set, destination composites, and exact EnvCell physics (`IsSpawnCellReady`); an outdoor claim requires those render domains plus terrain/collision residency for the priority near ring. Hard-recenter generations and tier-aware completion application prevent stale overlapping loads/unloads or Far/Near jobs from opening or erasing the gate; mesh upload remains separate from balanced landblock ownership. Claims beyond NumCells still take the loud forced-placement path. `WorldRevealCoordinator` owns this shared lifetime; diagnostic telemetry observes its generation without defining another readiness path. The portal hold→materialize→regain-control lifecycle remains owned by `TeleportAnimSequencer`. | `src/AcDream.App/Streaming/WorldRevealCoordinator.cs`; `src/AcDream.App/Streaming/WorldRevealReadinessBarrier.cs`; `src/AcDream.App/Rendering/GameWindow.cs` (owner wiring + draw eligibility); `src/AcDream.App/Streaming/StreamingController.cs` (`IsRenderNeighborhoodResident`); `src/AcDream.App/Streaming/GpuWorldState.cs` (`IsRenderReady`); `src/AcDream.App/Rendering/Wb/LandblockSpawnAdapter.cs`; `src/AcDream.Core/Physics/PhysicsEngine.cs` (`IsSpawnCellReady`, `IsNeighborhoodTerrainResident`) | This is the asynchronous equivalent of retail leaving `SmartBox::position_update_complete` false while `CellManager::blocking_for_cells` is set: neither initial login nor portal arrival may reveal an empty collision world, a terrain-only Far shell, or a published-but-not-drawable GPU landblock. Indoor does not require a terrain heightmap, only the owning render landblock and exact EnvCell. | Gate opens early → grey/untextured first login or portal reveal, free-fall, wrong-cell rooting, or missing scenery; predicate never satisfies (streamer/DAT/upload failure) → login remains behind the world render gate, while portal transit reaches its existing loud timeout/forced-placement diagnostic. | `SmartBox::UseTime` 0x00455410; `gmSmartBoxUI::EndTeleportAnimation` 0x004D65A0 |
|
||||
| AD-2 | Async readiness gates replace retail's synchronous destination cell load. **#229 refinement (2026-07-20):** login and F751 portal-space exit now share `WorldRevealReadinessBarrier`, so neither path can expose the normal viewport until the same render-publication, composite-texture, and collision domains converge. A hydratable indoor claim requires its owning Near-tier static/EnvCell mesh set, destination composites, and exact EnvCell physics (`IsSpawnCellReady`); an outdoor claim requires those render domains plus terrain/collision residency for the priority near ring. Hard-recenter generations and tier-aware completion application prevent stale overlapping loads/unloads or Far/Near jobs from opening or erasing the gate; mesh upload remains separate from balanced landblock ownership. Claims beyond NumCells still take the loud forced-placement path. `WorldRevealCoordinator` owns this shared lifetime; diagnostic telemetry observes its generation without defining another readiness path. The portal hold→materialize→regain-control lifecycle remains owned by `TeleportAnimSequencer`. | `src/AcDream.App/Streaming/WorldRevealCoordinator.cs`; `src/AcDream.App/Streaming/WorldRevealReadinessBarrier.cs`; `src/AcDream.App/Streaming/StreamingOriginRecenterCoordinator.cs`; `src/AcDream.App/Streaming/LandblockPresentationPipeline.cs`; `src/AcDream.App/Rendering/GameWindow.cs` (owner wiring + draw eligibility); `src/AcDream.App/Streaming/StreamingController.cs` (`IsRenderNeighborhoodResident`); `src/AcDream.App/Streaming/GpuWorldState.cs` (`IsRenderReady`); `src/AcDream.App/Rendering/Wb/LandblockSpawnAdapter.cs`; `src/AcDream.Core/Physics/PhysicsEngine.cs` (`IsSpawnCellReady`, `IsNeighborhoodTerrainResident`) | This is the asynchronous equivalent of retail leaving `SmartBox::position_update_complete` false while `CellManager::blocking_for_cells` is set: neither initial login nor portal arrival may reveal an empty collision world, a terrain-only Far shell, or a published-but-not-drawable GPU landblock. Indoor does not require a terrain heightmap, only the owning render landblock and exact EnvCell. | Gate opens early → grey/untextured first login or portal reveal, free-fall, wrong-cell rooting, or missing scenery; predicate never satisfies (streamer/DAT/upload failure) → login remains behind the world render gate, while portal transit reaches its existing loud timeout/forced-placement diagnostic. | `SmartBox::UseTime` 0x00455410; `gmSmartBoxUI::EndTeleportAnimation` 0x004D65A0 |
|
||||
| AD-3 | Outdoor seeds always walk the transit array (retail skips the walk when the seed CLandCell is null/unloaded); per-cell lookups no-op on unhydrated data | `src/AcDream.Core/Physics/CellTransit.cs:503` | Equivalence argument: with nothing hydrated every lookup inside the walk no-ops, so the result matches retail's skipped walk | Near partially-streamed landblocks, building-transit promotion silently can't fire until structs hydrate — membership stays outdoor while the player is inside a building | `CObjCell::find_cell_list` 0052b535-0052b56c (null-CLandCell case) |
|
||||
| AD-4 | `point_in_cell` against an unhydrated CellBSP returns false (skip) rather than the null-node "inside" default; retail never queries unloaded cells | `src/AcDream.Core/Physics/CellTransit.cs:588` | The null-node default would make an unhydrated cell spuriously claim every point; skipping is the conservative streaming-safe choice | During hydration, a point genuinely inside a not-yet-loaded cell resolves outdoor/stale — transient membership misclassification driving wrong collision set and render root | `CEnvCell::find_visible_child_cell` :311397; cell-BSP vtable[0x84] |
|
||||
| AD-5 | Outdoor `point_in_cell` is an identity compare against the global XY-column cell from `LandDefs.AdjustToOutside` (no per-cell containment test) | `src/AcDream.Core/Physics/CellTransit.cs:865` | Landcells are disjoint 24 m columns — identity-compare against the column under the sphere centre is exactly equivalent to retail's per-candidate test | If block-origin/lcoord math is wrong at a landblock seam, the compare silently never matches — outdoor membership freezes at boundaries (the pre-#106 symptom) | `find_cell_list` pick pc:308788-308825; `CLandCell::point_in_cell` (get_block_offset pc:308804) |
|
||||
|
|
|
|||
|
|
@ -47,15 +47,16 @@ passes 6,940 tests with five intentional skips. The 310-second connected R6
|
|||
gate passed seven destinations/revisits, movement/jump/combat exercises, and
|
||||
graceful close.
|
||||
|
||||
**Current:** Slice 5 checkpoints A–G have extracted the DAT-backed worker
|
||||
Slice 5 is complete: checkpoints A–G extracted the DAT-backed worker
|
||||
build plus render, physics, DAT-static, and retryable Near/full presentation
|
||||
ownership into `LandblockPresentationPipeline`. Production has no callback
|
||||
facade back into the deleted GameWindow apply bodies. A retained shared-origin
|
||||
transaction retires the complete old window before teleport recenter or
|
||||
session replacement, including failure/retry and fast relogin. `GameWindow` is
|
||||
8,793 raw lines (44% below the campaign baseline) and the Release suite passes
|
||||
7,052 tests with five intentional skips. Slice 5H deterministic and connected
|
||||
closeout is active.
|
||||
session replacement, including failure/retry and fast relogin. Shutdown keeps
|
||||
the reset graph alive until disposal converges. `GameWindow` is 8,811 raw
|
||||
lines / 247 fields / 153 methods (44% below the campaign baseline); 7,054
|
||||
Release tests, the capped/reconnect lifecycle gate, and the synchronized
|
||||
nine-stop resource soak pass. Slice 6 update-frame orchestration is active.
|
||||
|
||||
This is a behavior-preserving structural program. Severe regressions still get
|
||||
root-cause fixes in separate commits; ordinary feature work resumes with M4
|
||||
|
|
|
|||
|
|
@ -19,14 +19,15 @@ layer, the active structural prerequisite is the behavior-preserving
|
|||
The 2026-07-21 audit baseline was 15,723 lines, 278 fields, and 205 methods.
|
||||
Selection/interaction Slice 1, live-animation-presentation Slice 2, complete
|
||||
live-session ownership Slice 3, and live-entity App integration Slice 4 are
|
||||
complete. Slice 5 landblock-presentation checkpoints A–G are also complete:
|
||||
complete. Slice 5 landblock presentation is also complete:
|
||||
the worker DAT transaction, render/physics/static publishers, and retryable
|
||||
Near/full retirement now have focused owners. The direct production cutover
|
||||
also serializes complete old-window retirement with teleport and session
|
||||
origin lifetimes. `GameWindow` is 8,793 raw lines, down 1,508 from the Slice-5
|
||||
baseline and 6,930 (44%) from the campaign baseline. The full Release suite
|
||||
passes 7,052 tests / 5 skips; Slice 4's seven-destination connected R6 route
|
||||
passed in 310 seconds. Slice 5H deterministic/connected closeout is active.
|
||||
origin lifetimes. `GameWindow` is 8,811 raw lines / 247 fields / 153 methods,
|
||||
down 1,490 lines from the Slice-5 baseline and 6,912 (44%) from the campaign
|
||||
baseline. The full Release suite passes 7,054 tests / 5 skips; the 311-second
|
||||
capped/reconnect lifecycle gate and synchronized 394-second nine-destination
|
||||
resource soak both pass. Slice 6 update-frame orchestration is next.
|
||||
|
||||
Carried:
|
||||
#153 far-teleport residual, #116 slide-response, the remaining R6 ownership cleanup plus
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# GameWindow Slice 5 — landblock presentation
|
||||
|
||||
**Status:** Active 2026-07-21.
|
||||
**Status:** Complete 2026-07-21 (`4a205a3e`).
|
||||
**Parent program:** [`docs/architecture/code-structure.md`](../architecture/code-structure.md), Slice 5.
|
||||
**Baseline:** `2b10e91e`; `GameWindow.cs` is 10,301 lines, 267 fields, and
|
||||
163 methods. Release baseline: 6,940 passed / 5 skipped. The connected R6
|
||||
|
|
@ -98,9 +98,23 @@ test, and bisectable commit rather than being hidden in a mechanical move.
|
|||
`GameWindow.cs` is 9,011 lines.
|
||||
- [x] G — cut `StreamingController` and `GameWindow` directly to the pipeline;
|
||||
delete old bodies, scratch state, and callback facades.
|
||||
- [ ] H — three-agent corrected-diff review, full Release suite, deterministic
|
||||
lifecycle gate, seven-destination resource soak, documentation, and durable
|
||||
- [x] H — three-agent corrected-diff review, full Release suite, deterministic
|
||||
lifecycle gate, nine-destination resource soak, documentation, and durable
|
||||
memory closeout.
|
||||
- Landed in `4a205a3e`: native shutdown now keeps the live-session reset
|
||||
dependencies alive until deferred/reentrant disposal actually converges;
|
||||
source and behavioral tests pin that completion barrier. Both connected
|
||||
harnesses scan the final post-close logs for shutdown/disposed-resource
|
||||
failures. The resource gate uses an already-warm Caul → Sawato → Caul
|
||||
plateau instead of comparing a cold first load to a warmed cache, and
|
||||
every route command blocks on its exact portal-materialization count.
|
||||
- All three final reviews are clean. Release gate: 7,054 passed / 5 skipped.
|
||||
The capped/reconnect lifecycle gate passed in 311.4 seconds. The
|
||||
synchronized nine-stop soak passed in 394.1 seconds; Caul return → plateau
|
||||
changed working/private memory by only +56.4/+48.4 MiB and update p95 by
|
||||
0.8 → 0.7 ms. `GameWindow.cs` closes Slice 5 at 8,811 raw lines, 247
|
||||
fields, and 153 methods—1,490 lines below the Slice-5 baseline and 6,912
|
||||
lines (44%) below the campaign baseline.
|
||||
|
||||
Every checked checkpoint is committed as a bisectable architectural unit.
|
||||
Documentation records the exact commit and accepted test count as work lands.
|
||||
|
|
@ -385,15 +399,15 @@ the shared origin may be reused. Reviews closed full-window overlap, radius
|
|||
reconfiguration, sealed-dungeon bootstrap, committed-callback retry,
|
||||
reentrancy, fast-relogin, and ordinary-logout gaps. Three final reviews are
|
||||
clean; the zero-warning Release build and 7,052 tests pass with five skips.
|
||||
`GameWindow.cs` is 8,793 raw lines, 1,508 below the Slice-5 baseline and 6,930
|
||||
(44%) below the campaign baseline.
|
||||
`GameWindow.cs` was 8,793 raw lines at checkpoint G, 1,508 below the Slice-5
|
||||
baseline and 6,930 (44%) below the campaign baseline.
|
||||
|
||||
### H — closeout
|
||||
|
||||
**Active.** No new landblock ownership moves are planned in H; it proves the
|
||||
landed graph under deterministic and connected lifecycle churn, reconciles
|
||||
divergence pointers/documentation, and records the final Slice-5 structural
|
||||
measurement before Slice 6 begins.
|
||||
**Complete in `4a205a3e`.** H proved the landed graph under deterministic and
|
||||
connected lifecycle churn, corrected shutdown-stage ordering so session reset
|
||||
converges before its streaming dependencies are disposed, and strengthened the
|
||||
resource oracle to compare already-warm steady-state revisits.
|
||||
|
||||
- Run focused App/Core/Net tests after each checkpoint.
|
||||
- After each code checkpoint, run three independent read-only reviews: retail/
|
||||
|
|
@ -401,7 +415,7 @@ measurement before Slice 6 begins.
|
|||
analysis. Fix confirmed findings and repeat review until clean.
|
||||
- Run `dotnet build AcDream.slnx -c Release` and the full Release test suite.
|
||||
- Run deterministic first-login/portal lifecycle automation and the connected
|
||||
seven-destination resource soak. Verify retirement/preparation queues drain,
|
||||
nine-destination resource soak. Verify retirement/preparation queues drain,
|
||||
residence matches the region, resource counts remain bounded, and graceful
|
||||
close succeeds.
|
||||
- Update the divergence register pointers in IA-14, AD-2, AD-22, and any other
|
||||
|
|
@ -410,6 +424,11 @@ measurement before Slice 6 begins.
|
|||
- Update architecture, milestones, roadmap, issues if needed, synchronized
|
||||
`AGENTS.md`/`CLAUDE.md`, and durable decomposition/render memory.
|
||||
|
||||
The final IA-14/AD-2/AD-22 audit found no new retail divergence. IA-14 and
|
||||
AD-22 still point at the correct WB/mesh owners; AD-2 now names the extracted
|
||||
origin-recenter/presentation owners. AD-6, AD-24, AP-31, and TS-52 remain open
|
||||
as required.
|
||||
|
||||
## 6. Acceptance matrix
|
||||
|
||||
Automated acceptance includes:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue