docs(architecture): reconcile GameWindow extraction program
Close the completed M3 and portal observer gates, make the behavior-preserving GameWindow ownership campaign the explicit M4 prerequisite, and replace the stale extraction sketch with an implementation-audited sequence. Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
parent
f4cf802330
commit
cf50ee3d50
8 changed files with 354 additions and 220 deletions
29
AGENTS.md
29
AGENTS.md
|
|
@ -108,23 +108,26 @@ movement queries.
|
||||||
|
|
||||||
## Current state
|
## Current state
|
||||||
|
|
||||||
**M3 — Cast a spell ACTIVE; automated implementation and connected
|
**M3 — Cast a spell LANDED 2026-07-21. M4 — Live in the world NEXT.** Retail
|
||||||
single-client gates complete.** Retail cast intent, component/target gates,
|
casting, spellbook/component-book UI, active effects, recall/portal-space
|
||||||
live enchantment wire, Magic-scoped input, spell bar, spellbook, component
|
presentation, the R6 locomotion/collision/projectile/teleport/radar rebaseline,
|
||||||
book, effect indicators, shared main-panel switching, and positive/negative
|
and the final two-client portal-out/materialization observer flow are
|
||||||
effects UI are implemented over the Step-9 projectile/DAT-effect foundation.
|
user-gated. Deterministic world-lifecycle automation protects fresh login,
|
||||||
The R6 complete-root-Frame/object-workset cutover and its unattended
|
|
||||||
seven-destination input/portal/performance rebaseline pass. The 2026-07-20
|
|
||||||
deterministic world-lifecycle gate additionally protects fresh login,
|
|
||||||
outdoor/world-edge/dungeon travel, same-location revisit, exact graceful
|
outdoor/world-edge/dungeon travel, same-location revisit, exact graceful
|
||||||
disconnect, and uncapped fresh-process reconnect with JSON/PNG artifacts.
|
disconnect, and uncapped fresh-process reconnect with JSON/PNG artifacts.
|
||||||
Release builds; 6,480 tests pass / 5 skip (17 tracked warnings, #228).
|
Release builds; 6,481 tests pass / 5 skip (17 tracked warnings, #228).
|
||||||
**Next:** the R6 locomotion/collision/projectile/teleport local visual
|
|
||||||
rebaseline when a local view is available, then the final two-client
|
**Active prerequisite before new M4 subsystem work:** complete the
|
||||||
portal-out/materialization observer gate. **Carried:** #153, #116, remaining
|
behavior-preserving `GameWindow` decomposition reconciled on 2026-07-21. The
|
||||||
|
next slice finishes selection/interaction ownership; later slices finish
|
||||||
|
animation presentation, live-session and live-entity App integration,
|
||||||
|
landblock presentation, update/render orchestration, and composition cleanup.
|
||||||
|
See `docs/architecture/code-structure.md`. **Carried:** #153, #116, remaining
|
||||||
R6 ownership cleanup, TS-50/TS-51, Modern Pipeline MP1b+, and #225's
|
R6 ownership cleanup, TS-50/TS-51, Modern Pipeline MP1b+, and #225's
|
||||||
lifestone/particle alpha visual gate.
|
lifestone/particle alpha visual gate.
|
||||||
Start magic work at `claude-memory/project_magic_ui_and_casting.md`; start
|
|
||||||
|
Start structural work at `docs/architecture/code-structure.md`; start
|
||||||
|
magic follow-up at `claude-memory/project_magic_ui_and_casting.md`; start
|
||||||
render/streaming work at `claude-memory/project_render_pipeline_digest.md`.
|
render/streaming work at `claude-memory/project_render_pipeline_digest.md`.
|
||||||
|
|
||||||
Documentation entry point: [`docs/README.md`](docs/README.md).
|
Documentation entry point: [`docs/README.md`](docs/README.md).
|
||||||
|
|
|
||||||
29
CLAUDE.md
29
CLAUDE.md
|
|
@ -106,23 +106,26 @@ movement queries.
|
||||||
|
|
||||||
## Current state
|
## Current state
|
||||||
|
|
||||||
**M3 — Cast a spell ACTIVE; automated implementation and connected
|
**M3 — Cast a spell LANDED 2026-07-21. M4 — Live in the world NEXT.** Retail
|
||||||
single-client gates complete.** Retail cast intent, component/target gates,
|
casting, spellbook/component-book UI, active effects, recall/portal-space
|
||||||
live enchantment wire, Magic-scoped input, spell bar, spellbook, component
|
presentation, the R6 locomotion/collision/projectile/teleport/radar rebaseline,
|
||||||
book, effect indicators, shared main-panel switching, and positive/negative
|
and the final two-client portal-out/materialization observer flow are
|
||||||
effects UI are implemented over the Step-9 projectile/DAT-effect foundation.
|
user-gated. Deterministic world-lifecycle automation protects fresh login,
|
||||||
The R6 complete-root-Frame/object-workset cutover and its unattended
|
|
||||||
seven-destination input/portal/performance rebaseline pass. The 2026-07-20
|
|
||||||
deterministic world-lifecycle gate additionally protects fresh login,
|
|
||||||
outdoor/world-edge/dungeon travel, same-location revisit, exact graceful
|
outdoor/world-edge/dungeon travel, same-location revisit, exact graceful
|
||||||
disconnect, and uncapped fresh-process reconnect with JSON/PNG artifacts.
|
disconnect, and uncapped fresh-process reconnect with JSON/PNG artifacts.
|
||||||
Release builds; 6,480 tests pass / 5 skip (17 tracked warnings, #228).
|
Release builds; 6,481 tests pass / 5 skip (17 tracked warnings, #228).
|
||||||
**Next:** the R6 locomotion/collision/projectile/teleport local visual
|
|
||||||
rebaseline when a local view is available, then the final two-client
|
**Active prerequisite before new M4 subsystem work:** complete the
|
||||||
portal-out/materialization observer gate. **Carried:** #153, #116, remaining
|
behavior-preserving `GameWindow` decomposition reconciled on 2026-07-21. The
|
||||||
|
next slice finishes selection/interaction ownership; later slices finish
|
||||||
|
animation presentation, live-session and live-entity App integration,
|
||||||
|
landblock presentation, update/render orchestration, and composition cleanup.
|
||||||
|
See `docs/architecture/code-structure.md`. **Carried:** #153, #116, remaining
|
||||||
R6 ownership cleanup, TS-50/TS-51, Modern Pipeline MP1b+, and #225's
|
R6 ownership cleanup, TS-50/TS-51, Modern Pipeline MP1b+, and #225's
|
||||||
lifestone/particle alpha visual gate.
|
lifestone/particle alpha visual gate.
|
||||||
Start magic work at `claude-memory/project_magic_ui_and_casting.md`; start
|
|
||||||
|
Start structural work at `docs/architecture/code-structure.md`; start
|
||||||
|
magic follow-up at `claude-memory/project_magic_ui_and_casting.md`; start
|
||||||
render/streaming work at `claude-memory/project_render_pipeline_digest.md`.
|
render/streaming work at `claude-memory/project_render_pipeline_digest.md`.
|
||||||
|
|
||||||
Documentation entry point: [`docs/README.md`](docs/README.md).
|
Documentation entry point: [`docs/README.md`](docs/README.md).
|
||||||
|
|
|
||||||
|
|
@ -24,12 +24,12 @@ What does NOT go here:
|
||||||
- Every session: scan OPEN issues at start; promote/close anything we touched during the session before ending.
|
- Every session: scan OPEN issues at start; promote/close anything we touched during the session before ending.
|
||||||
- Promoting to a Phase: mark as `DONE (promoted to Phase X)` + commit SHA where the Phase entry landed.
|
- Promoting to a Phase: mark as `DONE (promoted to Phase X)` + commit SHA where the Phase entry landed.
|
||||||
|
|
||||||
## Current queue — 2026-07-20
|
## Current queue — 2026-07-21
|
||||||
|
|
||||||
- **Next visual gate:** R6 locomotion/collision/projectile/teleport comparison
|
- **Active structural work:** `GameWindow` decomposition, beginning with the
|
||||||
after the complete-root-Frame/object-workset cutover.
|
selection/interaction ownership slice in
|
||||||
- **M3 closing gate:** `#218`, final two-client portal-out/materialization and
|
[`docs/architecture/code-structure.md`](architecture/code-structure.md).
|
||||||
indoor observer comparison.
|
This is the behavior-preserving prerequisite before new M4 feature bodies.
|
||||||
- **Separate rendering gate:** `#225`, lifestone/particle alpha ordering. Its
|
- **Separate rendering gate:** `#225`, lifestone/particle alpha ordering. Its
|
||||||
connected performance, lifetime, and unattended portal routes pass.
|
connected performance, lifetime, and unattended portal routes pass.
|
||||||
- **Carried behavior debt:** `#153` far-teleport unstreamed-edge arrival and
|
- **Carried behavior debt:** `#153` far-teleport unstreamed-edge arrival and
|
||||||
|
|
@ -98,7 +98,7 @@ production runtime failure.
|
||||||
|
|
||||||
**Acceptance:** A non-incremental Release solution build reports zero warnings
|
**Acceptance:** A non-incremental Release solution build reports zero warnings
|
||||||
and zero errors without suppressing analyzers or weakening nullable checking;
|
and zero errors without suppressing analyzers or weakening nullable checking;
|
||||||
the full 6,480-pass / 5-skip suite remains green.
|
the full 6,481-pass / 5-skip suite remains green.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -565,7 +565,7 @@ Passed 2026-07-17: “Yes works.”
|
||||||
|
|
||||||
## #218 — Portal silhouette pose, destination reveal, and indoor observer snap
|
## #218 — Portal silhouette pose, destination reveal, and indoor observer snap
|
||||||
|
|
||||||
**Status:** IN-PROGRESS — root fixes implemented 2026-07-16; pending connected visual gate
|
**Status:** DONE — 2026-07-21, final two-client observer gate user-confirmed
|
||||||
**Severity:** HIGH
|
**Severity:** HIGH
|
||||||
**Filed:** 2026-07-16
|
**Filed:** 2026-07-16
|
||||||
**Component:** portal VFX / streaming / physics / outbound movement
|
**Component:** portal VFX / streaming / physics / outbound movement
|
||||||
|
|
@ -635,6 +635,9 @@ pose; outdoor exits reveal only fully rendered terrain/scenery; and a retail
|
||||||
observer sees acdream run and stop repeatedly inside a dungeon without any
|
observer sees acdream run and stop repeatedly inside a dungeon without any
|
||||||
snap back to the entrance.
|
snap back to the entrance.
|
||||||
|
|
||||||
|
**Gate:** Passed 2026-07-21. The user confirmed the final two-client
|
||||||
|
portal-out/materialization and indoor observer comparison on the R6 baseline.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## #217 — Character windows did not receive live 64-bit experience updates
|
## #217 — Character windows did not receive live 64-bit experience updates
|
||||||
|
|
|
||||||
|
|
@ -4,23 +4,26 @@ This page is the entry point for project documentation. It distinguishes
|
||||||
current sources of truth from implementation history so an old plan or issue
|
current sources of truth from implementation history so an old plan or issue
|
||||||
banner cannot silently override the current program state.
|
banner cannot silently override the current program state.
|
||||||
|
|
||||||
## Current snapshot — 2026-07-20
|
## Current snapshot — 2026-07-21
|
||||||
|
|
||||||
- **Active milestone:** M3, “Cast a spell.” The automated implementation and
|
- **Milestone state:** M3, “Cast a spell,” landed 2026-07-21. M4, “Live in the
|
||||||
connected single-client magic/portal presentation gates are complete.
|
world,” is next.
|
||||||
- **Next visual gates:** the R6 locomotion/collision/projectile/teleport retail
|
- **Active program:** behavior-preserving `GameWindow` decomposition before
|
||||||
comparison, then the final two-client portal-out/materialization observer
|
new M4 subsystem work. The reconciled ownership ledger and slice order are
|
||||||
comparison (`#218`).
|
in [`architecture/code-structure.md`](architecture/code-structure.md); the
|
||||||
|
next slice finishes selection/interaction ownership.
|
||||||
|
- **Completed gates:** R6 locomotion/collision/projectile/teleport/radar and
|
||||||
|
the final two-client portal-out/materialization observer comparison (`#218`).
|
||||||
- **Separate visual verification:** the shared-alpha lifestone/particle result
|
- **Separate visual verification:** the shared-alpha lifestone/particle result
|
||||||
in `#225`; its connected resource-lifetime and performance routes pass.
|
in `#225`; its connected resource-lifetime and performance routes pass.
|
||||||
- **Carried behavior debt:** `#153` (far teleport onto an unstreamed edge),
|
- **Carried behavior debt:** `#153` (far teleport onto an unstreamed edge),
|
||||||
`#116` (two narrowed slide-response cases), and divergence rows TS-50/TS-51.
|
`#116` (two narrowed slide-response cases), and divergence rows TS-50/TS-51.
|
||||||
- **Deferred engineering tracks:** Modern Pipeline MP1b+ and Linux/headless
|
- **Deferred engineering tracks:** Modern Pipeline MP1b+ and Linux/headless
|
||||||
automation (Track LH). Neither is part of the active M3 gate.
|
automation (Track LH). Neither is part of the active structural campaign.
|
||||||
- **Divergence audit:** 178 active rows — IA 17, AD 37, AP 85, TS 34,
|
- **Divergence audit:** 178 active rows — IA 17, AD 37, AP 85, TS 34,
|
||||||
and UN 5 — plus the retained retired TS-37 history note.
|
and UN 5 — plus the retained retired TS-37 history note.
|
||||||
- **Latest automated baseline:** Release build succeeds with 17 known
|
- **Latest automated baseline:** Release build succeeds with 17 known
|
||||||
test-project warnings (`#228`); 6,457 tests passed and 5 intentionally
|
test-project warnings (`#228`); 6,481 tests passed and 5 intentionally
|
||||||
skipped. The unattended connected R6 route
|
skipped. The unattended connected R6 route
|
||||||
completed seven portal materializations, production input exercises, and a
|
completed seven portal materializations, production input exercises, and a
|
||||||
graceful close. See
|
graceful close. See
|
||||||
|
|
|
||||||
|
|
@ -829,12 +829,18 @@ Current movement/collision ownership:
|
||||||
- **G.3 is shipped**: dungeon streaming, portal-space presentation, collision,
|
- **G.3 is shipped**: dungeon streaming, portal-space presentation, collision,
|
||||||
lighting, doors, and the full round-trip gate landed. The separate far-
|
lighting, doors, and the full round-trip gate landed. The separate far-
|
||||||
teleport unstreamed-edge residual is issue #153, not unfinished G.3.
|
teleport unstreamed-edge residual is issue #153, not unfinished G.3.
|
||||||
- **M3** owns current connected magic/portal acceptance; Track LH is the future
|
- **M3 landed 2026-07-21** with connected magic/portal acceptance and the final
|
||||||
presentation-independent Linux/headless extraction.
|
two-client observer gate; Track LH is the future presentation-independent
|
||||||
|
Linux/headless extraction.
|
||||||
|
- **The behavior-preserving thin-`GameWindow` ownership campaign is the active
|
||||||
|
prerequisite before new M4 subsystem bodies.** Its reconciled ledger and
|
||||||
|
sequence live in `docs/architecture/code-structure.md`. This decision does
|
||||||
|
not reclassify the remaining L.2 conformance work or Track LH.
|
||||||
|
|
||||||
The GameEntity / thin GameWindow refactor remains a valid target architecture,
|
Full `GameEntity` type aggregation remains a separate, higher-risk target after
|
||||||
but it is not a prerequisite for L.2. Do not resurrect old R1-R8 phase numbers
|
the thin-`GameWindow` campaign. The current campaign reuses canonical
|
||||||
for new work; add or update roadmap phases instead.
|
`LiveEntityRuntime` rather than introducing another entity owner. Do not
|
||||||
|
resurrect old R1-R8 phase numbers for new work; update the roadmap instead.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
# acdream — code structure & extraction sequence
|
# acdream — code structure & extraction sequence
|
||||||
|
|
||||||
**Status:** Living document. Created 2026-05-16 as the companion to the
|
**Status:** Living document. Created 2026-05-16; implementation reconciliation
|
||||||
"Code Structure Rules" section in `CLAUDE.md`.
|
completed 2026-07-21. This is the active structural program before new M4
|
||||||
|
subsystems enter the App layer.
|
||||||
**Purpose:** Describe the desired structural state of 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
|
explain the rules we've adopted, and lay out the safe extraction
|
||||||
sequence from today's reality (one 14,557-line `GameWindow.cs` at the
|
sequence from today's reality (one 15,723-line `GameWindow.cs` at the
|
||||||
2026-07-20 audit) to the
|
2026-07-21 audit) to the
|
||||||
target (thin `GameWindow`, small focused collaborators).
|
target (thin `GameWindow`, small focused collaborators).
|
||||||
**Companion to:** [`acdream-architecture.md`](acdream-architecture.md)
|
**Companion to:** [`acdream-architecture.md`](acdream-architecture.md)
|
||||||
(the layered architecture) and
|
(the layered architecture) and
|
||||||
|
|
@ -21,30 +22,37 @@ layer is wire-compatible, the UI has a stable contract, plugins load.
|
||||||
The structural debt is concentrated in **one file**:
|
The structural debt is concentrated in **one file**:
|
||||||
|
|
||||||
```
|
```
|
||||||
src/AcDream.App/Rendering/GameWindow.cs 14,557 lines (2026-07-20)
|
src/AcDream.App/Rendering/GameWindow.cs 15,723 lines (2026-07-21)
|
||||||
|
258 fields / ~259 methods
|
||||||
```
|
```
|
||||||
|
|
||||||
`GameWindow` is the single object that:
|
`GameWindow` is the single object that:
|
||||||
|
|
||||||
- Owns the GL context, the window, input, and shaders.
|
- Owns the GL context, the window, input, and shaders.
|
||||||
- Reads ~40 different environment variables across its lifetime.
|
- Reads ~40 different environment variables across its lifetime.
|
||||||
- Hosts the live network session (`WorldSession`) and the offline
|
- Still owns live-session bootstrap, character entry, roughly 440 lines of
|
||||||
pre-login state.
|
event subscription, and most App-side packet handlers even though
|
||||||
- Owns parallel dictionaries for entity lookup (`_entitiesByServerGuid`,
|
`LiveSessionController` owns the socket/session shell.
|
||||||
the per-landblock entity lists in `GpuWorldState`, plus the player
|
- Owns the adapters that hydrate canonical `LiveEntityRuntime` records into
|
||||||
controller's own state).
|
animation, collision, rendering, and DAT-backed appearance resources.
|
||||||
- Drives selection / interaction (`WorldPicker`, `SendUse`,
|
- Still drives selection / interaction (`WorldPicker`, target classification,
|
||||||
`SendPickUp`).
|
`SendUse`, `SendPickUp`, auto-walk deferral) despite the shipped item and
|
||||||
|
combat controllers.
|
||||||
- Drives per-frame render orchestration (sky → terrain → opaque mesh →
|
- Drives per-frame render orchestration (sky → terrain → opaque mesh →
|
||||||
transparent mesh → particles → debug lines → UI).
|
transparent mesh → particles → debug lines → UI).
|
||||||
|
- Builds and applies streamed landblock presentation (DAT decode, scenery,
|
||||||
|
EnvCells, mesh publication, collision, and retirement) around the shipped
|
||||||
|
`StreamingController` and `GpuWorldState` owners.
|
||||||
- Wires up every plugin hook sink, every diagnostic, every panel.
|
- Wires up every plugin hook sink, every diagnostic, every panel.
|
||||||
|
|
||||||
Almost every M1 / M2 bug touches this file. Every new feature adds a
|
The extracted controllers are valuable and tested, but line count alone proves
|
||||||
field plus a method plus a wiring call. It is not getting better on its
|
that creating collaborators has not yet made the window thin. A collaborator
|
||||||
own.
|
is a completed extraction only when it owns the state and behavior body;
|
||||||
|
wrapping a `GameWindow` method in a delegate preserves ordering but remains a
|
||||||
|
partial extraction.
|
||||||
|
|
||||||
The fix is **not** "rewrite `GameWindow` in one pass" — that's a
|
The fix is **not** "rewrite `GameWindow` in one pass" — that is a
|
||||||
high-risk change that would block M2. The fix is to **extract one
|
high-risk change. The fix is to **extract one
|
||||||
collaborator at a time**, verify behavior is unchanged, ship, and
|
collaborator at a time**, verify behavior is unchanged, ship, and
|
||||||
move on. This document defines that sequence.
|
move on. This document defines that sequence.
|
||||||
|
|
||||||
|
|
@ -167,6 +175,7 @@ src/AcDream.App/
|
||||||
│ ├── GameWindow.cs # thin: GL/window lifecycle + delegates per-frame to RenderFrameOrchestrator
|
│ ├── GameWindow.cs # thin: GL/window lifecycle + delegates per-frame to RenderFrameOrchestrator
|
||||||
│ ├── RenderFrameOrchestrator.cs # per-frame draw order (sky → terrain → opaque → trans → particles → debug → UI)
|
│ ├── RenderFrameOrchestrator.cs # per-frame draw order (sky → terrain → opaque → trans → particles → debug → UI)
|
||||||
│ ├── LiveEntityAnimationScheduler.cs # shipped: ordinary live-object update workset
|
│ ├── LiveEntityAnimationScheduler.cs # shipped: ordinary live-object update workset
|
||||||
|
│ ├── LiveEntityAnimationPresenter.cs # final part-pose/mesh/effect composition after scheduler output
|
||||||
│ ├── RetailStaticAnimatingObjectScheduler.cs # shipped: separate static-animation workset
|
│ ├── RetailStaticAnimatingObjectScheduler.cs # shipped: separate static-animation workset
|
||||||
│ ├── StaticLiveRootCommitter.cs # live static root → pose + collision boundary
|
│ ├── StaticLiveRootCommitter.cs # live static root → pose + collision boundary
|
||||||
│ ├── TerrainModernRenderer.cs # (already exists)
|
│ ├── TerrainModernRenderer.cs # (already exists)
|
||||||
|
|
@ -176,11 +185,13 @@ src/AcDream.App/
|
||||||
│ ├── Wb/ # WB seam + EnvCellLandblockBuild transaction
|
│ ├── Wb/ # WB seam + EnvCellLandblockBuild transaction
|
||||||
│ └── Vfx/ # (already exists)
|
│ └── Vfx/ # (already exists)
|
||||||
├── Net/
|
├── Net/
|
||||||
│ └── LiveSessionController.cs # owns WorldSession lifecycle, login/handshake, reconnect
|
│ ├── LiveSessionController.cs # owns complete WorldSession connect/enter/logout/reconnect lifecycle
|
||||||
|
│ └── LiveSessionEventRouter.cs # typed subscriptions → focused domain handlers
|
||||||
├── Physics/
|
├── Physics/
|
||||||
│ ├── ProjectileController.cs # canonical live-record projectile orchestration
|
│ ├── ProjectileController.cs # canonical live-record projectile orchestration
|
||||||
│ ├── RemotePhysicsUpdater.cs # ordinary/Hidden remote narrow-tick integration
|
│ ├── RemotePhysicsUpdater.cs # ordinary/Hidden remote narrow-tick integration
|
||||||
│ ├── LiveEntityOrdinaryPhysicsUpdater.cs # manager-less canonical body Transition path
|
│ ├── LiveEntityOrdinaryPhysicsUpdater.cs # manager-less canonical body Transition path
|
||||||
|
│ ├── LiveEntityNetworkUpdateController.cs # Position/Vector/State/Motion App integration
|
||||||
│ ├── LiveEntityShadowPublisher.cs # authoritative exact-owner/residency collision gate
|
│ ├── LiveEntityShadowPublisher.cs # authoritative exact-owner/residency collision gate
|
||||||
│ ├── RemoteInboundMotionDispatcher.cs # shared animated/headless UpdateMotion funnel
|
│ ├── RemoteInboundMotionDispatcher.cs # shared animated/headless UpdateMotion funnel
|
||||||
│ ├── RemoteTeleportController.cs # loaded/pending teleport placement ownership
|
│ ├── RemoteTeleportController.cs # loaded/pending teleport placement ownership
|
||||||
|
|
@ -189,13 +200,18 @@ src/AcDream.App/
|
||||||
├── World/
|
├── World/
|
||||||
│ ├── InboundPhysicsStateController.cs # timestamps + accepted spawn snapshots
|
│ ├── InboundPhysicsStateController.cs # timestamps + accepted spawn snapshots
|
||||||
│ ├── LiveEntityRuntime.cs # shipped: logical lifetime + ServerGuid↔entity.Id translation
|
│ ├── LiveEntityRuntime.cs # shipped: logical lifetime + ServerGuid↔entity.Id translation
|
||||||
|
│ ├── LiveEntityHydrationController.cs # spawn/appearance/parent/delete resource integration
|
||||||
│ ├── RetailInboundEventDispatcher.cs # update-thread packet/frame FIFO barrier
|
│ ├── RetailInboundEventDispatcher.cs # update-thread packet/frame FIFO barrier
|
||||||
|
│ ├── RetailLiveFrameCoordinator.cs # shipped: object/network/command/reconcile phase order
|
||||||
│ ├── LiveEntityPresentationController.cs # ordered Hidden/NoDraw/effect/collision side effects
|
│ ├── LiveEntityPresentationController.cs # ordered Hidden/NoDraw/effect/collision side effects
|
||||||
│ ├── LiveEntityTeardown.cs # failure-isolated multi-owner lifecycle drain
|
│ ├── LiveEntityTeardown.cs # failure-isolated multi-owner lifecycle drain
|
||||||
│ └── ParentAttachmentState.cs # parent generations + pending ParentEvent relations
|
│ └── ParentAttachmentState.cs # parent generations + pending ParentEvent relations
|
||||||
├── Interaction/
|
├── Interaction/
|
||||||
│ └── SelectionInteractionController.cs # owns WorldPicker, selection state, Use/PickUp dispatch
|
│ ├── WorldSelectionQuery.cs # read-only picking/classification/description queries
|
||||||
├── Streaming/ # LandblockStreamer + immutable LandblockBuild completion
|
│ └── SelectionInteractionController.cs # owns selection intents, Use/PickUp, auto-walk deferral
|
||||||
|
├── Streaming/
|
||||||
|
│ ├── LandblockPresentationPipeline.cs # DAT build/apply/retire transaction and resource publication
|
||||||
|
│ └── ... # shipped streamer/world-state/reveal owners
|
||||||
├── Input/ # (already exists)
|
├── Input/ # (already exists)
|
||||||
├── Audio/ # (already exists)
|
├── Audio/ # (already exists)
|
||||||
└── Plugins/ # (already exists)
|
└── Plugins/ # (already exists)
|
||||||
|
|
@ -206,22 +222,27 @@ What `GameWindow` keeps:
|
||||||
- `IWindow` / `GL` / `IInputContext` lifecycle (constructor + `OnLoad` +
|
- `IWindow` / `GL` / `IInputContext` lifecycle (constructor + `OnLoad` +
|
||||||
`Run` + `OnClosing`).
|
`Run` + `OnClosing`).
|
||||||
- `RuntimeOptions` reference (the typed startup config).
|
- `RuntimeOptions` reference (the typed startup config).
|
||||||
- One field per collaborator (`_liveSessionController`,
|
- GL resource construction and top-level collaborator composition. Construction
|
||||||
`_liveEntityRuntime`, `_selectionInteraction`,
|
is allowed here; feature algorithms and mutable subsystem state are not.
|
||||||
`_renderFrameOrchestrator`).
|
- One field per top-level collaborator (`_liveSessionController`,
|
||||||
|
`_liveEntityRuntime`, `_selectionInteraction`, `_streamingPresentation`,
|
||||||
|
`_liveObjectFrame`, `_renderFrameOrchestrator`).
|
||||||
- The Silk.NET event-handler stubs that delegate to collaborators.
|
- The Silk.NET event-handler stubs that delegate to collaborators.
|
||||||
|
|
||||||
What `GameWindow` loses:
|
What `GameWindow` loses:
|
||||||
|
|
||||||
- The 7 startup-time env var fields → moved into `RuntimeOptions`.
|
- Live connect/enter/logout and event-subscription bodies → completed inside
|
||||||
- `TryStartLiveSession` + the post-login network drain → moved into
|
`LiveSessionController` / `LiveSessionEventRouter`.
|
||||||
`LiveSessionController`.
|
- Live-object hydration adapters and final animated-part presentation → focused
|
||||||
- `_entitiesByServerGuid` + per-entity dictionaries + ServerGuid↔Id
|
world/render owners over canonical `LiveEntityRuntime` records.
|
||||||
translation → moved into `LiveEntityRuntime`.
|
- `WorldPicker`, target queries, and selection-driven Use/PickUp/auto-walk →
|
||||||
- `WorldPicker` + selection-driven `SendUse` / `SendPickUp` orchestration → moved
|
`WorldSelectionQuery` + `SelectionInteractionController`. Core
|
||||||
into `SelectionInteractionController`; Core `SelectionState` remains the
|
`SelectionState` remains the injected session owner.
|
||||||
already-shipped session owner and is injected into that controller.
|
- Landblock DAT build/apply/retirement presentation →
|
||||||
- Per-frame draw orchestration → moved into `RenderFrameOrchestrator`.
|
`LandblockPresentationPipeline`; `StreamingController` remains the residency
|
||||||
|
scheduler and `GpuWorldState` remains the spatial registry.
|
||||||
|
- Per-frame draw orchestration and its frame-local scratch state →
|
||||||
|
`RenderFrameOrchestrator`.
|
||||||
|
|
||||||
The eventual `GameEntity` aggregation (target state described in
|
The eventual `GameEntity` aggregation (target state described in
|
||||||
`acdream-architecture.md` §"GameEntity: The Unified Entity") happens
|
`acdream-architecture.md` §"GameEntity: The Unified Entity") happens
|
||||||
|
|
@ -247,10 +268,14 @@ allocators fail fast instead of wrapping into another landblock's namespace.
|
||||||
All other non-Parent packet
|
All other non-Parent packet
|
||||||
families still need the future general queue tracked by divergence AD-32.
|
families still need the future general queue tracked by divergence AD-32.
|
||||||
|
|
||||||
The per-frame object body is no longer an animation-dictionary loop inside
|
The per-frame object scheduler is extracted, but final animated-part
|
||||||
`GameWindow`. `LiveEntityAnimationScheduler` snapshots canonical spatial root
|
presentation is not. `LiveEntityAnimationScheduler` snapshots canonical spatial
|
||||||
records and advances the incarnation-stable object clock, PartArray, hooks,
|
root records and advances the incarnation-stable object clock, PartArray,
|
||||||
one selected movement owner, and manager tail in retail order. Manager-less
|
hooks, one selected movement owner, and manager tail in retail order. The
|
||||||
|
remaining `GameWindow.TickAnimations` loop still composes part transforms,
|
||||||
|
drawable `MeshRef`s, and effect poses from the scheduler output; moving that
|
||||||
|
body into `LiveEntityAnimationPresenter` is an explicit pending slice.
|
||||||
|
Manager-less
|
||||||
bodies delegate their candidate/Transition/cell/shadow commit to
|
bodies delegate their candidate/Transition/cell/shadow commit to
|
||||||
`LiveEntityOrdinaryPhysicsUpdater`; retained projectile bodies and remote
|
`LiveEntityOrdinaryPhysicsUpdater`; retained projectile bodies and remote
|
||||||
MovementManagers remain mutually exclusive movement owners. Static animation
|
MovementManagers remain mutually exclusive movement owners. Static animation
|
||||||
|
|
@ -336,145 +361,194 @@ strand teleport, movement, shadow, light, or GUID-scoped state.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. Extraction sequence — safest first
|
## 4. Reconciled ownership ledger — 2026-07-21
|
||||||
|
|
||||||
Each step is **one PR-sized refactor**. Each must build clean, all
|
This section replaces the original six-step sketch. That sketch correctly
|
||||||
tests pass, and visual verification at Holtburg looks identical to
|
identified the target but overstated some extractions and omitted large bodies
|
||||||
the previous step. Don't bundle two steps.
|
added during M2/M3. The current audit is based on implementation ownership, not
|
||||||
|
whether a class with the planned name exists.
|
||||||
|
|
||||||
### Step 1 — `RuntimeOptions` — SHIPPED (`eda936dc`)
|
### 4.1 What counts as extracted
|
||||||
|
|
||||||
**Scope:** Replace startup-time env var reads with a typed options
|
An extraction is **complete** only when:
|
||||||
object built once in `Program.cs`.
|
|
||||||
|
|
||||||
**Behavior change:** None. Same env vars, same defaults, same effects.
|
1. the collaborator owns the mutable state and behavior body;
|
||||||
|
2. `GameWindow` constructs it and delegates through a narrow method;
|
||||||
|
3. the collaborator does not call back into arbitrary `GameWindow` methods;
|
||||||
|
4. focused tests exercise the collaborator without constructing a Silk window;
|
||||||
|
5. the accepted connected/visual behavior is unchanged.
|
||||||
|
|
||||||
**Risk:** Low. Mechanical substitution at ~10-15 call sites in
|
A class that stores delegates back to substantial `GameWindow` methods is a
|
||||||
`GameWindow.cs` + one constructor signature change.
|
useful ordering seam, but its ownership status is **partial**.
|
||||||
|
|
||||||
**Test:** Unit tests for `RuntimeOptions.FromEnvironment` parsing (the
|
### 4.2 Current implementation truth
|
||||||
new `tests/AcDream.App.Tests/` project).
|
|
||||||
|
|
||||||
**Verification:** `dotnet build` + `dotnet test` green. Visual launch
|
| Area | Status | Current truth |
|
||||||
verifies live mode + dat dir resolution still work.
|
|---|---|---|
|
||||||
|
| Startup options | **Complete** | `RuntimeOptions` owns startup configuration (`eda936dc`). Remaining direct environment reads are legacy runtime diagnostics, not startup configuration. |
|
||||||
|
| Network session | **Partial** | `LiveSessionController` owns endpoint resolution, `WorldSession` construction, ticking, and disposal (`0b25df53`). `TryStartLiveSession`, character choice/entry, session clearing, about 440 lines of subscriptions, and most App packet handlers remain in `GameWindow`. |
|
||||||
|
| Live identity/lifetime | **Complete core owner** | `LiveEntityRuntime` owns incarnation identity, accepted snapshots/timestamps, runtime components, logical/spatial lifetime, and teardown. `GameWindow` still owns large hydration and wire-to-presentation adapter bodies. |
|
||||||
|
| Inbound/object-frame order | **Partial** | `RetailInboundEventDispatcher`, `RetailLiveFrameCoordinator`, `LiveEntityAnimationScheduler`, static scheduler, remote/projectile updaters, and teleport owners are shipped. `AdvanceLiveObjectRuntimeCore`, final part/mesh/effect composition, and several integration tails remain in `GameWindow`. |
|
||||||
|
| 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 | **Partial** | `ItemInteractionController`, `CombatTargetController`, and `CombatAttackController` own focused rules. `GameWindow` still owns picking, target queries, selection intent, Use/PickUp sends, range/auto-walk deferral, and related input cases. |
|
||||||
|
| Landblock presentation | **Not extracted** | Residency scheduling is extracted, but DAT build, scenery/EnvCell construction, apply, collision/resource publication, and retirement glue remain a large `GameWindow` body. |
|
||||||
|
| 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. |
|
||||||
|
|
||||||
### Step 2 — `LiveSessionController` — SHIPPED (`0b25df53`)
|
### 4.3 Revised extraction sequence
|
||||||
|
|
||||||
**Scope:** Extract `TryStartLiveSession` + the WorldSession ownership +
|
Every numbered slice is behavior-preserving and independently committed. A
|
||||||
the post-EnterWorld drain (`OnLiveStateUpdated`, `OnLiveEntityDeleted`,
|
slice does not include feature work or opportunistic gameplay fixes.
|
||||||
etc.) into a controller class.
|
|
||||||
|
|
||||||
**Behavior change:** None. Same wire behavior, same handshake.
|
#### Gate 0 — deterministic baseline — COMPLETE
|
||||||
|
|
||||||
**Risk:** Medium. WorldSession lifecycle is load-bearing — every
|
The Release suite, connected R6 soak, world-lifecycle screenshots/checkpoints,
|
||||||
session-state crash would surface here. The change is a class
|
graceful reconnect, local locomotion/collision/projectile/teleport gate, and
|
||||||
extraction with the same event subscriptions, not a rewrite.
|
two-client portal observer gate form the pre-refactor baseline. Each later
|
||||||
|
slice runs the subset capable of detecting its risk; render/session slices run
|
||||||
|
the complete connected lifecycle gate.
|
||||||
|
|
||||||
**Test:** Existing `AcDream.Core.Net.Tests` already cover the wire
|
#### Slice 1 — finish selection/interaction ownership — NEXT
|
||||||
layer. The controller itself gets a smoke test that verifies it can be
|
|
||||||
constructed without a live socket (offline mode).
|
|
||||||
|
|
||||||
**Verification:** Visual login + Holtburg traversal + door interaction
|
Split the old Step 4 into three reviewable commits:
|
||||||
identical to pre-extraction.
|
|
||||||
|
|
||||||
### Step 3 — `LiveEntityRuntime` — SHIPPED 2026-07-14
|
1. `WorldSelectionQuery` receives camera/scene/live-object read seams and owns
|
||||||
|
picking, target classification, selection bounds, closest-target lookup,
|
||||||
|
names, and descriptions. It cannot mutate selection or send packets.
|
||||||
|
2. `SelectionInteractionController` owns selection intents, double-click Use,
|
||||||
|
Use/PickUp packet requests, range decisions, speculative facing, and the
|
||||||
|
pending auto-walk action. It composes the existing item/combat controllers
|
||||||
|
rather than duplicating their rules.
|
||||||
|
3. Selection/Use/PickUp/combat-target `InputAction` cases delegate to the new
|
||||||
|
controller; the old methods and fields are deleted from `GameWindow`.
|
||||||
|
|
||||||
**Shipped scope:** One `LiveEntityRecord` per server-object incarnation now owns
|
Tests cover read-only query classification separately from stateful intents,
|
||||||
ServerGuid↔local-ID translation, accepted state, runtime components, parent
|
including direct use, distant auto-walk completion, corpse/container opening,
|
||||||
relations, logical resource activation, exact teardown, and spatial projection
|
pickup placement, hostile-only targeting, Hidden objects, and same-GUID reuse.
|
||||||
state. `RegisterLiveEntity`, `RebucketLiveEntity`, and `UnregisterLiveEntity`
|
The connected gate is select → use door/NPC → distant corpse → loot/pickup →
|
||||||
make the lifetime boundary explicit. Landblock unload/reload moves the same
|
combat target. This is the safest next slice because its outbound boundaries
|
||||||
`WorldEntity`; it cannot reconstruct from a stale CreateObject or replay setup
|
are typed and existing controllers already hold most retail rules.
|
||||||
scripts. Equipped children use an attached projection and never enter the
|
|
||||||
top-level target/radar/status view. Canonical materialized lookup remains
|
|
||||||
available while a projection is pending; the separate visible view is the only
|
|
||||||
surface radar, picking, status, and targeting consume. Pickup/parent leave-world
|
|
||||||
clears cell membership and pauses root movement/animation without destroying the
|
|
||||||
retained owners. Top-level spawn publication is one-shot per incarnation, so
|
|
||||||
leave/re-entry restores presentation without duplicating plugin event replay.
|
|
||||||
|
|
||||||
**Remaining target:** the player-specific controller is still a separate
|
#### Slice 2 — finish live animation presentation
|
||||||
aggregation. The focused effect queue is shipped; AD-32 now tracks only the
|
|
||||||
future non-effect, non-Parent packet queue.
|
|
||||||
|
|
||||||
**Behavior change:** Spatial withdrawal and re-entry now preserve logical
|
Move `TickAnimations`, final rigid/visual part composition, effect-pose
|
||||||
identity and active resources instead of replaying create-time effects.
|
publication, and motion-done binding into `LiveEntityAnimationPresenter`.
|
||||||
|
`LiveEntityAnimationScheduler` remains the time/movement owner; the presenter
|
||||||
|
only consumes one scheduler result and publishes the final draw/effect pose.
|
||||||
|
Move the surviving motion diagnostics with this owner instead of adding more
|
||||||
|
environment reads to `GameWindow`.
|
||||||
|
|
||||||
**Risk:** Medium-high. Entity lookup is in every hot path. The change
|
Tests pin legacy and sequencer paths, Hidden/static eligibility, ObjScale versus
|
||||||
is structural (one owner instead of three) but the lookup semantics
|
rigid effect poses, part availability, same-frame hook pose publication, and
|
||||||
must be byte-identical.
|
incarnation replacement. Run the R6 object-frame and projectile/effect suites
|
||||||
|
plus the connected locomotion/projectile gate.
|
||||||
|
|
||||||
**Test:** `LiveEntityRuntimeTests` cover duplicate CreateObject, generation
|
#### Slice 3 — complete live-session ownership
|
||||||
replacement, appearance mutation, loaded/pending rebucketing, attached
|
|
||||||
projection, pickup leave/re-entry, canonical-versus-visible lookup, resource
|
|
||||||
rollback, GUID reuse, and idempotent session teardown.
|
|
||||||
|
|
||||||
**Verification:** Walk Holtburg, click NPC, open door, pick up item.
|
Expand `LiveSessionController` to own connect, character-list validation,
|
||||||
All four M1 demo targets must still work.
|
character selection, EnterWorld, graceful character logout, reconnect, and
|
||||||
|
session-scoped disposal. Add `LiveSessionEventRouter` for typed subscriptions;
|
||||||
|
it routes events to focused domain handlers and owns unsubscription, but owns
|
||||||
|
no entity or UI state.
|
||||||
|
|
||||||
### Step 4 — `SelectionInteractionController`
|
Move `TryStartLiveSession`, `ClearInboundEntityState`, and
|
||||||
|
`WireLiveSessionEvents` out of `GameWindow`. Do not create a giant context bag
|
||||||
|
or a second world-state owner. The connected gate must prove login, fresh world
|
||||||
|
reveal, command/chat, portal, exact `0xF653` logout, ACE endpoint disconnect,
|
||||||
|
and fresh-process reconnect.
|
||||||
|
|
||||||
**Scope:** Extract `WorldPicker`, the Core `SelectionState` consumers, `SendUse`,
|
#### Slice 4 — extract live-entity App integration
|
||||||
`SendPickUp`, and the `InputAction.Select*` / `UseSelected` /
|
|
||||||
`SelectionPickUp` switch cases into one controller. Depends on Step 3
|
|
||||||
(uses `LiveEntityRuntime`).
|
|
||||||
|
|
||||||
**Behavior change:** None.
|
This is two owners, not one replacement god object:
|
||||||
|
|
||||||
**Risk:** Low-medium. Selection state is local to interactions; the
|
- `LiveEntityHydrationController` owns CreateObject/ObjDesc/Parent/Pickup/Delete
|
||||||
network outbound side is well-defined (`InteractRequests.BuildUse` /
|
integration, DAT-backed appearance hydration, resource registration, and
|
||||||
`BuildPickUp`).
|
exact teardown callbacks over `LiveEntityRuntime`.
|
||||||
|
- `LiveEntityNetworkUpdateController` owns App routing for accepted
|
||||||
|
Position/Vector/State/Movement updates into the existing remote physics,
|
||||||
|
motion, projectile, presentation, and teleport controllers.
|
||||||
|
|
||||||
**Test:** Selection state machine tests in `tests/AcDream.App.Tests/`.
|
Neither may own a GUID dictionary. Both resolve the current incarnation only
|
||||||
|
through `LiveEntityRuntime` and must preserve the inbound FIFO/authority-token
|
||||||
|
rules. Run the complete live-entity stress suite, R6 connected route, inventory
|
||||||
|
equip/parenting, death/corpse, and portal gates.
|
||||||
|
|
||||||
**Verification:** Click-to-select, double-click-to-Use, F-key pickup
|
#### Slice 5 — extract landblock presentation
|
||||||
all still work.
|
|
||||||
|
|
||||||
### Step 5 — `RenderFrameOrchestrator`
|
Create `LandblockPresentationPipeline` around the existing immutable
|
||||||
|
`LandblockBuild` transaction. It owns DAT build context, scenery/EnvCell
|
||||||
|
construction, mesh/collision/light publication, demotion/full-retirement, and
|
||||||
|
the single-reader DAT lock contract. `StreamingController` continues deciding
|
||||||
|
what is resident; `GpuWorldState` continues owning spatial buckets.
|
||||||
|
|
||||||
**Scope:** Extract the per-frame draw sequence (sky → terrain →
|
Tests pin loaded/pending/demoted/unloaded symmetry, stale build generations,
|
||||||
opaque mesh → translucent mesh → particles → debug → UI) into a
|
resource pin/release balance, collision footprints across landblock seams, and
|
||||||
dedicated orchestrator that `GameWindow.OnRender` delegates to.
|
first-login bootstrap replacement. Run the deterministic world-lifecycle gate
|
||||||
|
and the seven-destination resource soak.
|
||||||
|
|
||||||
**Behavior change:** None. Same draw order, same GL state.
|
#### Slice 6 — extract update-frame orchestration
|
||||||
|
|
||||||
**Risk:** Medium. GL state management is touchy; the orchestrator
|
After the stateful bodies above have owners, make the update path a real
|
||||||
must hand the GL context to the same renderers in the same order with
|
orchestrator instead of delegates back into the window. It owns the fixed
|
||||||
the same per-pass state setup.
|
retail phase order: input/local object → ordinary/static objects → hooks/
|
||||||
|
particles/scripts → inbound network → command interpreter → non-advancing
|
||||||
|
spatial reconcile → streaming/UI updates. `GameWindow.OnUpdate` becomes a
|
||||||
|
short time/input handoff.
|
||||||
|
|
||||||
**Test:** Visual verification only. Render orchestration is hard to
|
Frame-order tests and the existing R6 gate must produce the same lifecycle and
|
||||||
unit-test without a GL context.
|
movement traces before and after extraction.
|
||||||
|
|
||||||
**Verification:** Holtburg at radius 4, radius 8, radius 12 looks
|
#### Slice 7 — extract `RenderFrameOrchestrator`
|
||||||
identical across all four quality presets.
|
|
||||||
|
|
||||||
### Step 6 — `GameEntity` aggregation (the big one)
|
Move the complete draw graph and its reusable frame-local scratch state into a
|
||||||
|
GL-owning App collaborator. Preserve the exact modern pipeline order, clip
|
||||||
|
routing, PView flood, landscape/opaque/shared-alpha flush boundaries,
|
||||||
|
particles, debug draw, paperdoll, retained UI, and frame fences. Do not pass a
|
||||||
|
hundred individual delegates or let the orchestrator reach back into
|
||||||
|
`GameWindow`; inject a small immutable service set plus explicit per-frame
|
||||||
|
input.
|
||||||
|
|
||||||
**Scope:** Consolidate `WorldEntity` + `AnimatedEntity` + the per-entity
|
Automated acceptance uses framebuffer artifacts and render/resource
|
||||||
state in `LiveEntityRuntime` into one `GameEntity` class (the target
|
checkpoints. Visual acceptance compares outdoor, building, dungeon, portal
|
||||||
described in `acdream-architecture.md`). Every entity in the world —
|
exit, translucent lifestone/particles, and UI at the same camera positions.
|
||||||
player, NPC, monster, door, item — becomes a single `GameEntity`.
|
|
||||||
|
|
||||||
**Behavior change:** None at the wire / visual level; substantial at
|
#### Slice 8 — composition and shutdown cleanup
|
||||||
the call-site level (everyone moves to the new entity API).
|
|
||||||
|
|
||||||
**Risk:** High. Touches every system that reads entity state.
|
Keep GL/window construction in `GameWindow.OnLoad`, but group creation into
|
||||||
|
small composition functions and delete feature state left behind by prior
|
||||||
|
slices. `OnClosing` delegates to the existing retryable shutdown transaction.
|
||||||
|
Silk callbacks become narrow calls into the input, update, render, resize,
|
||||||
|
focus, and shutdown owners.
|
||||||
|
|
||||||
**Test:** All existing tests + the new `AcDream.App.Tests` suite. Visual
|
### 4.4 Exit criteria
|
||||||
verification at every M1 / M2 scenario.
|
|
||||||
|
|
||||||
**Verification:** Full M2 demo loop (equip sword, kill drudge, pick up
|
The campaign is complete when:
|
||||||
loot, open inventory) works identically.
|
|
||||||
|
- `GameWindow` contains no AC gameplay algorithm, entity scan, packet builder,
|
||||||
|
DAT landblock builder, animation-part composer, or draw-graph body;
|
||||||
|
- `OnUpdate`, `OnRender`, `OnInputAction`, and live-session callbacks are short
|
||||||
|
delegation methods;
|
||||||
|
- every extracted owner has App-layer tests and symmetric teardown;
|
||||||
|
- the Release suite and connected lifecycle/resource gates stay green after
|
||||||
|
every slice;
|
||||||
|
- the final local visual matrix passes unchanged.
|
||||||
|
|
||||||
|
Line count is a progress signal, not the acceptance test. The expected result
|
||||||
|
is below roughly 5,000 lines, but ownership and dependency direction decide
|
||||||
|
completion. Full `GameEntity` type aggregation is evaluated only afterwards as
|
||||||
|
a separate migration; it is not folded into this campaign.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5. Rules of the road during the extraction
|
## 5. Rules of the road during the extraction
|
||||||
|
|
||||||
1. **One step at a time.** A PR that ships Step 1 ships only Step 1.
|
1. **One slice at a time.** Each commit ships one ownership boundary or
|
||||||
Bundling steps makes failures hard to isolate.
|
mechanical call-site cutover. Bundling slices makes failures hard to
|
||||||
2. **Behavior preservation is the acceptance criterion.** Every step
|
isolate.
|
||||||
|
2. **Behavior preservation is the acceptance criterion.** Every slice
|
||||||
must build clean, all tests pass, and visual verification at the
|
must build clean, all tests pass, and visual verification at the
|
||||||
appropriate M1 / M2 scenarios must succeed. We're moving code, not
|
appropriate accepted milestone scenarios must succeed. We're moving code, not
|
||||||
changing it.
|
changing it.
|
||||||
3. **No new features during an extraction step.** If you spot a real
|
3. **No new features during an extraction step.** If you spot a real
|
||||||
bug while extracting, file it in `docs/ISSUES.md` and address it in
|
bug while extracting, file it in `docs/ISSUES.md` and address it in
|
||||||
|
|
@ -484,9 +558,15 @@ loot, open inventory) works identically.
|
||||||
moves to a new owner, the diagnostic flag inside it can move to a
|
moves to a new owner, the diagnostic flag inside it can move to a
|
||||||
diagnostic class as part of the same commit. We do not do a bulk
|
diagnostic class as part of the same commit. We do not do a bulk
|
||||||
diagnostic-cleanup pass.
|
diagnostic-cleanup pass.
|
||||||
5. **Update this document when the plan changes.** If Step 3 turns out
|
5. **Update this document when the plan changes.** If a slice turns out
|
||||||
to need a different shape than described above, update §4 in the
|
to need a different ownership shape than described above, update §4 in the
|
||||||
same session you discover the divergence.
|
same session you discover the divergence.
|
||||||
|
6. **No façade-only completion claims.** A delegate from a new class back to a
|
||||||
|
substantial `GameWindow` method is a useful intermediate seam, not a
|
||||||
|
completed extraction.
|
||||||
|
7. **No duplicate ownership.** New collaborators query `LiveEntityRuntime`,
|
||||||
|
`GpuWorldState`, `SelectionState`, or the relevant existing owner. They do
|
||||||
|
not create replacement GUID, visibility, session, or resource maps.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -494,8 +574,9 @@ loot, open inventory) works identically.
|
||||||
|
|
||||||
- **Not a full rewrite plan.** The point is the *opposite* — small
|
- **Not a full rewrite plan.** The point is the *opposite* — small
|
||||||
steps, verified at each boundary.
|
steps, verified at each boundary.
|
||||||
- **Not blocking M2.** Step 1 is small enough to ship without
|
- **Not a feature phase.** Following the 2026-07-21 user decision, this
|
||||||
disrupting M2 work. Later steps interleave with M2 / M3 phases as
|
behavior-preserving campaign is the structural prerequisite before new M4
|
||||||
the corresponding code paths come into focus.
|
subsystem bodies are added. Severe regressions remain fixable in separate
|
||||||
|
commits; ordinary feature work waits.
|
||||||
- **Not a substitute for the milestones / roadmap.** Those drive the
|
- **Not a substitute for the milestones / roadmap.** Those drive the
|
||||||
feature work. This drives the structural work that runs underneath.
|
feature work. This drives the structural work that runs underneath.
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,32 @@
|
||||||
# acdream — strategic roadmap
|
# acdream — strategic roadmap
|
||||||
|
|
||||||
**Status:** Living document. Updated 2026-07-20. **M3 active; automated implementation and connected single-client magic/portal gates complete.** M2's connected demo loop is complete. M3 now has the retail cast-intent/component/target lifecycle, exact live enchantment wire state, scoped Magic input, retained spell bar, spellbook, component book, positive/negative effects panels with authored rows and selected-spell details, the complete seven-control gameplay indicator strip and its Character Information/Link/Vitae detail pages, and shared `gmPanelUI` geometry/switching over the Step 9 projectile/PhysicsScript/particle/portal foundation. Fresh-login and portal world reveal are additionally protected by a deterministic capped/uncapped connected lifecycle gate with screenshots, resource snapshots, exact graceful disconnect, and fresh-process reconnect. The next gate is a local visual rebaseline of the new R6 object-frame path; the final M3 requirement is the two-client portal-out/materialization observer gate. Issue #225's lifestone/particle alpha comparison is a separate rendering visual gate.
|
**Status:** Living document. Updated 2026-07-21. **M3 landed; M4 is next after the active `GameWindow` structural prerequisite.** M3's retail casting/UI, R6 locomotion/collision/projectile/teleport/radar rebaseline, deterministic fresh-login/portal world lifecycle, and final two-client portal observer flow are user-gated. The current program is the behavior-preserving ownership campaign in [`docs/architecture/code-structure.md`](../architecture/code-structure.md); new M4 quest/emote/character-creation feature bodies wait until that campaign is complete. Issue #225's lifestone/particle alpha comparison remains a separate rendering visual gate.
|
||||||
**Purpose:** One source of truth for where the project is and where it's going. Every observed defect or missing feature has a named phase that owns it; when something looks wrong in-game, look here to find the phase that'll address it. Implementation details live in per-phase specs under `docs/superpowers/specs/`, not in this file.
|
**Purpose:** One source of truth for where the project is and where it's going. Every observed defect or missing feature has a named phase that owns it; when something looks wrong in-game, look here to find the phase that'll address it. Implementation details live in per-phase specs under `docs/superpowers/specs/`, not in this file.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Current program: M3 — Cast a spell
|
## Current program: `GameWindow` structural stabilization (M4 prerequisite)
|
||||||
|
|
||||||
|
**Outcome:** `GameWindow` becomes a thin Silk.NET composition/lifecycle shell
|
||||||
|
without changing accepted gameplay or rendering behavior. Focused App owners
|
||||||
|
take responsibility for selection, animation presentation, live-session and
|
||||||
|
live-entity integration, landblock presentation, and update/render frame
|
||||||
|
orchestration.
|
||||||
|
|
||||||
|
**Current sequence:** The implementation audit, exact ownership ledger, slice
|
||||||
|
boundaries, tests, connected gates, and exit criteria live in
|
||||||
|
[`docs/architecture/code-structure.md`](../architecture/code-structure.md) §4.
|
||||||
|
The next slice is selection/interaction: extract the read-only world query,
|
||||||
|
move stateful Use/PickUp/auto-walk intent into one controller, then cut the
|
||||||
|
related input cases over and delete the old `GameWindow` bodies.
|
||||||
|
|
||||||
|
This is a behavior-preserving structural program. Severe regressions still get
|
||||||
|
root-cause fixes in separate commits; ordinary feature work resumes with M4
|
||||||
|
after the campaign exit criteria pass.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Completed program: M3 — Cast a spell (landed 2026-07-21)
|
||||||
|
|
||||||
**Outcome:** Cast a projectile spell at a hostile target, see the complete
|
**Outcome:** Cast a projectile spell at a hostile target, see the complete
|
||||||
turn/windup/release/projectile/impact lifecycle, self-cast a buff and see its
|
turn/windup/release/projectile/impact lifecycle, self-cast a buff and see its
|
||||||
|
|
@ -39,14 +60,14 @@ active enchantment, then recall through the DAT-driven portal presentation.
|
||||||
same-location revisit, graceful logout, and uncapped fresh-process
|
same-location revisit, graceful logout, and uncapped fresh-process
|
||||||
reconnect. The gate records structured readiness/resource checkpoints and
|
reconnect. The gate records structured readiness/resource checkpoints and
|
||||||
full-frame PNGs, and rejects early world visibility or stranded owners.
|
full-frame PNGs, and rejects early world visibility or stranded owners.
|
||||||
5. **Pending local visual gate:** locomotion, collision, projectile, and
|
5. **Done (connected user gate):** locomotion, collision, projectile, teleport,
|
||||||
teleport comparison after the R6 complete-root-Frame/object-workset cutover.
|
and radar comparison after the R6 complete-root-Frame/object-workset cutover.
|
||||||
6. **Pending two-client visual gate:** portal-out/materialization observer
|
6. **Done (two-client user gate):** portal-out/materialization observer
|
||||||
presentation before M3 closes, including #218's finished Hidden silhouette,
|
presentation, including #218's finished Hidden silhouette, fully rendered
|
||||||
fully rendered destination reveal, and no indoor stop-time position snap.
|
destination reveal, and no indoor stop-time position snap.
|
||||||
|
|
||||||
Opportunistic UI/physics fixes are no longer the work-order driver. They enter
|
M3 is closed. Its detailed ledger remains here as the landing record; the
|
||||||
the active slice only when they block this demo or represent a severe regression.
|
structural program above is the only current work-order driver before M4.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -937,8 +958,7 @@ diagnostic scaffolding, not yet the final collision system.
|
||||||
and 0.2 -> 0.3 ms at Sawato. ACE generator population changes are reported
|
and 0.2 -> 0.3 ms at Sawato. ACE generator population changes are reported
|
||||||
rather than treated as client leaks. Absolute FPS/GPU timing remains
|
rather than treated as client leaks. Absolute FPS/GPU timing remains
|
||||||
session/display-path evidence, not an RDP-stable gate. The connected visual
|
session/display-path evidence, not an RDP-stable gate. The connected visual
|
||||||
locomotion/collision/projectile/teleport comparison remains for the next
|
locomotion/collision/projectile/teleport/radar comparison passed 2026-07-21.
|
||||||
local viewing session.
|
|
||||||
- **L.2g — Inbound motion interpretation (remote-entity CMotionInterp funnel).**
|
- **L.2g — Inbound motion interpretation (remote-entity CMotionInterp funnel).**
|
||||||
ACTIVE 2026-07-02. Port retail's inbound motion pipeline verbatim for ALL
|
ACTIVE 2026-07-02. Port retail's inbound motion pipeline verbatim for ALL
|
||||||
remote entities (players, NPCs, monsters — one funnel, user-approved):
|
remote entities (players, NPCs, monsters — one funnel, user-approved):
|
||||||
|
|
@ -1453,7 +1473,7 @@ OpenGL ceiling; revisit macOS only if a supported graphics backend is chosen.
|
||||||
|
|
||||||
## Cross-cutting work tracked in parallel
|
## Cross-cutting work tracked in parallel
|
||||||
|
|
||||||
- **Test coverage.** Each phase lands with layer-matched unit and integration tests in `tests/`. Current Release baseline: 6,480 passed / 5 intentional skips (2026-07-20).
|
- **Test coverage.** Each phase lands with layer-matched unit and integration tests in `tests/`. Current Release baseline: 6,481 passed / 5 intentional skips (2026-07-21).
|
||||||
- **Memory files.** Live subsystem state and digests are indexed by `claude-memory/MEMORY.md`; stable engineering references remain under `memory/`. Canonical program status stays in milestones/roadmap/issues.
|
- **Memory files.** Live subsystem state and digests are indexed by `claude-memory/MEMORY.md`; stable engineering references remain under `memory/`. Canonical program status stays in milestones/roadmap/issues.
|
||||||
- **`CLAUDE.md` discipline.** Check all four references (ACE, ACViewer, WorldBuilder, Chorizite) before committing to an approach. WorldBuilder is the closest stack match and should be checked first.
|
- **`CLAUDE.md` discipline.** Check all four references (ACE, ACViewer, WorldBuilder, Chorizite) before committing to an approach. WorldBuilder is the closest stack match and should be checked first.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,28 +2,28 @@
|
||||||
|
|
||||||
**Status:** Living document. Created 2026-05-12.
|
**Status:** Living document. Created 2026-05-12.
|
||||||
**Sits above:** [`docs/plans/2026-04-11-roadmap.md`](2026-04-11-roadmap.md) (the strategic phase index).
|
**Sits above:** [`docs/plans/2026-04-11-roadmap.md`](2026-04-11-roadmap.md) (the strategic phase index).
|
||||||
**Currently working toward:** **M3 — "Cast a spell." M2 — "Kill a drudge"
|
**Currently working toward:** **M4 — "Live in the world." M3 — "Cast a
|
||||||
LANDED 2026-07-15.** The complete connected melee/missile, death/loot,
|
spell" LANDED 2026-07-21.** Projectile/self-buff casting, protection effects,
|
||||||
inventory, and item-giving demo is user-gated. The shared projectile/effect
|
spellbook/component-book filtering and deletion, favorite spell bars, active
|
||||||
foundation is hardened through Step 9. Spellbook/component-book filtering,
|
effects, recall, portal-space presentation, and the complete two-client
|
||||||
favorite spell bar, connected casting/enchantment effects, and portal-space
|
portal-out/materialization observer flow are user-gated. The R6 locomotion,
|
||||||
presentation have passed their single-client visual gates. The corrective bounded
|
collision, projectile, teleport, and radar rebaseline also passes. Deterministic
|
||||||
render/resource-lifetime integration passed its seven-destination connected
|
world-lifecycle automation protects fresh login, outdoor/world-edge/dungeon
|
||||||
stress gate without a crash or cumulative collapse. A second deterministic
|
travel, same-location revisit, exact graceful disconnect, and uncapped
|
||||||
world-lifecycle gate now protects fresh login, outdoor/world-edge/dungeon
|
fresh-process reconnect with canonical JSON/PNG evidence.
|
||||||
travel, same-location revisit, exact graceful disconnect, and an uncapped
|
|
||||||
fresh-process reconnect with canonical readiness snapshots and saved PNG/JSON
|
Before new M4 quest/emote/character-creation subsystem bodies enter the App
|
||||||
artifacts. The remaining M3 visual requirement is the final two-client
|
layer, the active structural prerequisite is the behavior-preserving
|
||||||
portal-out/materialize observer gate. The new R6 object-update cutover has
|
`GameWindow` decomposition in
|
||||||
passed its unattended connected input/portal/performance rebaseline; its
|
[`docs/architecture/code-structure.md`](../architecture/code-structure.md).
|
||||||
locomotion/collision/projectile/teleport visual gate remains for the next local
|
The 2026-07-21 audit found 15,723 lines, 258 fields, and about 259 methods;
|
||||||
viewing session before that observer gate.
|
the next slice finishes selection/interaction ownership.
|
||||||
|
|
||||||
Carried:
|
Carried:
|
||||||
#153 far-teleport residual, #116 slide-response, the remaining R6 ownership cleanup plus
|
#153 far-teleport residual, #116 slide-response, the remaining R6 ownership cleanup plus
|
||||||
registered TS-50/TS-51 timing residuals (the complete-root-Frame/object-workset
|
registered TS-50/TS-51 timing residuals (the complete-root-Frame/object-workset
|
||||||
cutover is automated-test complete 2026-07-20; three independent re-reviews are
|
cutover is automated- and visual-gate complete; Release builds with 17 known
|
||||||
clean, Release builds with 17 known test-project warnings tracked by #228, and
|
test-project warnings tracked by #228, and 6,481 tests pass / 5 skip), and
|
||||||
6,480 tests pass / 5 skip after the world-reveal gate), and
|
|
||||||
the deferred Modern Pipeline track (MP1b+). The separate #225 shared-alpha
|
the deferred Modern Pipeline track (MP1b+). The separate #225 shared-alpha
|
||||||
implementation has passed connected lifetime/performance gates and awaits only
|
implementation has passed connected lifetime/performance gates and awaits only
|
||||||
its lifestone/particle visual comparison.
|
its lifestone/particle visual comparison.
|
||||||
|
|
@ -662,8 +662,8 @@ include dungeons.
|
||||||
publishes outdoor landcells independently of surviving object meshes.
|
publishes outdoor landcells independently of surviving object meshes.
|
||||||
Terrain/entity streaming distance is
|
Terrain/entity streaming distance is
|
||||||
unchanged; the user-requested default Extended setting doubles only particle
|
unchanged; the user-requested default Extended setting doubles only particle
|
||||||
range, while Retail remains available as the exact cutoff. The
|
range, while Retail remains available as the exact cutoff. The final
|
||||||
final two-client visual gate is still pending.
|
two-client visual gate passed 2026-07-21.
|
||||||
- **L.1c local attack receive path (implemented and live-gated 2026-07-15)** —
|
- **L.1c local attack receive path (implemented and live-gated 2026-07-15)** —
|
||||||
local non-autonomous mt-0 UpdateMotion now uses retail's wholesale interpreted
|
local non-autonomous mt-0 UpdateMotion now uses retail's wholesale interpreted
|
||||||
funnel and action-stamp gate, so ACE's server-selected melee/missile action
|
funnel and action-stamp gate, so ACE's server-selected melee/missile action
|
||||||
|
|
@ -713,7 +713,17 @@ a game.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### M3 — "Cast a spell" — 🔵 ACTIVE (started 2026-07-15)
|
### M3 — "Cast a spell" — ✅ LANDED 2026-07-21
|
||||||
|
|
||||||
|
**Landing writeup:** Mages now work end to end. A connected player can manage
|
||||||
|
the retail spellbook/component book and favorite bars, cast projectile and
|
||||||
|
self-targeted spells with the correct components/target gates, see traveling
|
||||||
|
missiles and DAT-driven protection/impact effects, inspect live enchantments,
|
||||||
|
and recall or portal through the retail tunnel/reveal lifecycle. The final
|
||||||
|
two-client observer gate confirms departure disappearance, destination
|
||||||
|
materialization, finished pose, rendered destination, and indoor movement
|
||||||
|
without snap-back. The R6 local locomotion/collision/projectile/teleport and
|
||||||
|
radar checks pass on the same Release baseline.
|
||||||
|
|
||||||
**Demo scenario:** Cast Flame Bolt at a drudge. Watch the cast animation,
|
**Demo scenario:** Cast Flame Bolt at a drudge. Watch the cast animation,
|
||||||
the projectile, the impact. Self-cast a buff (Strength Self). See the
|
the projectile, the impact. Self-cast a buff (Strength Self). See the
|
||||||
|
|
@ -740,9 +750,9 @@ The strip now uses retail DAT states for link quality, Helpful/Harmful effects,
|
||||||
Vitae, burden, mini-game availability, and end-character-session; live link
|
Vitae, burden, mini-game availability, and end-character-session; live link
|
||||||
age, player load, and enchantment registries drive their retail thresholds and
|
age, player load, and enchantment registries drive their retail thresholds and
|
||||||
the burden/effect/logout actions use the shared panel/dialog owners. Main-panel
|
the burden/effect/logout actions use the shared panel/dialog owners. Main-panel
|
||||||
visibility now flows through retail's one-active `gmPanelUI` owner. M3 remains
|
visibility now flows through retail's one-active `gmPanelUI` owner. The
|
||||||
active only for the connected single-client magic
|
connected single-client magic UI/casting gates and final two-client portal
|
||||||
UI/casting visual gate and the final two-client portal observer gate.
|
observer gate passed before landing.
|
||||||
The 2026-07-17 indicator follow-up also mounts authored Character Information,
|
The 2026-07-17 indicator follow-up also mounts authored Character Information,
|
||||||
Link Status, Vitae, and Mini Game detail roots as children of that same
|
Link Status, Vitae, and Mini Game detail roots as children of that same
|
||||||
main-panel owner. Helpful, Harmful, Character Information, Link, and Vitae
|
main-panel owner. Helpful, Harmful, Character Information, Link, and Vitae
|
||||||
|
|
@ -795,7 +805,12 @@ from M3 = retail-equivalent gameplay loop for melee and casters.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### M4 — "Live in the world" — 🔵 (~6–10 weeks)
|
### M4 — "Live in the world" — 🟡 NEXT (~6–10 weeks)
|
||||||
|
|
||||||
|
**Entry condition:** complete the behavior-preserving `GameWindow`
|
||||||
|
decomposition campaign before adding H.3/H.4/L.1e feature bodies. This protects
|
||||||
|
M4 from deepening the App-layer composition debt; it does not change M4's demo
|
||||||
|
scope.
|
||||||
|
|
||||||
**Demo scenario:** Create a fresh character from scratch (no ACE admin).
|
**Demo scenario:** Create a fresh character from scratch (no ACE admin).
|
||||||
Spawn. Talk to an NPC. Accept a quest. Walk to a dungeon entrance. Portal
|
Spawn. Talk to an NPC. Accept a quest. Walk to a dungeon entrance. Portal
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue