Banks the next clean inventory win (container-switching: Use 0x0036 -> ViewContents 0x0196 full-replace + the selected-container indicator that retires AP-56) as a handoff for a fresh session, per the late-session-handoff lesson. Wire layer already exists; design sketch + open questions captured. Also flags the CLAUDE.md "Current state" banner as stale — it still tracks M1.5 (indoor world, 2026-06-14) while the active stream has been the D.2b retail-UI track for weeks. Left the milestone reframing for a fresh reconciliation against the milestones doc rather than a tired guess. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6.8 KiB
Handoff — D.2b inventory container-switching (next clean win)
Date: 2026-06-22 (banked at the end of the empty-slot-art session, per feedback_session_handoff)
Branch: claude/hopeful-maxwell-214a12, tip 1f8dd7a (+ this docs commit). main is a clean ff ancestor (68 commits behind).
Status: SCOPED, not started. Brainstorm explored the wire + controller; this captures the design sketch so a fresh session executes it with the live-wire round-trip getting proper attention. Run the full brainstorm → spec → plan → execute flow.
Line numbers drift — grep the symbol.
Why this is the next pick
After the empty-slot-art arc (inventory contents/side-bag/main-pack empty cells now dat-resolve their art — see project_d2b_retail_ui + the empty-slot handoff), the side-bag column is rendered but inert: clicking a bag does nothing. Container-switching makes it functional AND closes the AP-56 deferral (the selected-container triangle + green/yellow selection square live here). The user picked this over the paperdoll (Sub-phase C) because the paperdoll's empty equip slots are entangled with the heavy 3D doll viewport (retail empties show the doll), whereas container-switching is self-contained.
This is the first inventory feature with live two-way wire interaction (a Use → ViewContents round-trip), a step up from the read-only display work so far — hence executing it fresh rather than tired.
Read first
- This doc.
claude-memory/project_d2b_retail_ui.md— the D.2b SSOT + the empty-slot-art SHIPPED entry (the resolver + AP-55/AP-56).claude-memory/reference_retail_inventory_paperdoll.md— the player-facing spec: the "preferred pack" auto-fit rules + the 7-side-bag / 102-main-pack capacities.docs/architecture/retail-divergence-register.md— AP-56 (the selected-container indicator deferred — this phase retires it) + AP-53 (container-switch noted as deferred).
What's already in place (the wire layer is DONE)
InteractRequests.BuildUse(0x0036) — open/use a container by guid (src/AcDream.Core.Net/Messages/InteractRequests.cs:38). This is how retail opens a container.GameEvents.ParseViewContents(0x0196) — the server's full contents list(ContainerGuid, [guid, containerType]×N)(src/AcDream.Core.Net/Messages/GameEvents.cs:372). Handler atGameEventWiring.cs:260.WorldSession.SendNoLongerViewingContents(0x0195) — close a container view (WorldSession.cs:1212).ClientObjectTable.GetContents(containerId)— the per-container item index (src/AcDream.Core/Items/ClientObjectTable.cs:313).- The standing TODO at
GameEventWiring.cs:256:ViewContentscurrently does an additive merge; container-open must treat it as a full REPLACE (flush the container's prior membership first) so server-side removals don't linger. This phase consumes that TODO.
Design sketch (to be confirmed in the brainstorm)
- Open-container state in
InventoryController. Add an_openContainerfield (default = the player guid / main pack).PopulateshowsGetContents(_openContainer)instead of always the player. Repaint when the open container's membership changes (extendConcerns). - Click a side-bag cell → open it. The side-bag
UiItemSlots already carry the bag guid (bound inPopulate). On click: set_openContainer = bagGuid;SendUse(bagGuid)(opens it server-side); when the previous container was a side bag,SendNoLongerViewingContents(prevGuid). Click the main-pack cell (0x100001C9) → reset_openContainerto the player. ViewContents 0x0196→ full REPLACE. Flush the container's membership inClientObjectTablebefore recording the entries (the TODO). ThenInventoryControllerrepaints the grid for_openContainer.- Selected-container indicator (retires AP-56). Draw the open-container triangle
0x06005D9C+ the green/yellow selection square on the selected side-bag cell — a newUiItemSlot"selected" overlay (model it on the existingDragAcceptoverlay inUiItemSlot.OnDraw; guardid != 0per feedback_ui_resolve_zero_magenta). - Caption. "Contents of Backpack" → the open container's name when a side bag is selected (the caption host is already driven by
InventoryController.AttachCaption).
Open questions for the brainstorm
- The green/yellow selection-square sprite id — the triangle is
0x06005D9C(from the container prototype0x1000033Fchild0x10000450); the selection square's id is NOT yet found. Dump0x21000037/ the gmBackpackUI layout (0x21000022) for the selected-container state media, or cdb a live retail client with a side bag open. - Are a side bag's contents pre-known, or do they arrive only on open? Likely the latter (retail sends contents on open via
ViewContents, not upfront) — so theUseround-trip is required, andGetContents(bagGuid)is empty until the reply lands. Confirm against a live capture (WireMCP on127.0.0.1:9000, or watch theViewContentshandler at the live gate). - Preferred-pack semantics (from
reference_retail_inventory_paperdoll): opening a pack makes it the "preferred" pack for auto-fit. Out of scope for the first cut (display-only switching), but note it. - Empty-container display — a side bag with no contents shows an empty 24-slot grid (its
ItemsCapacity, default 24 per AP-52/the wiki). Pad like the main pack does.
Acceptance / scope
- First cut: click a side bag → its contents show in the grid; the selected bag shows the triangle + selection square; click the main pack → back.
ViewContentsis a full replace. Build + full suite green; visual gate (F12, the user clicks bags and confirms the grid switches + the selected indicator). - Retires AP-56 (selected-container indicator) in the same commit that draws it.
- Out of scope: preferred-pack auto-fit, drag-INTO a side bag (that's B-Drag), the side-bag column scrollbar (
0x100001CB, inert — 7 fit).
New-session prompt
Continue acdream's D.2b retail-UI inventory arc. Read
docs/research/2026-06-22-container-switching-handoff.mdfirst. The empty-slot art shipped + was visually confirmed (claude/hopeful-maxwell-214a12, tip1f8dd7a). Next: inventory container-switching — click a side bag → show its contents in the grid (viaUse 0x0036→ViewContents 0x0196full-replace), draw the selected-container triangle0x06005D9C+ green/yellow selection square (retires AP-56), click the main pack to go back. The wire builders/parsers all exist (BuildUse,ParseViewContents,SendNoLongerViewingContents); consume theGameEventWiring.cs:256full-REPLACE TODO. Run the full brainstorm → spec → plan → subagent-driven → visual-gate flow. DO NOT auto-kill the running client — launch with plaindotnet run; if a rebuild is locked, ask the user to close it.