[Parity][inv-skills][S1][F/R] 联机物品变体图形丢失:graphicIndex 解析后没接到 UI,珠宝显示成宝石图,戒指/项链/护身符永远是第 1 个变体;另有按 id 哈希、按名字猜图 #681

Closed
opened 2026-10-02 11:42:54 +00:00 by troytt · 0 comments
Owner

1.13c 客户端保真度审计立项(基准快照:7bd1090 / main @ 77a20c7)

证据标记说明:V-data = 1.13c MPQ 数据表 (.txt / animdata.d2 / .tbl / pal.pl2);V-src = D2MOO 逆向源码;V-bin = 1.13c DLL 反汇编;K = 1.13c 公认行为。

来源审计项:inv-skills#3 — [S1][F/R] 联机物品变体图形丢失:graphicIndex 解析后没接到 UI,珠宝显示成宝石图,戒指/项链/护身符永远是第 1 个变体;另有按 id 哈希、按名字猜图

  • 位置:
    • src/netproto/d2gs/items/item-bitstream.ts:326-328:解析出了 graphicIndex,但通往 UI 的链路(item-bridge 在线适配 → hud-model toUiItem)从来不设置 UiInventoryItem.variant。
    • src/client/ui/inventory.ts:237-378(resolveItemSpriteRect 的 Tier 0.5):
      • 写死变体数组;
      • 没有 variant 时,按 item.id 字符串哈希挑变体(310-320、333-344);
      • 按名字匹配 Annihilus/Torch/Gheed;
      • crs、cta 或名字含 Call to Arms 的一律返回 invcrs(376-377)。
    • src/common/items/item-bridge.ts:553-640(resolveItemInvFile)。
  • 代码:
    const graphicIndex = hasGraphic ? reader.readBits(3) : undefined   // item-bitstream.ts:328,之后没有任何地方使用
    hash = ((hash << 5) - hash + idStr.charCodeAt(i)) | 0              // inventory.ts:315
    if (item.code === 'crs' || item.code === 'cta' || item.name?.includes('Call to Arms')) return itemRects['invcrs'] ?? null
    
  • 原版:
    • itemtypes.txt 的 VarInvGfx / InvGfx1..6(V-data):
      • ring #10=5(invrin1–5)、amul #12=3(invamu1–3)、jewl #59=6(invjw1–6)
      • scha #83=3(invch1/4/7)、mcha #84=3(invch2/5/8)、lcha #85=3(invch3/6/9)
    • misc.txt 中这些物品的 invfile 只是占位(V-data):jew #136=invgswe、cm1 #96=invchm、cm2 #97=invwnd、cm3 #98=invsst、rin #14=invrin、amu #12=invamu。
    • 服务器创建物品时随机生成 nInvGfxIdx(V-src D2MOO D2Game/src/ITEMS/Items.cpp:748-751,ITEMS_SetVarGfxIndex(*ppUnit, ITEMS_RollLimitedRandomNumber(..., ITEMS_GetVarInvGfxCount(*ppUnit))))。
    • 存盘和传输用 1 位标志加 3 位索引(V-src D2Common/src/Items/Items.cpp:5073-5076 读、6745-6761 写)。客户端应按 InvGfx[nInvGfxIdx] 选图。
    • 符文之语沿用底材图形,Call to Arms 不应固定画成 Crystal Sword(K-高)。
  • 影响(本地 tsx 核对):
    • 联机时珠宝显示为 invgswe(宝石图)。
    • 所有戒指都是 invrin1,所有项链都是 invamu1;小/大/超大护身符固定为 invch1/invch2/invch3。原版的随机外观完全丢失。
    • 离线路径用 id 哈希来"伪随机",结果与原版无关。
    • 做在 Flail 等其他底材上的 Call to Arms 会画成水晶剑。
  • 建议:
    • 把 graphicIndex 透传为 variant,按 itemtypes 的 InvGfx{variant+1} 取图。VarInvGfx=0 时再用 invfile,或 uniqueitems/setitems 的 invfile。
    • 删掉 id 哈希、按名字匹配和 invcrs 特判。
    • 缺图时报错,不要回退到第 1 个变体。
  • 已有 issue:—(#540 是 object/NPC 色块,不是同一问题)
> **1.13c 客户端保真度审计立项**(基准快照:`7bd1090` / `main @ 77a20c7`) > 证据标记说明:`V-data` = 1.13c MPQ 数据表 (`.txt` / `animdata.d2` / `.tbl` / `pal.pl2`);`V-src` = D2MOO 逆向源码;`V-bin` = 1.13c DLL 反汇编;`K` = 1.13c 公认行为。 ### 来源审计项:`inv-skills#3` — [S1][F/R] 联机物品变体图形丢失:graphicIndex 解析后没接到 UI,珠宝显示成宝石图,戒指/项链/护身符永远是第 1 个变体;另有按 id 哈希、按名字猜图 - 位置: - `src/netproto/d2gs/items/item-bitstream.ts:326-328`:解析出了 `graphicIndex`,但通往 UI 的链路(item-bridge 在线适配 → hud-model `toUiItem`)从来不设置 `UiInventoryItem.variant`。 - `src/client/ui/inventory.ts:237-378`(`resolveItemSpriteRect` 的 Tier 0.5): - 写死变体数组; - 没有 variant 时,按 `item.id` 字符串哈希挑变体(310-320、333-344); - 按名字匹配 `Annihilus`/`Torch`/`Gheed`; - `crs`、`cta` 或名字含 `Call to Arms` 的一律返回 `invcrs`(376-377)。 - `src/common/items/item-bridge.ts:553-640`(`resolveItemInvFile`)。 - 代码: ```ts const graphicIndex = hasGraphic ? reader.readBits(3) : undefined // item-bitstream.ts:328,之后没有任何地方使用 hash = ((hash << 5) - hash + idStr.charCodeAt(i)) | 0 // inventory.ts:315 if (item.code === 'crs' || item.code === 'cta' || item.name?.includes('Call to Arms')) return itemRects['invcrs'] ?? null ``` - 原版: - itemtypes.txt 的 `VarInvGfx` / `InvGfx1..6`(V-data): - ring #10=5(invrin1–5)、amul #12=3(invamu1–3)、jewl #59=6(invjw1–6) - scha #83=3(invch1/4/7)、mcha #84=3(invch2/5/8)、lcha #85=3(invch3/6/9) - misc.txt 中这些物品的 `invfile` 只是占位(V-data):jew #136=`invgswe`、cm1 #96=`invchm`、cm2 #97=`invwnd`、cm3 #98=`invsst`、rin #14=`invrin`、amu #12=`invamu`。 - 服务器创建物品时随机生成 `nInvGfxIdx`(V-src D2MOO `D2Game/src/ITEMS/Items.cpp:748-751`,`ITEMS_SetVarGfxIndex(*ppUnit, ITEMS_RollLimitedRandomNumber(..., ITEMS_GetVarInvGfxCount(*ppUnit)))`)。 - 存盘和传输用 1 位标志加 3 位索引(V-src `D2Common/src/Items/Items.cpp:5073-5076` 读、`6745-6761` 写)。客户端应按 `InvGfx[nInvGfxIdx]` 选图。 - 符文之语沿用底材图形,Call to Arms 不应固定画成 Crystal Sword(K-高)。 - 影响(本地 tsx 核对): - 联机时珠宝显示为 `invgswe`(宝石图)。 - 所有戒指都是 invrin1,所有项链都是 invamu1;小/大/超大护身符固定为 invch1/invch2/invch3。原版的随机外观完全丢失。 - 离线路径用 id 哈希来"伪随机",结果与原版无关。 - 做在 Flail 等其他底材上的 Call to Arms 会画成水晶剑。 - 建议: - 把 `graphicIndex` 透传为 `variant`,按 itemtypes 的 `InvGfx{variant+1}` 取图。`VarInvGfx`=0 时再用 invfile,或 uniqueitems/setitems 的 invfile。 - 删掉 id 哈希、按名字匹配和 `invcrs` 特判。 - 缺图时报错,不要回退到第 1 个变体。 - 已有 issue:—(#540 是 object/NPC 色块,不是同一问题)
Sign in to join this conversation.
No Label
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

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