diff --git a/README.md b/README.md index 630d13f..5385568 100644 --- a/README.md +++ b/README.md @@ -1,327 +1,248 @@ -# d2web +# Diablo II: Lord of Destruction (v1.13c) — Web Port -从零实现的**暗黑破坏神 II(v1.13c)Web 引擎**(纯 TypeScript + Vite + WebGL2,**零运行时依赖**),在浏览器里读取 -用户自备的经典版 D2 归档(MPQ)或离线烘焙包,完整还原等距地图与 Glide 动态光影、原版等距精灵自动地图(Automap / Minimap)、七大职业 16 层角色合成、221 个原版技能、流式怪物生态、1.13c 宝藏等级(TC)掉落与未鉴定辨识系统、以及城镇 NPC 交易/赌博/修理交互。 +## 1. 项目概述 -- **仓库不含任何暴雪资源**:没有 `.mpq` / `.dc6` / `.dt1` / 地图图集 PNG;原版数据要自己放进 `samples/d2/`。 -- **代码可复现一切**:格式解码、DRLG 地图构建、资源包烘焙、角色与特效合成都在这份代码里,脚本可重跑。 -- 路线图、实现细节、验证方法论与未完成项在 [`ROADMAP.md`](ROADMAP.md)(README 只做总览与部署使用)。 +本项目是 **《暗黑破坏神 II:毁灭之王》(Diablo II: Lord of Destruction v1.13c)** 的高精度 Web 移植实现。项目严格遵循原版 1.13c 反编译二进制汇编(`D2Common.dll`、`D2Client.dll`、`D2Game.dll`、`D2Net.dll`、`Bnclient.dll`、`D2MCPClient.dll`、`Fog.dll`)与官方 MPQ 数据表(`Levels.txt`、`LvlTypes.txt`、`SuperUniques.txt`、`Skills.txt`、`TreasureClassEx.txt` 等)作为唯一事实基准(Ground Truth): -## 总览 +- **1:1 原生网络协议兼容**:完整实现 BNCS(战网登录/聊天,端口 `6112`)、MCP(Realm 角色管理/建房加房,端口 `6113`)与 D2GS(Huffman 压缩帧、167 个 S2C 操作码、C2S 指令及物品比特流,端口 `4000`),浏览器客户端可通过轻量 TCP-to-WebSocket 桥直接连入原版 C++ **PvPGN + D2GS (1.13c)** 战网服务器。 +- **种子驱动的确定性 DRLG 地图重建**:1:1 复刻 `D2Common.dll` 64 位进位乘法随机数 (`0x6FDAA9E0`) 与三大 DRLG 拓扑算法(Preset 预设、Maze 地牢迷宫、Outdoors 野外生成),客户端仅凭 D2GS 下发的 32 位 `mapSeed` 即可在浏览器端还原与 C++ 服务端逐格一致的瓦片地图与碰撞网格。 +- **WebGL2 高性能等距渲染与离线资产管线**:通过 Node.js 离线烘焙管线 (`src/baker`) 将原版 MPQ 中的 DT1/DS1 瓦片、DC6/DCC 角色与怪物动画、COF 复合图层、PL2 调色板与 TBL 字符串表预编译为静态图集与二进制包,配合 Service Worker 增量缓存与 WebGL2 合批渲染实现 60fps 流畅体验。 +- **严格的模块化架构隔离**:全仓按原版 DLL 职责划分为五大核心代码模块与独立工具集,由多套独立 `tsconfig.*.json` 与架构边界测试(`tests/arch/boundaries.test.ts`)强制保障零跨层污染。 -| 能力 | 说明 | -| --- | --- | -| **等距地图与动态光影** | DS1 + DT1 投影(2:1 dimetric,格 80×40 px),地板 / **阴影层(`type 13`)** / 墙体与场景物件(按画家序交错深度排序) / **屋顶**(进屋自动渐隐)多层绘制;SplitMix64 空间哈希 + `RarityFrameIndex` 加权选瓦片变体;**1.13c 原版 Glide 动态光照系统**(子格视线遮挡、玩家火炬、飞行投射物/爆炸动态光源、火把/火盆/小站/神殿环境光源、昼夜流转与顶部 9 档光照预设切换);动态瓦片序列与错峰物件动画 | -| **碰撞与 A* 寻路系统** | 每格 5×5 个 sub-tile(16×8 px 各向异性)标志位(全层 OR 合并,含 `type 13` 阴影层及通用 `Blank.dt1` / `InvisWal.dt1` / `Warp.dt1` 阻挡规则),虚空越界格子全封闭保护;角色与怪物按真实阻挡子格计数梯度脱困;支持鼠标点击 A* 自动寻路移动、攻击、拾取掉落、NPC 交谈与跨图 | -| **真实关卡与世界连通** | 已烘焙 **365 张地图**,覆盖 5 幕全部 **136 个关卡 ID**(35 个预置关卡 `65` 变体 + **70 个随机迷宫 `210` 变体 + 31 个野外关卡 `90` 变体**,1:1 移植自 D2MOO / `D2Common.dll` DRLG 算法);支持鼠标点击楼梯/洞穴入口(Warp / Entrance)切图、野外边界无缝跨越、**双向回城传送门(Town Portal,精确对齐 DS1 Object #33 城镇落点)**与跨幕**小站(Waypoint)传送网络** | -| **七大职业与角色合成** | 完整支持亚马逊(Amazon)、刺客(Assassin)、野蛮人(Barbarian)、德鲁伊(Druid)、死灵法师(Necromancer)、圣骑士(Paladin)、女巫(Sorceress)七大职业的 DCC + COF 16 层组件装配与 8 方向动画,支持顶部工具栏实时热切换职业并自动装配初始专属套装与储物箱 | -| **全技能系统(221 技能)** | 210 个各职业技能(7 职业 × 3 系 × 10 技能,已全部通过 M1–M30 全职业终极质量门禁)与 11 个通用技能(普攻/踢击/投掷/反召唤/辨识与回城卷轴和书等),严格复现 1.13c 汇编公式、协同加成(Synergies)、`AnimData.d2` 关键帧事件、149 项原版投射物/爆炸图集(零黑边加法混合)、558+ 项施法/状态/光环(含 33 个圣骑士光环)叠加特效、死灵/德鲁伊召唤物与刺客陷阱系统 | -| **怪物生态、掉落鉴定与商人交易** | 基于 `Levels.txt` / `MonStats.txt` / `SuperUniques.txt` 流式房间激活(`MonsterStreamingManager`),还原普通怪、头目(Champion `[2,4]`)、金怪(Unique `[3,6]` 随从)及全幕固定暗金 Boss(含秘密母牛关地狱母牛等 78 套实体动画包),支持实时调节怪物密度与精英倍率;完整实现 1.13c 多难度宝藏等级(TC)递归掉落、16×8 子格防卡死扇形散落、原版 `flp*.dc6` 抛物线弹跳与星光闪烁、魔法/稀有/套装/暗金**未鉴定(Unidentified)掉落与卷轴/书辨识**、以及城镇 NPC 原版对话菜单与**商人买卖/赌博/修理(`buysell.dc6`)**完整闭环 | -| **原版等距自动地图(Automap & Minimap)** | 基于 `D2Client.dll` (`0x6fb0f080..0x6fb12c28`) 逆向复现,烘焙 8 张原版 DC6 自动地图图集(`MaxiMap` / `Act2Map` / `Act4Map` / `ExTnMap` 全尺寸与半尺寸),按 `floors -> walls -> objects -> extras` 四层等距投影渲染;支持**右上角缩略小地图(`nDivisor=20`)**与**全屏自动地图(`nDivisor=10`)**双模式(面板开启自动避让/偏移)、八向距离迷雾揭露、12 段闭合多边形方向十字标(玩家/NPC/召唤物/Boss)、双向传送门与出口 `Font6` 标签及 `F9` 透明度 / `F10` 标签开关 | -| **完整 UI / HUD 交互** | 800×600 原版底栏控制台(流体红蓝血球与中毒覆盖、按技能树行序排列的 Speedbar 技能弹窗与 `F1~F8` 绑定、可展开腰带)、左/右宽屏 400px 停靠面板(背包与装备纸娃娃、角色属性面板、3 系技能树、私人储物箱、赫拉迪克方块及合成按钮、商人/赌博面板、羊皮纸任务日志、小站传送菜单)、严格对齐 `.tbl` 的中英双语词缀 Tooltip、动态手套/交易/修理/辨识专属鼠标光标、鼠标悬浮与 `Alt` 地面物品高亮标签、以及 `/players 1-8` 控制台指令 | -| **资源包(离线烘焙)** | 索引色与 32-bit RGBA PNG 图集页(≤2048²,PLTE + tRNS 取自各幕 `pal.pl2`)+ `.r8` 紧凑像素包 + `scene.json`(绘制列表、阴影层、Automap 层、碰撞 RLE、出生点、怪物与对象元数据)+ `manifest.json` | -| **按需读归档** | 也可不烘焙,直接用 HTTP Range 只拉需要的 MPQ 字节当场解码(`?live=1`,慢,作为回退路径) | -| **多维场景与调试选择器** | 顶部工具栏支持实时切换:职业 → 章节 → 场景 → 细分场景 → 光照预设(9 档) → 怪物密度(`0.5x~8x`) → 精英倍率(`0.5x~All Elite`);中文场景名见 `src/game/level-names-zh.ts` | +--- -**开发进展**:当前底层引擎、1:1 D2MOO DRLG 迷宫与野外地图生成、Glide 动态光影、1.13c 原版等距精灵自动地图/小地图、七大职业 221 技能、流式怪物与精英群生态、1.13c 掉落/未鉴定辨识/城镇商人交易以及全套 UI 面板已全面打通。下一步将继续推进 `.d2s` 官方二进制存档双向互通与可破坏场景物件深入演进,详见 [`ROADMAP.md`](ROADMAP.md)。 +## 2. 模块概述与 README 链接 -### 代码结构 +项目源码按职责边界严格拆分为以下模块,点击各模块的 `README.md` 可查看详细的子目录结构、核心算法与验证命令: -``` -src/mpq/ MPQ v1 容器:hash/block 表、Storm 加密、分扇区编解码、PKWARE implode/explode、ADPCM/Huffman 音频、Range 读取 -src/formats/ dc6 / ds1 / dt1 / pal / pl2 / cel / pcx / tbl / sprite / dcc / cof / animdata / automap-table / bitstream -src/game/ 等距场景与碰撞、关卡拓扑与跨图、DCC+COF 角色合成、怪物流式生成、1.13c 掉落/鉴定/商人系统、确定性 RNG - drlg/ 1:1 移植自 D2MOO / D2Common.dll 的 DRLG 地图生成管线(迷宫 drlg-maze、野外 drlg-outdoors/outplace/outwild、预置房间与瓦片替换) - engine/ 1.13c 真实战斗管线、AST 公式求值器、Glide 动态光照栅格(light-grid / environment)、投射物引擎、光环扫描与召唤物管理 - skills/ 221 个技能的具体实现模块与注册表(uni / ama / sor / nec / pal / bar / dru / ass) -src/ui/ 完整 UI / HUD 模块:原版等距自动地图与小地图(minimap)、背包、属性面板、技能树、控制底栏、小站、储物箱、方块、商人面板、任务日志、字体、鼠标指针 -src/render/ WebGL2 渲染器(多图集、动态光照着色、加法/常规混合、视口裁剪;含 missiles-meta 与 overlays-meta) -src/scene/ 页面级装配(act-scene 主游戏循环、A* 鼠标控制器、跨图过渡;资源包优先,失败回退到直读归档) -src/data/ 1.13c 权威内嵌数据表(canonical-drop-data / canonical-tbl-strings / canonical-vendor-data / canonical-quest-data / skills-catalog / gitea-skill-issues.json) -scripts/ 资源包多进程烘焙(地图/UI/动画/实体/投射物/叠加特效)、格式/数据/部署校验、无头浏览器全量走查、夹具生成 -*.html 入口页面:index.html(双语选择门户)、acts.html / acts-zh.html / acts-en.html(中英战役主页面)、bnet.html(原版片头与战网完整流程) +| 模块路径 | 对标原版组件 | 运行环境与边界约束 | 核心职责简述 | 详细文档 | +| :--- | :--- | :--- | :--- | :--- | +| [`src/common`](./src/common) | `D2Common.dll` `Storm.dll` `D2Lang.dll` | 纯 TypeScript (`ES2022`),零 DOM / 零 Node.js 依赖 | MPQ 与原生二进制格式解析器 (DC6/DCC/DT1/DS1/COF/PL2/TBL)、`D2DataRegistry` 数据表中心、1.13c DRLG 随机地图生成算法、64 位 `D2Rng` 与烘焙校验契约 (`pack-contract`) | [src/common/README.md](./src/common/README.md) | +| [`src/netproto`](./src/netproto) | `D2Net.dll` `Bnclient.dll` `D2MCPClient.dll` `Fog.dll` | 纯协议栈模块,零外部模块依赖,唯一入口 `src/netproto/index.ts` | BNCS (`6112`) / MCP (`6113`) / D2GS (`4000`) 二进制协议编解码、XSHA-1 与 CheckRevision 认证、Fog.dll Huffman 解压、167 个 S2C 操作码解析、物品比特流与 WebSocket/TCP 传输层抽象 | [src/netproto/README.md](./src/netproto/README.md) | +| [`src/client`](./src/client) | `D2Client.dll` `D2Gfx.dll` `D2Win.dll` `D2Launch.dll` | 纯浏览器客户端 (`DOM` + `WebGL2`),零 Node / 零 `server` / 零 `baker` 依赖 | 唯一页面入口 `play.html`、战网登录/选人/大厅前端界面、`OnlineSession` 与 `ClientWorld` 状态镜像、种子驱动的实时 DRLG 地图重建、移动预测与内插、WebGL2 渲染器、全套经典 HUD 面板与抓包检查器 | [src/client/README.md](./src/client/README.md) | +| [`src/server`](./src/server) | `D2Game.dll` | 纯确定性模拟 (`ES2022` + `WebWorker`),禁 DOM / 禁 Node / 禁非确定性随机与时钟 | 25fps (40ms/tick) 权威游戏循环、1.13c 战斗伤害与抗性管线、7 职业 221 个技能执行器、投射物与光环引擎、怪物 AI 与房间流式激活、TC 掉落管线与 `.d2s` 存档读写 | [src/server/README.md](./src/server/README.md) | +| [`src/baker`](./src/baker) | 离线资源构建管线 | 纯 Node.js CLI 环境 (`types: ["node"]`),禁 DOM / 禁 `client` / 禁 `server` | 从原版 1.13c MPQ 归档中提取并烘焙瓦片图集 (`tiles`)、角色/怪物/NPC 实体 (`entities`)、投射物 (`missiles`)、覆盖层 (`overlays`)、HUD/前端 UI、动画表 (`animdata`) 与 SHA-256 资产清单 (`asset-manifest.json`) | [src/baker/README.md](./src/baker/README.md) | +| [`tools/`](./tools) | 开发者与 QA 工具集 | Node.js / Playwright CLI | 无头协议测试机器人 (`d2-bot.ts`)、`.d2cap` 抓包离线重放器 (`netproto-replay.ts`)、`.d2s` 存档全解锁工具 (`d2s-unlock.ts`)、全谱系 136 关卡浏览器审计 (`audit-levels-browser.ts`) 与 DRLG 差分对比工具 | [tools/README.md](./tools/README.md) | + +### 模块依赖拓扑图 + +```text + ┌──────────────────┐ ┌────────────────────┐ + │ src/common │ │ src/netproto │ + │ (Pure TS Base) │ │ (1.13c Wire Stack) │ + └────────┬─────────┘ └─────────┬──────────┘ + │ │ + ┌─────────┼──────────────────┐ │ + ▼ ▼ ▼ ▼ +┌─────────────┐ ┌──────────────┐ ┌─────────────────────────┐ +│ src/baker │ │ src/server │◄──┤ src/client │ +│ (Node CLI) │ │ (D2Game Sim) │ │ (Browser WebGL2 Client) │ +└─────────────┘ └──────────────┘ └─────────────────────────┘ + *(注:src/client 与 src/server 之间完全解耦,仅各自依赖 src/common 与 src/netproto)* ``` -## 美术资源与图集资产(Assets) +--- -项目在离线烘焙和客户端运行时划分了清晰的美术资产目录结构,所有视觉素材均可从 1.13c 原版 MPQ 自动导出与打包: +## 3. 单客户端模式使用方法(Single-Client Mode Guide) -### 1. UI 界面图集、自动地图图集与面板切片 (`public/ui/` & `public/assets/ui/automap/`) +在**单客户端模式**下,Web 前端作为纯粹的 1.13c 在线客户端运行([`play.html`](./play.html)),所有战网账号认证、角色存档、房间管理与游戏权威战斗逻辑均由远端原版 **PvPGN (`bnetd` + `d2cs` + `d2dbs`) + D2GS (v1.13c)** 服务器承载。 -- **综合图集 (Atlases)**: - - `items-atlas.png`:装备与物品大图集,同时包含背包/储物箱物品图标(`invfile`)与地面 2:1 等距掉落精灵(`flippyfile` / `flp*.dc6`),覆盖所有武器、防具、饰品(戒指、护身符、珠宝)、符文、药水、卷轴与金币堆,完整支持大/中/小护身符与首饰的原版 `VarInvGfx` 多视觉外观变体。 - - `quests-atlas.png`:1–5 幕全部任务状态图标图集(未触发、进行中、已完成)。 - - `skill-tree-tabs.png`:七大职业技能树的 3 系专属垂直选项卡图集(激活/未激活切片)。 -- **1.13c 原版等距自动地图精灵图集 (`public/ui/automap-*.png` & `public/assets/ui/automap/`)**: - - 完整烘焙原版 `data\global\ui\AUTOMAP\` 下的 8 张 DC6 精灵表: - - 全屏自动地图(`nDivisor = 10`):`MaxiMap.png`(Slot 0 基础图集)、`Act2Map.png`(Slot 1 第二幕)、`Act4Map.png`(Slot 2 第四幕)、`ExTnMap.png`(Slot 3 资料片第五幕)。 - - 右上角缩略小地图(`nDivisor = 20`):`MaxiMapS.png`、`Act2MapS.png`、`Act4MapS.png`、`ExTnMapS.png`。 -- **经典功能面板背景与控件**: - - `ctrlpnl-800.png`:800×600 原版底栏控制台面板(包含左右技能槽底框、经验槽、腰带槽)。 - - `inv-sheet.png` / `inv-tab-0.png` / `inv-tab-1.png` / `goldcoinbtn.png`:装备纸娃娃界面与 10×4 背包网格、主副手武器切换 Tab、金币丢弃按钮。 - - `char-sheet.png`:角色属性与抗性详情面板。 - - `stash-bg.png`:营地私人储物箱面板(`TradeStash.dc6`,含顶部标题凹槽与金币槽)。 - - `cube-bg.png` / `miniconvert.png`:赫拉迪克方块(3×4 合成面板)与原版转化(Transmute)按钮。 - - `vendor-bg.png` / `vendor-tabs.png` / `buysellbtn.png`:原版 `buysell.dc6` NPC 商人交易/赌博界面、分类选项卡与买/卖/修理交互按钮。 - - `boxpieces.png` / `focus16.png`:原版 1.13c NPC 对话弹出菜单边框切片与焦点指示动画。 - - `quest-bg.png` / `quest-tabs.png`:羊皮纸任务日志背景与 1–5 幕选项卡。 - - `waypoint-bg.png` / `waypoint-tabs.png` / `waypoint-icons.png`:传送点菜单、各幕选项卡与石碑传送状态图标。 -- **指示器与动态视觉元素**: - - `globe-life.png` / `globe-mana.png` / `globe-poison.png`:经典流体红蓝血球与中毒、法力燃烧覆盖层。 - - `cursor.png` / `cursor-hand.png`:暗黑手套鼠标指针图集(包含空闲/点击状态机、商人买/卖/修理专用交易光标与辨识卷轴目标十字光标)。 - - `border-left.png` / `border-right.png` / `overlap-left.png` / `overlap-right.png`:宽屏自适应下的左右面板停靠石柱边框与过渡阴影。 - - `minipanel.png` / `minipanel-btns.png` / `popbelt.png` / `runbutton.png` / `menubutton.png` / `level-btn.png` / `skillpoints.png`:菜单微型按钮、升级加点按钮、跑步状态切换钮等。 -- **原版位图字体 (`public/ui/fonts/`)**: - - 提供 6 套暗黑 II 经典字体纹理:`font6.png`、`font8.png`、`font16.png`、`font30.png`、`fontexocet10.png`、`fontformal12.png`。 +完整跑通单客户端模式包含以下三个核心步骤: -### 2. 技能树背景、技能图标与法术投射物/叠加特效图集 (`public/skills/`、`public/missiles/`、`public/overlays/`) +--- -- **全职业技能树背景切片 (`public/skills/bg__.png`)**: - - 共 21 张 256×432 px 原版复古羊皮纸技能树背景原画,覆盖 7 大职业各自的 3 大技能分支: - - 亚马逊:`bg_ama_0.png`(标枪与长矛)、`bg_ama_1.png`(被动与魔法)、`bg_ama_2.png`(弓与十字弓) - - 刺客:`bg_ass_0.png`(武学艺术)、`bg_ass_1.png`(影子训练)、`bg_ass_2.png`(陷阱) - - 野蛮人:`bg_bar_0.png`(战吼)、`bg_bar_1.png`(战斗专家)、`bg_bar_2.png`(战斗技能) - - 德鲁伊:`bg_dru_0.png`(元素)、`bg_dru_1.png`(变形)、`bg_dru_2.png`(召唤) - - 死灵法师:`bg_nec_0.png`(召唤术)、`bg_nec_1.png`(毒素与白骨)、`bg_nec_2.png`(诅咒) - - 圣骑士:`bg_pal_0.png`(战斗技能)、`bg_pal_1.png`(攻击灵气)、`bg_pal_2.png`(防御灵气) - - 女巫:`bg_sor_0.png`(火焰法术)、`bg_sor_1.png`(闪电法术)、`bg_sor_2.png`(冰冷法术) -- **技能图标资产 (`public/skills/icon_*.png` 与 `public/ui/`)**: - - 包含 221 个技能的 48×48 px 原版技能图标,细分为普通态(`icon_.png`)与激活/按下高光态(`icon__active.png`)。 - - 涵盖七大职业全部 210 个技能,以及 11 个通用技能(普通攻击、踢击、投掷、反召唤、辨识/回城卷轴与书、迪勒瑞姆变身等)。 - - 动态普通攻击图标:根据当前主手装备自动切换拳头图标(`icon_0_fist.png`)或武器剑图标(`icon_0_sword.png`),并具备投掷(`icon_2.png`)与反召唤(`icon_3.png`)专用图标。 -- **法术投射物与爆炸图集 (`public/missiles/` & `samples/d2-packs/missiles/`)**: - - 由 `scripts/pack-missiles.ts` 结合 `Missiles.txt` 的 `CelFile` 字段从原版 DCC 解包烘焙的 **149 套** 32-bit RGBA PNG 精灵图集与同名 `.json` 帧锚点元数据。 - - 对魔法投射物(`Trans: 1`)严格执行暗部底色零黑边过滤并在 WebGL 中以加法混合(`blendMode: 'additive'`)渲染,覆盖火焰弹/火球/陨石/九头蛇、冰弹/冰风暴/暴风雪/冰封球、充能弹/闪电链、牙齿/骨矛/骨灵、祝福之锤、标枪/箭矢与全部次生爆炸特效。 -- **施法叠加层、光环与传送门特效图集 (`public/overlays/` & `samples/d2-packs/overlays/`)**: - - 由 `scripts/pack-overlays.ts` 结合 `Overlays.txt` 从原版 DCC 解包烘焙的 **558+ 套**特效图集。 - - 涵盖各系施法前摇光效(Cast Overlays)、全部 33 个圣骑士进攻/防御光环与通用光环脚底环绕特效、死灵法师诅咒与野蛮人战吼头顶标记、德鲁伊变形/充能球、刺客聚气球,以及双向回城传送门的开启(`OP` 15 帧)与常驻(`ON` 15 帧)双层混合动画。 +### 3.1 第一步:在 D2GS / PvPGN 机器上设置 TCP-to-WebSocket 桥 -### 3. 角色与怪物实体动画包 (`samples/d2-packs/entities/`) +由于浏览器只支持 WebSocket (`ws://` / `wss://`) 而不支持直接建立原始 TCP Socket,需要在运行 PvPGN 与 D2GS 的服务器(或同内网网关机)上部署 **`websockify` + Nginx** 反向代理,将浏览器的三路 WebSocket 子路径桥接到对应的原生 TCP 端口: -- **七大职业模型**: - - 亚马逊(`char-am`)、刺客(`char-ai`)、野蛮人(`char-ba`)、德鲁伊(`char-dz`)、死灵法师(`char-ne`)、圣骑士(`char-pa`)、女巫(`char-so`)。 - - 由 16 个装备图层复合装配,解包出行走(`wl`)、跑动(`rn`)、待机(`nu`)、近战/远程攻击(`a1`/`a2`)、施法(`sc`)、受击(`gh`)、死亡(`dt`/`dd`)等 8 方向完整序列。 - - 伴随同名 `.r8` 紧凑二进制像素包,用于在 WebGL/Canvas 中零拷贝极速解码渲染。 -- **怪物与召唤物实体模型(共 78 套实体包)**: - - 包含沉沦魔(Fallen)、骷髅(Skeleton)、僵尸(Zombie)、血鸟(Blood Raven)、格瑞斯华尔德(Griswold)、安达利尔(Andariel)、督瑞尔(Duriel)、墨菲斯托(Mephisto)、暗黑破坏神(Diablo)、巴尔(Baal)、秘密母牛关地狱母牛(Hell Bovine,`hellbovine`)等各幕常规怪物、固定暗金头目(SuperUniques)及其随从、死灵/德鲁伊/亚马逊/刺客召唤物的完整动画包与 `.r8` 调色板像素数据。 +```text +浏览器 Web 客户端 (src/netproto WsStream) + │ + ├─ wss:///d2net/bnet ──► Nginx :443 ──► websockify 127.0.0.1:7001 ──► PvPGN bnetd (TCP :6112) + ├─ wss:///d2net/realm ──► Nginx :443 ──► websockify 127.0.0.1:7002 ──► PvPGN d2cs (TCP :6113) + └─ wss:///d2net/game ──► Nginx :443 ──► websockify 127.0.0.1:7003 ──► D2GS 1.13c (TCP :4000) +``` -### 4. 场景瓦片图集 (`samples/d2-packs/act[1-5]/`) +#### 1) 安装 `websockify` +在 Linux 网关/宿主机(例如 Ubuntu/Debian)上安装 `websockify`: +```bash +sudo apt-get update && sudo apt-get install -y websockify nginx +``` -- 365 个地图场景(65 个预置场景、210 个随机迷宫变体、90 个野外场景变体)分块切片图集,每个图集包含 ≤2048² 尺寸的索引色 PNG 瓦片页(地板层、阴影层、墙体层、屋顶层与场景物件层),附带 PLTE 调色板与透明度表。 - -## 结构化数据与 JSON 规范(Data & JSON) - -引擎采用结构化 JSON 与内嵌权威数据表来驱动界面排版、图集映射、场景还原与游戏逻辑: - -### 1. `public/ui/manifest.json` & `src/ui/baked-ui-meta.ts`(UI 与自动地图图集总清单) -由 `scripts/pack-ui.ts` 自动烘焙生成,为 UI 与自动地图系统提供像素级定位映射: -- `atlasWidth` / `atlasHeight`:`items-atlas.png` 装备与地面物品图集的分辨率规格。 -- `questsAtlasWidth` / `questsAtlasHeight`:`quests-atlas.png` 任务图集的分辨率规格。 -- `codeToInvFile` / `itemRects`:物品 3 字母代码到背包图标文件名的映射与 UV 矩形坐标表(`{ x, y, w, h }`),支持戒指、项链、珠宝和护身符的 `VarInvGfx` 多变体定位。 -- `codeToFlippyFile` / `flippyRects`:物品代码到地面掉落精灵(`flp*.dc6`)的映射与 UV 坐标表,支撑地面真实 2:1 等距物品渲染。 -- `automapAtlases`:8 张原版自动地图精灵表(`MaxiMap` / `MaxiMapS` / `Act2Map` / `Act2MapS` / `Act4Map` / `Act4MapS` / `ExTnMap` / `ExTnMapS`)的全部帧 UV 与 DC6 基线锚点偏移(`offsetX` / `offsetY`)。 -- `questRects` & `images`:1–5 幕任务日志切片与各独立 UI 面板背景、边框、按键在 `public/ui/` 下的文件索引。 - -### 2. `public/ui/fonts/metrics.json`(位图字体排版度量) -- 记录 6 套经典字体(Exocet、Formal、Font6/8/16/30)的字形度量参数。 -- 包含每个 ASCII 字符在字体图集上的矩形包围盒、字宽(`charWidths`)、字符高度、基线偏移与字间距(Kerning),为游戏内悬浮 Tooltip、装备描述、小地图标签和任务日志提供完全原版的排版效果。 - -### 3. `samples/d2-packs/index.json`(全关卡全局场景目录) -- 记录全游戏 5 幕 365 个地图块的元数据。 -- 包含字段:章节编号(Act 1..5)、关卡 ID(Level ID 1..136)、内部场景标识、关卡类型(预置场景 `preset` / 随机迷宫 `maze` / 野外关卡 `wilderness`)、网格尺寸(Grid Bounds)、可用变体数(Variants)与对应的烘焙目录相对路径。 - -### 4. `samples/d2-packs/world-graph.json`(世界拓扑连通网络图) -- 从 `Levels.txt` 的连接参数(`Vis0..7`、`Warp0..7`)生成的全局世界拓扑图。 -- 记录场景之间的连通边(Edges)、传送点(Waypoints)分布、楼梯/洞穴出入口(Warps)、野外边界开放开口(Perimeter Openings),支撑自动地图标注与跨关卡无缝切换。 - -### 5. `samples/d2-packs/anim/animdata.json`(动画关键帧事件权威表) -由 `scripts/pack-animdata.ts` 直接解析 1.13c `AnimData.d2` 二进制文件(570,304 字节,3,558 条记录)生成: -- 记录每个动作 Hash 的播放帧率(Frame Speed)、总帧数(Total Frames)。 -- 精确解析动作事件标志位:`0x01` 判定为近战命中/施法触发判定帧,`0x02` 判定为投射物(Missile)发射事件帧,确保 25Hz 动作逻辑与原版单机完全一致。 - -### 6. `samples/d2-packs/anim/monstats2.json`(怪物组件与动画模式配置) -- 结构化提取自 `MonStats2.txt`。 -- 记录所有怪物的身体构成组件、图层合成规则、各武器模式下的动作代码映射(如 `hth`、`1hs`、`2ht`、`bow`)。 - -### 7. `samples/d2-packs/entities/char-*.json` 与 `monster-*.json`(实体模型定义) -- 描述 7 大角色职业与 71 种怪物/召唤物的骨骼装配结构。 -- 包含复合图层映射、8 方向动作切片元数据、每帧中心偏移(Pivot),搭配同名 `.r8` 文件在渲染管线中执行高效逐像素着色。 - -### 8. `samples/d2-packs/act//scene.json` & `manifest.json`(单场景规格) -- `manifest.json`:当前场景所需的瓦片图集页清单与调色板信息。 -- `scene.json`:记录等距地图的地板(`floors`)、阴影(`shadows`,`type 13`)、墙体(`walls`)、屋顶(`roofs`)与场景物件(`objectDrawables`)绘制列表、经 `Automap.txt` 规则预映射的自动地图四层单元格数据(`automap`)、采用 RLE 压缩的 5×5 子格碰撞阻挡网格(`grid`),以及出生点、小站、跨图入口与预设怪物群(`monsterPacks`)。 - -### 9. `src/data/canonical-*.ts` & `src/render/*-meta.ts`(1.13c 权威内嵌数据表) -- `canonical-drop-data.ts`:完整内嵌 `Weapons.txt`、`Armor.txt`、`Misc.txt`、`TreasureClassEx.txt`、`ItemRatio.txt`、`UniqueItems.txt`、`SetItems.txt`、`MagicPrefix/Suffix.txt`、`MonStats.txt` 与 `SuperUniques.txt` 多难度掉落与属性表。 -- `canonical-tbl-strings.ts`:从原版 `string.tbl`、`expansionstring.tbl`、`patchstring.tbl` 提取的官方物品、词缀、怪物与技能名称字典。 -- `canonical-vendor-data.ts` & `canonical-quest-data.ts`:各幕城镇 NPC 商人库存生成规则与 1–5 幕任务文本数据。 -- `missiles-meta.ts` & `overlays-meta.ts`:投射物、爆炸、施法叠加层与光环图集的帧序列及锚点注册表。 - -## 部署与使用 - -### 1. 前置:自备游戏数据 - -把你自己合法拥有的**经典版暗黑破坏神 II(1.13c)** 数据放进 `samples/d2/`,至少需要 -`d2data.mpq`、`d2char.mpq`、`d2exp.mpq`、`Patch_D2.mpq`。资源包模式(页面默认)只需要 -`samples/d2-packs/`——它不在 Git 里,按下面的「资源包从哪来」下载解包后,**没有原版数据也能直接运行全部烘焙地图与角色战斗**。 - -`samples/d2/` 通常做成软链接,指向一个**磁盘上的持久目录**。切勿链到 `/tmp`——它是内存盘, -重启即清空,链接会变死链而角色/怪物退化成占位方块。本机的实际摆放、清单与逆向参考用的原版 -DLL 见 [`docs/LOCAL_DATA.md`](docs/LOCAL_DATA.md)。 - -### 2. 资源包从哪来(不在 Git 里) - -烘焙资源包(365 个地图块 / 136 关、78 套角色与怪物实体、投射物与叠加特效图集、动画表与世界拓扑图)**不在本仓库里**——因为索引色与 RGBA PNG 无法被 git 的 delta 压缩,随代码仓库分发会让每次重烘都使仓库体积暴涨。它放在独立的**图库仓库**,那里刻意**只保留一个提交**(每次重烘 orphan 提交 + force push),体积恒定在「一份快照」: +#### 2) 配置 `systemd` 守护服务管理 3 个桥接端口 +创建环境变量配置目录 `/etc/d2ws` 及三个端点的配置文件(若 D2GS 运行在另一台内网 Windows 机器上,将 `TARGET` 中的 `127.0.0.1` 替换为对应的内网 IP 即可): ```bash -git clone https://git.projectdiablo2.cn/troytt/diablo2-web-assets.git samples/d2-packs +sudo mkdir -p /etc/d2ws + +# 1. BNCS (bnetd, TCP 6112) +sudo tee /etc/d2ws/bnet.env >/dev/null <<'EOF' +LISTEN=127.0.0.1:7001 +TARGET=127.0.0.1:6112 +EOF + +# 2. MCP Realm (d2cs, TCP 6113) +sudo tee /etc/d2ws/realm.env >/dev/null <<'EOF' +LISTEN=127.0.0.1:7002 +TARGET=127.0.0.1:6113 +EOF + +# 3. D2GS Game Server (D2GS.exe 1.13c, TCP 4000) +sudo tee /etc/d2ws/game.env >/dev/null <<'EOF' +LISTEN=127.0.0.1:7003 +TARGET=127.0.0.1:4000 +EOF ``` -只想要一份压缩包(不需要 git): +创建模板单元文件 `/etc/systemd/system/d2ws@.service` 并启动服务: ```bash -curl -O https://www.laiseek.xyz/diablo2/assets/d2-packs-2026-09-14.tar.xz -sha256sum d2-packs-2026-09-14.tar.xz # 应为 9cdfd0c19ac68de842c6725070b65d056e25f5bcc77f36d6d9a29cd9f1b431e8 -tar xJf d2-packs-2026-09-14.tar.xz # 解出 samples/d2-packs/ +sudo tee /etc/systemd/system/d2ws@.service >/dev/null <<'EOF' +[Unit] +Description=Diablo II WebSocket-to-TCP Bridge (%i) +After=network.target + +[Service] +Type=simple +EnvironmentFile=/etc/d2ws/%i.env +ExecStart=/usr/bin/websockify --heartbeat=30 ${LISTEN} ${TARGET} +Restart=always +RestartSec=2 + +[Install] +WantedBy=multi-user.target +EOF + +sudo systemctl daemon-reload +sudo systemctl enable --now d2ws@bnet d2ws@realm d2ws@game ``` -仓库里只保留 `.gitignore` 规则与本文档;要自己生成包就照第 3 步从原版 MPQ -烘焙,再用 `npm run publish:packs` 发布到图库仓库(脚本会自动打包地图、动画、实体、投射物、叠加层与世界图并重建单提交历史)。 - -### 3. 本地跑起来 - -```bash -npm install # 仅 vite / typescript / tsx / vitest / @types/node -tsx scripts/make-fixtures.ts samples/fixtures # 夹具:DC6 + 调色板 + 文本表 -tsx scripts/make-map-fixtures.ts samples/fixtures # 夹具:DT1 + DS1 + 夹具 MPQ -npm run pack:data # 从 samples/d2/ 烘焙 365 场景图集与 Automap 层 → samples/d2-packs -npm run pack:ui # 烘焙 UI 综合图集、地面物品图集、8 张 Automap 图集与 manifest.json -npm run pack:animdata # 烘焙 AnimData.d2 与 monstats2.json -npm run pack:entities # 多进程并发烘焙 7 大职业模型与 71 套怪物/召唤物实体动画包 -npm run pack:missiles # 烘焙 149 套法术投射物与爆炸 RGBA 图集及 missiles-meta.ts -npm run pack:overlays # 烘焙 558+ 套施法叠加层、光环与传送门图集及 overlays-meta.ts -npm run dev # 启动 Vite:http://127.0.0.1:5173/acts.html -``` - -`pack:*` 系列脚本需要原版 MPQ;只用上面下载来的 `samples/d2-packs/` 可以跳过烘焙步骤直接 `npm run dev`, -代价是 `?live=1` 与重新烘焙不可用。 - -### 4. 页面与操作 - -| 页面 | 用途 | -| --- | --- | -| `/index.html`(或访问根路径 `/`) | **双语版本选择门户页**:选择简体中文版(`CHI.tbl`)或英文原版(`ENG.tbl`)进入庇护之地 | -| `/acts.html` / `/acts-zh.html` / `/acts-en.html` | **战役主场景(中/英双语)**:全屏 WebGL2 画布 + Glide 动态光影 + 等距精灵自动地图/小地图 + HUD 控制底栏 + 左右停靠全套功能面板 + 7 职业漫步战斗与打宝交易 | -| `/bnet.html` | **原版前端与战网(Battle.net)7 阶段完整流程页**:800×600 原版片头、主菜单、战网登录、篝火 7 职业角色创建/选择、大厅建房并无缝进入第一幕罗格营地 | - -#### 页面查询参数(`/acts.html`) - -``` -?hero=so|am|ne|pa|ba|dz|ai 指定初始职业(女巫/亚马逊/死灵/圣骑/野蛮人/德鲁伊/刺客) -?act=1..5 指定章节(1..5) -?level=<地图块 label> 直接指定细分场景,如 33-act-1-cathedral-cathy3 -?lighting=auto|noon|morning|sunset|night|cave|hell|eclipse|off 指定场景光照预设 -?density=0.5|1|2|4|8 指定怪物密度倍率(默认 1,即 1.13c 原版密度) -?elite=0.5|1|2|4|all 指定精英怪(头目/金怪)生成倍率 -?quadrant= 直读归档模式下指定该关卡的某个 DS1 -?live=1 不走资源包,直接按 HTTP Range 读 MPQ 解码(慢) -?pack=<目录> 换一个资源包目录 ?base=<目录> 换一个归档目录 -?arena=1&class=&skill=&slvl=&autocast=1 启动竞技场自动验证模式 -``` - -#### 完整操作快捷键 - -- **移动、交互与视口**: - - **鼠标左键点击**:A* 自动寻路移动、近战/左键技能攻击怪物、拾取地面掉落物品/金币、点击城镇 NPC 弹出对话菜单(交谈/交易/赌博/修理)、点击储物箱/小站/双向传送门交互、**点击楼梯/洞穴口(Warp / Entrance)切换关卡** - - **鼠标右键点击**:向鼠标方向施放当前选中的右手技能;在背包中**右击回城之书/卷轴**开启双向回城传送门,**右击辨识之书/卷轴**切换为辨识十字光标后左击未鉴定装备完成鉴定,**右击药水**直接饮用 - - 方向键(当全屏自动地图未开启时):按等距屏幕方向移动角色 - - 鼠标滚轮 或 `+` / `-`:视口无级缩放;`0`:缩放复位 -- **自动地图与小地图(Automap & Minimap)**: - - `Tab` / `M`:开启 / 关闭自动地图(默认开启右上角缩略小地图) - - `V`:在**右上角缩略小地图(Corner Minimap,`nDivisor=20`)**与**全屏自动地图(Full-Screen Automap,`nDivisor=10`)**之间切换 - - `F9`:循环切换自动地图 3 档透明度(`100%` → `75%` → `50%`) - - `F10`:开启 / 关闭自动地图上的友方名称与出口目的地文字标签 - - 方向键(全屏自动地图开启时):平移全屏自动地图视口(每步 `±8px`);`Home`:重置自动地图平移偏移 -- **功能面板(宽屏左右停靠)**: - - `I` / `B`:开启 / 关闭背包与装备纸娃娃面板(右停靠) - - `A` / `C`:开启 / 关闭角色属性面板(左停靠) - - `T` / `S`:开启 / 关闭技能树面板(右停靠,3 系垂直选项卡切换与加点) - - `Q`:开启 / 关闭任务日志面板(左停靠,按幕查看真实任务状态) - - `P`:快捷施放双向回城传送门(Town Portal) - - `Esc` / `Space`:关闭当前开启的所有停靠面板、商人界面与弹出层 -- **战斗与技能快捷栏**: - - 点击底栏左 / 右技能槽图标:打开向上展开的 Speedbar 技能选择弹窗(按技能树行序排列) - - 鼠标悬浮在 Speedbar 技能上按 `F1` ~ `F8`:绑定技能快捷键;在游戏过程中按 `F1` ~ `F8`:即时切换对应技能 - - `Shift`(按住):强制原地站立攻击 / 施法(Force Stand Still) - - `1` ~ `4`:快捷饮用腰带第 1 ~ 4 列药水;`~` / `` ` ``:展开 / 折叠 4×4 腰带弹窗 - - `Alt`(按住)或鼠标悬浮地面物品:高亮显示地面掉落物品名称标签(带防重叠阶梯排布) - - `R`:切换跑步 / 走路模式 - - `W`:主副手武器切换(`I` / `II` 套) -- **控制台与调试功能**: - - `Enter`:打开游戏内聊天/控制台输入框,支持输入 `/players 1` ~ `/players 8` 动态调整游戏人数难度与掉落率 - - 顶部工具栏下拉菜单:实时热切换 **7 大职业(`#hero`)**、**章节与细分场景**、**9 档场景光照预设(`#lighting`)**、**怪物密度(`#density`)** 与 **精英倍率(`#elite`)** - - `K` / `L`:快速保存 / 读取 `localStorage` 角色快照存档 - -### 5. 部署到服务器 - -```bash -npm run build:game # → dist-game/(base=/diablo2/) -rm -rf /var/www/d2web && mkdir -p /var/www/d2web && cp -r dist-game/. /var/www/d2web/ -rm -rf /var/www/d2packs && mkdir -p /var/www/d2packs && cp -r samples/d2-packs/. /var/www/d2packs/ -mkdir -p /var/www/d2data && ln -f samples/d2/*.mpq /var/www/d2data/ # 只有 ?live=1 用得到 -``` - -nginx(`/etc/nginx/sites-enabled/default`): +#### 3) 配置 Nginx `/d2net/*` WebSocket 反向代理 +在 Nginx 站点配置(如 `/etc/nginx/sites-enabled/default`)的 `server` 块中加入 `/d2net/` 路由规则: ```nginx -location = /diablo2 { return 301 /diablo2/; } -location = /diablo2/ { rewrite ^ /diablo2/acts.html last; } -location /diablo2/ { alias /var/www/d2web/; autoindex off; add_header Cache-Control 'no-store'; } - -location /diablo2/packs/ { # 资源包:可缓存 - alias /var/www/d2packs/; - autoindex off; - add_header Cache-Control 'public, max-age=3600'; +# BNCS (端口 6112) +location = /d2net/bnet { + proxy_pass http://127.0.0.1:7001; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_read_timeout 3600s; + proxy_send_timeout 3600s; + proxy_buffering off; } -location ~ ^/diablo2/data/(?[A-Za-z0-9_.-]+\.mpq)$ { # 只暴露 .mpq,不列目录 - alias /var/www/d2data/$d2file; - autoindex off; - add_header Accept-Ranges bytes; - add_header Cache-Control 'public, max-age=3600'; +# MCP Realm (端口 6113) +location = /d2net/realm { + proxy_pass http://127.0.0.1:7002; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_read_timeout 3600s; + proxy_send_timeout 3600s; + proxy_buffering off; +} + +# D2GS Game Server (端口 4000) +location = /d2net/game { + proxy_pass http://127.0.0.1:7003; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_read_timeout 3600s; + proxy_send_timeout 3600s; + proxy_buffering off; } ``` -要点:归档必须支持 **Range**(否则页面会退化成整文件下载);`/root` 是 0700,所以用硬链接暴露给 nginx。 -部署后跑 `npm run verify:deploy` 自检。 +重载 Nginx 配置并验证服务状态: +```bash +sudo nginx -t && sudo systemctl reload nginx +systemctl is-active d2ws@bnet d2ws@realm d2ws@game +``` -### 6. 自检命令 +> **提示**:客户端的 `createWsBridgeResolver`(位于 [`src/netproto/transport/endpoint.ts`](./src/netproto/transport/endpoint.ts))会自动根据协议握手阶段返回的端口(`6112`、`6113`、`4000`)将连接重写至 `/bnet`、`/realm` 与 `/game`,因此无需修改 D2GS 内部下发的 IP,只需确保 PvPGN 的 `realm.conf` / `address_translation.conf` 中配置的端口保持标准 `6113` 与 `4000` 即可。 + +--- + +### 3.2 第二步:如何烘焙离线美术资源(Offline Asset Baking) + +Web 客户端运行所需的瓦片地图图集、角色/怪物 DCC 精灵、HUD 面板与动画速度表均通过 `src/baker` 从原版 1.13c MPQ 离线烘焙生成到 `public/` 目录。 + +#### 1) 安装项目依赖 +```bash +npm install +``` + +#### 2) 放置原版 1.13c MPQ 文件 +将原版 **Diablo II: Lord of Destruction v1.13c** 的 MPQ 文件放入(或软链接至)`samples/d2/` 目录: ```bash -npm run verify:deploy # 线上:页面 / 资源包索引 / 图集 / Range 206 / 旧入口 410 -npm run verify:packs # 资源包与"现读现解"逐项比对(绘制序、阴影层、碰撞栅格逐字节、每帧像素哈希) -npm run verify:entity-packs # 校验 7 大职业与全部怪物实体动画包及 .r8 像素数据完整性 -npm run verify:generators # 校验 1:1 D2MOO DRLG 迷宫与野外地图生成器(缺瓦片率 0.00%,连通可达率 100%) -npm run verify:world-graph # 校验全 5 幕世界拓扑连通图(Vis0..7 / Warp0..7 / 小站与边界开口) -npm run verify:world-walk # 校验跨关卡行走、楼梯切图、双向回城传送门与小站传送网络 -npm run verify:monsters # 校验 Levels.txt 怪物群生成、头目/金怪精英配比与 SuperUniques 固定头目 -npm run verify:tiles # 每个槽位画的是不是该有的瓦片类型(地面=type 0)+ 位置公式 -npm run verify:alignment # 墙 / 地面基线、屋顶偏移与引擎公式一致 -npm run verify:object-lookup # DS1 对象 id → token/mode 与 Objects.txt 交叉核对 -npm run verify:acts # 关卡表 → DS1 → DT1 → 等距场景 + 碰撞 -npm run verify:d2 # 真 MPQ 数据端到端解码 -npm run verify:implode # PKWARE implode 解码器(全成员) -npm run verify:all # 综合校验:战斗 / 物品 / 任务 / 存档 / 网络 / 碰撞方向 / TBL / 音频 / 格式 -tsx scripts/verify-automap.ts # 校验 1.13c 等距精灵自动地图(Automap.txt 映射、8 图集烘焙、双模式渲染与交互) -npm run typecheck # tsc --noEmit(0 errors 门禁) -npm test # 运行 Vitest 完整测试套件 +mkdir -p samples/d2 +# 确保以下 4 个核心 MPQ 存在(音频 MPQ 如 d2sfx.mpq / d2music.mpq / d2xmusic.mpq 可选): +ls -lh samples/d2/ +# d2data.mpq d2char.mpq d2exp.mpq Patch_D2.mpq ``` -## 数据与许可 +#### 3) 执行全量烘焙与契约校验 +```bash +# 一键烘焙全部离线资源到 public/act-packs/ 并生成 public/asset-manifest.json +npm run bake -- all -- 仓库**不含**暴雪美术:原版 MPQ、`reference/` 下的第三方参考源码都不入库(规则写在 `.gitignore` 与 - [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md));`samples/fixtures/`(本项目自产)与 - `samples/d2-packs/`(派生数据)只作为 `/diablo2/assets/` 下的归档发布,不进 Git 历史。 - 图集包每次重烘都会让 Git 仓库再长 ~60 MB(PNG 无法 delta 压缩),所以不再入库。 -- 使用本引擎需要你自己合法拥有的游戏数据。生成类关卡(70 个随机迷宫 + 31 个野外关卡)严格移植自 D2MOO / 1.13c `D2Common.dll` 官方参数表与 DRLG 算法复现。 +# 烘焙完成后执行严格完整性校验(验证 233+3 个 DT1 瓦片、实体图集与 0 缺失文件) +npm run bake:verify +``` +如果需要单独重新烘焙某一部分资源,也可以使用细粒度命令: +- `npm run pack:tiles`:仅烘焙全部 5 幕瓦片图集与 `drlg-bundle.{json,bin}` +- `npm run pack:frontend`:仅烘焙战网登录、角色选择与大厅前置界面资源 +- `npm run pack:ui`:仅烘焙游戏内 HUD 面板、技能图标与鼠标指针 +- `npm run pack:animdata`:仅提取 `AnimData.d2` 动画帧率表 +- `npm run pack:entities`:仅烘焙怪物、SuperUniques(含随从)与场景交互物图集 +- `npm run pack:missiles` / `npm run pack:overlays`:仅烘焙投射物或光环/状态覆盖层特效 +- `npm run pack:manifest`:重新扫描 `public/` 并更新 `public/asset-manifest.json`(触发客户端 Service Worker 增量更新) + +--- + +### 3.3 第三步:如何启动服务与连接游戏 + +#### 方式 A:本地开发模式启动(Vite Dev Server) + +```bash +npm run dev +``` + +- 启动后浏览器访问 **`http://127.0.0.1:5173/play.html`**(访问根路径 `/` 也会自动重写到 `/play.html`)。 +- **默认代理配置**:[`vite.config.ts`](./vite.config.ts) 已内置 `/d2net` WebSocket 代理(默认转发至远端测试服 `wss://www.laiseek.xyz/d2net/*`),因此本地启动后可直接登录进入游戏。 +- **自定义切换 D2GS 服务器地址**: + 1. **URL 参数方式**:访问 `http://127.0.0.1:5173/play.html?wsBridge=wss://your-d2gs-domain.com/d2net`(或本地桥 `ws://127.0.0.1:8080/d2net`)。 + 2. **UI 设置面板方式**:点击画面顶部 32px 工具栏右侧的 **⚙ Settings** 按钮,修改 **WS Bridge URL** 并保存刷新。 + +#### 方式 B:生产环境构建与静态部署 + +```bash +# 1. 全仓类型检查(同时校验 common / netproto / server / client / baker 五套 tsconfig) +npm run typecheck + +# 2. 构建生产静态产物(输出至 dist/,若需部署在 /diablo2/ 子路径下可执行 npm run build:game 输出至 dist-game/) +npm run build + +# 3. 本地预览生产构建包 +npm run preview +``` + +在生产环境 Nginx 中,只需将构建生成的 `dist/` 目录挂载为静态站点根目录(或子路径 `/diablo2/`),并与 **3.1 节** 中的 `/d2net/{bnet,realm,game}` WebSocket 反向代理配置在同一个域名下,即可通过浏览器直接访问完整的在线暗黑 II 体验。 + +#### 方式 C:使用命令行无头 Bot 快速验证服务连通性 + +无需打开浏览器,可在终端使用 [`tools/d2-bot.ts`](./tools/d2-bot.ts) 直接测试 TCP 桥与 D2GS 建房/进图流程: + +```bash +npm run bot -- --bridge wss://your-d2gs-domain.com/d2net --user <账号> --pass <密码> --char <角色名> +``` diff --git a/src/baker/README.md b/src/baker/README.md new file mode 100644 index 0000000..8e75214 --- /dev/null +++ b/src/baker/README.md @@ -0,0 +1,76 @@ +# `src/baker` — 离线 MPQ 美术资产与数据表烘焙管线 + +`src/baker` 是运行在 Node.js 环境下的离线资产烘焙(Baking)工具链,负责将原版 **Diablo II: Lord of Destruction (v1.13c)** 的 MPQ 归档文件(`d2data.mpq`、`d2char.mpq`、`d2exp.mpq`、`Patch_D2.mpq` 等)解码、调色板转换、合批打包并生成供浏览器客户端零 MPQ 开销直接消费的静态资产包(输出至 `public/`)。 + +## 1. 模块职责与架构边界 + +- **TypeScript 工程约束(`tsconfig.baker.json`)**: + - `lib: ["ES2022"]`, `types: ["node"]` —— **纯 Node.js CLI 模块,严禁包含任何浏览器 DOM API**。 + - 仅依赖 `src/common`(共享 MPQ 读取器、二进制格式解析器与 `pack-contract` 校验契约),严禁导入 `src/client`、`src/server` 或 `src/netproto`。 +- **统一 CLI 入口**:[`src/baker/cli.ts`](./cli.ts)(通过 `npm run bake -- ` 调用)。 + +--- + +## 2. 目录结构 + +```text +src/baker/ +├── cli.ts # 统一命令行入口,支持分项烘焙、全量烘焙 (all) 与契约校验 (verify) +├── packers/ # 核心美术与数据打包器 (瓦片、实体、投射物、覆盖层、UI、前置界面、动画表、字体等) +├── extract/ # 1.13c 权威 TXT/BIN 数据表与 D2Net/D2MOO 常量提取脚本 +├── io/ # PNG/WebP 图像编码、SHA-256 资产清单生成 (asset-manifest.ts) 与发布辅助工具 +└── audit/ # Fail-Fast 烘焙产物完整性校验器 (verify-packs, verify-tiles, verify-entity-packs) +``` + +--- + +## 3. 烘焙目标与产物对照表 + +运行 `npm run bake -- `(或对应 `npm run pack:*` 快捷命令)将从 `samples/d2/` 下的 MPQ 文件提取并生成以下静态资产: + +| 烘焙子命令 (`cli.ts`) | 对应 `npm run` 快捷脚本 | 核心实现文件 | 输出目录 / 产物 (`public/`) | 说明 | +| :--- | :--- | :--- | :--- | :--- | +| `tiles` | `npm run pack:tiles` | `packers/pack-tiles.ts` | `public/act-packs/tiles/` | 烘焙全部 5 幕共 233 个关卡 DT1 + 3 个通用 DT1 (`Blank.dt1`, `InvisWal.dt1`, `Warp.dt1`) 瓦片图集及 `drlg-bundle.{json,bin}` | +| `ui` | `npm run pack:ui` | `packers/pack-ui.ts` | `public/act-packs/ui/` | 烘焙游戏内 HUD 底栏、面板背景、按钮、7 职业技能图标、鼠标指针与物品栏网格 DC6 精灵图 | +| `frontend` | `npm run pack:frontend` | `packers/pack-frontend-ui.ts` | `public/act-packs/frontend/` | 烘焙战网登录界面、角色选择营火背景、7 职业创建角色动画与大厅 UI 资源 | +| `animdata` | `npm run pack:animdata` | `packers/pack-animdata.ts` | `public/act-packs/animdata.json` | 提取 `data/global/AnimData.d2` 全量 COF 动画帧数、速度与关键帧触发事件表 | +| `entities` | `npm run pack:entities` | `packers/pack-entity-assets.ts` | `public/act-packs/entities/` | 烘焙全部怪物、SuperUniques(自动捆绑其随从 Minions)、NPC 与场景交互 Object 的 DCC/DC6/COF 图集 | +| `missiles` | `npm run pack:missiles` | `packers/pack-missiles.ts` | `public/act-packs/missiles/` | 烘焙 `Missiles.txt` 全部投射物 DCC 图集与发光混合模式元数据 | +| `overlays` | `npm run pack:overlays` | `packers/pack-overlays.ts` | `public/act-packs/overlays/` | 烘焙 `Overlays.txt` 全部光环、诅咒、Buff、命中特效与升级光柱 DCC 图集 | +| `acts` | `npm run pack:acts` | `packers/pack-act-assets.ts` | `public/act-packs/act1..act5/` | 按幕聚合关卡音频、环境调色板 (`PL2`)、物品掉落图标与角色纸娃娃分层 (`pack-char-so-layers.ts`) | +| `manifest` | `npm run pack:manifest` | `io/asset-manifest.ts` | `public/asset-manifest.json` | 递归扫描 `public/` 计算所有资产的字节大小与 SHA-256 哈希,供客户端 Service Worker 增量更新使用 | +| `verify` | `npm run bake:verify` | `audit/verify-packs.ts` | *(控制台校验报告)* | 执行 `src/common/pack-contract` 严格校验,确保零缺失文件 (`missingFiles === 0`) 且通用 DT1 完整 | + +--- + +## 4. 使用方法 + +### 4.1 准备原版 1.13c MPQ 文件 +在执行烘焙前,请将原版 **Diablo II: Lord of Destruction v1.13c** 的 MPQ 文件放置在仓库根目录下的 `samples/d2/` 目录中(支持软链接): + +```text +samples/d2/ +├── d2data.mpq # 必需:基础数据、Act 1-4 瓦片、怪物、UI、音效 +├── d2char.mpq # 必需:角色纸娃娃分层 DCC/COF 动画 +├── d2exp.mpq # 必需:毁灭之王资料片 (Act 5、德鲁伊/刺客、扩展暗金/符文) +├── Patch_D2.mpq # 必需:1.13c 最终补丁数据表 (Levels.txt, Skills.txt, SuperUniques.txt 等) +├── d2sfx.mpq # 可选:音效资源 +├── d2music.mpq # 可选:Act 1-4 背景音乐 +└── d2xmusic.mpq # 可选:Act 5 背景音乐 +``` + +### 4.2 执行全量或分项烘焙 + +```bash +# 一键执行全量离线资产烘焙 (tiles -> ui -> frontend -> animdata -> entities -> missiles -> overlays -> acts -> manifest) +npm run bake -- all + +# 或者按需单独烘焙某一类资源(例如仅重打包瓦片或前端 UI): +npm run pack:tiles +npm run pack:frontend +npm run pack:entities +npm run pack:manifest + +# 烘焙完成后执行严格完整性校验(Fail-Fast 契约检查) +npm run bake:verify +``` diff --git a/src/client/README.md b/src/client/README.md new file mode 100644 index 0000000..dd12bb5 --- /dev/null +++ b/src/client/README.md @@ -0,0 +1,77 @@ +# `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`](../../play.html) $\rightarrow$ [`src/client/main.ts`](./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. 目录结构 + +```text +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. 常用开发与验证命令 + +```bash +# 启动本地开发服务器 (默认监听 http://127.0.0.1:5173/play.html) +npm run dev + +# 单独对 src/client 进行严格类型检查 +npx tsc -p tsconfig.client.json --noEmit + +# 构建生产环境客户端静态包 +npm run build +``` diff --git a/src/common/README.md b/src/common/README.md new file mode 100644 index 0000000..80946cc --- /dev/null +++ b/src/common/README.md @@ -0,0 +1,74 @@ +# `src/common` — 纯 TypeScript 共享底座模块 + +`src/common` 是 **Diablo II: Lord of Destruction (v1.13c)** Web 移植版的纯计算与数据结构底座,1:1 对齐原版 `D2Common.dll`、`Storm.dll` 与 `D2Lang.dll` 的核心逻辑。 + +## 1. 模块职责与架构边界 + +- **对应原版 DLL**:`D2Common.dll`(DRLG 地图生成、数据表、碰撞掩码、单位/技能/物品基础公式、64 位随机数)、`Storm.dll`(MPQ 归档解析与 PKWARE/Huffman/Adpcm 解压)、`D2Lang.dll`(`.tbl` 字符串表与本地化)。 +- **TypeScript 工程约束(`tsconfig.common.json`)**: + - `lib: ["ES2022"]`, `types: []` —— **零 DOM 依赖、零 Node.js API 依赖、零外部运行时依赖**。 + - 严禁依赖 `src/client`、`src/server`、`src/baker` 或 `src/netproto`(由 `tests/arch/boundaries.test.ts` 强制门禁校验)。 + - 所有文件 I/O 均通过依赖注入的 `ArchiveSource` 接口完成,确保本模块可在浏览器主线程、WebWorker 与 Node.js 离线工具中无差别运行。 + +--- + +## 2. 目录结构 + +```text +src/common/ +├── mpq/ # Storm.dll MPQ 归档读取器、Hash/Block 表解密、多算法解压扇区 +├── formats/ # 原生二进制格式解析器 (DC6, DCC, DT1, DS1, COF, PL2, PAL, CEL, PCX, TBL, AnimData, Bitstream) +├── data/ # D2DataRegistry 数据表注册中心与 TXT/JSON 数据模型定义 +├── drlg/ # D2Common.dll 1.13c DRLG 随机地图生成器与碰撞/光照网格 +├── world/ # 跨端共享的地图/关卡几何拓扑与寻路网格辅助计算 +├── items/ # 物品基础属性、词缀、品质、孔数与符文之语公共计算逻辑 +├── skills/ # 技能基础公式、协同加成 (Synergy) 与等级曲线解析 +├── units/ # 单位属性 (StatList)、帧率驱动、状态位 (States) 与怪物基础数据 +├── i18n/ # D2Lang.dll 字符串哈希与中英文双语 TBL 查找表 +├── rng/ # D2Rng (64-bit Carry-Multiply 0x6FDAA9E0) 与 SplitMix64 空间哈希 +└── pack-contract/ # 烘焙管线 (Baker) 与客户端 (Client) 共享的离线资产包 Schema 及校验契约 +``` + +--- + +## 3. 核心子系统详解 + +### 3.1 MPQ 与二进制格式解析 (`mpq/`, `formats/`) +- **`mpq-reader.ts`**:完整实现 MPQ v1 归档格式解析,支持 Hash Table / Block Table 加密种子计算、单文件与多扇区 PKWARE DCL / Zlib / Huffman 组合解压。 +- **`dc6-parser.ts` / `dcc-parser.ts`**:解析 UI/物品/怪物/角色序列帧图像及方向图层数据,还原 DCC 变长比特流(Cell 缓冲与 EqualCells/PixelMask 双阶段编码)。 +- **`dt1-parser.ts` / `ds1-parser.ts`**:解析地面/墙壁/屋顶瓦片(256×128 Isometric Diamond 与 RLE 子块)以及预制地图块(Floor/Wall/Shadow/Object/Substitution 图层与 NPC 巡逻路径)。 +- **`cof-parser.ts` / `animdata-parser.ts`**:解析复合对象动画帧数、16 图层优先级组合顺序、关键帧触发事件(攻击命中、投射物释放、音效帧)及 `AnimData.d2` 动画速度表。 +- **`pl2-parser.ts` / `pal-parser.ts`**:解析各幕 256 色调色板、光照衰减表、阴影混合表与色彩变换矩阵(染色/冰冻/毒素/暗金变色)。 + +### 3.2 数据注册中心 (`data/`) +- **`D2DataRegistry` (`data/index.ts`)**:集中加载并索引 `Levels.txt`、`LvlTypes.txt`、`LvlPrest.txt`、`LvlMaze.txt`、`LvlSub.txt`、`MonStats.txt`、`MonStats2.txt`、`SuperUniques.txt`、`Missiles.txt`、`Overlays.txt`、`Objects.txt`、`Skills.txt`、`Armor/Weapons/Misc.txt` 等全量 1.13c 数据表。 +- 支持注入内存 JSON 快照或基于 `ArchiveSource` 的 MPQ 实时解析。 + +### 3.3 1.13c DRLG 地图生成引擎 (`drlg/`) +严格复刻 `D2Common.dll` 的确定性关卡生成流水线: +- **通用 DT1 强制加载 (`drlg-room-tiles.ts`)**:遵循 `DRLGROOM_LoadDt1Files` (`0x6fdb8400`),所有关卡无条件挂载 `Act1/Outdoors/Blank.dt1`、`InvisWal.dt1`(含 `style=49, sequence=7` 隐形碰撞地板)与 `Warp.dt1`。 +- **三种生成拓扑**: + - `drlg-preset.ts`:固定预设关卡(如罗格营地、鲁·高因、崔斯特瑞姆、混沌避难所等)。 + - `drlg-maze.ts`:地牢迷宫房间拼接算法(如墓穴、修道院地下城、塔拉夏古墓、憎恨囚牢等)。 + - `drlg-outdoors.ts`:野外随机边界、道路、河流、预设营地塞入与主题墙壁围合(如鲜血荒地、冰冷之原、库拉斯特丛林等)。 +- **变体选择与碰撞构建 (`tile-library.ts`, `collision.ts`)**: + - 使用 SplitMix64 空间哈希 `pickVariant(worldX, worldY, orient, style, seq)` 彻底消除 45° 机械条纹伪影。 + - 稀疏/未填充子格严格打上 `COLLIDE_MASK_INVALID` (`COLLIDE_BLANK | COLLIDE_WALL`),防止角色出生或穿墙掉入虚空。 + +### 3.4 确定性随机数 (`rng/`) +- **`D2Rng` (`rng/d2-rng.ts`)**:1:1 复刻 `D2Common.dll` 64 位进位乘法 PRNG(`seed = (0x6AC690C5 * low32 + carry) >>> 0`),保证给定相同的 32 位地图种子与难度,生成的地图拓扑与原生 C++ D2GS 完全一致。 + +### 3.5 离线资产契约 (`pack-contract/`) +- **`schemas.ts` / `validators.ts`**:定义 `public/act-packs/` 下所有离线资产包(`tiles`、`entities`、`missiles`、`overlays`、`ui`、`frontend`、`animdata`)的 JSON Schema 与 Fail-Fast 校验器(强制要求 `missingFiles === 0` 且三大通用 DT1 齐全)。 + +--- + +## 4. 常用验证命令 + +```bash +# 单独对 src/common 进行严格无 DOM / 无 Node 类型检查 +npx tsc -p tsconfig.common.json --noEmit + +# 运行架构边界与 DRLG / 格式解析单元测试 +npx vitest run tests/arch/boundaries.test.ts tests/drlg/ +``` diff --git a/src/netproto/README.md b/src/netproto/README.md new file mode 100644 index 0000000..9116b31 --- /dev/null +++ b/src/netproto/README.md @@ -0,0 +1,75 @@ +# `src/netproto` — 1.13c 权威网络协议与传输引擎 + +`src/netproto` 是 **Diablo II: Lord of Destruction (v1.13c)** 的独立网络协议栈模块,1:1 复刻原版 `D2Net.dll`、`Bnclient.dll`、`D2MCPClient.dll` 与 `Fog.dll` 的二进制封包编解码、加密哈希、Huffman 压缩与状态机流转。 + +## 1. 模块职责与架构边界 + +- **对应原版 DLL**: + - `Bnclient.dll`:BNCS(Battle.net Chat Server,默认 TCP `6112`)握手、CheckRevision 校验、CD-Key 哈希、XSHA-1 密码认证、账户注册与大厅聊天频道。 + - `D2MCPClient.dll`:MCP(Realm Server / `d2cs`,默认 TCP `6113`)领域登录、角色列表读取、角色创建/删除、游戏房间创建 (`0x03`) 与加入 (`0x04`)。 + - `D2Net.dll` + `Fog.dll`:D2GS(Game Server,默认 TCP `4000`)帧头解析、动态 Huffman 解压、167 个 S2C 服务端下行指令解析、C2S 客户端上行指令编码、以及 `0x9C`/`0x9D` 物品比特流解析。 +- **架构强隔离约束(`tsconfig.netproto.json`)**: + - **零外部模块依赖**:`src/netproto` **不依赖** `src/common`、`src/client`、`src/server` 或 `src/baker`。 + - **单一门面入口**:外部模块(如 `src/client`、`src/server`、`tools/`)**必须且只能**通过 [`src/netproto/index.ts`](./index.ts) 导入符号,禁止跨入子目录深层路径导入(由 `tests/arch/boundaries.test.ts` 强制守护)。 + +--- + +## 2. 目录结构 + +```text +src/netproto/ +├── index.ts # 模块唯一公开导出门面 (Public Facade) +├── core/ # Little-Endian BinaryReader / BinaryWriter / BitReader 及基础协议类型 +├── transport/ # ByteStream 传输抽象、WebSocket 桥接流 (WsStream)、内存回环流与端点解析器 +├── crypto/ # Broken SHA-1 (XSHA-1)、CheckRevision、CD-Key 解密哈希等 1.13c 加密算法 +├── bncs/ # BNCS (端口 6112) 报文成帧、状态机、登录/注册/Realm 切换/大厅聊天协议 +├── mcp/ # MCP (端口 6113) 报文成帧、角色列表 (0x19)、创建角色 (0x02)、建房/加房协议 +├── d2gs/ # D2GS (端口 4000) Huffman 解压、S2C 167 操作码注册表、C2S 编码与物品 Bitstream +├── flow/ # D2OnlineFlow:串联 BNCS -> MCP -> D2GS 全链路自动重连与令牌交接编排器 +├── domain/ # 协议无关领域契约:GameServerAdapter、ServerEvent (37 种事件)、ClientCommand (30 种指令) +└── ts/ # 预留的 TypeScript 远端服务协议适配层 (TsServerAdapter) +``` + +--- + +## 3. 核心子系统详解 + +### 3.1 传输层与 WebSocket/TCP 桥接 (`transport/`) +由于浏览器无法直接发起原生 TCP 连接,而原生 PvPGN + D2GS 在消息体内嵌返回了内部 IP 与原始 TCP 端口(如 MCP 返回 D2GS IP + 端口 `4000`),`transport/endpoint.ts` 提供了可插拔的 `EndpointResolver`: +- **`createWsBridgeResolver(bridgeBaseUrl)`**:将目标端口动态映射为 Nginx + `websockify` 反向代理路径: + - 端口 `6112` (BNCS) $\rightarrow$ `/bnet`(如 `wss://host/d2net/bnet`) + - 端口 `6113` (MCP) $\rightarrow$ `/realm`(如 `wss://host/d2net/realm`) + - 端口 `4000` (D2GS) $\rightarrow$ `/game`(如 `wss://host/d2net/game`) +- **`createTcpResolver()`**:供 Node.js 环境下的无头 Bot (`tools/d2-bot.ts`) 直连原生 TCP 端口。 +- **`MemoryStream`**:零拷贝内存全双工字节流,供单元测试与本地闭环验证使用。 + +### 3.2 BNCS 与 MCP 战网前置协议 (`crypto/`, `bncs/`, `mcp/`) +- **加密算法 (`crypto/`)**:精确实现暴雪特有的无左移循环 Broken SHA-1 (`xsha1.ts`)、基于 MPQ 版本特征码的 `CheckRevision` (`check-revision.ts`) 以及 16/26 位 D2/LoD 双 CD-Key 哈希封装。 +- **全链路状态机 (`flow/online-flow.ts`)**: + 1. `BncsClient` 完成 `SID_AUTH_INFO (0x50)` $\rightarrow$ `SID_AUTH_CHECK (0x51)` $\rightarrow$ `SID_LOGONRESPONSE2 (0x3A)` $\rightarrow$ `SID_LOGONREALMEX (0x3E)` 获取 64 字节 MCP Cookie。 + 2. `McpClient` 携带 Cookie 连接 `d2cs`,执行 `MCP_STARTUP (0x01)` $\rightarrow$ `MCP_CHARLIST2 (0x19)` $\rightarrow$ `MCP_CHARLOGON (0x07)` $\rightarrow$ `MCP_CREATEGAME (0x03)` / `MCP_JOINGAME (0x04)` 获取 D2GS GameHash 与 GameToken。 + 3. 自动交接至 `D2gsClient` 发起 `0x68 (D2GS_GAMELOGON)` 进入游戏世界。 + +### 3.3 D2GS 游戏服协议与 Huffman 解压 (`d2gs/`) +- **报文成帧与解压 (`framer.ts`, `huffman.ts`)**: + - 处理首包 `0xAF` 压缩协商握手。 + - 实现 `Fog.dll` 静态预置 Huffman 树比特流解码,并将单帧解压后的粘包数据依赖于 `packet-sizes.ts`(167 个 S2C 操作码定长/变长/回调计算表)精确切分为独立指令帧。 +- **S2C 解析与领域映射 (`s2c-registry.ts`, `adapter.ts`)**: + - 将底层二进制包(如 `0x03 LoadAct`、`0x07/0x08 MapAdd/Remove`、`0x0F/0x10 PlayerMove`、`0x15 ReassignPlayer`、`0x51 AssignObject`、`0xAC AssignNPC`、`0x9C/0x9D ItemAction`、`0x18..0x1F Attribute/Orb Update` 等)无损转化为强类型的 `ServerEvent` 领域事件流。 +- **物品比特流解码 (`item-bitstream.ts`)**: + - 逐比特解析 `0x9C`(地面/容器/商店物品)与 `0x9D`(穿戴/佣兵/鼠标物品)变长属性流,由 D2DataRegistry 驱动读取 `ItemStatCost.txt` 的 `Save Bits` 与 `Save Add`。 + +--- + +## 4. 常用验证命令 + +```bash +# 单独对 src/netproto 进行类型检查 +npx tsc -p tsconfig.netproto.json --noEmit + +# 运行协议编解码、Huffman 解压与在线流程单元测试 +npx vitest run tests/netproto/ + +# 重放并检查 .d2cap 抓包录制文件 +npx tsx tools/netproto-replay.ts +``` diff --git a/src/server/README.md b/src/server/README.md new file mode 100644 index 0000000..57ecac4 --- /dev/null +++ b/src/server/README.md @@ -0,0 +1,64 @@ +# `src/server` — 1.13c 权威游戏模拟引擎 (`D2Game.dll`) + +`src/server` 是 **Diablo II: Lord of Destruction (v1.13c)** 的确定性服务端权威逻辑实现,1:1 复刻原版 `D2Game.dll` 的 25fps (40ms/tick) 帧循环、战斗管线、221 个技能、怪物 AI、掉落表(TreasureClass)与存档系统。 + +## 1. 模块职责与架构边界 + +- **对应原版 DLL**:`D2Game.dll`。 +- **TypeScript 工程约束(`tsconfig.server.json`)**: + - `lib: ["ES2022", "WebWorker"]`, `types: []` —— **严禁使用任何浏览器 DOM API 或 Node.js API**。 + - **纯确定性模拟(Deterministic Simulation)**:模块内严禁调用 `Math.random`、`Date.now` 或 `performance.now`;所有随机性必须由种子的 `D2Rng` 驱动,所有时间推进必须由 25fps 离散帧号(`tickCount`)驱动。 + - 仅允许依赖 `src/common` 与 `src/netproto`(门面入口),严禁导入 `src/client` 或 `src/baker`。 + +--- + +## 2. 目录结构 + +```text +src/server/ +├── engine/ # 25fps 核心模拟引擎 (GameEngine, combat-pipeline, missile-engine, aura-scanner, summon-manager, stat-list) +├── ai/ # 怪物 AI 决策树、仇恨/索敌、视野碰撞与动态房间流式加载 (room-streamer) +├── skills/ # 七大职业共 221 个技能与通用技能服务端执行器 (Amazon, Sorceress, Necromancer, Paladin, Barbarian, Druid, Assassin) +├── items/ # 1.13c 掉落管线 (TC NoDrop/Quality/Affix)、符文之语、宝石镶嵌、赫拉迪克方块合成与 NPC 商店服务 +├── world/ # 场景交互物体 (神殿/宝箱/传送门/小站)、任务状态机 (Quests)、NPC 对话与治疗/赌博交易 +├── save/ # 原版 1.13c .d2s 二进制角色存档读写器 (Checksum, Attributes, Skills, QuestData, Waypoints, ItemList) +├── scene/ # 服务端关卡实例生命周期与跨幕切换管理 +└── adapter/ # LocalLoopbackAdapter:将 GameEngine 封装为标准 GameServerAdapter 契约接口 +``` + +--- + +## 3. 核心子系统详解 + +### 3.1 25fps 核心引擎与战斗管线 (`engine/`) +- **`GameEngine` (`engine/game-engine.ts`)**:维护权威世界状态,按 40ms 固定步长推进: + 1. 玩家输入指令队列消费(移动、普通攻击、技能施放、拾取/穿戴/药水、NPC 交互)。 + 2. 状态持续时间衰减(中毒、冰冻、诅咒、战吼、神殿 Buff)与生命/法力自然回复。 + 3. 光环扫描器 (`aura-scanner.ts`) 周期性范围索敌与属性挂载。 + 4. 投射物引擎 (`missile-engine.ts`) 步进碰撞检测与子投射物分裂。 + 5. 怪物与召唤物 (`summon-manager.ts`) AI 决策与动作帧推进。 + 6. 状态总线 (`state-bus.ts`) 收集本帧脏状态并生成增量事件。 +- **战斗伤害管线 (`combat-pipeline.ts`)**:严格遵循 1.13c 命中率公式(AR vs DR + 等级差修正)、盾牌格挡判定、物理/魔法/元素(火/电/冰/毒)六系伤害结算、抗性穿透/上限、碾压性打击 (Crushing Blow)、致命一击 (Deadly Strike / Critical Strike) 与撕开伤口 (Open Wounds)。 + +### 3.2 全职业技能系统 (`skills/`) +- **`skill-table.ts` & 各职业模块**:基于 `Skills.txt` 的 `srvdofunc` / `srvstfunc` 分发机制,完整实现亚马逊、法师、死灵法师、圣骑士、野蛮人、德鲁伊、刺客七大职业共 **221 个技能**(含协同加成公式、施法延迟 Cooldown、法力消耗、多段投射物生成与尸体交互)。 + +### 3.3 怪物 AI 与房间流式激活 (`ai/`) +- **`monster-ai.ts`**:基于 `MonStats.txt` 的 AI 参数(`aidel`, `aip1..aip8`)驱动沉沦魔复活、巫师远程风筝、冥河娃娃自爆、精英怪暗金词缀(闪电强化、特别快速、狂热灵气、免疫计算)及 Act Boss 专属 AI。 +- **`room-streamer.ts`**:围绕玩家所在子格坐标按九宫格动态激活/休眠 DRLG 房间并按 `MonDen` 与 `SuperUniques.txt` 刷怪。 + +### 3.4 1.13c 物品掉落与存档系统 (`items/`, `save/`) +- **掉落管线 (`items/drop-pipeline.ts`)**:完整复刻 `TreasureClassEx.txt` 递归寻路、多人难度 `NoDrop` 指数衰减、MF (Magic Find) 边际递减有效值转换(Unique / Set / Rare / Magic 四级判定)以及 `MagicPrefix.txt` / `MagicSuffix.txt` 词缀池权重抽样。 +- **`.d2s` 存档兼容 (`save/d2s-reader.ts`, `save/d2s-writer.ts`)**:支持直接导入或导出与原版 Diablo II v1.13c 二进制逐字节兼容的 `.d2s` 角色存档(含 `0xAA55AA55` 文件头、循环移位累加校验和、`gf` 属性比特流、`if` 技能表与 `JM` 物品列表)。 + +--- + +## 4. 常用验证命令 + +```bash +# 单独对 src/server 进行类型检查(验证零 DOM / 零 Node 依赖) +npx tsc -p tsconfig.server.json --noEmit + +# 运行服务端战斗、技能、掉落与存档单元测试 +npx vitest run tests/server/ tests/skills/ tests/items/ +``` diff --git a/tools/README.md b/tools/README.md new file mode 100644 index 0000000..5ddfe0f --- /dev/null +++ b/tools/README.md @@ -0,0 +1,49 @@ +# `tools` — 开发者调试、协议重放与自动化验证工具集 + +`tools/` 目录收录了围绕 **Diablo II Web (v1.13c)** 的命令行辅助工具、无头协议测试机器人、封包回放分析器、存档修改器以及全谱系浏览器自动化验证脚本。 + +--- + +## 1. 核心工具概览 + +| 脚本文件 | 运行命令示例 | 功能说明 | +| :--- | :--- | :--- | +| [`d2-bot.ts`](./d2-bot.ts) | `npm run bot -- --help` | 无头 (Headless) 战网/D2GS 协议测试机器人。基于 `src/netproto` 直接通过原生 TCP 或 WebSocket 桥走完 BNCS 登录 $\rightarrow$ MCP 选人/建房 $\rightarrow$ D2GS 进图移动/施法全流程,无需启动浏览器即可验证服务端连通性。 | +| [`netproto-replay.ts`](./netproto-replay.ts) | `npx tsx tools/netproto-replay.ts ` | `.d2cap` 网络抓包录制文件离线重放与解析工具。逐帧还原 Huffman 解压后的 S2C/C2S 十六进制流与解码后的 `ServerEvent` 明细,用于排查协议死锁或未知操作码。 | +| [`d2s-unlock.ts`](./d2s-unlock.ts) | `npx tsx tools/d2s-unlock.ts ` | 原版 1.13c `.d2s` 角色存档一键解锁工具。支持修改角色等级、属性点、技能点、金币,一键点亮全部三难度(Normal / Nightmare / Hell)全部 5 幕小站 (Waypoints) 与通关任务状态,并自动重算 `.d2s` 校验和。 | +| [`audit-levels-browser.ts`](./audit-levels-browser.ts) | `npx tsx tools/audit-levels-browser.ts` | **全谱系 136 关卡无头浏览器审计工具**。驱动 Playwright 遍历 `Levels.txt` 中全部 136 个关卡 ID,校验 DRLG 地图生成、通用 DT1 加载、出生点连通性(非虚空)与 WebGL2 瓦片渲染零报错。 | +| [`drlg-diff.ts`](./drlg-diff.ts) | `npx tsx tools/drlg-diff.ts` | DRLG 确定性差分对比工具。给定相同的 `mapSeed` 与 `areaId`,对比本仓库 DRLG 输出与 `D2Common.dll` Ground Truth 房间拓扑、瓦片 Style/Sequence 及碰撞网格的一致性。 | +| [`render-drlg-compare.ts`](./render-drlg-compare.ts) | `npx tsx tools/render-drlg-compare.ts` | 将 DRLG 生成的关卡碰撞网格、房间边界与瓦片图层渲染为可视化对比 PNG 图像,便于直观排查墙壁接缝与门洞连通性。 | +| [`verify-play.ts`](./verify-play.ts) | `npx tsx tools/verify-play.ts` | 端到端 `play.html` 冒烟验证脚本:使用 Playwright 启动客户端,验证战网前端 UI 加载、WebGL2 上下文初始化、静态资产零 404 以及 HUD 交互响应。 | + +--- + +## 2. 专项回归验证脚本 (`tools/verify-*.ts`) + +除了上述日常开发工具外,`tools/` 下还包含针对关键子系统的专项无头验证脚本: + +- **`verify-360-comprehensive.ts` / `verify-all-features.ts`**:客户端 360° 全功能特性巡检(面板开关、小地图、技能栏、物品提示框、音效与设置面板)。 +- **`verify-act-transitions.ts` / `verify-waypoints.ts`**:跨幕传送与全部 5 幕小站传送门跳转验证。 +- **`verify-combat-vfx.ts` / `verify-lighting.ts`**:投射物、覆盖层特效 (Overlays) 与分幕环境光照着色器渲染验证。 +- **`verify-monsters.ts` / `verify-save.ts`**:怪物/暗金 Boss 纸娃娃图集加载与 `.d2s` 存档导入导出闭环验证。 + +--- + +## 3. 典型使用示例 + +### 使用 `d2-bot.ts` 测试远端 D2GS 连通性 +```bash +# 通过 WebSocket 桥连接远端战网并自动登录角色创建房间 +npm run bot -- \ + --bridge wss://www.laiseek.xyz/d2net \ + --user myaccount \ + --pass mypassword \ + --char MySorceress \ + --game test01 +``` + +### 使用 `netproto-replay.ts` 分析客户端录制的 `.d2cap` +在浏览器顶部工具栏点击 **Packet Inspector** 导出 `.d2cap` 文件后,可在终端离线回放: +```bash +npx tsx tools/netproto-replay.ts ./captures/session-2026.d2cap +```