diablo2-web/src/client
troytt 28496d6889 Merge remote-tracking branch 'origin/main' 2026-10-01 13:33:09 +00:00
..
assets refactor(client): remove leftover single-player client code 2026-10-01 06:03:55 +00:00
audio refactor: split into isolated common/netproto/server/client/baker modules 2026-10-01 00:10:18 +00:00
automap refactor: split into isolated common/netproto/server/client/baker modules 2026-10-01 00:10:18 +00:00
frontend fix(client): return to the login screen with a 1.13c reason on session loss 2026-10-01 12:02:30 +00:00
i18n feat(client): server-driven vendor, repair, stash-gold and gamble UI 2026-10-01 11:09:53 +00:00
input refactor(client): remove leftover single-player client code 2026-10-01 06:03:55 +00:00
inspector feat(netproto,client): implement pure-browser D2 1.13c online client (N0-N10) 2026-09-30 04:41:08 +00:00
map fix(client): render on the 1.13c 32x16 sub-tile lattice and pick the LevelView by server position (#539) 2026-10-01 10:13:09 +00:00
motion feat(netproto,client): implement pure-browser D2 1.13c online client (N0-N10) 2026-09-30 04:41:08 +00:00
render refactor(client): remove leftover single-player client code 2026-10-01 06:03:55 +00:00
scene fix(client): render on the 1.13c 32x16 sub-tile lattice and pick the LevelView by server position (#539) 2026-10-01 10:13:09 +00:00
session fix(client): return to the login screen with a 1.13c reason on session loss 2026-10-01 12:02:30 +00:00
settings refactor: split into isolated common/netproto/server/client/baker modules 2026-10-01 00:10:18 +00:00
sw feat(client,baker): implement incremental SHA-256 Service Worker asset caching 2026-10-01 01:09:17 +00:00
toolbar fix(toolbar): enforce single-row flex layout and remove server host control 2026-10-01 09:47:19 +00:00
ui feat(client): display semantic asset resource type instead of filename during boot 2026-10-01 13:28:45 +00:00
ui-model feat(client): server-driven vendor, repair, stash-gold and gamble UI 2026-10-01 11:09:53 +00:00
view feat(view): stretch game stage to fit browser viewport across resolutions with 4:3 pillarbox 2026-10-01 13:14:38 +00:00
world Merge branch 'fix/issue-539-spawn' (#539) 2026-10-01 11:25:14 +00:00
README.md docs: add dedicated module READMEs and rewrite root README with single-client guide 2026-10-01 13:31:15 +00:00
main.ts Merge branch 'feat/asset-type-display': display semantic asset resource type instead of filename during boot 2026-10-01 13:29:48 +00:00

README.md

src/client — 纯浏览器 WebGL2 渲染与交互客户端

src/client 是 Diablo II: Lord of Destruction (v1.13c) 的纯浏览器客户端实现,对标原版 D2Client.dll、D2Gfx.dll、D2Win.dll、D2Launch.dll 与 D2Sound.dll。

在**单客户端模式(Single-Client Mode)**下,本模块仅通过 src/netproto 的 WebSocket 桥接协议与远端原生 C++ PvPGN + D2GS (1.13c) 通信,在浏览器端完成种子驱动的 DRLG 地图重建、WebGL2 等距视角渲染、客户端移动预测与全套经典 UI 交互。

1. 模块职责与架构边界

  • 唯一 HTML 入口:play.html \rightarrow src/client/main.ts。
  • TypeScript 工程约束(tsconfig.client.json):
    • lib: ["ES2022", "DOM", "DOM.Iterable"], types: []。
    • 严禁依赖 src/server 或 src/baker,严禁导入任何 Node.js 内置模块(fs, path, net, Buffer 等)。
    • 仅依赖 src/common(DRLG 算法、格式解析器、数据表定义)与 src/netproto(协议门面与 D2gsServerAdapter)。

2. 目录结构

src/client/
├── main.ts          # 客户端主入口:组装 WebGL2 画布、工具栏、前端战网状态机、OnlineSession 与 60fps 渲染循环
├── session/         # OnlineSession 会话协调器与 C2S 发包速率限制器 (OutboundRateLimiter)
├── world/           # ClientWorld:由 ServerEvent 驱动的客户端权威状态镜像 (玩家/怪物/NPC/地面物品/投射物/传送门)
├── map/             # 种子驱动的客户端 DRLG 地图服务 (MapService, LevelView, TileAtlas GPU 瓦片加载)
├── motion/          # 本地玩家移动预测 (LocalMovementPredictor)、远端实体插值器与 A* 寻路 (pathfind)
├── render/          # WebGL2 渲染管线 (SpriteRenderer, TileAtlasGpuCache, EntityArtLoader, 投射物/覆盖层/地面物品渲染)
├── scene/           # 场景摄像机、屏幕/世界等距坐标转换与分幕环境光照预设 (lighting-presets)
├── ui/              # 游戏内 HUD 渲染与交互 (HudManager, 底部状态栏, 小地图 Automap, 7 大面板, D2 点阵字体渲染)
├── ui-model/        # UI 纯视图状态模型 (HudModel, 属性加点/技能树/背包网格/商店/赫拉迪克方块交互逻辑)
├── frontend/        # 战网前置界面 (FrontendRenderer:Gateway 选择、账号登录/注册、8 角色选择、建房/加房大厅)
├── toolbar/         # 顶部 32px 窄条工具栏 (FPS/Ping、网络抓包开关、设置弹窗、全屏与音量控制)
├── settings/        # 客户端持久化设置存储 (SettingsStore / client-settings.ts,管理 WS Bridge 地址与显示偏好)
├── inspector/       # 实时网络封包检查器 (PacketInspector) 与 .d2cap 录制/回放面板
├── sw/              # Service Worker (sw.ts) + CacheUpdater:基于 SHA-256 清单的离线资产增量缓存
├── audio/           # Web Audio API 音效与背景音乐服务 (SoundService)
└── assets/          # OPFS (Origin Private File System) 本地 MPQ 导入与缓存支持

3. 核心数据流与子系统详解

3.1 单客户端连接与会话生命周期 (frontend/, session/, world/)

  1. 战网前置流程 (FrontendRenderer + D2OnlineFlow):
    • 启动后加载 /act-packs/frontend/frontend-ui.json,渲染原版风格登录界面、角色选择界面(支持 7 职业动态纸娃娃预览)与战网大厅(Create Game / Join Game 房间列表)。
    • 通过 wsBridgeUrl(默认 /d2net,可通过 URL 参数 ?wsBridge=... 或顶部工具栏 Settings 面板配置)依次握手 BNCS (/bnet) 与 MCP (/realm)。
  2. 进入游戏 (OnlineSession + ClientWorld):
    • 拿到 MCP 颁发的 GameHash 与 GameToken 后,连接 D2GS (/game) 并创建 D2gsServerAdapter。
    • OnlineSession 订阅全部 37 种 ServerEvent,实时更新 ClientWorld 中的本地玩家属性、背包/穿戴物品、周围怪物/NPC 状态、地面掉落与任务/小站进度。

3.2 种子驱动的客户端 DRLG 地图重建 (map/)

原生 D2GS 不会在网络上传输完整的瓦片地图数据,仅在 0x03 (LoadAct) 包中下发 32 位 mapSeed 与当前 areaId(并伴随 0x07/0x08 房间加载通知):

  • MapService 在收到 LoadAct 后,使用 src/common/drlg 与服务端完全一致的 1.13c DRLG 算法,根据 mapSeed 在浏览器端毫秒级还原整张地图的 Floor / Wall / Roof / Collision 网格。
  • 从 /act-packs/tiles/ 按需流式加载对应 LvlType 的 WebP/PNG 瓦片图集并上传至 TileAtlasGpuCache。

3.3 移动预测与网络平滑 (motion/)

  • LocalMovementPredictor:玩家左键点击地面或按住移动时,本地立即沿 A* 路径按角色 Velocity 推進预测坐标,同时由 OutboundRateLimiter 按 250ms 节流向 D2GS 发送 0x01 (Walk) / 0x03 (Run)。当收到服务端 0x15 (ReassignPlayer) 强制拉回包时平滑纠正坐标。
  • RemoteEntityInterpolator:将 D2GS 下发的离散实体移动目标点 (0x0F/0x10, 0x67/0x68) 转化为 60fps 连续内插位移与 8/16 方向朝向切换。

3.4 WebGL2 等距视角渲染器 (render/)

  • 深度排序 (Painter's Algorithm + Sub-tile Sorting):将地面瓦片、阴影、地面物品、角色/怪物多部位 DCC/DC6 纸娃娃图层 (EntityArtLoader)、投射物 (missile-overlay-renderer) 与悬挑屋顶按等距子格深度 (X + Y) 严格排序合批绘制。
  • 完整 HUD 面板 (ui/):支持角色属性面板 (C/A)、背包与穿戴 (I/B)、技能树与快捷技能选择 (T/S)、任务日志 (Q)、佣兵面板 (O)、小站传送菜单、NPC 商店/赌博/修理、储物箱与赫拉迪克方块以及 Tab 小地图 (Minimap)。

4. 常用开发与验证命令

# 启动本地开发服务器 (默认监听 http://127.0.0.1:5173/play.html)
npm run dev

# 单独对 src/client 进行严格类型检查
npx tsc -p tsconfig.client.json --noEmit

# 构建生产环境客户端静态包
npm run build