acdream/docs/research/2026-06-18-item-object-model-handoff.md
Erik 5b568d000a docs(D.5): sub-phase ledger + item-model cold-start prompt
Roadmap: refresh the D.5.2 entry to its final shipped state (per-pixel gradient
surface overload 0x004415b0; AP-43/AP-44 retired by visual verification; range
419c3ac..fb288ad). Add an explicit D.5 sub-phase ledger: D.5.4 client object/item
data model (foundation, NEXT) -> D.5.3 selected-object + spell shortcuts -> window
manager -> D.5.5+ core panels. Handoff doc gains a paste-ready new-session prompt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 10:41:08 +02:00

7.7 KiB
Raw Blame History

Handoff — the client object/item data model (next phase, post-D.5.2)

Date: 2026-06-18 From: the D.5.2 stateful-icon session (icon system SHIPPED + visually confirmed on a live Coldeve server). This handoff frames the NEXT phase: the real item/object data model. Status of this work: branch claude/hopeful-maxwell-214a12 (kept, not merged). D.5.2 is complete: 52306d9..fb288ad.


0. Why this phase exists (the root cause we uncovered)

Visual-verifying D.5.2 on a live server (character Barris on Coldeve) showed 4 of 6 hotbar items render no icon. The diagnostic (icon-dump.txt, since removed) proved the cause: those items are NOT-ENRICHEDItemRepository.GetItem(guid) returns null because their CreateObject was dropped.

The mechanism is acdream's scaffold item model:

  • EnrichItem is enrich-existing-only: it updates an item ONLY if it was already seeded as a stub (from PlayerDescription at login). A CreateObject for an item with no pre-existing stub is silently discarded (the toolbar handoff called this out: "new-item ingestion is the inventory phase").
  • So only items in the login seed set get icons; everything else (most pack contents) falls on the floor. The 2 that showed (Energy Crystal, Revenant's Scythe) are wielded items the server announces up front.

This is NOT a D.5.2 bug (the icon composite is correct for every item that reaches it — confirmed: Energy Crystal's Magical gradient tint + the no-mana scroll's black edges both match retail). It is the item/object data model being a placeholder.

1. The retail model to port (the oracle)

Retail has one master object tableClientObjMaintSystem — and CreateObject is the canonical create/update for every object (item, creature, player). The UI never owns item data: a hotbar slot, an inventory cell, a paperdoll slot, a vendor cell all hold a guid and resolve it live via ClientObjMaintSystem::GetWeenieObject(guid). (Confirmed in our spine research: "the cell never holds item data — it holds an itemID and resolves it live.")

acdream inverted this: login snapshot = source of truth, CreateObject = second-class enrich. The fix is to flip it: CreateObject is the authoritative ingestion; PlayerDescription / ViewContents (0x0196) / shortcuts become references + supplementary data, not the primary seed. Every object the server tells us about is tracked; the UI resolves by guid.

2. THE crux design question (settle this FIRST in the brainstorm)

acdream currently has two object tracks:

  • the WorldEntity system (3D creatures / players / world items, fed by CreateObjectGameWindow.OnLiveEntitySpawnedWorldEntity), and
  • the ItemRepository (inventory items, src/AcDream.Core/Items/).

Retail unifies these under one ClientObjMaintSystem (every object is an ACCWeenieObject). Decision to make: unify acdream into ONE object table (retail shape), or keep the two tracks with a shared ingestion seam? This choice drives everything downstream (inventory, equipment/paperdoll, vendor, trade all resolve items from whatever table wins). Think it through up front — don't discover it halfway in.

3. Sources that feed the model (the ingestion surface to design around)

Wire message Role
CreateObject (0xF745) canonical object create/update (full weenie: icon/name/type/stack/container/wielder/effects/…)
DeleteObject (0xF747) remove
PlayerDescription (0x0013) login snapshot: inventory + equipped + shortcuts (references; some props)
ViewContents (0x0196) a container's {guid, slot} list when opened
move events 0x0019/1A/1B, 0x0022/23, 0x019A re-parent (container/wield/3D)
Public/PrivateUpdateProperty* (0x02CD0x02DA) per-property live updates (D.5.2 wired 0x02CE UiEffects → icon)
InventoryServerSaveFailed (0x00A0) speculative-move rollback

4. Grounding research (already written — read before the brainstorm)

  • docs/research/2026-06-16-inventory-deep-dive.md — inventory panel + the wire catalog
  • docs/research/2026-06-16-ui-item-slot-icon-dragdrop-spine-deep-dive.mdClientObjMaintSystem, ServerSaysMoveItem, the resolve-by-guid model
  • docs/research/deepdives/r06-items-inventory.md — the item/container property model
  • docs/research/2026-06-16-ui-panels-synthesis.md — core-panels build order (item-model is the prerequisite for the inventory panel)
  • claude-memory/project_d2b_retail_ui.md — D.2b/D.5.1/D.5.2 state
  • claude-memory/feedback_weenie_vs_static.md — items are server weenies, not dat-baked

Full process (the user values it): brainstorm → spec → plan → subagent implementation. Open the brainstorm on the unify-vs-separate question (§2) first, then the ingestion lifecycle (§3), then how the UI (toolbar/inventory/paperdoll) binds by guid. This is the foundation the remaining D.5 core panels sit on — get it solid.

NOTE the user's standing constraint for this phase: "No quick fixes — needs to be architecturally solid and thought through." Do not band-aid EnrichItem to add new items; design the model properly.

6. New-session prompt (paste into a fresh session)

Design and build acdream's client object/item data model — the foundation under the D.5 core panels (inventory, equipment/paperdoll, vendor, trade). This is roadmap D.5.4 and it blocks D.5.5+. Read this handoff first: docs/research/2026-06-18-item-object-model-handoff.md, then docs/research/2026-06-16-ui-item-slot-icon-dragdrop-spine-deep-dive.md and docs/research/2026-06-16-inventory-deep-dive.md.

The problem (confirmed live on Coldeve, character Barris): acdream's item model is enrich-existing-onlyItemRepository.EnrichItem only fills items pre-seeded as stubs from PlayerDescription, and DROPS CreateObjects for anything else, so most hotbar/pack items render no icon (4 of 6 hotbar slots were blank). Port retail's ClientObjMaintSystem: CreateObject is the canonical object create/update, PlayerDescription/ViewContents/ shortcuts become references, and the UI resolves items by guid. This is NOT a D.5.2 icon bug (the composite is correct for every item that reaches it).

Do this as a proper design — the user's standing constraint is "architecturally solid, no quick fixes" (do NOT band-aid EnrichItem to add new items). Use the full brainstorm → spec → plan → subagent-driven-development flow. Open the brainstorm by settling the crux FIRST (§2): unify acdream's two object tracks — the WorldEntity 3D system (fed by GameWindow.OnLiveEntitySpawned) and ItemRepository — into ONE object table like retail, or keep them separate with a shared ingestion seam? Then the ingestion lifecycle (§3 wire surface) and how the toolbar/inventory/paperdoll bind by guid. Follow the mandatory grep-named→cross-ref→pseudocode→port workflow for any AC-specific wire format; conformance tests throughout. Work continues on branch claude/hopeful-maxwell-214a12 (kept, unmerged; D.5.2 = 52306d9..fb288ad).

MEMORY.md index line:

  • Handoff: client object/item data model (2026-06-18) — next phase after D.5.2. Root cause of the live-Coldeve "4/6 hotbar items missing": acdream's item model is enrich-existing-only (drops CreateObjects without a pre-seeded stub). Fix = port retail's ClientObjMaintSystem (CreateObject = canonical ingestion; UI resolves by guid). CRUX to settle first: unify the WorldEntity + ItemRepository tracks into one object table, or keep separate w/ shared ingestion? Grounding research + ingestion surface listed. User constraint: architecturally solid, no quick fixes.