acdream/docs/research/2026-06-20-window-manager-inventory-handoff.md
Erik a391b86a2e docs(handoff): window manager → inventory window → paperdoll (next D.2b arc)
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>
2026-06-20 20:38:41 +02:00

14 KiB

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 collapseUiCollapsibleFrame 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 == 0CreateShortcutToItem) 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.mdgmInventoryUI 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 LayoutImportergmInventoryUI 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) — 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.