docs(D.2b): container-switching handoff + flag stale M1.5 banner
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>
This commit is contained in:
parent
1f8dd7a93f
commit
ad27d1395a
2 changed files with 61 additions and 0 deletions
|
|
@ -121,6 +121,13 @@ M2 (CombatMath) deferred. Detail in ISSUES (#135–#138) + the render/physics di
|
||||||
Recent closes (2026-06-14): #135, #136. Keep this paragraph ≤6 lines + pointers — detail
|
Recent closes (2026-06-14): #135, #136. Keep this paragraph ≤6 lines + pointers — detail
|
||||||
in the docs below, NOT here.
|
in the docs below, NOT here.
|
||||||
|
|
||||||
|
**⚠ Reconcile (banner stale as of 2026-06-22):** the active recent work stream has been the
|
||||||
|
parallel **D.2b retail-UI track** (inventory window / panels — the inventory empty-slot art
|
||||||
|
shipped + was visually confirmed this session; next is container-switching), NOT the M1.5
|
||||||
|
dungeon items above. See [`claude-memory/project_d2b_retail_ui.md`] + the handoff
|
||||||
|
`docs/research/2026-06-22-container-switching-handoff.md`. Decide in the milestones doc whether
|
||||||
|
M1.5 is paused or D.2b retail-UI is its own milestone, then rewrite this banner.
|
||||||
|
|
||||||
For canonical state, read in this order:
|
For canonical state, read in this order:
|
||||||
- [`docs/plans/2026-05-12-milestones.md`](docs/plans/2026-05-12-milestones.md) — milestone targets + freeze list per milestone
|
- [`docs/plans/2026-05-12-milestones.md`](docs/plans/2026-05-12-milestones.md) — milestone targets + freeze list per milestone
|
||||||
- [`docs/plans/2026-04-11-roadmap.md`](docs/plans/2026-04-11-roadmap.md) — what's shipped, what's in flight, what's next
|
- [`docs/plans/2026-04-11-roadmap.md`](docs/plans/2026-04-11-roadmap.md) — what's shipped, what's in flight, what's next
|
||||||
|
|
|
||||||
54
docs/research/2026-06-22-container-switching-handoff.md
Normal file
54
docs/research/2026-06-22-container-switching-handoff.md
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
# 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 at `GameEventWiring.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`: `ViewContents` currently 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)
|
||||||
|
|
||||||
|
1. **Open-container state in `InventoryController`.** Add an `_openContainer` field (default = the player guid / main pack). `Populate` shows `GetContents(_openContainer)` instead of always the player. Repaint when the open container's membership changes (extend `Concerns`).
|
||||||
|
2. **Click a side-bag cell → open it.** The side-bag `UiItemSlot`s already carry the bag guid (bound in `Populate`). 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 `_openContainer` to the player.
|
||||||
|
3. **`ViewContents 0x0196` → full REPLACE.** Flush the container's membership in `ClientObjectTable` before recording the entries (the TODO). Then `InventoryController` repaints the grid for `_openContainer`.
|
||||||
|
4. **Selected-container indicator (retires AP-56).** Draw the open-container triangle `0x06005D9C` + the green/yellow selection square on the selected side-bag cell — a new `UiItemSlot` "selected" overlay (model it on the existing `DragAccept` overlay in `UiItemSlot.OnDraw`; guard `id != 0` per [[feedback_ui_resolve_zero_magenta]]).
|
||||||
|
5. **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 prototype `0x1000033F` child `0x10000450`); the selection square's id is NOT yet found. Dump `0x21000037` / 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 the `Use` round-trip is required, and `GetContents(bagGuid)` is empty until the reply lands. Confirm against a live capture (WireMCP on `127.0.0.1:9000`, or watch the `ViewContents` handler 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. `ViewContents` is 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.md` first.** The empty-slot art shipped + was visually confirmed (`claude/hopeful-maxwell-214a12`, tip `1f8dd7a`). **Next: inventory container-switching** — click a side bag → show its contents in the grid (via `Use 0x0036` → `ViewContents 0x0196` full-replace), draw the selected-container triangle `0x06005D9C` + green/yellow selection square (retires AP-56), click the main pack to go back. The wire builders/parsers all exist (`BuildUse`, `ParseViewContents`, `SendNoLongerViewingContents`); consume the `GameEventWiring.cs:256` full-REPLACE TODO. Run the full brainstorm → spec → plan → subagent-driven → visual-gate flow. **DO NOT auto-kill the running client** — launch with plain `dotnet run`; if a rebuild is locked, ask the user to close it.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue