docs(ui): align architecture with retained runtime
This commit is contained in:
parent
00ab4a2a64
commit
f98050854d
6 changed files with 109 additions and 70 deletions
|
|
@ -1,11 +1,11 @@
|
|||
# UI framework plan
|
||||
|
||||
**Date:** 2026-04-24 (design), shipped 2026-04-25
|
||||
**Status:** **Phase D.2a shipped** — `AcDream.UI.Abstractions` + ImGui backend
|
||||
+ `VitalsPanel` gated on `ACDREAM_DEVTOOLS=1`. Backend pivoted from
|
||||
`Hexa.NET.ImGui` to `ImGui.NET` + `Silk.NET.OpenGL.Extensions.ImGui` during
|
||||
first-light integration — see the pivot note below. Phase D.2b (custom
|
||||
retail-look backend) remains design-only.
|
||||
**Status:** **Phase D.2a and the D.2b retained gameplay UI have shipped.**
|
||||
ImGui remains the `ACDREAM_DEVTOOLS=1` developer stack. Retail gameplay UI is
|
||||
the independent `UiHost`/`UiRoot` retained tree under `AcDream.App/UI`, built
|
||||
from production LayoutDesc/DAT assets. The stable cross-stack seam is game
|
||||
state, ViewModels, and commands — not an `IPanelRenderer` backend swap.
|
||||
**Owner:** lead engineer (erik) + Claude
|
||||
|
||||
Captures the UI strategy agreed via discussion on 2026-04-24. Documents
|
||||
|
|
@ -53,12 +53,12 @@ panel, skills, spellbook, fellowship, allegiance, trade, options, map,
|
|||
quest log, tooltips — and a first-class plugin API so plugin authors can
|
||||
ship their own panels.
|
||||
|
||||
## Strategy: two-phase, one stable interface
|
||||
## Current strategy: two coexisting stacks, shared state contracts
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ UI backend ─ ImGui (short-term) │ ← swappable
|
||||
│ ─ Custom retail (later) │
|
||||
│ Developer UI ─ ImGui + IPanelRenderer │
|
||||
│ Gameplay UI ─ UiRoot retained widgets │
|
||||
├─────────────────────────────────────────┤
|
||||
│ ViewModels + Commands (per panel) │ ← stable contracts
|
||||
├─────────────────────────────────────────┤
|
||||
|
|
@ -66,14 +66,16 @@ ship their own panels.
|
|||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
- **Near term:** wire an ImGui-based overlay so we can iterate on game
|
||||
logic fast — chat that actually sends + receives, inventory that
|
||||
reflects real state, vitals bar that reads real HP/stam/mana. Looks
|
||||
like a debugger, that's fine for now.
|
||||
- **Later:** replace the visual layer with a custom toolkit that uses
|
||||
retail dat assets (icons, panels, fonts) and matches retail's feel.
|
||||
- **Always:** ViewModels and Commands stay stable across the swap. The
|
||||
game logic never learns which backend is drawing it.
|
||||
- **Developer stack:** `AcDream.UI.Abstractions` panels render through
|
||||
`IPanelRenderer` on ImGui. This stack is permanent for diagnostics, packet
|
||||
inspection, settings development, and other devtools.
|
||||
- **Gameplay stack:** `UiHost` owns a retained `UiRoot` tree. `LayoutImporter`
|
||||
builds retail windows from LayoutDesc/DAT assets and focused `gm*UI`-style
|
||||
controllers bind runtime values and actions.
|
||||
- **Shared seam:** both stacks consume the same session state, ViewModels, and
|
||||
command/event services. A panel is ported to retained UI by binding those
|
||||
shared models to its DAT-authored tree, not by implementing
|
||||
`IPanelRenderer` a second time.
|
||||
|
||||
## Choice: Hexa.NET.ImGui for the short-term backend
|
||||
|
||||
|
|
@ -158,7 +160,7 @@ public sealed record EquipItemCmd(uint ItemGuid, EquipSlot Slot);
|
|||
Dispatched to an `ICommandBus` that routes to the appropriate subsystem
|
||||
(`WorldSession.SendSelect`, `ChatService.Send`, etc.).
|
||||
|
||||
### Layer 3 — UI backend
|
||||
### Layer 3a — ImGui developer backend
|
||||
|
||||
New module: `src/AcDream.UI.ImGui/`. References `AcDream.UI.Abstractions`.
|
||||
|
||||
|
|
@ -168,11 +170,34 @@ New module: `src/AcDream.UI.ImGui/`. References `AcDream.UI.Abstractions`.
|
|||
per frame.
|
||||
- Keyboard / mouse / focus handled by ImGui natively.
|
||||
|
||||
Later: `src/AcDream.UI.Retail/` references the same `AcDream.UI.Abstractions`
|
||||
and implements the same `IPanel` / `IPanelHost` interfaces — but draws
|
||||
with our own retained-mode toolkit + retail dat assets.
|
||||
This layer remains the permanent devtools surface. It is not the production
|
||||
retail gameplay renderer.
|
||||
|
||||
## Plugin API (must be backend-agnostic)
|
||||
### Layer 3b — retained retail gameplay UI
|
||||
|
||||
`src/AcDream.App/UI/` contains the GL-free widget tree, LayoutDesc importer,
|
||||
window runtime, and panel controllers. Rendering dependencies enter through
|
||||
small sprite/font/viewport resolver seams. Controllers consume the same
|
||||
ViewModels and command services used by the ImGui panels, while binding
|
||||
behavior to existing retail element ids instead of procedurally redrawing the
|
||||
panel through `IPanelRenderer`.
|
||||
|
||||
## Plugin UI API
|
||||
|
||||
The shipped plugin-facing gameplay UI contract is
|
||||
`AcDream.Plugin.Abstractions.IUiRegistry.AddMarkupPanel`: a plugin provides
|
||||
KSML-style markup and a binding object; the host builds it into the retained
|
||||
`UiRoot` tree. `IPanel`/`IPanelRenderer` remains a first-party developer-panel
|
||||
contract and is intentionally not referenced by `Plugin.Abstractions`.
|
||||
|
||||
This makes plugin gameplay panels independent of ImGui while allowing them to
|
||||
share the retained input, window, and DAT-sprite runtime. Registrations made
|
||||
before the GL host exists are buffered. In builds where retail UI is disabled,
|
||||
they remain registered but have no gameplay surface; the long-term release
|
||||
configuration enables retained gameplay UI.
|
||||
|
||||
The following was the original pre-D.2b proposal and remains historical
|
||||
context, not the shipped plugin contract:
|
||||
|
||||
```csharp
|
||||
public interface IPanel
|
||||
|
|
@ -227,32 +252,34 @@ walk around / take damage / regen.
|
|||
to equip, drag target for future move.
|
||||
- `CharacterPanel` — attributes, skills, XP.
|
||||
|
||||
### Sprint 3 — Plugin API hardening
|
||||
### Sprint 3 — Plugin API hardening (superseded shape)
|
||||
|
||||
- Document the `IPanel` contract.
|
||||
- Port the smoke plugin to register a demo panel via the API.
|
||||
- Confirm plugins can subscribe to game events AND draw UI through the
|
||||
same interface.
|
||||
- The shipped route is `IUiRegistry.AddMarkupPanel`, not plugin-owned
|
||||
`IPanel` implementations.
|
||||
- Confirm plugins can subscribe to game events and expose retained markup
|
||||
bindings without referencing App or ImGui assemblies.
|
||||
|
||||
### Sprint 4+ — More panels
|
||||
|
||||
Spellbook, allegiance, fellowship, trade, map, quest log, options.
|
||||
Continue to expand `InventoryPanel` with drag-drop, split, appraise.
|
||||
|
||||
### Later — Custom retail-look backend
|
||||
### D.2b — retained retail-look gameplay UI (shipped, expanding panel by panel)
|
||||
|
||||
`AcDream.UI.Retail` implements `IPanelRenderer` with our own toolkit +
|
||||
retail dat assets. Swap panels one at a time. ImGui overlay remains for
|
||||
devtools.
|
||||
`AcDream.App/UI` imports LayoutDesc trees and draws retail DAT assets through
|
||||
the retained `UiRoot` runtime. ImGui remains available for devtools; shared
|
||||
ViewModels and commands prevent duplicate game-state logic.
|
||||
|
||||
## Non-goals for this first pass
|
||||
|
||||
- **Not** going to theme ImGui to look retail. Waste of effort when we'll
|
||||
swap the backend. Devtools aesthetic is fine.
|
||||
- **Not** porting retail's widget code. We use their ASSETS later, not
|
||||
their widget implementation.
|
||||
- **Not** building layout DSL / XAML-like markup. Panels register and
|
||||
draw procedurally, same as ImGui.
|
||||
- **Not** byte-porting Keystone internals that are unavailable. Observable
|
||||
widget behavior is recovered from the named client call sites, DAT
|
||||
properties, and live retail evidence.
|
||||
- **Not** hand-authoring first-party gameplay layouts where retail LayoutDesc
|
||||
data exists. KSML-style markup remains the plugin/extension layout surface.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
|
|
@ -271,13 +298,13 @@ devtools.
|
|||
**Mitigation:** code review every addition; if a feature only exists
|
||||
in ImGui and the retail toolkit can't express it, don't add it.
|
||||
|
||||
- **Risk:** Swap to custom backend breaks a dozen panels simultaneously.
|
||||
**Mitigation:** swap one panel at a time, keep ImGui rendering the
|
||||
rest until all are ported.
|
||||
- **Risk:** ImGui and retained controllers grow separate game-state truth.
|
||||
**Mitigation:** one session model/ViewModel and one command path per
|
||||
subsystem; each surface is only a projection.
|
||||
|
||||
- **Risk:** Plugin authors write panels that only work in ImGui.
|
||||
**Mitigation:** smoke plugin registers a panel early; use it as a
|
||||
canary whenever backend changes.
|
||||
- **Risk:** Plugin markup relies on App-only widget details.
|
||||
**Mitigation:** keep `IUiRegistry` BCL-only, resolve bindings by contract,
|
||||
and use a smoke plugin as the retained-runtime canary.
|
||||
|
||||
- **Risk:** Hexa.NET.ImGui stops being maintained.
|
||||
**Mitigation:** integration is small (<100 LOC), switching to
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue