Commit graph

811 commits

Author SHA1 Message Date
Erik
3b66858893 docs(D.2b): inventory drag-drop (item moving) design spec
Brainstorm output for B-Drag. Drop an inventory item: empty grid slot ->
first empty; on an item -> insert before; on a side-bag cell -> into that
container. Green insert-arrow (valid) / red circle (full). Movement is
OPTIMISTIC/instant per the user — local MoveItem on drop + repaint, server
reconciles via 0x0022 echo, rolls back via 0x00A0 (the rollback the B-Wire
note reserved). InventoryController : IItemListDragHandler; pending-move
tracking in ClientObjectTable (Core, reachable from the Core.Net handlers);
SendPutItemInContainer wraps BuildPickUp 0x0019. Retail anchors: InqDropIconInfo
0x004e26f0 / ItemList_InsertItem / HandleDropRelease / ServerSaysMoveItem.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 19:28:05 +02:00
Erik
c937db11c7 docs: file ISSUES #147 (inventory scroll polish) + #148 (status-bar backpack toggles inventory)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 19:16:25 +02:00
Erik
8fbde99441 Revert "fix(world): AP-48 client-side visibility cull (FPS sink across portal-hops)"
This reverts commit e5b2d15b63.
2026-06-22 18:58:15 +02:00
Erik
a45c421bd1 feat(D.2b): per-container capacity bar on inventory cells
Faithful port of retail UIElement_UIItem::UpdateCapacityDisplay (0x004e16e0):
each container cell (side bags + main pack) shows a vertical UIElement_Meter
(element 0x10000347, back 0x06004D22 / fill 0x06004D23) filled to
GetNumContainedItems / ItemsCapacity, clamped [0,1]; hidden for non-containers
(CapacityFill=-1). Drawn procedurally on UiItemSlot like the triangle/square
overlays (back full + front clipped bottom-up). Right-anchored flush to the cell
edge (visual gate: the dat X=26 sat ~5px off the right edge). Visually confirmed
2026-06-22. Divergence AP-59; polish deferred to ISSUES #146 (exact rect/anchor,
fill direction vs m_eDirection 0x6f, closed-bag lazy-load).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 15:54:54 +02:00
Erik
e5b2d15b63 fix(world): AP-48 client-side visibility cull (FPS sink across portal-hops)
acdream accumulated every CreateObject from every town visited and never pruned by
distance/time (only on server DeleteObject / respawn de-dup), so the entity tables +
the O(N^2) TickAnimations scan grew with each hop and sank FPS (confirmed in Release).

Faithful port of holtburger liveness.rs (ACE_DESTRUCTION_TIMEOUT_SECS=25,
CONSERVATIVE_VISIBILITY_DISTANCE_M=384): a world entity is evicted only after being
>384m AND outside the 3x3 landblock neighborhood for 25s continuous (arm-on-leave /
clear-on-return). Logic in a pure, unit-tested EntityVisibilityCuller; GameWindow
wires a 1Hz tick that snapshots the world entities + player and tears each evicted
guid down through the existing pruner. Player + held/equipped/contained items are
excluded (player by guid; inventory items never carry a world position so they never
enter the culled map). A re-created object starts fresh (deadline cleared on remove).
Skipped during a teleport hold (frozen player position). AD-32 registered.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 15:45:07 +02:00
Erik
077586a0f0 fix(D.2b): main-pack backpack icon is 0x0600127E, not 0x060011F4
The prior commit pinned 0x060011F4 from a research dat-dump of
GetDIDByEnum(0x10000004,7) — it rendered as a GREEN TILE (green slot, no
pack) at the visual gate. Dat-exported the candidates (AcDream.Cli
dump-sprite-sheet / export-ui-sprite): 0x0600127E is the 32x32 brown
backpack (user-hinted, PNG-confirmed). Swap the pinned literal; the
test + AP-51 register row updated to the visually-verified id. Container
type-underlay (green) + backpack base still composited via _iconIds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 15:33:58 +02:00
Erik
c71b32f73d feat(D.2b): main-pack cell draws the constant backpack icon (AP-51)
The m_topContainer cell (0x100001C9) rendered blank (tex=0). Retail's
IconData::RenderIcons (0x0058d1ee) has an IsThePlayer() branch that draws a
CONSTANT backpack — m_idIcon = GetDIDByEnum(0x10000004, 7) = 0x060011F4,
m_itemType = TYPE_CONTAINER — NOT the player's body icon (the original AP-51
"equipped-pack weenie icon" premise was wrong). Compose that base over the
Container type-underlay via the existing _iconIds delegate. Verified vs decomp
(407546-407549) + IconComposer.GetIcon (base=arg2, type drives underlay) + a
live dat dump (map 0x25000008 index 7 = 0x060011F4). Test locks type+literal.
AP-51 reworded to the residual hardcoded-vs-runtime-resolve nuance (cf. AP-55).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 15:04:08 +02:00
Erik
895d8eed80 docs(D.2b): divergence register — retire AP-56, reword AP-53, add overlay/selection rows
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 14:33:53 +02:00
Erik
24a0b84162 docs(D.2b): container-switching implementation plan
8-task TDD plan: ReplaceContents (Core) -> ViewContents full-replace
wiring (Core.Net) -> SendUse wrapper -> UiItemSlot triangle/square
overlays -> InventoryController _openContainer/_selectedItem +
click roles + indicators -> GameWindow callback wiring -> divergence
register -> full-suite + visual gate. Exact code per step.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 14:22:39 +02:00
Erik
bfdab5b9e0 docs(D.2b): container-switching design spec
Brainstorm output for inventory container-switching. Key decision from
the brainstorm: the handoff conflated two orthogonal retail mechanisms —
the open-container TRIANGLE (0x06005D9C, UpdateOpenContainerIndicator) and
the selected-item SQUARE (0x06004D21, ItemList_SetSelectedItem). User
confirmed both are real (a bag is just an item, so it gets the square too)
and chose to ship both this phase, the square uniform across grid+bags and
visual-only (no selected-object-bar wiring yet).

Pins the ViewContents full-REPLACE (ACE writes entries OrderBy
PlacementPosition, no slot field -> ContainerSlot=index), the Use 0x0036 ->
ViewContents 0x0196 round-trip, and the 6 touched files.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 14:15:42 +02:00
Erik
3ce1fae332 feat(teleport C): TAS-driven fade transit + retire TeleportArrivalController
Wires the dormant TeleportAnimSequencer as the transit driver: on PlayerTeleport
the player holds in PortalSpace behind a full-screen fade (FadeOverlay) until the
destination terrain is resident (TeleportWorldReady, gated on the priority-applied
landblock), then materializes (Place), and after the world fades back in regains
control + acks the server (FireLoginComplete). No movement resolves against the
empty world, so the outbound cell frame can't corrupt. Outdoor changes from
place-immediately back to hold-until-resident (now fast, not a band-aid).

- FadeOverlay: fullscreen NDC black quad, alpha = ShowTunnel ? 1 : FadeAlpha.
- Retires TeleportArrivalController + its 2 tests (TAS subsumes the driver role).
- Divergence register: AD-2 updated to the new mechanism; AD-31 (fade vs swirl).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 14:03:25 +02:00
Erik
02f4be72c0 fix(teleport D): cell-march preserves seed landblock id when no resident LB (no more lbX=0 outbound)
BuildCellSetAndPickContaining discarded the bool from TryGetTerrainOrigin — when
the current landblock's terrain hadn't been applied yet (priority-apply in flight
after a teleport or dungeon exit), blockOrigin was silently set to (0,0,0). The
AdjustToOutside/GetOutsideLcoord math treated world-frame sphere coordinates as
block-local and marched the cell one landblock per tick in the direction of movement
until lbX or lbY underflowed to 0x00. ACE rejected every subsequent move as a
failed transition.

Fix: honor the bool return. When terrain is unregistered for an OUTDOOR seed
(low < 0x0100), return currentCellId verbatim — "no block-local frame →
preserve". This mirrors the NO-LANDBLOCK verbatim contract in PhysicsEngine.Resolve
and is correct: the cell stays last-known-correct until terrain registers.
Indoor seeds are explicitly excluded (blockOrigin is never consumed by the indoor
pick path; outdoorPickAllowed=false for indoor seeds).

Reproduce + verify via CellMarchLandblockPreservationTests (two new FAILING-before
tests: WestEdge and SouthEdge with empty cache, no anchor → lbX/lbY preserved).
TeleportFarTownRunawayTests updated: no-anchor path now also preserves (pre-fix it
marched south to 0x59; post-fix returns currentCell unchanged).
CellTransitFindCellSetTests, Issue112MembershipTests, PhysicsEngineTests: added
RegisterTerrain for the streaming-center block (in production it is always resident
before outdoor resolves run; tests that used blockOrigin=(0,0,0) as an implicit
fallback now register the block explicitly). All 1567 tests pass.

Divergence AD-30 added to retail-divergence-register.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 13:38:48 +02:00
Erik
ad27d1395a 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>
2026-06-22 13:17:55 +02:00
Erik
b869128df3 docs(teleport): TDD implementation plan — priority residency + fade cover
6 tasks: (1) StreamingController priority-apply, (2) PhysicsEngine residency
query, (3) TAS drives transit + outdoor hold-until-resident (retire the
TeleportArrivalController driver), (4) fullscreen fade overlay, (5) cell-march
lbX hardening, (6) verify + strip the tp-probe. Reuses the dormant
TeleportAnimSequencer as the transit driver; worldReady gates on the
priority-applied destination landblock.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 12:51:07 +02:00
Erik
1f8dd7a93f docs: D.2b empty-slot art — inventory portion visually confirmed
User confirmed the container column reads correct after the inheritance-resolved
fix (22d9231). Status: inventory empty-slot art FIXED + VISUALLY CONFIRMED.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 12:49:29 +02:00
Erik
22d92315e5 fix(ui): D.2b empty-slot art — container cells use inner slot bg, not the selected-container triangle
Visual gate (2026-06-22) showed the side-bag/main-pack empty cells drawing yellow
triangles. Root cause: the frame-first heuristic grabbed the 36x36 container
prototype's DirectState child 0x06005D9C — which is the open/SELECTED-container
triangle indicator, NOT a background frame — and stamped it onto every empty cell.

Fix: drop frame-first; FindIconEmpty resolves the inner m_elem_Icon ItemSlot_Empty
THROUGH BaseElement inheritance (0x1000033F -> 0x10000340 -> base 0x1000033E ->
0x1000033B -> 0x06000F6E), so containers get the dark slot background matching the
inventory. Pin test now asserts exact ids (0x06004D20 contents / 0x06000F6E
containers) — the old structural-only assertion let the wrong-but-valid 0x06005D9C
pass (Opus review Minor 2, now vindicated). The triangle + green/yellow selection
square is deferred to container-switching (AP-56 reworded). Full suite green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 12:45:36 +02:00
Erik
31602c6a24 docs(teleport): spec — retail residency + fade-cover (refutes _datLock starvation)
Live tp-probe capture refuted the handoff's _datLock-starvation hypothesis:
worker BUILD is fast + uncontended (waited=0ms); the 10-14s 'long transition'
is render-thread APPLY latency, and 'dropped at wrong position' is the
per-frame resolve corrupting the outbound cell frame (lbX zeroed) while the
player sits on an empty world. Design: priority-apply the player's dest
landblock + hold-until-resident behind a retail fade cover (reuse the dormant
TeleportAnimSequencer) + cell-march landblock-id hardening. Foundation-first,
not a hold over slow streaming. Flood-timeslicing + 3D swirl deferred.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 11:18:16 +02:00
Erik
499485a672 docs: D.2b empty-slot art — close inventory portion of the empty-slot-art issue
Inventory contents grid / side-bag / main-pack empty cells now dat-resolve their
art via ItemListCellTemplate (0x1000000e -> 0x21000037). Paperdoll equip
silhouettes + main-pack icon remain open (Sub-phase C / AP-51).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 11:10:39 +02:00
Erik
edbe5bafd5 feat(ui): D.2b empty-slot art — GameWindow resolves + wires per-list empty sprites
Inventory contents grid / side-bag / main-pack cells now render the retail
pack-slot empty art (dat cell template via ItemListCellTemplate) instead of the
generic toolbar square. Divergence rows AP-55 (toolbar still hardcoded) + AP-56
(flat single-sprite cell vs retail''s layered prototype).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 11:07:58 +02:00
Erik
69ad2cf12d docs(D.2b): implementation plan — inventory empty-slot art via cell-template resolution
5-task TDD plan for the OPEN empty-slot-art issue: ItemListCellTemplate resolver
(ports UIElement_ItemList::InternalCreateItem's 0x1000000e -> 0x21000037 lookup),
UiItemList.CellEmptySprite, InventoryController + GameWindow wiring, divergence
rows AP-55/AP-56, ISSUES close + visual gate. Each task is test-first with exact
code; Task 1 pins the exact retail sprites from the live dat.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 10:40:51 +02:00
Erik
660bcc2fcf docs(D.2b): design — faithful inventory empty-slot art via cell-template resolution
Brainstorm + decomp investigation for the OPEN issue "Inventory + equipment
slots show the wrong empty-slot background art". Verified against the named
decomp that retail's UIElement_ItemList::InternalCreateItem (004e3570) sources
each list's empty-cell sprite from attribute 0x1000000e on the list's own
ElementDesc -> catalog LayoutDesc 0x21000037 -> the prototype's ItemSlot_Empty
(0x1000001c) media. acdream hardcodes 0x060074CF (the generic toolbar square),
bypassing the per-list cell-template inheritance entirely.

Design ports the resolver: a new ItemListCellTemplate.ResolveEmptySprite helper
(mirrors the existing GameWindow 0x21000037 digit-array read), a
UiItemList.CellEmptySprite property, and InventoryController wiring for the
contents grid / side-bag / main-pack lists. Toolbar untouched (its 0x060074CF
is correct); paperdoll silhouettes stay Sub-phase C.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 10:31:38 +02:00
Erik
f8cda7e86d docs(teleport): foundation-investigation handoff for a fresh-look session
Captures the full teleport-flow journey (Slice 1 kept, Slice 2 hold built +
reverted), the root-cause findings (the IsLandblockLoaded key bug + the real
foundation problem: destination doesn't stream fast/complete during teleport,
likely _datLock starvation from the CreateObject flood), the open foundation
issues (#138 slow/incomplete streaming, lost-collision-after-teleport, FPS
leak Work-C, the PortalSpace freeze-vs-run-through question), and the clean
baseline (dd2eb8b). Written as evidence + open questions, not conclusions, so
a fresh session can re-examine the whole approach.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 10:00:23 +02:00
Erik
e6c8b65f77 docs(D.2b): inventory finish Stage 1 — handoff + divergence rows + ISSUES
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) <noreply@anthropic.com>
2026-06-21 21:31:24 +02:00
Erik
7aba6d235c docs(D.2b): inventory window finish (Stage 1) implementation plan
6 tasks: (1) UiItemList clip+scroll via the shared UiScrollable + whole-row
clip; (2) mouse-wheel; (3) InventoryController binds the gutter scrollbar
0x100001C7 like ChatWindowController; (4) side-bag column 36px pitch + empty-
slot padding to capacity; (5) backdrop coverage — screenshot-gated, primary
fix is the clip; (6) verify + bookkeeping. TDD on the pure/controller logic
(internals test-visible); backdrop is the visual gate. Grounded in the dat
dumps + the existing scroll/scrollbar machinery.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 20:15:48 +02:00
Erik
0fbb76b2e7 docs(D.2b): inventory window finish (Stage 1) spec
Stage 1 of the "full retail inventory" arc (Stage 2 = paperdoll, separate
spec). Grounded in the dat dumps: contents grid 0x100001C6 is 192x96 (6x3) +
scrollbar 0x100001C7 (16x96); backdrop 0x100001D0 is full-window 300x362
(so the "torn" look is the unclipped grid overflowing below the frame —
fixed by clipping); side-bag column 0x100001CA is 36x252 (7 slots).
Components: (A) UiItemList clip+scroll reusing UiScrollable + bind the gutter
scrollbar like ChatWindowController; (B) backdrop coverage — primary fix is A,
residual gated on the post-A screenshot; (C) side-bag column pads empty slots
up to capacity at 36px pitch. Paperdoll + B-Drag out of scope.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 20:07:10 +02:00
Erik
2c8cd887e5 docs(slice-1): retail-divergence-register — TAS smoothstep approximation row (spec §5 row 2)
AP-49: TeleportAnimSequencer.ComputeFadeAlpha uses smoothstep in place of
retail's unrecovered 1024-entry GetAnimLevel lookup table
(gmSmartBoxUI::UseTime 0x004d6e30). Retire when the table contents are
extracted via cdb (spec §8).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 20:03:03 +02:00
Erik
82462ff153 docs(teleport-flow): implementation plan — 22 TDD tasks across 5 slices (Work item B)
Bite-sized TDD plan for the retail teleport flow. Slice 1: pure
TeleportAnimSequencer (7-state TAS) + golden-timing tests. Slice 2: the
#145 readiness-gate fix (IsLandblockLoaded + Decide outdoorReady axis +
apparatus probe) — ships independently of the visuals. Slice 3:
TeleportFlowController (delegate-injected, unit-tested) + TeleportFadeOverlay
+ portal wiring (PlaceTeleportArrival split: place vs InWorld so the input
lock persists the whole animation). Slice 4: one yaw-freeze + portal sounds
via the EnumIDMap chain. Slice 5: de-dup login readiness onto Decide, route
login/death through the controller, logout (Shift+Esc) + 0xF653 + disconnect,
remove dead _teleportArrival plumbing. Slice 6 (literal 3D swirl) is a
follow-up plan gated on a cdb asset trace.

Drafted via two research + drafting workflows; slices 3-5 redrafted as one
cohesive unit against a pinned controller API after the first parallel pass
produced cross-slice inconsistencies (missing controller task, triplicated
yaw-freeze, a fabricated PlayerMovementController.Update signature). All
load-bearing signatures personally verified against the tree.

Plan: docs/superpowers/plans/2026-06-21-retail-teleport-flow.md

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 19:42:28 +02:00
Erik
7c006d103a docs(D.2b-B): B-Wire shipped — AP-48/AP-49 fallback-only + ISSUES entry
Reword AP-48 (burden) and AP-49 (carry-aug) to fallback/default-only: B-Wire
ports the retail wire read (login PD-bundle UpsertProperties + live 0x02CD;
ObjectTableWiring applies all ints), so SumCarriedBurden / aug=0 are now
defensive only. Confirm the server sends EncumbranceVal/0xE6 at the visual
gate, then delete the rows. Add the D.2b-B B-Wire SHIPPED entry to ISSUES.
(Memory digest project_d2b_retail_ui.md + MEMORY.md updated out-of-tree.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 19:24:25 +02:00
Erik
aab9ddaf6b docs(teleport-flow): design — unified retail TeleportAnimState flow (Work item B keystone)
Brainstormed + decomp-researched the retail teleport flow, the keystone of
the #138/#145 teleport cluster. Five oracle calls locked: full retail TAS;
hold-until-landblock-loaded readiness (folds in the #145 residual / Work
item A); unify all four entry points (login/logout/death/portal); build the
literal portal swirl this pass; logout = animation + 0xF653 + disconnect
(char-select UI deferred).

Grounded in a verified 5-agent decomp pass (workflow wf_f0c07c93-7aa): the
7-state TeleportAnimState machine + golden constants (FADE=1s, MIN/MAX
CONTINUE=2/5s, FPS=40), the teleport_in_progress hold gate, per-entry start
states, sounds, input lock, exit (LoginComplete 0xA1). Load-bearing acdream
facts re-verified personally: AddLandblock atomicity, streaming-progresses-
during-hold, outdoor place-immediately.

Spec: docs/superpowers/specs/2026-06-21-retail-teleport-flow-design.md

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 19:03:10 +02:00
Erik
ca94d1d2f6 docs(D.2b-B): B-Wire implementation plan
16 bite-sized TDD tasks for the inventory wire pass: ClientObjectTable
UpsertProperties/UpdateStackSize (Core); PrivateUpdatePropertyInt 0x02CD,
SetStackSize 0x0197, InventoryRemoveObject 0x0024 parsers; ParseViewContents
0x0196; 0x0022 4th-field + 0x00A0 error fixes; DropItem/GetAndWieldItem/
NoLongerViewingContents builders + Send wrappers; PD player-property delivery
+ GameEvent registration; WorldSession dispatch; ObjectTableWiring apply-all-
ints + player-int route + stack/remove; GameWindow + InventoryController
wiring; divergence/ISSUES/roadmap/memory bookkeeping. Each pure parser/builder
/table-method is TDD'd; glue follows the codebase convention (dispatcher-
routed GameEvents unit-tested via the GameEventWiringTests harness, top-level
GameMessages build+run-verified). Plan derived from reading every call site.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 18:41:43 +02:00
Erik
5737951a19 docs(D.2b-B): B-Wire spec — inventory wire layer
Design/spec for B-Wire (follows B-Controller c38f098). Root cause found:
the burden binding already reads wire EncumbranceVal (PropertyInt 5) but
the value never arrives — login PD parses the player's int table then
drops it, the live 0x02CD (PrivateUpdatePropertyInt, no guid) is unparsed,
and ObjectTableWiring gates all non-UiEffects ints out.

Scope (user chose the full wire pass): player-property delivery (login PD
bundle upsert + 0x02CD parse + loosen the apply gate, retiring AP-48/AP-49),
latent-bug fixes (0x0022 4th field, 0x00A0 error), new C→S builders
(DropItem 0x001B / GetAndWieldItem 0x001A / NoLongerViewingContents 0x0195),
new S→C parsers (ViewContents 0x0196 GameEvent; SetStackSize 0x0197 +
InventoryRemoveObject 0x0024 GameMessages), and WireAll registration.
Opcodes pinned against ACE GameMessageOpcode.cs / GameActionType.cs; every
format requires grep-named → cross-ref → pseudocode → port + conformance.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 18:25:58 +02:00
Erik
adaec1845f docs: handoff — fold in retail teleport-anim (TAS) flow + acdream gap analysis for the teleport-flow feature
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 18:24:08 +02:00
Erik
59b4868408 docs: handoff — teleport issues cluster (#145 residual + retail teleport flow + FPS leak)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 18:11:37 +02:00
Erik
1230c07af3 docs(handoff): D.2b B-Controller shipped + visually confirmed; B-Wire next
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 18:08:05 +02:00
Erik
b7ca33118b docs(#145): REOPEN — cascade recurs on unstreamed-arrival-near-edge (streamed case fixed)
3rd live session found the carried-anchor fix is incomplete: the cascade recurs
when a teleport arrives onto a NOT-YET-STREAMED landblock near an edge (0xC98C
arrival at local Y=190.3, NO-LANDBLOCK -> marches 0x8C->0xFE, wire localY=-21684,
ACE rejects). Streamed-arrival case IS fixed (verified ~10 landblocks). Same root
as the Z free-fall (#135/#138 placed-but-unstreamed gap). Prior 'gate passed' was
premature. Needs apparatus (anchor/guard diagnostic at the crossing) before a fix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 18:04:54 +02:00
Erik
c38f098ec0 docs(D.2b-B): B-Controller visually confirmed; #145 continuation + overflow follow-up
- #145: the original fix was incomplete (mounted panels inherited ZLevel 1000 →
  behind the backdrop → washed out); continuation 417b137 closes it. Updated status.
- D.2b-B SHIPPED entry: visually confirmed; the two render bugs (backdrop wash-out
  + captions host-direct) documented.
- New OPEN issue: contents grid overflows (needs the gutter scrollbar wired; scroll
  was out-of-scope for B-Controller per the spec).
- Roadmap ledger: B-Controller visually confirmed + the render fix noted.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 18:01:38 +02:00
Erik
b0cbc09ba0 docs(#145): cascade FIXED + user-gate passed — far-town round-trip works (Slices 1-3+7)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 17:30:11 +02:00
Erik
865aae8876 docs(#145): Slice 3 — capture cellId/anchor-consistency + indoor-staleness edge cases + sweep threading map
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 11:08:13 +02:00
Erik
9e184eb861 docs(#145): Slice 3 design — carried-anchor (body.Position - CellPosition.Origin) replaces TryGetTerrainOrigin
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 11:05:54 +02:00
Erik
7cae03951e docs(#145): plan — split Slice 2 into 2a (Core, shipped) + fold 2b seeding into Slice 3
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 10:57:04 +02:00
Erik
c980763322 refactor(physics #145): Slice 1 — rename Frame->CellFrame to avoid DatReaderWriter.Types.Frame collision
The new value type collided with DatReaderWriter.Types.Frame (used in
physics-adjacent code like ShadowShapeBuilder), which the structural fix
(per-file using-aliases across 6 files) would have re-incurred in every
later physics slice. Renamed the TYPE to CellFrame; the Position.Frame
MEMBER keeps retail's name. Restored the 5 alias-only files to their
pre-Slice-1 state; synced spec + plan. Core 1522 passed / 0 failed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 10:34:36 +02:00
Erik
ed32db70d7 docs(#145): implementation plan — cell-relative physics frame (7 slices)
Bite-sized, TDD-structured 7-slice plan for subagent-driven execution:
(1) Position/Frame types + GetBlockOffset, (2) PhysicsBody carries
Position, (3) membership via AdjustToOutside — closes the cascade,
(4) inter-tick collision state cell-relative + validate_transition
lockstep, (5) wire off Position, (6) _liveCenter render-only, (7)
teleport velocity-idle. Conformance via transform-on-read.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 10:23:37 +02:00
Erik
fd1f86b771 docs(#145): Option B design spec — cell-relative physics Position frame
Approved design for the cell-relative physics frame port: retire
_liveCenter from physics (render-only), carry Position{ObjCellId,
Frame{local in [0,192), quat}} as the source of truth, port
get_block_offset (verified 0x0043e630 nets to delta-landblock * 192 m),
translate inter-tick collision state per-cell like retail (0x0050a592).
7-slice parallel-frame migration; conformance via transform-on-read (no
fixture re-capture).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 10:18:18 +02:00
Erik
67f98e8e72 docs(#145): verified root cause + decision to port cell-relative physics frame (Option B) + handoff
Workflow wf_87607d15-c43 (4 research streams + synthesis + 3 adversarial verifiers, HIGH confidence) confirmed the far-town runaway is a cell-membership label cascade from a discarded TryGetTerrainOrigin bool (CellTransit.cs:736 -> (0,0) origin for unstreamed neighbors), not a free-fall; 17410 is a wire artifact. User chose the architectural fix: port retail's cell-relative Position + retire _liveCenter from physics. Handoff doc carries the verified mechanism, the retail port table (decomp addresses), acdream divergence sites, apparatus (desync-capture.jsonl + probes + harness template), and the brainstorming-gate requirement.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 09:47:01 +02:00
Erik
1ccf07b705 fix(ui): D.2b-B — address phase-boundary review (burden % saturation + equipped filter)
Opus phase-boundary review findings:
- I1 (faithfulness): LoadToPercent now computes from the CLAMPED fill
  (floor(LoadToFill(load)*300)), so the burden % SATURATES at 300% like retail
  (decomp 176544-176576 clamps arg2 to [0,1] BEFORE the *300). The old
  floor(load*100) over-read to 400% at 4x capacity. Golden test corrected.
- I2 (partition): exclude equipped items (CurrentlyEquippedLocation != None) from
  the contents grid + selector — a mid-session self-wield routes them through
  MoveItem(item, WielderGuid=player) into GetContents(player); retail's gm3DItemsUI
  shows pack contents only. New conformance test.
- N1: drop dead 'using System.Collections.Generic' (left after the 383e8b7 cleanup).
- N3: AP-48 risk wording (drift can be low OR high vs server EncumbranceVal).

Build green; BurdenMath 17, InventoryController/UiMeter 10 tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 09:28:29 +02:00
Erik
7bb4bd3ae8 docs(D.2b-B): divergence rows + issues/roadmap for inventory population
AP-48: client-side SumCarriedBurden fallback (EncumbranceVal not yet wired).
AP-49: aug capacity (PropertyInt 0xE6) not tracked → un-augmented Str×150.
AP-50: meter direction from geometry (m_eDirection/0x6f not read from LayoutDesc).
AP-51: main-pack cell placeholder icon (equip-pack DID deferred to Sub-phase C).

AP count: 43 → 47 rows. ISSUES: D.2b-B closed entry + remaining B-Wire/B-Drag/C
gaps noted. Roadmap: D.5 sub-phase ledger updated to reflect B-Controller shipped.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-21 09:15:05 +02:00
Erik
a4f0b51894 docs(issues): reopen #145 — far-town teleport resolver runaway (residual of the source-drop fix)
Captured: teleport to far town (201,91) places correctly via the #145 verbatim path, then the per-frame resolve marches membership one landblock south/frame (un-rebased local position) until ACE rejects the inconsistent (cell, local) pair. #138 re-hydrate exonerated. Root cause under multi-agent research (acdream code + retail decomp oracle + capture).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 08:54:05 +02:00
Erik
5b3295ad13 docs(D.2b-B): InventoryController implementation plan (8 tasks, TDD)
Bite-sized TDD tasks: BurdenMath encumbrance ports (T1), SumCarriedBurden
fallback (T2), UiMeter vertical fill (T3), InventoryController bind+populate
(T4) + burden+captions (T5), GameWindow wiring (T6), divergence/docs (T7),
visual gate (T8). Self-reviewed against the spec; test helpers verified
against the shipped widget APIs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 08:50:21 +02:00
Erik
0e273ff2ac docs(D.2b-B): InventoryController (B-Controller) design spec
Read-only population of the gmInventoryUI tree: bind 0x21000023 by id,
fill the 'Contents of Backpack' grid + the right-strip pack-selector from
ClientObjectTable, drive the vertical burden meter, render the Type-0
captions. Faithful selector + full faithful burden meter (per brainstorm).

Ported AC algorithms with decomp anchors: CACQualities::InqLoad (0x0058f130),
EncumbranceSystem::EncumbranceCapacity (0x004fcc00) / Load (0x004fcc40),
gmBackpackUI::SetLoadLevel (0x004a6ea0), UIElement_Meter::DrawChildren
(0x0046fbd0) / Initialize (0x0046f7b0, m_eDirection from property 0x6f).
Key finding: BuildMeter's single-image sprite assignment is already correct
(meter-own=track, child=fill); only vertical fill is new.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 08:31:21 +02:00
Erik
b07825cd24 docs(research): #138 handoff — RESOLVED banner + correct the re-hydrate source (not ClientObjectTable)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 08:09:36 +02:00