[Parity][hud][S2][H][R] 光标状态机:空闲阈值 2000ms(原版 5000ms),帧时长固定 125ms,缺少按下、收手和随机摆动 #646

Closed
opened 2026-10-02 11:42:51 +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 公认行为。

来源审计项:hud#12 — [S2][H][R] 12. 光标状态机:空闲阈值 2000ms(原版 5000ms),帧时长固定 125ms,缺少按下、收手和随机摆动

  • 位置:src/client/ui/cursor.ts:75-82(idleThresholdMs = 2000、frameDurationMs = 125、openingFrameDurationMs = 125)、:112-130(鼠标移动、按下、抬起都调用 resetIdle,直接回到 POINTING)、:137-203
  • 原版(V-bin,D2Client.dll):
    • 空闲判定:state==1 时(0x6fac682b)用 GetTickCount(导入 0x6fb7ef5c)和上次活动时间比较,add ecx,0x1388,即 5000 ms(0x6fac6840)。
    • 光标表在 0x6fba8558(每项 0x1c 字节,共 7 项,计数在 0x6fba861c):0 Gaunt(1 帧)、1 grasp(8 帧)、2 ohand(8 帧,速度 0x40)、3 orotate(循环 8 帧,0x20)、4 ppress(循环 8 帧,0x40)、5 protate(循环 8 帧,0x40)、6 buysell(1 帧)。帧号 = 计数器 >> 8(sar ecx,8,0x6fac68e3)。
    • 指向态 protate:每次更新只有在 (rand & 0x3f) < 0x10(25%)时才前进 0x20(0x6fac650e–0x6fac6538)。ohand 播完后切到 state 4(orotate)(0x6fac65b5–0x6fac65c9)。手张开时移动鼠标会进入 state 3:ohand 从 (nFrames<<8) − 0x100 开始,每次 −0x40 倒放,放完回到 protate(0x6fac647c–0x6fac64ca、0x6fac6250)。按下左键进入 state 5,光标切到 4(ppress)(0x6fac63a6–0x6fac63b6),抬起时中止(0x6fac6300)。
    • 代码注释里的 0x6fac62f0 D2CLIENT_UpdateCursorIdle 落在 0x6fac62e9 处一条 10 字节 mov 指令的中间,这个地址不成立。
  • 影响:手张开得太早(2 秒而不是 5 秒);指向态是匀速摆动,而原版是随机抖动;没有按下手势;手张开时移动鼠标会瞬间切回,而不是倒放收手。
  • 建议:按光标表实现 8.8 定点计数器和 state 1/3/4/5,阈值改为 5000ms。更新函数的调用频率还没核实(见待确认),换算成毫秒前需要先确认。
  • 已有 issue:—
> **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 公认行为。 ### 来源审计项:`hud#12` — [S2][H][R] 12. 光标状态机:空闲阈值 2000ms(原版 5000ms),帧时长固定 125ms,缺少按下、收手和随机摆动 - 位置:`src/client/ui/cursor.ts:75-82`(`idleThresholdMs = 2000`、`frameDurationMs = 125`、`openingFrameDurationMs = 125`)、`:112-130`(鼠标移动、按下、抬起都调用 `resetIdle`,直接回到 POINTING)、`:137-203` - 原版(V-bin,D2Client.dll): - 空闲判定:state==1 时(0x6fac682b)用 `GetTickCount`(导入 0x6fb7ef5c)和上次活动时间比较,`add ecx,0x1388`,即 5000 ms(0x6fac6840)。 - 光标表在 0x6fba8558(每项 0x1c 字节,共 7 项,计数在 0x6fba861c):0 Gaunt(1 帧)、1 grasp(8 帧)、2 ohand(8 帧,速度 0x40)、3 orotate(循环 8 帧,0x20)、4 ppress(循环 8 帧,0x40)、5 protate(循环 8 帧,0x40)、6 buysell(1 帧)。帧号 = 计数器 >> 8(`sar ecx,8`,0x6fac68e3)。 - 指向态 protate:每次更新只有在 `(rand & 0x3f) < 0x10`(25%)时才前进 0x20(0x6fac650e–0x6fac6538)。ohand 播完后切到 state 4(orotate)(0x6fac65b5–0x6fac65c9)。手张开时移动鼠标会进入 state 3:ohand 从 (nFrames<<8) − 0x100 开始,每次 −0x40 倒放,放完回到 protate(0x6fac647c–0x6fac64ca、0x6fac6250)。按下左键进入 state 5,光标切到 4(ppress)(0x6fac63a6–0x6fac63b6),抬起时中止(0x6fac6300)。 - 代码注释里的 `0x6fac62f0 D2CLIENT_UpdateCursorIdle` 落在 0x6fac62e9 处一条 10 字节 mov 指令的中间,这个地址不成立。 - 影响:手张开得太早(2 秒而不是 5 秒);指向态是匀速摆动,而原版是随机抖动;没有按下手势;手张开时移动鼠标会瞬间切回,而不是倒放收手。 - 建议:按光标表实现 8.8 定点计数器和 state 1/3/4/5,阈值改为 5000ms。更新函数的调用频率还没核实(见待确认),换算成毫秒前需要先确认。 - 已有 issue:—
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#646
No description provided.