From e6c8b65f77a0dd59fc517636703c981dff5fdda7 Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 21 Jun 2026 21:31:24 +0200 Subject: [PATCH] =?UTF-8?q?docs(D.2b):=20inventory=20finish=20Stage=201=20?= =?UTF-8?q?=E2=80=94=20handoff=20+=20divergence=20rows=20+=20ISSUES?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Handoff doc for the fresh session (scroll/frame/resize/102-slots shipped + visually confirmed; next = wrong empty-slot art, then main-pack icon, then Sub-phase C paperdoll). Divergence AP-52 (side-bag 7 fallback), AP-53 (main-pack 102 fallback), AP-54 (resize approximation). ISSUES: closed the contents-grid overflow; filed the wrong empty-slot-background issue; Stage 1 SHIPPED entry. (Memory digest project_d2b_retail_ui.md + MEMORY.md + the don't-kill-clients feedback updated out-of-tree.) Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/ISSUES.md | 34 ++++- .../retail-divergence-register.md | 3 + ...2026-06-21-d2b-inventory-finish-handoff.md | 130 ++++++++++++++++++ 3 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 docs/research/2026-06-21-d2b-inventory-finish-handoff.md diff --git a/docs/ISSUES.md b/docs/ISSUES.md index 20b08888..473c1e68 100644 --- a/docs/ISSUES.md +++ b/docs/ISSUES.md @@ -5344,6 +5344,20 @@ outdoors at the angle that previously erased it. # Recently closed +## D.2b — Inventory window finish (Stage 1): scroll + frame + resize + 102 slots SHIPPED + +**Closed:** 2026-06-21 +**Component:** ui — D.2b inventory window (UiItemList scroll, UiNineSlicePanel frame, vertical resize) + +The inventory window now matches retail's 2D presentation (minus the 3D paperdoll doll = Stage 2). Shipped `366af0c`→`1be7e65` (build + full suite green: Core.Net 334 / App 543 / UI 425 / Core 1530; spec/plan `docs/superpowers/{specs,plans}/2026-06-21-d2b-inventory-window-finish*.md`): +- **Scroll** — `UiItemList` clip+scroll via the shared `UiScrollable` (whole-row clip; cells exempted from the per-frame anchor pass — that was the "grid escapes the window" root cause); gutter scrollbar `0x100001C7` bound like ChatWindowController; mouse-wheel. +- **Frame** — wrapped in the 8-piece bevel chrome (`UiNineSlicePanel`) like vitals/chat/toolbar. +- **Vertical resize** — bottom-edge drag, horizontal blocked (`ResizeX=false`); grid/sub-window/scrollbar/backdrop stretch (`Left|Top|Bottom`), paperdoll + side-bags pinned; scrollbar thumb reflects view/content. Expand-only Min=default..Max=560 (AP-54). +- **102-slot grid** — contents grid pads empty frames to the main-pack capacity (default 102, AP-53); side-bag column pads to 7 (AP-52). +**Visually confirmed** (scroll, frame, resize, 102 slots). **Remaining (handoff `docs/research/2026-06-21-d2b-inventory-finish-handoff.md`):** wrong empty-slot background art (inventory + equip slots — the OPEN issue above) + main-pack backpack icon (AP-51); Stage 2 = paperdoll `UiViewport` doll + per-slot equip silhouettes. + +--- + ## D.2b-B — Inventory wire layer (B-Wire): player-property delivery + builders/parsers SHIPPED **Closed:** 2026-06-21 @@ -5366,13 +5380,31 @@ The burden bar now reads the server's wire `EncumbranceVal` (PropertyInt 5) inst ## Inventory "Contents of Backpack" grid overflows (no scroll) -**Status:** OPEN — LOW (B-Controller polish) +**Status:** DONE (2026-06-21 · D.2b inventory finish Stage 1, `366af0c`→`1be7e65`) — the grid clips to its panel + scrolls via the gutter scrollbar `0x100001C7` (`UiScrollable` + whole-row clip; cells exempted from the anchor pass), pads to the full 102-slot main-pack capacity, and the window is vertically resizable (bottom edge). Visually confirmed. **Component:** ui — D.2b inventory (gm3DItemsUI grid `0x100001C6`) **Description:** `InventoryController` populates the 6-col contents grid with ALL of the player's loose pack items via `UiItemList` grid mode, so a pack with >18 items (6 cols × 3 visible rows in the 192×96 panel) overflows BELOW the panel/frame ("part of the inventory hanging off the window"). Retail scrolls the grid via the side gutter scrollbar (`0x100001C7`). Fix: wire the gutter `UiScrollbar` to the grid + clip the grid to the panel (scroll the overflow). Spec listed scrolling as out-of-scope for B-Controller (`docs/superpowers/specs/2026-06-21-d2b-inventory-controller-design.md` §10), so this is a deliberate follow-up, not a regression. --- +## Inventory + equipment slots show the wrong empty-slot background art + +**Status:** OPEN — MEDIUM (D.2b inventory polish; the immediate next task) +**Filed:** 2026-06-21 +**Component:** ui — D.2b inventory (UiItemSlot empty sprite + paperdoll equip slots) + +**Description:** User-flagged at the Stage-1 visual gate: the empty cells in the contents grid + side-bag column use `UiItemSlot.EmptySprite = 0x060074CF` (the TOOLBAR empty-slot border) — the wrong art for inventory pack slots. The paperdoll equipment slots render a generic blue `UiDatElement` border, not per-slot equip silhouettes. Both look wrong vs retail. + +**Root cause / status:** `UiItemSlot.EmptySprite` is a single hardcoded default (`0x060074CF`) shared by all empty cells. The inventory/side-bag pack slots need the gm3DItemsUI/gmBackpackUI cell-template (`0x21000037`) empty-state background instead. The equip slots need the `0x10000032` `UIElement_UIItem` registration + per-slot silhouette art (Sub-phase C). + +**Files:** `src/AcDream.App/UI/UiItemSlot.cs` (`EmptySprite`); `src/AcDream.App/UI/Layout/InventoryController.cs` (set the inventory pack-slot empty sprite on the cells it creates); paperdoll equip slots → Sub-phase C. + +**Research:** `.layout-dumps/uiitem-0x21000037.txt` (cell template states); `docs/research/2026-06-16-equipment-paperdoll-deep-dive.md`. Also pending: the main-pack backpack icon (AP-51). + +**Acceptance:** empty inventory + side-bag cells show the retail pack-slot frame; equip slots show per-slot silhouettes. + +--- + ## #113 — Phantom staircase: REOPENED 2026-06-11, folded into the HOLISTIC BUILDING-RENDER PORT **Status:** REOPENED — root cause #2 found (drawing-BSP-orphaned no-draw polys: diff --git a/docs/architecture/retail-divergence-register.md b/docs/architecture/retail-divergence-register.md index 55dde69b..76aa4865 100644 --- a/docs/architecture/retail-divergence-register.md +++ b/docs/architecture/retail-divergence-register.md @@ -151,6 +151,9 @@ accepted-divergence entries (#96, #49, #50). | AP-49 | Carry-capacity augmentation (PropertyInt `0xE6`) read from the player's wire property bundle when present (B-Wire PD `UpsertProperties`); defaults to 0 (correct for un-augmented characters) when absent. | `src/AcDream.App/UI/Layout/InventoryController.cs` (`RefreshBurden`) caller of `BurdenMath.EncumbranceCapacity` | B-Wire delivers the player's full PropertyInt table (incl. `0xE6` when the server sets it) via `UpsertProperties`; aug=0 is the correct no-aug default. CONFIRM the server sends `0xE6` for an augmented char at the gate, then DELETE. | An augmented character whose server omits `0xE6` reads slightly low capacity (bar fills higher than retail); un-augmented chars are exact. | `EncumbranceSystem::EncumbranceCapacity` decomp 256393 (0x004fcc00); retail `0xE6` PropertyInt augmentation | | AP-50 | Burden meter orientation/direction set programmatically (`Vertical=true`, `FillFromBottom=true`) rather than reading retail's `m_eDirection` property from the LayoutDesc element (property id `0x6f`). | `src/AcDream.App/UI/Layout/InventoryController.cs`; `src/AcDream.App/UI/UiMeter.cs` (`Vertical`/`FillFromBottom`) | The `m_eDirection` property is not yet read by `ElementReader`; bottom-up fill is visually confirmed against retail's burden bar art. Retire when `0x6f` is wired through `ElementReader`→`DatWidgetFactory`. | Wrong fill direction (top-down instead of bottom-up, or horizontal) if a future meter whose art requires a different direction is forced through the same code path. | `UIElement_Meter::DrawChildren` @0x46fbd0; property `0x6f` (`m_eDirection`) in the LayoutDesc | | AP-51 | Main-pack `m_topContainer` cell (element `0x100001C9`) uses a placeholder/empty icon (`tex=0u`), not a weenie-driven backpack icon. | `src/AcDream.App/UI/Layout/InventoryController.cs` (`Populate`) | The player's own container entity has no item `IconId` on the client (it's a character, not an item); retail uses the equipped-pack's icon via the character's equipped-pack `CreateObject`. The equipped-pack DID path is deferred to Sub-phase C. | Main-pack cell renders blank (no icon) where retail shows the equipped backpack art — cosmetic gap visible when F12 is open. | `gmBackpackUI::PostInit` @0x4a8520 (m_topContainer bind); `CreateObject` weenie icon path | +| AP-52 | Side-bag column slot count defaults to 7 (the dat column height) when the player's `ContainersCapacity` is absent/0. | `src/AcDream.App/UI/Layout/InventoryController.cs` (`Populate`) | `ContainersCapacity` is not reliably on the player ClientObject yet; 7 is the standard side-pack cap + the dat column (`0x100001CA`, 36×252) holds exactly 7. | An 8th-pack (Shadow of the Seventh Mule aug) character shows one too few side-bag slots — cosmetic. | retail gmBackpackUI side-pack column; ACE `ContainersCapacity` | +| AP-53 | Contents grid slot count defaults to 102 when the player's `ItemsCapacity` is absent/0; the grid always shows the main pack (container-switch to a side pack's 24 not wired). | `src/AcDream.App/UI/Layout/InventoryController.cs` (`Populate`) | `ItemsCapacity` is not reliably on the player ClientObject yet; 102 is the retail main-pack standard. ViewContents-driven container switching is a later sub-phase. | A non-102 pack shows the wrong empty-slot count; selecting a side pack doesn't show its 24-slot contents yet. | retail main-pack capacity 102; ACE `ItemsCapacity`; `ViewContents 0x0196` (deferred) | +| AP-54 | Inventory window vertical resize is a toolkit approximation: bottom-edge drag, expand-only (Min = dat default 372 px, Max = 560 px constant), contents grid/sub-window/scrollbar/backdrop stretched via overridden `Left\|Top\|Bottom` anchors. | `src/AcDream.App/Rendering/GameWindow.cs` (inventory frame setup) | retail's gmInventoryUI resize lives in keystone.dll (no decomp); the anchor-stretch + 372..560 range matches the observed retail behavior for the dev loop. | The expand range / which elements reflow could differ from retail (e.g. retail may allow shrink-below-default); shrink is intentionally disabled for now. | retail gmInventoryUI resize (keystone.dll, no decomp); `UiNineSlicePanel` resize | --- diff --git a/docs/research/2026-06-21-d2b-inventory-finish-handoff.md b/docs/research/2026-06-21-d2b-inventory-finish-handoff.md new file mode 100644 index 00000000..fbd03774 --- /dev/null +++ b/docs/research/2026-06-21-d2b-inventory-finish-handoff.md @@ -0,0 +1,130 @@ +# Handoff — D.2b inventory window finish (Stage 1) shipped + visually confirmed; slot-art + paperdoll next + +**Date:** 2026-06-21 (after B-Wire) +**From:** the session that shipped **B-Wire** (inventory wire layer) **and Stage 1 of the +inventory window finish** (scroll + frame + vertical resize + 102-slot grid), both visually +confirmed at the live gate. +**Branch:** `claude/hopeful-maxwell-214a12`, tip **`1be7e65`** (+ this docs commit). `main` is a +clean ff ancestor — ff `main` + branch fresh, or continue this branch. +**Line numbers drift — grep the symbol.** + +--- + +## 0. What shipped this session (all committed, build + full suite green, VISUALLY CONFIRMED) + +Full suite green (`--no-build`, with the client running): **Core.Net 334 / App 543 / UI 425 / +Core 1530**, 0 failures. + +### B-Wire — inventory wire layer (`b56087b`→`7c006d1`) +The burden bar now reads the server's wire `EncumbranceVal` (PropertyInt 5). Root cause was +**delivery, not binding**: login PD dropped the player's int table, live `0x02CD` was unparsed, and +`ObjectTableWiring` gated non-UiEffects ints out. Plus the full inventory wire pass (DropItem 0x001B +/ GetAndWieldItem 0x001A / NoLongerViewingContents 0x0195 builders; ViewContents 0x0196 / +SetStackSize 0x0197 / InventoryRemoveObject 0x0024 parsers; 0x0022 + 0x00A0 field fixes). Spec/plan +`docs/superpowers/{specs,plans}/2026-06-21-d2b-inventory-wire*.md`. Detail: the B-Wire SHIPPED entry +in `claude-memory/project_d2b_retail_ui.md`. + +### Inventory window finish Stage 1 (`366af0c`→`1be7e65`) +Spec/plan `docs/superpowers/{specs,plans}/2026-06-21-d2b-inventory-window-finish*.md`. +- **Scroll** — `UiItemList` clip+scroll via the shared `UiScrollable`; gutter scrollbar `0x100001C7` + bound like `ChatWindowController`; mouse-wheel. +- **Frame** — wrapped in the 8-piece bevel chrome (`UiNineSlicePanel`), like vitals/chat/toolbar. +- **Vertical resize** — bottom-edge only (horizontal blocked); the grid + sub-window + scrollbar + + backdrop stretch, paperdoll + side-bags pinned; scrollbar thumb reflects view/content. +- **102-slot grid** — contents grid pads empty frames to the main-pack capacity (default 102); + side-bag column pads to 7. + +--- + +## 1. Read first + +- This doc. +- `claude-memory/project_d2b_retail_ui.md` — the **Stage 1 SHIPPED** entry + DO-NOT-RETRY (updated this session). +- `docs/ISSUES.md` — the **OPEN** "Inventory + equipment slots show the wrong empty-slot background art" issue (the immediate next task) + the two **SHIPPED** entries. +- `docs/architecture/retail-divergence-register.md` — AP-52 (side-bag 7 fallback), AP-53 (main-pack 102 fallback), AP-54 (resize approximation), AP-51 (main-pack icon, still open). +- `docs/research/2026-06-16-equipment-paperdoll-deep-dive.md` — for Stage 2 (paperdoll). +- `.layout-dumps/uiitem-0x21000037.txt` — the UIItem cell template states (for the correct empty-slot sprite). + +--- + +## 2. Key discoveries (durable, non-obvious — DO-NOT-RETRY) + +1. **Grid cells must be `Anchors = None`.** `UiElement.DrawSelfAndChildren` runs `ApplyAnchor` on + every child AFTER `OnDraw`; with default `Left|Top` anchors it captured each cell's scroll-0 + position and reset `Top` to it every frame, fighting `UiItemList.LayoutCells`' scroll offset → + the grid "escaped the window" when scrolled. `AddItem` now sets `cell.Anchors = None` so + `LayoutCells` is the sole authority. **The unit tests missed it by calling `LayoutCells` in + isolation, never the draw traversal** — the regression test now drives the `ApplyAnchor` + interaction. (Fix `14ea938`.) +2. **Scroll reuses `UiScrollable` + a whole-row logical clip (no GL scissor)** — mirrors + `UiText.cs:198` (`cell.Visible = top >= 0 && top + h <= Height`). The gutter scrollbar `0x100001C7` + is a factory Type-11 `UiScrollbar` inheriting base `0x2100003E`; bind its `Model` to `grid.Scroll` + + the same scrollbar sprite ids the chat scrollbar uses. +3. **Vertical-resize cascade via anchors.** Frame: `Resizable=true; ResizeX=false; + ResizableEdges=Bottom`. The stretch elements (grid `0x100001C6`, its sub-window `0x100001CF`, + scrollbar `0x100001C7`, backdrop `0x100001D0`, + the content root) get `Anchors=Left|Top|Bottom` + (fixed width, height tracks parent); paperdoll `0x100001CD` + side-bag `0x100001CE` pinned + `Left|Top`. `ComputeAnchoredRect`: Top|Bottom ⇒ `h = parentH − mB − mT`. +4. **Capacity-padding pattern.** The contents grid + side-bag column pad empty `UiItemSlot`s up to + the pack capacity (player `ItemsCapacity` default 102; `ContainersCapacity` default 7) after the + loose-item loop in `InventoryController.Populate`. Padding changed several existing tests' counts + (intended — update, don't revert). +5. **DO-NOT auto-kill the client.** The user manages client lifecycle: launch with a **plain + `dotnet run --no-build`** (no `Get-Process … CloseMainWindow/Stop-Process` preamble). If a rebuild + is blocked by a running client (`MSB3021`/`MSB3027` "locked by AcDream.App"), **ASK the user to + close it** — do not kill it. (`feedback_dont_kill_clients_before_launch`.) This overrides the + CLAUDE.md graceful-close snippet. + +--- + +## 3. Current visual state (F12, `ACDREAM_RETAIL_UI=1`) + +Renders correctly + confirmed: 8-piece bevel frame; vertical bottom-edge resize (expand-only, +372..560 px); contents grid clips to its panel, scrolls (wheel + gutter scrollbar), shows the full +**102-slot** main pack (items + empty frames); side-bag column with bags + empty slots; vertical +burden bar; backdrop covers the window. **Known-wrong (next task):** +- **Empty-slot background art is wrong** — inventory + side-bag empty cells use the TOOLBAR empty + sprite (`UiItemSlot.EmptySprite = 0x060074CF`); paperdoll equip slots show a generic blue + `UiDatElement` border. (User-flagged.) +- **Main-pack cell has no backpack icon** (AP-51, placeholder `tex=0`). + +--- + +## 4. What's next (build order) + +**(a) FIX the empty-slot background art — RECOMMENDED NEXT (the OPEN ISSUE).** Inventory + side-bag +empty cells should use the retail pack-slot frame, not the toolbar's `0x060074CF`. Find the correct +sprite from the UIItem cell template `0x21000037` (`.layout-dumps/uiitem-0x21000037.txt`) empty +state; set it on the cells `InventoryController` creates (an `EmptySprite` override per slot kind, or +a controller-set default distinct from the toolbar's). The paperdoll equip slots' per-slot +silhouettes are Sub-phase C (below). Small, self-contained; brainstorm → spec → plan as usual. + +**(b) Main-pack backpack icon (AP-51).** The main-pack cell (`m_topContainer 0x100001C9`) should show +the equipped-backpack art. Pin the backpack RenderSurface DID (or the equipped-pack `CreateObject` +icon path). + +**(c) Sub-phase C — paperdoll.** The 3D character doll via a Core→App `IUiViewportRenderer` seam +(`UiViewport`, Type `0xD`) + the `0x10000032` `UiItemSlot` registration so equip slots draw per-slot +silhouettes. Research: `2026-06-16-equipment-paperdoll-deep-dive.md`. The heaviest piece. + +**(d) Deferred polish:** container-switching (select a side pack → show its 24-slot contents via the +already-parsed `ViewContents 0x0196`); the side-bag column scrollbar (`0x100001CB`, inert — 7 fit); +shrink-below-default resize (currently expand-only); the selected-target bar + stack split slider +(per the wiki notes the user pasted). B-Drag (drag items between slots) also remains. + +Each gets the full brainstorm → spec → plan → execute flow. + +--- + +## 5. New-session prompt (paste into a fresh session) + +> Continue acdream's D.2b retail-UI inventory arc. **Read +> `docs/research/2026-06-21-d2b-inventory-finish-handoff.md` first.** B-Wire + the inventory window +> finish Stage 1 (scroll, 8-piece frame, vertical resize, 102-slot grid) shipped + visually confirmed +> on `claude/hopeful-maxwell-214a12` (tip `1be7e65`; `main` is a clean ff ancestor). **Next: fix the +> wrong empty-slot background art** — inventory + side-bag empty cells use the toolbar empty sprite +> `0x060074CF`; they need the retail pack-slot frame from the UIItem cell template `0x21000037` (see +> `.layout-dumps/uiitem-0x21000037.txt`). Then the main-pack backpack icon (AP-51), then Sub-phase C +> (paperdoll `UiViewport` doll + `0x10000032` per-slot equip silhouettes). Use the full brainstorm → +> spec → plan → subagent/inline flow. **DO NOT auto-kill the running client** — launch with plain +> `dotnet run --no-build`; if a rebuild is locked by a running client, ask the user to close it.