fix(client): ground items cannot be picked up and holding Alt does not display ground item labels #555

Closed
opened 2026-10-02 09:18:16 +00:00 by troytt · 1 comment
Owner

Summary

In play.html, dropped items on the ground (such as scrolls, potions, gold, and equipment dropped by slain monsters) cannot be picked up when clicked, and holding Alt does not display ground item name labels.

Root Causes

  1. Alt Key Swallowed in Capture Phase:
    • src/client/main.ts attaches window.addEventListener('keydown'/'keyup', ..., true) in the capture phase.
    • CommandMapper.handleKeyDown (src/client/input/command-mapper.ts) handles e.key === 'Alt', sets this.altHeld = true, and returns true, causing main.ts to call e.stopImmediatePropagation().
    • Because propagation stops in capture phase, HudManager's bubble-phase listener never receives Alt, and CommandMapper never syncs this.hudManager.showGroundLabels.
  2. Ground Item Labels (layoutGroundItemLabels) Never Rendered or Hit-Tested:
    • layoutGroundItemLabels (src/common/items/ground-items.ts) was imported in src/client/scene/world-renderer.ts but never invoked in world-renderer.ts or hud-manager.ts.
    • Neither holding Alt (showGroundLabels) nor hovering a ground item renders the 1.13c dark translucent plaque and quality-colored item name (D2Client.dll 0x6FB1F4A0) onto hudCanvas.
    • CommandMapper.resolvePointerTarget also never hit-tests visible GroundItemLabelBox rectangles when Alt is held.
  3. Ground Item Pickup Fails at Distance (dist > 4) and Close Up (dist <= 4):
    • Premature 0x16 (ItemPickup) while out of range (dist > 4): CommandMapper.triggerPrimaryWorldAction emits MoveToUnit (0x02/0x04) and immediately in the same frame emits ItemPickup (0x16). D2GS (D2Game.dll 0x6FC45FB0) rejects 0x16 when the player is > 4 subtiles away on the server, and no 0x16 is emitted when the player arrives at the item.
    • Camera -16 px Y-offset & small sprite hit-testing mismatch: world-renderer.ts renders the WebGL scene with camY = snapshot.playerWorld.y - 16 and draws ground items at (worldX - rect.w / 2, worldY - rect.h + groundYOffset), whereas CommandMapper.resolvePointerTarget projects screenToSubtile without compensating for the -16 px camera Y shift or testing the ground item sprite bounding box.
    • Dead monster mode & ground item mode: decode0x11ReportKill sets mode: 0x09 instead of 12 (MONMODE_DEAD), resolvePointerTarget omits unit.mode === 0 (MONMODE_DEATH), and ClientWorld inverted 0x9C action === 0x02 (ITMODE_DROPPING = 5) vs 0x03 (ITMODE_ON_GROUND = 3).

Expected Behavior (1.13c Ground Truth)

  • Holding Alt displays all visible ground item labels (D2Client.dll 0x6FB1F4A0) with vertical anti-overlap stacking and 1.13c quality colors; hovering a ground item without Alt displays that item's label.
  • Clicking a visible ground item label box (while Alt is held) or clicking a ground item sprite walks to the item if dist > 4 and sends 0x16 (PickItem) once within pickup range (dist <= 4), or immediately sends 0x16 when already within dist <= 4.
## Summary In `play.html`, dropped items on the ground (such as scrolls, potions, gold, and equipment dropped by slain monsters) cannot be picked up when clicked, and holding `Alt` does not display ground item name labels. ## Root Causes 1. **`Alt` Key Swallowed in Capture Phase**: - `src/client/main.ts` attaches `window.addEventListener('keydown'/'keyup', ..., true)` in the capture phase. - `CommandMapper.handleKeyDown` (`src/client/input/command-mapper.ts`) handles `e.key === 'Alt'`, sets `this.altHeld = true`, and returns `true`, causing `main.ts` to call `e.stopImmediatePropagation()`. - Because propagation stops in capture phase, `HudManager`'s bubble-phase listener never receives `Alt`, and `CommandMapper` never syncs `this.hudManager.showGroundLabels`. 2. **Ground Item Labels (`layoutGroundItemLabels`) Never Rendered or Hit-Tested**: - `layoutGroundItemLabels` (`src/common/items/ground-items.ts`) was imported in `src/client/scene/world-renderer.ts` but never invoked in `world-renderer.ts` or `hud-manager.ts`. - Neither holding `Alt` (`showGroundLabels`) nor hovering a ground item renders the 1.13c dark translucent plaque and quality-colored item name (`D2Client.dll` `0x6FB1F4A0`) onto `hudCanvas`. - `CommandMapper.resolvePointerTarget` also never hit-tests visible `GroundItemLabelBox` rectangles when `Alt` is held. 3. **Ground Item Pickup Fails at Distance (`dist > 4`) and Close Up (`dist <= 4`)**: - **Premature `0x16` (`ItemPickup`) while out of range (`dist > 4`)**: `CommandMapper.triggerPrimaryWorldAction` emits `MoveToUnit` (`0x02`/`0x04`) and immediately in the same frame emits `ItemPickup` (`0x16`). D2GS (`D2Game.dll` `0x6FC45FB0`) rejects `0x16` when the player is > 4 subtiles away on the server, and no `0x16` is emitted when the player arrives at the item. - **Camera `-16` px Y-offset & small sprite hit-testing mismatch**: `world-renderer.ts` renders the WebGL scene with `camY = snapshot.playerWorld.y - 16` and draws ground items at `(worldX - rect.w / 2, worldY - rect.h + groundYOffset)`, whereas `CommandMapper.resolvePointerTarget` projects `screenToSubtile` without compensating for the `-16` px camera Y shift or testing the ground item sprite bounding box. - **Dead monster mode & ground item mode**: `decode0x11ReportKill` sets `mode: 0x09` instead of `12` (`MONMODE_DEAD`), `resolvePointerTarget` omits `unit.mode === 0` (`MONMODE_DEATH`), and `ClientWorld` inverted `0x9C` `action === 0x02` (`ITMODE_DROPPING` = 5) vs `0x03` (`ITMODE_ON_GROUND` = 3). ## Expected Behavior (1.13c Ground Truth) - Holding `Alt` displays all visible ground item labels (`D2Client.dll` `0x6FB1F4A0`) with vertical anti-overlap stacking and 1.13c quality colors; hovering a ground item without `Alt` displays that item's label. - Clicking a visible ground item label box (while `Alt` is held) or clicking a ground item sprite walks to the item if `dist > 4` and sends `0x16` (`PickItem`) once within pickup range (`dist <= 4`), or immediately sends `0x16` when already within `dist <= 4`.
Author
Owner

Resolved and merged into main via PR #560 (commit b839301).

Fix Summary

  1. Alt Key Synchronization: Fixed capture-phase event swallowing in main.ts by directly synchronizing HudManager.showGroundLabels from CommandMapper.handleKeyDown / handleKeyUp, with window blur modifier reset.
  2. Ground Item Labels: Wired layoutGroundItemLabels in renderSceneSourceFrame to populate hudManager.groundItemLabelBoxes with 1.13c quality hex colors and bilingual (English/Chinese) names. Rendered dark translucent plaques on hudCanvas.
  3. Hit-Testing & Pickup Execution:
    • CommandMapper.resolvePointerTarget checks groundItemLabelBoxes first so clicking directly on an item's overhead label immediately targets and picks up the item.
    • Added camera -16px Y-offset compensation for sprite hit-testing and ignored dead monsters.
    • Implemented deferred arrival pickup: clicking distant items (dist > 4) dispatches ItemPickup (0x16) as soon as the player walks within 4 subtiles, without getting canceled by mouse-hold ground move ticks.
  4. ReportKill Mode: Mapped 0x11 monster kills to mode: 12 (MONMODE_DEAD) instead of 0x09.
  5. Testing: Added tests/client/ground-item-pickup-and-alt-labels-555.test.ts (6/6 passing). All 20 client test files (175 tests) and 5 E2E test suites (204 tests) pass with 0 TypeScript errors.
Resolved and merged into `main` via PR #560 (commit `b839301`). ### Fix Summary 1. **Alt Key Synchronization**: Fixed capture-phase event swallowing in `main.ts` by directly synchronizing `HudManager.showGroundLabels` from `CommandMapper.handleKeyDown` / `handleKeyUp`, with window blur modifier reset. 2. **Ground Item Labels**: Wired `layoutGroundItemLabels` in `renderSceneSourceFrame` to populate `hudManager.groundItemLabelBoxes` with 1.13c quality hex colors and bilingual (English/Chinese) names. Rendered dark translucent plaques on `hudCanvas`. 3. **Hit-Testing & Pickup Execution**: - `CommandMapper.resolvePointerTarget` checks `groundItemLabelBoxes` first so clicking directly on an item's overhead label immediately targets and picks up the item. - Added camera -16px Y-offset compensation for sprite hit-testing and ignored dead monsters. - Implemented deferred arrival pickup: clicking distant items (`dist > 4`) dispatches `ItemPickup` (0x16) as soon as the player walks within 4 subtiles, without getting canceled by mouse-hold ground move ticks. 4. **ReportKill Mode**: Mapped 0x11 monster kills to `mode: 12` (MONMODE_DEAD) instead of 0x09. 5. **Testing**: Added `tests/client/ground-item-pickup-and-alt-labels-555.test.ts` (6/6 passing). All 20 client test files (175 tests) and 5 E2E test suites (204 tests) pass with 0 TypeScript errors.
Sign in to join this conversation.
No Label
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: troytt/diablo2-web#555
No description provided.