diablo2-web/PROJECT.md

23 KiB
Raw Blame History

Project: Diablo II: Lord of Destruction (v1.13c) Pure-Browser Online Client (diablo2-web feat/netproto)

Architecture

  • Pluggable, Zero-Dependency Network & Protocol Layer (src/netproto/):
    • Strictly isolated from DOM, Node.js, rendering, and game simulation (tsconfig.netproto.json sets lib: ["ES2022"], types: [] for core src/netproto/**, excluding only transport/ws-stream.ts and transport/node-tcp-stream.ts).
    • L0 Transport (src/netproto/transport/): ByteStream interface implemented by MemoryStream (testing/offline replay), WsStream (browser WebSocket), and NodeTcpStream (Node CLI bot), plus EndpointResolver (wsBridgeResolver mapping 6112 -> /d2net/bnet, 6113 -> /d2net/realm, 4000 -> /d2net/game; tcpResolver; and mixedResolver using direct TCP 101.37.117.183:6112 for BNCS and WSS for MCP/D2GS so Node bots do not consume the 5-per-IP 127.0.0.1 WSS bridge quota).
    • L1–L3 Protocol Engines (src/netproto/{core,crypto,bncs,mcp,d2gs}/):
      • crypto/: Battle.net broken SHA-1 (xsha1), doubleHash, 1.13c CheckRevision constants (exeVersion=0x01000d00, exeHash=0x7686beca, exeInfo="Game.exe 03/09/10 04:10:51 61440"), and 16-char D2DV/D2XP CD-Key decode & hash.
      • bncs/: 0x01 greeting + 0xFF | id | u16 len framing, OLS auth (0x50, 0x25, 0x51, 0x3D, 0x3A), chat (0x0A..0x0F), and realm handoff (0x40, 0x3E).
      • mcp/: 0x01 greeting + u16 len | u8 id framing (D2MCPClient.dll), 0x01 STARTUP, 0x19 CHARLIST2 (with 33-byte charStatString parser), 0x02 CHARCREATE, 0x0A CHARDELETE, 0x18 CHARUPGRADE, 0x07 CHARLOGON, 0x03 CREATEGAME, 0x04 JOINGAME, 0x05 GAMELIST, 0x06 GAMEINFO, 0x12 MOTD.
      • d2gs/: Generated 1.13c S→C packet size table (D2Net.dll 0x6fbfa900 181 entries + 14 variable-length formulas at 0x6fbf6750 and C→S 0x6fbfabd8 113 entries) and canonical Huffman bit-length table (Fog.dll 0x6ff7f210 + Fog.10219/Fog.10224 MSB-first decompressor); initial uncompressed [0xAF, 0x01] greeting followed by 1/2-byte totalFrameSize compressed blocks (compressedPayloadLen = totalFrameSize - headerSize); fail-fast ProtocolError on unknown packet IDs or size mismatches; complete S→C (0x00..0xB4) and C→S (0x01..0x70) codecs, 0x9C/0x9D LSB-first item bitstream decoder (ItemDataTables injection), and D2gsSession (0x68 37-byte GameLogon, 0x6B EnterGame, 5s 13-byte 0x6D Ping).
    • L4 Neutral Domain & Flow (src/netproto/domain/, src/netproto/flow/, src/netproto/index.ts):
      • src/netproto/index.ts exports ONLY protocol-neutral domain types (ServerEvent, ClientCommand, GameServerAdapter, D2OnlineFlow, EndpointResolver, TextCodec, PacketTap, lobby models). External code (src/client/**, src/ui/**, src/scene/**, src/render/**, src/frontend/**) never imports src/netproto/{bncs,mcp,d2gs,crypto}/**.
  • Runtime Seed-Driven DRLG & Tile Atlas Pipeline (scripts/pack-tiles.ts, src/game/drlg/, src/client/map/):
    • scripts/pack-tiles.ts packs all LvlTypes.txt DT1s across Acts 1–5 plus the 3 mandatory universal DT1s (Blank.dt1, InvisWal.dt1 with style=49 sequence=7 collision floor, Warp.dt1) and compact DRLG .bin/.ds1/DT1-header metadata into public/act-packs/tiles/.
    • map-worker.ts & map-service.ts run createDrlgActSession on (act, mapSeed, difficulty, areaId) from LoadAct and RoomReveal to produce exact pinned tile references, 16-bit sub-tile collision grids (COLLIDE_MASK_INVALID on void cells), warps, waypoints, and preset units matching D2GS cell-for-cell.
  • Packet-Driven Browser Client, Dual Viewport, Toolbar, Lobby, Audio & Inspector (play.html, src/client/, src/ui/, src/frontend/):
    • ClientWorld maintains the authoritative server mirror (units, modes, directions, stats, states, skills, inventory/equipment/belt/stash/cube/cursor/trade/merc).
    • ViewportProfile supports 800×600 (1.13c native) and 1024×768 (HUD anchored at native pixel dimensions with (barOffsetX=112, barOffsetY=168), accurate screen-to-world mouse picking).
    • Top DOM Toolbar (src/client/toolbar/) & ClientSettings (localStorage['d2web.settings.v1']): connection status/RTT + 5-per-IP/TLS diagnostics, Server Host editor (rejecting bare IP over https:), live 中/EN toggle, lighting level selector (auto/1.13c, LIGHTING_PRESETS, fullbright), automap reveal (off/level/act), viewport toggle (800×600/1024×768), and Packet Inspector toggle.

Feature Inventory

Every feature from the Survey phase and ORIGINAL_REQUEST.md appears here with its assigned milestone. No feature is left unassigned.

# Feature Description Milestone Source
F1 Module Isolation & TypeScript Boundary Enforcement tsconfig.netproto.json (lib: ["ES2022"], types: []), tests/netproto/boundary.test.ts, and src/netproto/index.ts exporting only protocol-neutral interfaces (ServerEvent, ClientCommand, GameServerAdapter, D2OnlineFlow, EndpointResolver). M1 R1, Survey 1
F2 Core Primitives, Framing, TextCodec & Transport Streams ByteReader, ByteWriter, BitReader, BitWriter, ProtocolError, TextCodec (defaulting to gbk via TextDecoder/TextEncoder), Clock, PacketTap, ByteStream, MemoryStream, WsStream, NodeTcpStream, EndpointResolver (wsBridgeResolver, tcpResolver, mixedResolver). M1 R1, R6, Survey 1 & 3
F3 Deterministic 1.13c D2Net.dll / Fog.dll Table Extraction scripts/extract-d2net-tables.ts generating src/netproto/d2gs/tables/s2c-sizes.ts (0x6fbfa900 181 S→C sizes + 0x6fbf6750 14 variable-length formulas + 0x6fbfabd8 113 C→S sizes) and huffman.ts (Fog.dll 0x6ff7f210 256-byte bit-lengths + Fog.10219 canonical builder) with SHA-1s and offsets. M1 R1, Survey 2
F4 Battle.net Crypto & BNCS Session State Machine xsha1 broken SHA-1, doubleHash, CheckRevision 1.13c constants (0x01000d00, 0x7686beca, "Game.exe 03/09/10 04:10:51 61440"), 16-char D2DV/D2XP CD-Key decode & hash, BNCS `0xFF id u16 len framing and packets (0x50, 0x25, 0x51, 0x3D, 0x3A, 0x0A..0x0F, 0x40, 0x3E`).
F5 MCP Realm Session & D2OnlineFlow Orchestration MCP 0x01 greeting + `u16 len u8 id framing (0x01STARTUP,0x19CHARLIST2 with 33B stat string,0x02CHARCREATE,0x0ACHARDELETE,0x18CHARUPGRADE,0x07CHARLOGON,0x03CREATEGAME,0x04JOINGAME,0x05GAMELIST,0x06GAMEINFO,0x12MOTD),D2OnlineFlow, and initial scripts/d2-bot.ts account registration (d2webbot1..3inscratch/bot-accounts.json`). M1
F6 D2GS Block Framing, Huffman Decompression & Session Handshake Initial uncompressed [0xAF, 0x01] greeting, 1/2-byte totalFrameSize block header (compressedPayloadLen = totalFrameSize - headerSize), Fog.10224 MSB-first Huffman decompressor (+ encoder for tests), D2NET_10033 packet splitter with fail-fast ProtocolError, 37-byte 0x68 GameLogon, 0x6B EnterGame, and 5s 13-byte 0x6D Ping loop. M2 R1, R2, Survey 2
F7 Complete D2GS S→C (0x00..0xB4) & C→S (0x01..0x70) Codecs & D2gsAdapter Full table-driven S→C and C→S packet definitions (load, units, movement, stats, skills, states, items, npc, quest, waypoint, party, trade, chat, merc, misc), registry.ts with D2Client.dll 0x6fb8de60 handler VAs, and D2gsAdapter implements GameServerAdapter. M2 R1, R2, Survey 2
F8 1.13c 0x9C / 0x9D Item Bitstream Decoder src/netproto/d2gs/items/item-bitstream.ts with injected ItemDataTables (ItemStatCost, Armor, Weapons, Misc), decoding 8B 0x9C and 13B 0x9D headers, ground 16+16b coords vs container 4+4+3b coords, "gld " gold piles, compact vs extended items, sockets, runewords, and 0x1FF-terminated stat lists. M2 R1, R2, Survey 2
F9 Headless ClientWorld Authoritative Mirror src/client/world/{client-world,client-unit,stat-list,states,inventory,self,item-tables-provider}.ts maintaining units, modes, directions, stats, states, skills, and all item containers (inventory, equipment, belt, stash, cube, cursor, trade, merc, shop, ground) from ServerEvents. M2 R2, R4, Survey 1 & 2
F10 Live .d2cap Capture Corpus & Strict Offline Replay (scripts/netproto-replay.ts) Complete scripts/d2-bot.ts (register, login, chars, create-char, games, create-game, join, idle, record, --world) + scripts/netproto-replay.ts --strict verifying tests/fixtures/netproto/*.d2cap with unknownPackets === 0, opaquePackets === 0, protocolErrors === 0, and >=60s live D2GS stability. M2 R2, Survey 2 & 3
F11 Seed-Independent Tile Library Asset Pack (scripts/pack-tiles.ts) Offline packer generating per-act DT1 tile atlases and compact DRLG .bin/.ds1/DT1-header bundles covering all LvlTypes.txt DT1s across Acts 1–5 plus the 3 mandatory universal DT1s (Blank.dt1, InvisWal.dt1 with style=49 sequence=7, Warp.dt1). M3 R3, Survey 1 & 3
F12 Runtime DRLG Web Worker, LevelView, TileAtlas & Motion/Pathfinding createDrlgActSession (drlg-dump.ts, drlg-map.ts), src/client/map/{level-view,tile-atlas,map-worker,map-service}.ts, and src/client/motion/{pathfind,predictor,interpolate}.ts generating exact pinned tile references, COLLIDE_MASK_INVALID void cell blocking, warps, and preset units on LoadAct / RoomReveal. M3 R3, Survey 1 & 3
F13 Offline .d2s Waypoint/Quest Unlock (scripts/d2s-unlock.ts) & 136-Level Parity Audit scripts/d2s-unlock.ts (backing up offline d2webbot* save on 101.37.117.183 /usr/local/var/pvpgn/charsave/ before unlocking all 39 waypoints & act-transition quests and recomputing checksum) + bot continuous walk test (0 UnitReassign pullbacks) + automated level audit verifying 100% coordinate parity across all reachable levels and all 136 level IDs. M3 R3, R6, Survey 1 & 3
F14 Persistent ClientSettings & Top DOM Toolbar (src/client/toolbar/) src/client/settings/{client-settings,settings-store}.ts (localStorage['d2web.settings.v1'] strict validation) and src/client/toolbar/{toolbar.ts,toolbar.css}: connection status/RTT + 5-per-IP & TLS diagnostics + Packet Inspector toggle, Server Host editor (rejecting bare IP over https: with explicit error, prompting mid-game), live 中/EN toggle, lighting selector, automap reveal (off/level/act), and viewport toggle (800×600/1024×768). M4 R5, Survey 1 & 3
F15 Dual Viewport Profiles (800×600 & 1024×768), SceneSource & LightingInputs src/client/view/{viewport-profile,scene-source,unit-drawables}.ts and non-breaking refactoring of src/scene/frontend/{lighting-presets,world-renderer,pack-loader,mouse-controller}.ts (adding fullbright preset and keeping acts.html 100% working). M4 R4, R5, Survey 1
F16 play.html Entry, Client Movement Prediction, Combat, Skills & Native Missile/Overlay FX play.html, src/client/{main,session/online-session,input/command-mapper}.ts rendering terrain, units, client-predicted movement with smooth UnitReassign reconciliation, left/right-hand skill casting, and native DCC/DC6 missile & overlay FX (Missiles.txt, additive blending Trans: 1 with zero black fringes). M4 R4, Survey 1 & 3
F17 Full HUD/Panel Rebinding (HudModel), 1024×768 Layout & Automap Reveal Modes src/client/ui-model/hud-model.ts, src/client/automap/automap-view.ts, and src/ui/** updates (anchoring panels at native pixel dimensions in 800×600 and 1024×768 without stretching art; wiring inventory, equipment, belt, stash, Horadric Cube, char sheet, skill tree, quest log, waypoint menu, NPC dialog/shop/repair/gamble/imbue, merc, party, trade, chat, Esc menu, death overlay, 1.13c hotkeys, and off/level/act automap reveal). M5 R4, R5, Survey 1
F18 Live Battle.net Lobby Flow (bnet.html & play.html via D2OnlineFlow) Connect src/frontend/{flow-state,bnet-main}.ts and play.html / bnet.html to real D2OnlineFlow sessions for login/register, channel chat, realm selection, char list/create/delete/convert, and game list/create/join, replacing mocks and transitioning into the in-game view. M5 R4, Survey 1 & 3
F19 Web Audio Engine (Sounds.txt, SoundEnviron.txt, HTTP Range & OPFS MPQ Caching) src/client/audio/sound-service.ts and src/client/assets/opfs-mpq.ts wiring server PlaySound events, skill/combat/UI actions, footsteps, per-level background music, and NPC speech audio to src/audio/manager.ts via HTTP 206 Range MPQ streaming (/diablo2/data/*.mpq) and optional browser OPFS MPQ caching. M5 R4, Survey 1, 2 & 3
F20 Hardening, Rate Limiting, Packet Inspector & .d2cap Replay Panel, and scripts/verify-play.ts Graceful disconnect handling to lobby with reason, C→S outbound packet rate limiter, in-browser Packet Inspector & .d2cap Replay Panel (src/client/inspector/packet-inspector.ts), and headless Chrome CDP verification script scripts/verify-play.ts testing the complete lobby, gameplay, audio, dual viewport, and Toolbar matrix. M5 R4, R5, Survey 1 & 3

Milestones

# Name Scope Dependencies Status
M1 M1-Netproto-Core-BNCS-MCP-Bot Phases N0–N1: tsconfig.netproto.json, scripts/extract-d2net-tables.ts (s2c-sizes.ts, huffman.ts), src/netproto/{core,transport,crypto,bncs,mcp,domain,flow,ts,index.ts}, tests/netproto/boundary.test.ts, unit tests, and initial scripts/d2-bot.ts (register, login, chars, create-char, games, create-game, join via mixed and wss resolvers, registering d2webbot1..3). none DONE (worker_m1_m2_1 3d592731-8e41-4232-8b8a-3c8ce484ed25)
M2 M2-D2GS-Protocol-Items-ClientWorld-Replay Phases N2–N3: src/netproto/d2gs/{compression,framing-s2c,framing-c2s,s2c/*,c2s/*,items/*,registry,session,adapter}.ts, headless src/client/world/**, scripts/d2-bot.ts (idle, record, --world >=60s live session), tests/fixtures/netproto/*.d2cap, and scripts/netproto-replay.ts --strict (0 unknown/opaque/error packets). M1 DONE (worker_m1_m2_1 3d592731-8e41-4232-8b8a-3c8ce484ed25, 949 records replayed with 0 unknown/opaque/errors)
M3 M3-Runtime-DRLG-TileAtlas-And-136Level-Parity Phase N4: createDrlgActSession (src/game/drlg/{drlg-dump,drlg-map}.ts), scripts/pack-tiles.ts (all LvlTypes.txt DT1s + 3 universal DT1s), src/client/map/{level-view,tile-atlas,map-worker,map-service}.ts, src/client/motion/{pathfind,predictor,interpolate}.ts, scripts/d2s-unlock.ts, and bot walk (0 UnitReassign) + 136-level coordinate parity audit. M1, M2 DONE (core DRLG/TileAtlas/motion/d2s-unlock/136-level parity by worker_m3_1 7ce7de0c-9422-4066-963f-d8a4fbbf4604; live bot walk/level audit in M5)
M4 M4-Browser-Client-Viewport-Toolbar-Combat-Lighting Phases N5–N6 + D1 & D5: src/client/settings/**, src/client/toolbar/**, src/client/view/{viewport-profile,scene-source,unit-drawables}.ts, src/scene/frontend/{lighting-presets,world-renderer,pack-loader,mouse-controller}.ts decoupling, src/client/{automap,audio,assets,inspector,session/rate-limiter}/**, src/i18n/lang.ts, and src/ui/** 1024×768 anchoring. M1, M2, M3 DONE (worker_m4_1 f4b38de0-c797-4090-adef-79975dd9303b, 61/61 tests passing)
M5 M5-UI-Panels-Automap-Lobby-Audio-Inspector Phases N7–N10: src/client/ui-model/hud-model.ts, src/client/input/command-mapper.ts, src/client/session/online-session.ts, src/client/main.ts, play.html, src/frontend/** live D2OnlineFlow lobby integration, scripts/d2-bot.ts live walk & level audit, and scripts/verify-play.ts. M4 DONE (worker_m5_1 9abb87be-ab83-4c74-a11a-6e7744dc79db, walk/audit-levels/verify-play 9/9 passed)
E2E E2E-Testing-Track Opaque-box requirement-driven E2E test infrastructure (TEST_INFRA.md) and 4-tier test suite (tests/e2e-netproto/tier1..4.test.ts covering all 20 features F1–F20 with >=100 Tier 1, >=100 Tier 2, >=20 Tier 3, >=10 Tier 4 test cases), publishing TEST_READY.md. M1–M5 DONE (test_writer_e2e_1 03a98a04-9653-4c1d-84e3-681be87b6f29, 236/236 E2E tests passing)
M6 M6-Final-E2E-Pass-And-Tier5-Hardening Phase 1: Pass 100% of E2E tests (Tiers 1–4) and all Acceptance Criteria (tsc, vitest, npm run build, boundary.test.ts, extract-d2net-tables.ts, d2-bot.ts, netproto-replay.ts --strict, verify-play.ts). Phase 2: Tier 5 white-box adversarial coverage hardening (tests/e2e-netproto/tier5-adversarial-coverage.test.ts 32/32 passed, 268/268 Tiers 1–5 passed) + clean git worktree check. M1–M5, E2E DONE (reviewer_m6_1 APPROVE, reviewer_m6_2 APPROVE, challenger_m6_1_gen2 APPROVE, challenger_m6_2 APPROVE, auditor_m6_1 CLEAN)
M7 M7-Round2-Victory-Audit-Remediation Remediate all 4 Round 1 Victory Auditor violations (B1: live FrontendAsyncHandlers lobby in play.html & bnet.html, deleting enterInGameDemo; B2: WebGL2 SpriteRenderer + TileAtlasGpuCache + LightGrid + Minimap on #view, deleting renderWorldAndAutomapOn2dCanvas; B3: canonical 167-opcode decodeD2gsS2cPacket + D2gsS2cFramer in OnlineSession with 0 UnknownS2c across all 4 .d2cap files + 9-Gate live scripts/verify-play.ts; B4: SSH ControlMaster .d2s unlock + live 5-Act 20-waypoint scripts/d2-bot.ts audit-levels tour across Acts 1–5 + map-service.ts Vite fix). M1–M6 DONE (worker_r2_1, worker_r2_2, worker_r2_3 DONE; reviewer_r2_1_gen2 APPROVE, reviewer_r2_2 APPROVE, challenger_r2_1_gen2 APPROVE, challenger_r2_2 APPROVE, auditor_r2_1 CLEAN, auditor_r2_2 CLEAN)

Interface Contracts

1. src/netproto/index.ts ↔ src/client/** & src/frontend/**

  • src/netproto/index.ts is the ONLY allowed entry point into src/netproto/ from outside src/netproto/ (except src/netproto/transport/* where needed by Node scripts).
  • Exports:
    • ByteStream, CloseReason, EndpointKind, EndpointResolver, createWsBridgeResolver, createTcpResolver, createMixedResolver, createMemoryStreamPair
    • TextCodec, createBrowserTextCodec, PacketTap, PacketTapEntry, ProtocolError, ClosedError, TimeoutError, Clock, systemClock
    • UnitType, UnitRef, Pt, Hand, ItemContainer, ItemData, ItemStat, ItemDataTables, UnitSnapshot, SkillLevel, CharSummary, GameSummary, RealmInfo, ChatEvent
    • ServerEvent (discriminated union: GameLoading, GameFlags, LoadAct, LoadComplete, UnloadComplete, GameLogout, RoomReveal, RoomHide, UnitAssign, UnitRemove, UnitMove, UnitReassign, UnitMode, SkillCast, StatSet, LifeMana, Experience, StateSet, StateEnd, ItemEvent, SkillList, ActiveSkill, Npc, WaypointMenu, QuestState, Party, Trade, Chat, PlaySound, Merc, Portal, Pong, Warden, SaveChunk, Opaque)
    • ClientCommand (discriminated union: Move, MoveToUnit, SkillAt, SkillOn, SelectSkill, Interact, TakeWarp, ItemPickup, ItemDrop, ItemToCursor, ItemPlace, ItemEquip, ItemUnequip, ItemSwap, BeltPut, BeltRemove, BeltUse, ItemUse, SocketItem, IdentifyItem, NpcInit, NpcCancel, NpcBuy, NpcSell, NpcRepair, NpcHeal, NpcGamble, NpcIdentifyAll, NpcResurrectMerc, HireMerc, AddStatPoint, AddSkillPoint, WaypointGo, TownPortal, ClickButton, Party, Hostile, Trade, Chat, OverheadChat, Resurrect, SwapWeapons, Ping, LeaveGame)
    • GameServerAdapter (state, send, onEvent, onClose, leave, stats)
    • OnlineConfig, D2OnlineFlow (connect, createAccount, login, enterChat, joinChannel, sendChat, onChatEvent, listRealms, realmLogon, listChars, createChar, deleteChar, upgradeChar, charLogon, listGames, getGameInfo, createGame, joinGame, close)

2. src/client/world/client-world.ts ↔ src/client/{map,motion,view,ui-model}/**

  • ClientWorld consumes ServerEvent via apply(ev: ServerEvent): void and exposes read-only snapshots of:
    • act, mapSeed, difficulty, hardcore, expansion, ladder, areaId, loading, selfId
    • self: SelfPlayerState (unitId, name, charClass, level, x, y, life, maxLife, mana, maxMana, stamina, maxStamina, gold, stashGold, experience, stats, skills, leftSkill, rightSkill, runMode, weaponSet, mercId)
    • units: ReadonlyMap<string, ClientUnit> (keyed by ${unitType}:${id})
    • containers: ClientItemContainers (inventory, equipment, belt, stash, cube, cursor, tradeSelf, tradePartner, merc, shop, ground)
    • revealedRooms: ReadonlySet<string> (${areaId}:${tileX}:${tileY})
    • waypoints: ReadonlySet<number>, quests: ReadonlyUint16Array, party, trade, chatLog, soundQueue

3. src/client/map/map-service.ts ↔ src/game/drlg/** & src/client/view/scene-source.ts

  • MapService.loadAct(act: number, mapSeed: number, difficulty: number, initialAreaId: number): Promise<LevelView>
  • MapService.revealRoom(areaId: number, roomTileX: number, roomTileY: number): Promise<LevelView>
  • LevelView: { act, mapSeed, difficulty, areaId, originX, originY, width, height, collision: Uint16Array, blocked: Uint8Array, floors, shadows, walls, roofs, warps, presetUnits, automap, rooms }

4. src/client/settings/client-settings.ts & ViewportProfile ↔ Toolbar, WorldRenderer, HudManager

  • ClientSettings stored under localStorage['d2web.settings.v1'] with strict schema validation.
  • ViewportProfile: { id: '800x600' | '1024x768', width: 800 | 1024, height: 600 | 768, barOffsetX: 0 | 112, barOffsetY: 0 | 168, panelOffsetY: 0 | 84 }.
  • LightingInputs decouples src/scene/frontend/lighting-presets.ts from GameEngine.
  • SceneSource decouples src/scene/frontend/world-renderer.ts from GameEngine.

Code Layout

  • src/netproto/: Isolated, zero-dependency network & protocol package (core/, transport/, crypto/, bncs/, mcp/, d2gs/, domain/, flow/, ts/, index.ts).
  • src/client/: Packet-driven online client (world/, map/, motion/, input/, view/, ui-model/, settings/, toolbar/, automap/, audio/, assets/, inspector/, session/, main.ts).
  • play.html: Online client HTML entry point with top DOM Toolbar and dual-viewport WebGL2 + 2D HUD canvas stage.
  • scripts/extract-d2net-tables.ts: Deterministic 1.13c D2Net.dll & Fog.dll table generator.
  • scripts/d2-bot.ts: Headless Node CLI bot (register, login, chars, create-char, games, create-game, join, idle, record, walk, audit-levels).
  • scripts/netproto-replay.ts: Offline .d2cap JSONL capture replay & strict coverage verifier.
  • scripts/pack-tiles.ts: Seed-independent DT1 tile library & DRLG metadata packer.
  • scripts/d2s-unlock.ts: Safe offline d2webbot* .d2s waypoint & act-progression unlocker with timestamped backup.
  • scripts/verify-play.ts: Headless Chrome CDP E2E verifier for play.html across 800×600 & 1024×768 viewports and all Toolbar controls.
  • tests/netproto/, tests/client/, tests/e2e-netproto/: Unit, boundary, golden replay, and 5-tier E2E test suites.