From a391b86a2e905d0f20ddbe9b3d52c7c5a1fad252 Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 20 Jun 2026 20:38:41 +0200 Subject: [PATCH] =?UTF-8?q?docs(handoff):=20window=20manager=20=E2=86=92?= =?UTF-8?q?=20inventory=20window=20=E2=86=92=20paperdoll=20(next=20D.2b=20?= =?UTF-8?q?arc)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- ...-06-20-window-manager-inventory-handoff.md | 200 ++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 docs/research/2026-06-20-window-manager-inventory-handoff.md diff --git a/docs/research/2026-06-20-window-manager-inventory-handoff.md b/docs/research/2026-06-20-window-manager-inventory-handoff.md new file mode 100644 index 00000000..d2b7b237 --- /dev/null +++ b/docs/research/2026-06-20-window-manager-inventory-handoff.md @@ -0,0 +1,200 @@ +# 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.