Frames the next core-panels work for a fresh session, after B.1 (drag spine) + B.2 (toolbar reorder/remove + wire) + toolbar collapse merged this session. Three sub-phases in order: (A) minimal window manager (open/close + I-key toggle; UiHost has no open/close API today, windows are always-on); (B) inventory window (Stream C, synthesis §4 — UiItemList grid + sub-window mount + wire gaps + InventoryController; the drag SOURCE that closes B.2's drag-from-inventory via a SourceKind==Inventory branch in ToolbarController.HandleDropRelease); (C) paperdoll UiViewport (Type 0xD) + Core→App IUiViewportRenderer seam, heaviest, last. Spell bar deferred. Reuse the shipped spine/ShortcutStore/wire. Paste-able new-session prompt + MEMORY index line inside. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
200 lines
14 KiB
Markdown
200 lines
14 KiB
Markdown
# Handoff — window manager → inventory window → paperdoll (the next D.2b core-panels arc)
|
|
|
|
**Date:** 2026-06-20
|
|
**From:** the D.5.3 session that shipped the drag-drop spine (B.1), toolbar shortcut reorder/remove +
|
|
wire (B.2), and toolbar collapse-to-one-row — all **merged to `main`** (merge commit `abbd97b`;
|
|
branch `claude/hopeful-maxwell-214a12`, tip `14443e5`). Full suite green (2752) at merge.
|
|
**Line numbers below WILL drift — grep the symbol, don't trust the line.**
|
|
|
|
---
|
|
|
|
## 0. What just shipped (the foundation the next work builds on)
|
|
|
|
This is now on `main` and visually confirmed:
|
|
|
|
- **Drag-drop spine (B.1)** — the shared widget-level drag machine. `UiRoot` holds the device-level
|
|
drag (BeginDrag/UpdateDragHover/FinishDrag, ghost snapshotted at begin, drop delivered only on a real
|
|
hit). `UiElement` has `GetDragPayload()`/`GetDragGhost()`/`IsDragSource` virtuals (UiRoot stays
|
|
item-agnostic). `UiItemSlot` is drag source + drop target + accept/reject overlay; `UiItemList` owns
|
|
a registered `IItemListDragHandler { OnDragLift; OnDragOver; HandleDropRelease }`. Payload =
|
|
`ItemDragPayload(ObjId, SourceKind, SourceSlot, SourceCell)`. Spec/plan:
|
|
`docs/superpowers/{specs,plans}/2026-06-20-d2b-drag-drop-spine*.md`.
|
|
- **Toolbar shortcut drag (B.2)** — retail **remove-on-lift / place-on-drop / no-restore**.
|
|
`ToolbarController : IItemListDragHandler` drives a `ShortcutStore` (`AcDream.Core.Items`, 18 slots)
|
|
+ the wire: `InventoryActions.BuildAddShortcut(seq,index,objectGuid,spellId,layer)` /
|
|
`BuildRemoveShortcut`, sent via `WorldSession.SendAddShortcut`/`SendRemoveShortcut`. Green-cross
|
|
accept sprite `0x060011FA`. Spec/plan: `docs/superpowers/{specs,plans}/2026-06-20-d2b-toolbar-shortcut-drag*.md`.
|
|
- **Toolbar collapse** — `UiCollapsibleFrame` bottom-edge snap resize (1-row ↔ 2-row). Spec:
|
|
`docs/superpowers/specs/2026-06-20-d2b-toolbar-collapse-design.md`.
|
|
|
|
**The one B-stream piece still owed:** *drag FROM inventory onto the bar.* B.2 did the within-bar
|
|
reorder/remove (`SourceKind == ShortcutBar`). The fresh-from-inventory branch (retail `flags & 0xE == 0`
|
|
→ `CreateShortcutToItem`) needs the inventory window as a drag SOURCE — so it lands WITH Stream C
|
|
below, not before it.
|
|
|
|
---
|
|
|
|
## 1. Read first
|
|
|
|
- This doc.
|
|
- `docs/research/2026-06-16-ui-panels-synthesis.md` §4 — **the build plan** for the core panels
|
|
(build order, widget list, cross-panel wire table). Stream C follows it.
|
|
- `docs/research/2026-06-16-inventory-deep-dive.md` — `gmInventoryUI 0x21000023` nests paperdoll
|
|
(`0x21000024`) + backpack (`0x21000022`) + 3D-items (`0x21000021`); backpack burden Meter
|
|
(`SetLoadLevel`→fill `0x69`); full inventory wire catalog + acdream parse-status.
|
|
- `docs/research/2026-06-16-equipment-paperdoll-deep-dive.md` — the doll = `UIElement_Viewport`
|
|
(Type `0xD`) hosting a re-dressed player clone; ~25 equip slots; wield = `GetAndWieldItem 0x001A`
|
|
(builder MISSING); needs a Core→App `IUiViewportRenderer` seam.
|
|
- `docs/research/2026-06-18-d53-bar-finish-and-inventory-handoff.md` §C — the predecessor's
|
|
current-code readiness for the inventory window (most still accurate; deltas noted below).
|
|
- `claude-memory/project_d2b_retail_ui.md` (the toolkit, now incl. B.1/B.2/collapse) +
|
|
`claude-memory/project_object_item_model.md` (the D.5.4 `ClientObjectTable`).
|
|
|
|
**Mandatory workflow** (CLAUDE.md): grep `docs/research/named-retail/acclient_2013_pseudo_c.txt` by
|
|
`class::method` → cross-ref ACE/holtburger → pseudocode → port; conformance tests throughout. Each
|
|
sub-phase gets its own brainstorm → spec → plan → subagent-driven (the flow this arc has been using).
|
|
|
|
---
|
|
|
|
## 2. Scope — three sub-phases, in order
|
|
|
|
| # | Sub-phase | One-liner |
|
|
|---|---|---|
|
|
| **A** | **Window manager (open/close + `I`-key)** | The small shared infra to open/close a window + a keybind to toggle the inventory window. Prerequisite for everything below. |
|
|
| **B** | **Inventory window (Stream C / D.5.5)** | `gmInventoryUI` nesting paperdoll + backpack + 3D-items. The drag SOURCE that completes "drag-from-inventory." |
|
|
| **C** | **Paperdoll** (`UiViewport`) | The 3D dressed-doll viewport — the heaviest piece, its own Core→App seam. Last. |
|
|
|
|
**Out of scope:** the spell bar (a separate spell-casting feature, NOT the action-bar spell shortcuts);
|
|
the faithful dragbar/resizebar window resize (IA-12 whole-window-drag + the new bottom-edge collapse
|
|
are the accepted approximations).
|
|
|
|
---
|
|
|
|
## 3. Sub-phase A — window manager (open/close + `I`-key) — DO THIS FIRST
|
|
|
|
**Current state:** every retail-UI window is **always-on at a hardcoded position** — the vitals,
|
|
chat, and toolbar are added to `_uiHost.Root` unconditionally at startup under `ACDREAM_RETAIL_UI=1`
|
|
(grep `_uiHost.Root.AddChild` in `GameWindow.cs`; the mounts are in the `_options.RetailUi` block).
|
|
`UiHost` has **no open/close API** (`src/AcDream.App/UI/UiHost.cs` — it exposes `Root`, `Tick`,
|
|
`Draw`, `WireMouse/Keyboard` only). Input flows through `InputDispatcher` (Phase K) —
|
|
`keybinds.json` + `KeyBindings`; the `I` key needs an action + binding.
|
|
|
|
**Minimum deliverable:** open/close a top-level window + toggle the inventory window with `I`.
|
|
Concretely:
|
|
- A small open/close concept on `UiHost`/`UiRoot` (e.g. register a named window + Show/Hide/Toggle that
|
|
flips `Visible` and brings it to front via `ZOrder`). Today windows are always `Visible=true`; the
|
|
manager makes a window default-hidden and toggleable. (z-order/persist can be minimal — `Visible` +
|
|
a top-most `ZOrder` bump on open.)
|
|
- An `InputAction` (e.g. `ToggleInventory`) + the retail default `I` keybind (cross-check
|
|
`docs/research/named-retail/retail-default.keymap.txt`), wired through the existing
|
|
`InputDispatcher` (see `claude-memory/project_input_pipeline.md`), gated by `WantsKeyboard` so it
|
|
doesn't fire while a chat input is focused.
|
|
|
|
**Brainstorm questions (A):** Is the window manager a property on `UiRoot` (a registry of named
|
|
top-level windows + Show/Hide/Toggle), or a thin `UiHost` API? How is z-order handled on open (bring
|
|
to front)? Does `I` toggle (open↔close) or only open (Esc/close-button to close)? Persist open-state
|
|
across the session (in-memory) only — no disk persistence yet (that's the deferred Plan-2)?
|
|
|
|
Faithful retail note: retail windows are opened by the radar/menu buttons + hotkeys and managed by
|
|
keystone.dll (no decomp) — so this is a toolkit-defined manager (IA-12/IA-15 umbrella), kept minimal.
|
|
|
|
---
|
|
|
|
## 4. Sub-phase B — inventory window (Stream C / D.5.5) — follow the synthesis §4
|
|
|
|
**The design is already written — follow `2026-06-16-ui-panels-synthesis.md` §4.** This section is the
|
|
**current-code readiness** + what's missing. Don't re-derive the design.
|
|
|
|
**READY (and stronger now, post-B.1/B.2):**
|
|
- `UiItemSlot` + `UiItemList` + `IconComposer` (`src/AcDream.App/UI/`) — the shared item-cell spine,
|
|
now with the full drag-drop machine (B.1). An inventory grid is `UiItemList` cells + an
|
|
`IItemListDragHandler` on the controller.
|
|
- `DatWidgetFactory` registers `0x10000031 → UiItemList` (grep `0x10000031` in
|
|
`src/AcDream.App/UI/Layout/DatWidgetFactory.cs`).
|
|
- The data path: `ClientObjectTable.GetContents(containerGuid)` → ordered guids → `Get(guid)` → full
|
|
icon fields (`src/AcDream.Core/Items/ClientObjectTable.cs`). The object/container model shipped in
|
|
D.5.4 (`project_object_item_model.md`).
|
|
- The shortcut wire + `ShortcutStore` (B.2) — so **drag-from-inventory-onto-the-bar** is now a small
|
|
addition: the inventory cell is a drag SOURCE (its handler's `OnDragLift` does NOT remove — an
|
|
inventory→bar drag creates a shortcut REFERENCE; the item stays in the pack), and `ToolbarController.
|
|
HandleDropRelease` gains the `SourceKind == Inventory` branch (place a new shortcut at the target via
|
|
`SendAddShortcut`, no source-bump) — retail's `flags & 0xE == 0` `CreateShortcutToItem` path.
|
|
|
|
**MISSING (the build, in synthesis order — see the 2026-06-18 handoff §C.1-6 for the detailed list):**
|
|
1. **Window manager** — §3 above (do first).
|
|
2. **`UiItemList` N-cell grid mode** — currently single-cell (`UiItemList.cs`; `Flush`/`AddItem`
|
|
skeleton exists, no column-count/pitch/wrap). LIKELY ~6 cols; confirm from
|
|
`UIElement_ItemList::ItemList_AddItem`.
|
|
3. **Sub-window mount in `LayoutImporter`** — `gmInventoryUI 0x21000023` nests `gm*UI` children with
|
|
their own `BaseLayoutId`; the importer only does TEMPLATE inheritance today
|
|
(`src/AcDream.App/UI/Layout/LayoutImporter.cs`) — instantiating a nested `gm*UI` window is new.
|
|
4. **Wire gaps** (inventory deep-dive §4.3): builders `DropItem 0x001B`, `GetAndWieldItem 0x001A`,
|
|
`NoLongerViewingContents 0x0195`; parsers `ViewContents 0x0196`, `SetStackSize 0x0197`,
|
|
`InventoryRemoveObject`; fix `ParsePutObjInContainer` (drops the 4th `containerType`) +
|
|
`ParseInventoryServerSaveFailed` (drops `weenieError`); register `ViewContents`/`0x019A`/`0x0052`/
|
|
`0x00A0` in `GameEventWiring`. (Grep these symbols — none landed this session.)
|
|
5. **`InventoryController`** (`gm*UI::PostInit` find-by-id pattern): backpack burden Meter
|
|
(`SetLoadLevel`→fill `0x69`), own-pack list + side-pack list, `ObjDescEvent 0xF625` → re-dress.
|
|
|
|
**Brainstorm questions (B):** Sub-window mount — recursive `Import()` in `LayoutImporter`, or an
|
|
external stitch by the controller? Grid column count (confirm 6 from decomp)? Open by `I`-key only, or
|
|
also a toolbar inventory button? The inventory cell's drag semantics (lift does NOT remove from the
|
|
pack — it's a copy-to-shortcut for the bar, but a real MOVE between packs DOES relocate via
|
|
`PutItemInContainer 0x0019`) — pin the SourceKind→action matrix (deep-dive §5.7 opcode table).
|
|
|
|
---
|
|
|
|
## 5. Sub-phase C — paperdoll (`UiViewport`, Type 0xD) — heaviest, last
|
|
|
|
**The single biggest new piece.** No widget, no factory registration, no renderer today. Needs an
|
|
`IUiViewportRenderer` **Core→App seam** (structure Rule 2) for a scissored single-entity GL pass — the
|
|
doll is the local player's ObjDesc-dressed entity in a fixed viewport. ~25 equip slots; the
|
|
element-id→`EquipMask` map; wield = `GetAndWieldItem 0x001A` (builder still MISSING). Brainstorm
|
|
separately (it's substantial). Follow `2026-06-16-equipment-paperdoll-deep-dive.md`.
|
|
|
|
**Brainstorm questions (C):** Does the doll clone the player `WorldEntity` or build a fresh
|
|
ObjDesc-dressed `AnimatedEntityState` (the player is the camera, so there's no player-as-renderable
|
|
today)? `IUiViewportRenderer` timing (post-world pass vs pre-pass)? Scissor infra (the toolkit has no
|
|
GL scissor yet — see the collapse spec's clipping discussion).
|
|
|
|
---
|
|
|
|
## 6. Build order + dependency graph
|
|
|
|
```
|
|
A. window manager (open/close + I-key) ← do first; unblocks B
|
|
│
|
|
▼
|
|
B. inventory window (grid + sub-window mount + wire gaps + InventoryController)
|
|
│ └─ also completes B.2's drag-from-inventory (inventory cell = drag source;
|
|
│ ToolbarController.HandleDropRelease gains the SourceKind==Inventory branch)
|
|
▼
|
|
C. paperdoll (UiViewport + IUiViewportRenderer seam + PaperDollController) ← heaviest, last
|
|
```
|
|
|
|
Critical-path note: A is small and unblocks B; the inventory window (B) is the big one and the drag
|
|
*source* that closes the B-stream; the paperdoll (C) is the heaviest and independent enough to come
|
|
last.
|
|
|
|
---
|
|
|
|
## 7. ⚠ State notes for the fresh session
|
|
|
|
- **Start from `main`** (merge `abbd97b`) — it has all of D.5.2 + D.5.4 + this session's D.5.3 B.1/B.2
|
|
+ the collapse, plus the indoor-lighting handoff (`f7f3e08`, issues `#142`/`#143` are LIGHTING, not
|
|
UI). Create a new worktree off `main`.
|
|
- **ISSUES:** `#144` is the (LOW, latent) empty-item-slot click note from B.1; `#141` is the toolbar
|
|
selected-object display (D.5.3a done; mana/stack deferred). `#142`/`#143` are the lighting issues.
|
|
- The drag spine's `IItemListDragHandler` + `ItemDragPayload` + `ShortcutStore` + the shortcut wire all
|
|
exist now — reuse them; don't rebuild.
|
|
- Don't re-port what WorldBuilder/the toolkit already gives (read `worldbuilder-inventory.md` first for
|
|
any dat/render work).
|
|
|
|
---
|
|
|
|
## 8. New-session prompt (paste into a fresh session)
|
|
|
|
> Continue acdream's D.2b retail-UI track. **Read `docs/research/2026-06-20-window-manager-inventory-handoff.md` first**, then the 2026-06-16 UI deep-dives + synthesis §4 it references. The drag-drop spine (B.1), toolbar shortcut reorder/remove + wire (B.2), and toolbar collapse all shipped + merged to `main` (`abbd97b`). Next, in order: **(A)** a minimal **window manager** — open/close + an `I`-key toggle for the inventory window (today every retail-UI window is always-on at a hardcoded position; `UiHost` has no open/close API); **(B)** the **inventory window** (`gmInventoryUI` nesting paperdoll/backpack/3D-items — `UiItemList` N-cell grid + sub-window mount in `LayoutImporter` + the inventory wire gaps + `InventoryController`; it's the drag SOURCE that completes B.2's drag-from-inventory via a `SourceKind==Inventory` branch in `ToolbarController.HandleDropRelease`); **(C)** the **paperdoll** `UiViewport` (Type 0xD) 3D doll, with a Core→App `IUiViewportRenderer` seam — heaviest, last. Spell bar DEFERRED. Use the full brainstorm → spec → plan → subagent-driven flow per sub-phase; mandatory grep-named→cross-ref→pseudocode→port for any wire format; conformance tests throughout. Reuse the shipped spine (`IItemListDragHandler`/`ItemDragPayload`/`ShortcutStore`/the AddShortcut/RemoveShortcut wire) — don't rebuild it. Resolve objects via `ClientObjectTable.Get(guid)` / `GetContents(containerGuid)`. Start a new worktree off `main`.
|
|
|
|
**MEMORY.md index line:**
|
|
- [Handoff: window manager → inventory → paperdoll (2026-06-20)](research/2026-06-20-window-manager-inventory-handoff.md) — next D.2b-UI arc after B.1/B.2/collapse (all merged to main `abbd97b`). 3 sub-phases: (A) window manager (open/close + I-key — UiHost has no open/close API today; windows are always-on); (B) inventory window (Stream C, synthesis §4 — UiItemList grid + sub-window mount + wire gaps DropItem 0x1B/GetAndWieldItem 0x1A/ViewContents 0x196 + InventoryController; the drag SOURCE that closes B.2's drag-from-inventory via a SourceKind==Inventory branch); (C) paperdoll UiViewport Type 0xD + Core→App IUiViewportRenderer seam (heaviest). Reuse the shipped drag spine + ShortcutStore + shortcut wire. Spell bar DEFERRED.
|