fix(waypoint): 修复冰冷之原等 14 处场景小站未渲染缺陷,根除 ALL_WAYPOINT_IDS 跨幕 ID 冲突与打包管线实体漏注 #409

Closed
opened 2026-09-24 03:24:44 +00:00 by troytt · 1 comment
Owner

1. 缺陷背景与现象 (Defect Symptoms)

  • 现象描述:玩家在小站传送菜单中选择进入 第一幕:冰冷之原(Cold Plains,Level 3,Waypoint ID 1) 后,角色能够正常传送落地,但场景中完全没有渲染小站(Waypoint)底座与蓝色发光能量环,地表仅显示普通的泥土地皮与杂草。
  • 交互异象:玩家在小站预设落脚点附近(~48px / 80px 交互半径内)点击地面,仍然能够触发唤起小站传送 UI 面板,但视觉上该小站处于完全隐形状态(Ghost / Invisible Waypoint)。
  • 实机截图:

    见附件截图:角色站在冰冷之原的泥土地上,左侧小站菜单处于激活状态,但场景中央空无一物,缺失小站模型。


2. 全量 39 个小站与 109 个关卡变体审查结果 (Full Spectrum Audit: 39 Waypoints / 109 Variants)

经自动化脚本对 samples/d2-packs 中全部关卡包进行逐一解析与审查,全游戏 39 处小站中,仅 25 处正常渲染,多达 14 处关卡(共计 37 个关卡变体)的小站物件完全或部分缺失未渲染!

统计概览

  • 正常渲染 [OK]:25 处(占比 64.1%)
  • 完全缺失 [ALL MISSING]:11 处(占比 28.2%,所有变体均缺失)
  • 部分变体缺失 [PARTIAL MISSING]:3 处(占比 7.7%)
  • 缺失变体总数:37 / 109 变体未包含小站实体物件(全部降级为 source: "placed")

详细审查清单

幕次 小站 ID 关卡 ID 关卡名称 渲染状态 变体支持率 缺失变体文件
Act 1 WP 0 Level 1 罗格营地 Rogue Encampment OK 4/4 无
Act 1 WP 1 Level 3 冰冷之原 Cold Plains ALL MISSING 0/3 3-act-1-wilderness-2-var1/var2/var3
Act 1 WP 2 Level 4 乱石旷野 Stony Field ALL MISSING 0/3 4-act-1-wilderness-3-var1/var2/var3
Act 1 WP 3 Level 5 黑暗森林 Dark Wood ALL MISSING 0/3 5-act-1-wilderness-4-var1/var2/var3
Act 1 WP 4 Level 6 黑色荒地 Black Marsh ALL MISSING 0/3 6-act-1-wilderness-5-var1/var2/var3
Act 1 WP 5 Level 27 外侧回廊 Outer Cloister OK 3/3 无
Act 1 WP 6 Level 29 监狱第一层 Jail Level 1 OK 3/3 无
Act 1 WP 7 Level 32 内侧回廊 Inner Cloister OK 1/1 无
Act 1 WP 8 Level 35 地下墓穴第二层 Catacombs Level 2 OK 3/3 无
Act 2 WP 9 Level 40 鲁·高因 Lut Gholein OK 2/2 无
Act 2 WP 10 Level 48 下水道第二层 Sewers Level 2 OK 3/3 无
Act 2 WP 11 Level 42 干燥高地 Dry Hills ALL MISSING 0/3 42-act-2-desert-2-var1/var2/var3
Act 2 WP 12 Level 57 死亡之殿第二层 Halls of the Dead Level 2 OK 3/3 无
Act 2 WP 13 Level 43 遥远绿洲 Far Oasis ALL MISSING 0/3 43-act-2-desert-3-var1/var2/var3
Act 2 WP 14 Level 44 遗失的城市 Lost City ALL MISSING 0/3 44-act-2-desert-4-var1/var2/var3
Act 2 WP 15 Level 52 皇宫监牢第一层 Palace Cellar Level 1 OK 3/3 无
Act 2 WP 16 Level 74 神秘避难所 Arcane Sanctuary ALL MISSING 0/3 74-act-2-arcane-var1/var2/var3
Act 2 WP 17 Level 46 群蛇峡谷/术士峡谷 Canyon of the Magi OK 3/3 无
Act 3 WP 18 Level 75 库拉斯特海港 Kurast Docks OK 1/1 无
Act 3 WP 19 Level 76 蜘蛛森林 Spider Forest PARTIAL 2/3 76-act-3-jungle-1-var2
Act 3 WP 20 Level 77 庞大湿地 Great Marsh PARTIAL 2/3 77-act-3-jungle-2-var2
Act 3 WP 21 Level 78 剥皮丛林 Flayer Jungle PARTIAL 1/3 78-act-3-jungle-3-var2/var3
Act 3 WP 22 Level 79 库拉斯特下层 Lower Kurast ALL MISSING 0/3 79-act-3-kurast-1-var1/var2/var3
Act 3 WP 23 Level 80 库拉斯特商场 Kurast Bazaar OK 3/3 无
Act 3 WP 24 Level 81 库拉斯特上层 Upper Kurast ALL MISSING 0/3 81-act-3-kurast-3-var1/var2/var3
Act 3 WP 25 Level 83 崔凡克 Travincal OK 3/3 无
Act 3 WP 26 Level 101 憎恨囚牢第二层 Durance of Hate Level 2 OK 3/3 无
Act 4 WP 27 Level 103 群魔堡垒 The Pandemonium Fortress OK 1/1 无
Act 4 WP 28 Level 106 绝望平原/受诅者之城 City of the Damned OK 3/3 无
Act 4 WP 29 Level 107 火焰之河 River of Flame OK 3/3 无
Act 5 WP 30 Level 109 哈洛加斯 Harrogath OK 1/1 无
Act 5 WP 31 Level 111 冰冻高地 Frigid Highlands OK 3/3 无
Act 5 WP 32 Level 112 亚瑞特高原 Arreat Plateau OK 3/3 无
Act 5 WP 33 Level 113 水晶通道 Crystalline Passage OK 3/3 无
Act 5 WP 34 Level 115 冰河路径 Glacial Trail OK 3/3 无
Act 5 WP 35 Level 123 痛楚之厅 Halls of Pain ALL MISSING 0/3 123-act-5-temple-2-var1/var2/var3
Act 5 WP 36 Level 117 冰冻苔原 Frozen Tundra OK 3/3 无
Act 5 WP 37 Level 118 远古之路 The Ancients' Way OK 3/3 无
Act 5 WP 38 Level 129 世界之石要塞第二层 Worldstone Keep Level 2 OK 3/3 无

3. 根因深度剖析(暴雪 1.13c Ground Truth 与源码缺陷)

根因 1:src/game/wilderness.ts 中 ALL_WAYPOINT_IDS 跨幕 ID 碰撞,导致生成器误判已有小站而提前短路

在暴雪 1.13c 汇编实现中(D2Common.dll ≈0x6FD92700 DRLGOUTDOORS_SpawnAct12Waypoint),DS1 物件的 id 在不同 Act / 关卡类型下是局部作用域的,必须结合 act 与 type 进行映射(见 object-lookup.ts)。
各幕真实的小站 DS1 ID 与对应 Objects.txt 关系为:

  • Act 1:小站 ID = 37(预设为 52),对应 Objects.txt row 119(Token WP)
  • Act 2:小站 ID = 10(预设为 306),对应 Objects.txt row 156(Token WM)
  • Act 3:小站 ID = 1(预设为 387),对应 Objects.txt row 237(Token WZ)
  • Act 4:小站 ID = 0(预设为 388),对应 Objects.txt row 238(Token WV)
  • Act 5:小站 ID = 12(预设为 188),对应 Objects.txt row 38(Token WT)

然而在 src/game/wilderness.ts 第 5997 行中,开发者为了检查预设是否已经放置了小站,错误地创建了一个跨幕混合的全局 Set:

// wilderness.ts line 5997
const ALL_WAYPOINT_IDS = new Set([37, 52, 269, 10, 306, 1, 387, 0, 388, 12, 188])
const existingWp = canvas.objects.find(
  o => o.type === 2 && ALL_WAYPOINT_IDS.has(o.id),
)
if (existingWp !== undefined) {
  stats.waypointsSpawned = 1
  stats.waypointTile = { ... }
  return // 💥 致命短路:直接跳过小站生成!
}

冲突事实:

  • Act 1 荒野预设图块(如沉沦魔营地、废墟小屋等)中大量包含���把 / 占位物件(Token TO),其 DS1 id = 1。
  • 由于 ALL_WAYPOINT_IDS 包含了 Act 3 的小站 ID 1,Act 1 荒野图块盖章后,canvas.objects.find() 必然命中普通火把(id = 1)!
  • 生成器误以为该地图已经包含了小站,立即将 stats.waypointsSpawned 设为 1 并直接 return,彻底抹杀了真正的户外小站生成逻辑(包括冰冷之原与血石荒地交界处专属的 DRLGOUTDOORS_SpawnAct12Waypoint 算法)!
  • 同理:
    • Act 2 荒野因包含地窖活板门(id = 0)和火把(id = 1),误匹配 Act 4(id = 0)和 Act 3(id = 1);
    • Act 3 库拉斯特因包含丛林树木(id = 0)和武器架(id = 12),误匹配 Act 4(id = 0)和 Act 5(id = 12)。

根因 2:scripts/pack-act-assets.ts 打包管线降级机制未注入实体物件,导致元数据孤立

在 scripts/pack-act-assets.ts 第 801~820 行:

const waypointId = worldGraph.levels.get(levelId)?.waypoint ?? 255
const waypoints: SceneWaypoint[] = []
if (waypointId !== 255) {
  const fromArt = waypointCells[0] ?? (mazeWaypoints?.[0] ? { x: mazeWaypoints[0].entityX, y: mazeWaypoints[0].entityY } : undefined)
  const spot = fromArt ?? findWaypointSpot(grid, region)
  if (spot !== null && spot !== undefined) {
    const arrive = nearestWalkable(grid, spot.x + 2, spot.y + 2, 16, region) ?? spot
    waypoints.push({
      waypointId,
      x: spot.x,
      y: spot.y,
      arriveX: arrive.x,
      arriveY: arrive.y,
      source: fromArt === undefined ? 'placed' : 'object',
    })
  }
}

当生成器因根因 1 未能生成小站时,美术中的 waypointCells 为空。打包器虽通过 findWaypointSpot 计算了备用放置坐标并生成了 SceneWaypoint(即 source: "placed"),但从未将该小站补入 level.objects!
导致:

  1. scene.json 中的 objects 数组完全没有小站条目。
  2. 小站的 DCC/DC6 原版动画图集(如 wptrlitonhth.dcc)没有被打包进关卡图集 objects-*.png。

根因 3:src/scene/act-scene.ts 渲染端仅依赖 scene.objects,对 waypoints 元数据缺乏渲染补全

在游戏运行端,小站交互(pendingInteraction = { kind: "waypoint" })通过 runtime.waypoints 进行坐标与距离匹配(80px),而场景绘制循环仅遍历 scene.objects / objectDrawables。
因为物件列表缺失小站,前端画布在对应坐标处没有画出任何像素,直接导致了玩家看到的“隐形小站”。

根因 4:迷宫与预设关卡(Level 74 神秘避难所、Level 123 痛楚之厅)小站映射缺陷

  • Level 74(神秘避难所):预设拼装时未包含对应的小站 DS1 部件。
  • Level 123(痛楚之厅):maze.ts 中的小站房间部件在未找到内嵌物件时,硬编码生成 id = 119(Act 1 物件),在 Act 5 环境下无法映射到合法美术资源。

4. 修复方案 (Remediation Plan)

  1. 重构 wilderness.ts 中的小站存在性检测:
    • 彻底废除跨 Act 全局 ALL_WAYPOINT_IDS 集合。
    • 改为严格按当前关卡所属 Act 的专属小站 ID 判定(或通过 lookupObject(act, 2, obj.id) 检测其解析后的 Token 是否为 WP / WM / WZ / WV / WT),消除火把、树木、武器架等非小站物件的误判短路。
  2. 完善打包管线 pack-act-assets.ts 实体注入:
    • 当小站由 findWaypointSpot 放置(source: "placed")或户外生成时,自动向 level.objects 中注入对应 Act 的规范小站物件。
    • 确保其自动提取对应 DCC 动画美术并打包入 objects-*.png,使 scene.json 同时拥有元数据与渲染实体。
  3. 修复 maze.ts 迷宫关卡小站生成:
    • 依据当前迷宫所属 Act 分配对应的小站物件 ID(Act 1: 37, Act 2: 10, Act 3: 1, Act 4: 0, Act 5: 12),修复 Level 123 等关卡。
  4. 全量关卡小站自动化测试守门:
    • 新增针对全部 39 个小���关卡(109 个变体)的自动化单测,断言每一个拥有小站的关卡必须 100% 包含有效小站 Drawable 与动画帧数据。
### 1. 缺陷背景与现象 (Defect Symptoms) - **现象描述**:玩家在小站传送菜单中选择进入 **第一幕:冰冷之原(Cold Plains,Level 3,Waypoint ID 1)** 后,角色能够正常传送落地,但场景中**完全没有渲染小站(Waypoint)底座与蓝色发光能量环**,地表仅显示普通的泥土地皮与杂草。 - **交互异象**:玩家在小站预设落脚点附近(~48px / 80px 交互半径内)点击地面,仍然能够触发唤起小站传送 UI 面板,但视觉上该小站处于完全隐形状态(Ghost / Invisible Waypoint)。 - **实机截图**: > 见附件截图:角色站在冰冷之原的泥土地上,左侧小站菜单处于激活状态,但场景中央空无一物,缺失小站模型。 --- ### 2. 全量 39 个小站与 109 个关卡变体审查结果 (Full Spectrum Audit: 39 Waypoints / 109 Variants) 经自动化脚本对 `samples/d2-packs` 中全部关卡包进行逐一解析与审查,全游戏 39 处小站中,仅 25 处正常渲染,**多达 14 处关卡(共计 37 个关卡变体)的小站物件完全或部分缺失未渲染**! #### 统计概览 - **正常渲染 [OK]**:25 处(占比 64.1%) - **完全缺失 [ALL MISSING]**:11 处(占比 28.2%,所有变体均缺失) - **部分变体缺失 [PARTIAL MISSING]**:3 处(占比 7.7%) - **缺失变体总数**:37 / 109 变体未包含小站实体物件(全部降级为 `source: "placed"`) #### 详细审查清单 | 幕次 | 小站 ID | 关卡 ID | 关卡名称 | 渲染状态 | 变体支持率 | 缺失变体文件 | | :--- | :--- | :--- | :--- | :---: | :---: | :--- | | **Act 1** | WP 0 | Level 1 | 罗格营地 Rogue Encampment | **OK** | 4/4 | 无 | | **Act 1** | **WP 1** | **Level 3** | **冰冷之原 Cold Plains** | **ALL MISSING** | **0/3** | `3-act-1-wilderness-2-var1/var2/var3` | | **Act 1** | **WP 2** | **Level 4** | **乱石旷野 Stony Field** | **ALL MISSING** | **0/3** | `4-act-1-wilderness-3-var1/var2/var3` | | **Act 1** | **WP 3** | **Level 5** | **黑暗森林 Dark Wood** | **ALL MISSING** | **0/3** | `5-act-1-wilderness-4-var1/var2/var3` | | **Act 1** | **WP 4** | **Level 6** | **黑色荒地 Black Marsh** | **ALL MISSING** | **0/3** | `6-act-1-wilderness-5-var1/var2/var3` | | **Act 1** | WP 5 | Level 27 | 外侧回廊 Outer Cloister | **OK** | 3/3 | 无 | | **Act 1** | WP 6 | Level 29 | 监狱第一层 Jail Level 1 | **OK** | 3/3 | 无 | | **Act 1** | WP 7 | Level 32 | 内侧回廊 Inner Cloister | **OK** | 1/1 | 无 | | **Act 1** | WP 8 | Level 35 | 地下墓穴第二层 Catacombs Level 2 | **OK** | 3/3 | 无 | | **Act 2** | WP 9 | Level 40 | 鲁·高因 Lut Gholein | **OK** | 2/2 | 无 | | **Act 2** | WP 10 | Level 48 | 下水道第二层 Sewers Level 2 | **OK** | 3/3 | 无 | | **Act 2** | **WP 11** | **Level 42** | **干燥高地 Dry Hills** | **ALL MISSING** | **0/3** | `42-act-2-desert-2-var1/var2/var3` | | **Act 2** | WP 12 | Level 57 | 死亡之殿第二层 Halls of the Dead Level 2 | **OK** | 3/3 | 无 | | **Act 2** | **WP 13** | **Level 43** | **遥远绿洲 Far Oasis** | **ALL MISSING** | **0/3** | `43-act-2-desert-3-var1/var2/var3` | | **Act 2** | **WP 14** | **Level 44** | **遗失的城市 Lost City** | **ALL MISSING** | **0/3** | `44-act-2-desert-4-var1/var2/var3` | | **Act 2** | WP 15 | Level 52 | 皇宫监牢第一层 Palace Cellar Level 1 | **OK** | 3/3 | 无 | | **Act 2** | **WP 16** | **Level 74** | **神秘避难所 Arcane Sanctuary** | **ALL MISSING** | **0/3** | `74-act-2-arcane-var1/var2/var3` | | **Act 2** | WP 17 | Level 46 | 群蛇峡谷/术士峡谷 Canyon of the Magi | **OK** | 3/3 | 无 | | **Act 3** | WP 18 | Level 75 | 库拉斯特海港 Kurast Docks | **OK** | 1/1 | 无 | | **Act 3** | **WP 19** | **Level 76** | **蜘蛛森林 Spider Forest** | **PARTIAL** | **2/3** | `76-act-3-jungle-1-var2` | | **Act 3** | **WP 20** | **Level 77** | **庞大湿地 Great Marsh** | **PARTIAL** | **2/3** | `77-act-3-jungle-2-var2` | | **Act 3** | **WP 21** | **Level 78** | **剥皮丛林 Flayer Jungle** | **PARTIAL** | **1/3** | `78-act-3-jungle-3-var2/var3` | | **Act 3** | **WP 22** | **Level 79** | **库拉斯特下层 Lower Kurast** | **ALL MISSING** | **0/3** | `79-act-3-kurast-1-var1/var2/var3` | | **Act 3** | WP 23 | Level 80 | 库拉斯特商场 Kurast Bazaar | **OK** | 3/3 | 无 | | **Act 3** | **WP 24** | **Level 81** | **库拉斯特上层 Upper Kurast** | **ALL MISSING** | **0/3** | `81-act-3-kurast-3-var1/var2/var3` | | **Act 3** | WP 25 | Level 83 | 崔凡克 Travincal | **OK** | 3/3 | 无 | | **Act 3** | WP 26 | Level 101 | 憎恨囚牢第二层 Durance of Hate Level 2 | **OK** | 3/3 | 无 | | **Act 4** | WP 27 | Level 103 | 群魔堡垒 The Pandemonium Fortress | **OK** | 1/1 | 无 | | **Act 4** | WP 28 | Level 106 | 绝望平原/受诅者之城 City of the Damned | **OK** | 3/3 | 无 | | **Act 4** | WP 29 | Level 107 | 火焰之河 River of Flame | **OK** | 3/3 | 无 | | **Act 5** | WP 30 | Level 109 | 哈洛加斯 Harrogath | **OK** | 1/1 | 无 | | **Act 5** | WP 31 | Level 111 | 冰冻高地 Frigid Highlands | **OK** | 3/3 | 无 | | **Act 5** | WP 32 | Level 112 | 亚瑞特高原 Arreat Plateau | **OK** | 3/3 | 无 | | **Act 5** | WP 33 | Level 113 | 水晶通道 Crystalline Passage | **OK** | 3/3 | 无 | | **Act 5** | WP 34 | Level 115 | 冰河路径 Glacial Trail | **OK** | 3/3 | 无 | | **Act 5** | **WP 35** | **Level 123** | **痛楚之厅 Halls of Pain** | **ALL MISSING** | **0/3** | `123-act-5-temple-2-var1/var2/var3` | | **Act 5** | WP 36 | Level 117 | 冰冻苔原 Frozen Tundra | **OK** | 3/3 | 无 | | **Act 5** | WP 37 | Level 118 | 远古之路 The Ancients\' Way | **OK** | 3/3 | 无 | | **Act 5** | WP 38 | Level 129 | 世界之石要塞第二层 Worldstone Keep Level 2 | **OK** | 3/3 | 无 | --- ### 3. 根因深度剖析(暴雪 1.13c Ground Truth 与源码缺陷) #### 根因 1:`src/game/wilderness.ts` 中 `ALL_WAYPOINT_IDS` 跨幕 ID 碰撞,导致生成器误判已有小站而提前短路 在暴雪 1.13c 汇编实现中(`D2Common.dll` ≈0x6FD92700 `DRLGOUTDOORS_SpawnAct12Waypoint`),DS1 物件的 `id` 在不同 Act / 关卡类型下是**局部作用域**的,必须结合 `act` 与 `type` 进行映射(见 `object-lookup.ts`)。 各幕真实的小站 DS1 ID 与对应 `Objects.txt` 关系为: - **Act 1**:小站 ID = 37(预设为 52),对应 `Objects.txt` row 119(Token `WP`) - **Act 2**:小站 ID = 10(预设为 306),对应 `Objects.txt` row 156(Token `WM`) - **Act 3**:小站 ID = 1(预设为 387),对应 `Objects.txt` row 237(Token `WZ`) - **Act 4**:小站 ID = 0(预设为 388),对应 `Objects.txt` row 238(Token `WV`) - **Act 5**:小站 ID = 12(预设为 188),对应 `Objects.txt` row 38(Token `WT`) 然而在 `src/game/wilderness.ts` 第 5997 行中,开发者为了检查预设是否已经放置了小站,错误地创建了一个跨幕混合的全局 Set: ```typescript // wilderness.ts line 5997 const ALL_WAYPOINT_IDS = new Set([37, 52, 269, 10, 306, 1, 387, 0, 388, 12, 188]) const existingWp = canvas.objects.find( o => o.type === 2 && ALL_WAYPOINT_IDS.has(o.id), ) if (existingWp !== undefined) { stats.waypointsSpawned = 1 stats.waypointTile = { ... } return // 💥 致命短路:直接跳过小站生成! } ``` **冲突事实**: - Act 1 荒野预设图块(如沉沦魔营地、废墟小屋等)中大量包含���把 / 占位物件(Token `TO`),其 DS1 `id = 1`。 - 由于 `ALL_WAYPOINT_IDS` 包含了 Act 3 的小站 ID `1`,Act 1 荒野图块盖章后,`canvas.objects.find()` 必然命中普通火把(`id = 1`)! - 生成器误以为该地图已经包含了小站,立即将 `stats.waypointsSpawned` 设为 1 并直接 `return`,**彻底抹杀了真正的户外小站生成逻辑**(包括冰冷之原与血石荒地交界处专属的 `DRLGOUTDOORS_SpawnAct12Waypoint` 算法)! - 同理: - Act 2 荒野因包含地窖活板门(`id = 0`)和火把(`id = 1`),误匹配 Act 4(`id = 0`)和 Act 3(`id = 1`); - Act 3 库拉斯特因包含丛林树木(`id = 0`)和武器架(`id = 12`),误匹配 Act 4(`id = 0`)和 Act 5(`id = 12`)。 #### 根因 2:`scripts/pack-act-assets.ts` 打包管线降级机制未注入实体物件,导致元数据孤立 在 `scripts/pack-act-assets.ts` 第 801~820 行: ```typescript const waypointId = worldGraph.levels.get(levelId)?.waypoint ?? 255 const waypoints: SceneWaypoint[] = [] if (waypointId !== 255) { const fromArt = waypointCells[0] ?? (mazeWaypoints?.[0] ? { x: mazeWaypoints[0].entityX, y: mazeWaypoints[0].entityY } : undefined) const spot = fromArt ?? findWaypointSpot(grid, region) if (spot !== null && spot !== undefined) { const arrive = nearestWalkable(grid, spot.x + 2, spot.y + 2, 16, region) ?? spot waypoints.push({ waypointId, x: spot.x, y: spot.y, arriveX: arrive.x, arriveY: arrive.y, source: fromArt === undefined ? 'placed' : 'object', }) } } ``` 当生成器因根因 1 未能生成小站时,美术中的 `waypointCells` 为空。打包器虽通过 `findWaypointSpot` 计算了备用放置坐标并生成了 `SceneWaypoint`(即 `source: "placed"`),**但从未将该小站补入 `level.objects`**! 导致: 1. `scene.json` 中的 `objects` 数组完全没有小站条目。 2. 小站的 DCC/DC6 原版动画图集(如 `wptrlitonhth.dcc`)没有被打包进关卡图集 `objects-*.png`。 #### 根因 3:`src/scene/act-scene.ts` 渲染端仅依赖 `scene.objects`,对 `waypoints` 元数据缺乏渲染补全 在游戏运行端,小站交互(`pendingInteraction = { kind: "waypoint" }`)通过 `runtime.waypoints` 进行坐标与距离匹配(80px),而场景绘制循环仅遍历 `scene.objects` / `objectDrawables`。 因为物件列表缺失小站,前端画布在对应坐标处没有画出任何像素,直接导致了玩家看到的“隐形小站”。 #### 根因 4:迷宫与预设关卡(Level 74 神秘避难所、Level 123 痛楚之厅)小站映射缺陷 - **Level 74(神秘避难所)**:预设拼装时未包含对应的小站 DS1 部件。 - **Level 123(痛楚之厅)**:`maze.ts` 中的小站房间部件在未找到内嵌物件时,硬编码生成 `id = 119`(Act 1 物件),在 Act 5 环境下无法映射到合法美术资源。 --- ### 4. 修复方案 (Remediation Plan) 1. **重构 `wilderness.ts` 中的小站存在性检测**: - 彻底废除跨 Act 全局 `ALL_WAYPOINT_IDS` 集合。 - 改为严格按当前关卡所属 Act 的专属小站 ID 判定(或通过 `lookupObject(act, 2, obj.id)` 检测其解析后的 Token 是否为 `WP` / `WM` / `WZ` / `WV` / `WT`),消除火把、树木、武器架等非小站物件的误判短路。 2. **完善打包管线 `pack-act-assets.ts` 实体注入**: - 当小站由 `findWaypointSpot` 放置(`source: "placed"`)或户外生成时,自动向 `level.objects` 中注入对应 Act 的规范小站物件。 - 确保其自动提取对应 DCC 动画美术并打包入 `objects-*.png`,使 `scene.json` 同时拥有元数据与渲染实体。 3. **修复 `maze.ts` 迷宫关卡小站生成**: - 依据当前迷宫所属 Act 分配对应的小站物件 ID(Act 1: 37, Act 2: 10, Act 3: 1, Act 4: 0, Act 5: 12),修复 Level 123 等关卡。 4. **全量关卡小站自动化测试守门**: - 新增针对全部 39 个小���关卡(109 个变体)的自动化单测,断言每一个拥有小站的关卡必须 100% 包含有效小站 Drawable 与动画帧数据。
troytt added this to the [M15] 生成器数据保真度:消除 hardcode 与静默降级 milestone 2026-09-24 03:24:44 +00:00
Author
Owner

实机复现截图 (In-Game Reproduction Screenshot)

冰冷之原小站未渲染缺陷截图

(角色传送至冰冷之原后,左侧已点亮小站菜单,但在场景中央只有空地皮,完全无小站实体模型)

### 实机复现截图 (In-Game Reproduction Screenshot) ![冰冷之原小站未渲染缺陷截图](https://git.projectdiablo2.cn/attachments/3e6da1a2-d135-4ec1-a1f5-57aa8c6c6baf) *(角色传送至冰冷之原后,左侧已点亮小站菜单,但在场景中央只有空地皮,完全无小站实体模型)*
Sign in to join this conversation.
No Label
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#409
No description provided.