Move pre-window loading, startup application, live settings mutation, toon context, quality reapply, and SettingsVM loans behind one RuntimeSettingsController. Preserve retail command behavior, ordered target publication, draft semantics, and retryable failure convergence while removing duplicate GameWindow state and feature bodies. Co-authored-by: Codex <codex@openai.com>
194 lines
11 KiB
Markdown
194 lines
11 KiB
Markdown
# GameWindow decomposition — current truth
|
||
|
||
## Current state
|
||
|
||
The behavior-preserving App ownership campaign is complete through Slice 7 and
|
||
Slice 8 checkpoints A–G. `GameWindow.cs` moved from the 2026-07-21 baseline of
|
||
15,723 lines / 278 fields / 205 methods to 3,663 lines / 162 fields / 37
|
||
methods: 12,060 lines (76.7%) were removed without changing accepted gameplay
|
||
or rendering behavior.
|
||
|
||
| Slice | Ownership moved out | Closeout size |
|
||
|---|---|---:|
|
||
| 1 | world selection and interaction intent | 14,912 / 278 / 191 |
|
||
| 2 | live animation presentation | 14,546 / 277 / 190 |
|
||
| 3 | complete live-session lifecycle and routing | 14,310 / 274 / 190 |
|
||
| 4 | live-entity hydration, teardown, and network presentation | 10,301 / 267 / 163 |
|
||
| 5 | landblock build, publication, retirement, and shared-origin lifetime | 8,811 / 247 / 153 |
|
||
| 6 | complete update-frame orchestration | 7,026 / 241 / 108 |
|
||
| 7 | complete render-frame orchestration and failure recovery | 4,666 / 196 / 70 |
|
||
| 8 A–E | shell freeze, native/session/environment composition, reversible pointer/input/framebuffer ownership | 4,266 / 194 / 65 |
|
||
| 8 F | sole gameplay action route, typed commands, retained-root callback lifetime | 4,057 / 198 / 54 |
|
||
| 8 G | pre-window/runtime settings ownership, one startup snapshot, inert late target binding | 3,663 / 162 / 37 |
|
||
|
||
Slice 8 is an ordered checkpoint campaign rather than another feature-body
|
||
move. A froze/pruned the shell boundary; B gave all nine native window callback
|
||
edges one reversible owner plus host quiescence; C added `LiveSessionHost` for
|
||
reset/selection/entry/route composition while keeping `LiveSessionController`
|
||
the sole session owner. C also replaced the embedded ACE shortcut with the
|
||
named-retail `SkillFormula::Calculate @ 0x00591960` port. Partial route
|
||
construction and individual detach edges are retained and retried; reset and a
|
||
new generation cannot pass an incompletely detached route. D added
|
||
`WorldEnvironmentController` as the one-shot owner of WorldTime, loaded sky,
|
||
day-group selection, Weather, server synchronization, AdminEnvirons, and debug
|
||
cycles. `GameWindow` retains only ABI-compatible readonly aliases and typed
|
||
composition edges. The named-oracle correction is
|
||
`SkyDesc::CalcPresentDayGroup @ 0x00500E10`; the carried AdminEnvirons audio and
|
||
full fog/ambient/radar gaps are TS-54/TS-55.
|
||
|
||
E adds `CameraPointerInputController`, `FramebufferResizeController`, terminal
|
||
publish-before-attach Silk/dispatcher/retained input owners, and a quiescent
|
||
non-owning input-context view for optional devtools. Mouse-only hosts still
|
||
receive raw camera/cursor behavior. Logical callback deactivation runs before
|
||
the graceful session close; physical removal and the local mouse-look release
|
||
run only after session retirement. This prevents both copied callback reentry
|
||
and a failed event accessor from blocking F653/transport teardown. The carried
|
||
non-retail post-filter camera scalars are explicitly registered as TS-56.
|
||
|
||
F adds `GameplayInputActionRouter` as the sole `InputDispatcher.Fired`
|
||
subscriber while preserving the frozen action priority. Typed command owners
|
||
replace the remaining combat, diagnostic, window/player mode, item-target,
|
||
and Escape bodies. `RetainedUiGameplayBinding` owns the outside-UI item-drop
|
||
event. The two deferred command slots release their targets before session
|
||
retirement; the retained binding alone detaches its physical edge
|
||
transactionally afterward. Retail
|
||
review also corrected the carried default-combat mismatch: active combat
|
||
short-circuits directly to peace, and an incompatible Held object prints the
|
||
exact retail notice without a wire request or local mode mutation.
|
||
|
||
G adds `RuntimeSettingsController` as the sole concrete settings-store,
|
||
current-state, startup-snapshot, resolved-quality, active-toon, and optional
|
||
Settings-draft owner. It is constructed before `Window.Create`; startup applies
|
||
monitor pacing, window state, saved FOV, and audio in order once, with
|
||
substep-granular retry after failure. Complete runtime targets bind only after
|
||
UI/terrain/dispatcher/render-range/streaming exist and binding performs no
|
||
replay. The Settings save order and five-step quality application order remain
|
||
frozen. Combat mutations preserve unrelated unsaved Gameplay draft fields, and
|
||
successful external gameplay commands advance only their fields in the
|
||
SettingsVM persisted baseline so Cancel cannot resurrect stale command state.
|
||
UI-lock target, persistence, and baseline publication share an explicit
|
||
convergence flag so target/save failures remain retryable for the same value.
|
||
Saved FOV now applies without devtools, fixing the former accidental
|
||
SettingsVM gate. AP-121 records the intentional modern persistence added to
|
||
the named-retail `/framerate` live toggle/notice.
|
||
|
||
Slice 6 implementation commits are `99a3e819`, `4e4aac2c`, `0bc9fda9`,
|
||
`c5570383`, `eeb0f6b4`, `947c61d2`, and production cutover `e91f3102`.
|
||
Slice 7 implementation commits are `7e4cfb37`, `733126a2`, `bc6f09f9`,
|
||
`6d6e5b5f`, `85239fb3`, `28e1cf80`, and production cutover `9d7df1bf`.
|
||
The detailed ledgers live under `docs/plans/2026-07-2*-gamewindow-slice-*.md` and
|
||
`docs/architecture/code-structure.md`.
|
||
|
||
## Frozen update graph
|
||
|
||
`GameWindow.OnUpdate` starts the profiler scope and calls one
|
||
`UpdateFrameOrchestrator.Tick`. The accepted production graph is:
|
||
|
||
1. retry retained live-entity teardown;
|
||
2. normalize/publish the update and PhysicsScript clocks;
|
||
3. converge streaming origin, residence, readiness, and rescued projections;
|
||
4. sample semantic input, raw mouse, and combat intent;
|
||
5. advance live objects and deferred presentation hooks;
|
||
6. drain inbound network traffic inside one world mutation batch;
|
||
7. run the local post-network position tail;
|
||
8. reconcile root/child/emitter/light presentation without advancing time;
|
||
9. expire liveness;
|
||
10. advance local teleport/reveal/tunnel presentation;
|
||
11. evaluate one-shot player-mode entry;
|
||
12. publish fly/chase/player camera presentation.
|
||
|
||
`LiveEntityRuntime` remains the canonical identity/incarnation owner.
|
||
`GpuWorldState` remains the spatial bucket owner. `LiveSessionController` owns
|
||
the session generation. Extracted phase owners query these typed runtimes and
|
||
must not create replacement dictionaries, service locators, or callback
|
||
facades into substantial `GameWindow` methods.
|
||
|
||
## Frozen render graph
|
||
|
||
`GameWindow.OnRender` creates one value-only `RenderFrameInput` and calls
|
||
`RenderFrameOrchestrator.Render`. The accepted healthy order is:
|
||
|
||
1. begin the GPU-flight transaction;
|
||
2. begin/reset frame resources, clear, and publish live resources;
|
||
3. begin the optional ImGui frame;
|
||
4. advance weather display preparation;
|
||
5. draw the complete world/PView/shared-alpha/particle/debug scene;
|
||
6. draw the portal/private viewport using the pre-private foundation snapshot;
|
||
7. refresh/draw paperdoll, retained gameplay UI, then submit ImGui;
|
||
8. capture a requested screenshot;
|
||
9. publish title/resource/frame diagnostics;
|
||
10. close the GPU-flight transaction.
|
||
|
||
Recovery is one reverse-lifetime transaction. An active ImGui frame closes
|
||
through the owning Silk controller, and text rendering restores exact borrowed
|
||
GL state on success or failure. The orchestrator and its immediate phase owners
|
||
retain no direct `GameWindow` or anonymous callback bag. Recursive reachability
|
||
through canonical UI/input owners is not frame ownership; the known paths and
|
||
review rule live in `docs/architecture/code-structure.md`.
|
||
|
||
## Accepted verification
|
||
|
||
- Slice 8 Checkpoint G Release suite: 7,553 passed / 5 fixture or environment
|
||
skips; App 3,183/3 skips, UI Abstractions 534/0, 35 focused App
|
||
settings/boundary tests, and all 43 `SettingsVMTests` pass. The production App
|
||
build has zero warnings/errors; the complete solution retains the 17 existing
|
||
test-project warnings tracked by #228. All three independent corrected-diff
|
||
reviews are clean.
|
||
- Slice 8 Checkpoint F Release suite: 7,524 passed / 5 fixture or environment
|
||
skips; App 3,155/3 skips, 54 focused App ownership tests and 20 Core combat
|
||
conformance tests pass, and all three independent corrected-diff reviews are
|
||
clean.
|
||
- Slice 8 Checkpoint E Release suite: 7,477 passed / 5 fixture or environment
|
||
skips; App 3,108/3 skips, UI Abstractions 533/0, and all three independent
|
||
corrected-diff reviews are clean.
|
||
- Slice 8 Checkpoint D Release suite: 7,419 passed / 5 fixture or environment
|
||
skips; App 3,059/3 skips. Focused environment/boundary tests and all three
|
||
independent corrected-diff reviews are clean.
|
||
- Slice 8 Checkpoint C Release suite: 7,408 passed / 5 fixture or environment
|
||
skips; App 3,048/3 skips and Core.Net 548/0. All three independent corrected-
|
||
diff reviews are clean.
|
||
- Release suite: 7,341 passed / 5 fixture or environment skips.
|
||
- Connected lifecycle/reconnect: 315.6 seconds, graceful capped close and fresh
|
||
process uncapped reconnect passed; only 25 expected world-edge empty
|
||
landblocks.
|
||
- The six lifecycle PNGs preserve Slice 6 world geometry, depth, UI/paperdoll,
|
||
private viewport, and presentation. Differences are live weather/particles,
|
||
authoritative vitals, and small scripted camera settling.
|
||
- Synchronized nine-stop resource soak: 395.2 seconds, nine materializations,
|
||
all movement/jump/combat exercises, and graceful exit passed; update p95 was
|
||
at or below 0.8 ms. Caul return → plateau working/private delta was
|
||
+85.7/+59.3 MiB, inside the unchanged gate.
|
||
- Two immediately preceding identical-binary runs exceeded the coarse process-
|
||
residency threshold while deterministic ownership/lifecycle/timing checks
|
||
passed. #232 adds canonical resource-owner snapshots; do not solve this by
|
||
loosening the process-memory threshold or treating residency alone as an
|
||
identified owner leak.
|
||
- The 18–33 missing VFX table/emitter diagnostics are known DAT-driven records,
|
||
not a Slice 7 regression.
|
||
- TS-50, TS-51, and TS-53 remain registered; Slice 7 introduced no new retail
|
||
divergence.
|
||
|
||
## Next work
|
||
|
||
Slice 8 checkpoints H–L group the remaining resource ownership, ordered
|
||
startup composition, and shutdown wiring and reduce Silk callbacks to
|
||
narrow calls into input, update, render, resize, focus, and shutdown owners.
|
||
It removes leftover feature state only where Slices 1–7 already established a
|
||
canonical owner; it does not redesign gameplay, rendering, or resource lifetime.
|
||
The reviewed A–L execution ledger is
|
||
`docs/plans/2026-07-22-gamewindow-slice-8-composition-lifecycle.md`.
|
||
|
||
## Do not retry
|
||
|
||
- Do not reintroduce delegate facades into `GameWindow`; an ordering wrapper is
|
||
not an extraction until the state and behavior body move.
|
||
- Do not reorder the frozen update or render graphs during structural work.
|
||
TS-53 records the known retail host-order difference for a separate evidence-
|
||
backed port.
|
||
- Do not add a second GUID, session, spatial, or resource owner.
|
||
- Do not fold full `GameEntity` aggregation into this campaign; evaluate it
|
||
after Slice 8.
|
||
- Do not loosen the soak process-memory threshold to hide #232. Add canonical
|
||
owner snapshots and preserve process residency as a secondary guard.
|
||
- Small value/policy callbacks and diagnostics are acceptable only when they do
|
||
not call a substantial window body or hide mutable ownership.
|