fix(movement): remove unreferenced [0.25,3.0] clamp on local player's movSpd scale
CInstanceBase::SetMoveSpeed only guards moving_speed > 1100 -> 0; the local player's set_server_speed() was additionally floor/ceil-clamping the scale to an arbitrary [0.25, 3.0] band with no basis in the reference or in this project's already-fixed remote-entity equivalent (EntityStore::motion_move_speed). A heavy haste stack or slow debuff on the local player would silently diverge from what everyone else sees. Removed the extra clamp; kept the moving_speed<=0 early-return guard against pre-spawn/malformed values. audit: movement.keyboard.motion/server-speed-scale-clamp closed with reference citation, regression test, and full related-suite pass; contract stays PARTIAL. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
a4ac48db24
commit
c5c183da37
@@ -89,7 +89,7 @@
|
||||
| Branch structure | PARTIAL | W/S、A/D、八方向、释放顺序和 `m_isCmrRot` 相机跟随已覆盖;Paralysis/Faint/Sleep 已调查——Paralysis 死代码、Sleep 已被 `stunned` 门覆盖、Faint 证据不足,均非差异 |
|
||||
| Algorithms/formulas | PARTIAL | 方向优先级、归一化和相机跟随的 fold-to-±90/rate 公式一致(`movement.keyboard.motion/camera-auto-follow-rotation`);固定 300 像素 Dst 与根运动仍被连续速度替代 |
|
||||
| State transition order | PARTIAL | 输入状态、锁门/移动技能恢复、PlayerController、NetPlay 入口已定位;资源事件与网络事件的完整顺序未证实 |
|
||||
| Constants/units | PARTIAL | 角度/旋转阈值和 0/300/100ms 节流已记录;米/厘米、移动速度和目标距离不同 |
|
||||
| Constants/units | PARTIAL | 角度/旋转阈值和 0/300/100ms 节流已记录;`movSpd` 缩放边界已与 `CInstanceBase::SetMoveSpeed` 对齐(`movement.keyboard.motion/server-speed-scale-clamp`);米/厘米和目标距离仍不同 |
|
||||
| Timing/event sources | PARTIAL | 当前是 `_process` 预测 + signal;参考是 Actor motion event 驱动 |
|
||||
| Resource/data sources | PARTIAL | 当前模型速度可从动作资源读取但有 fallback;`.msa` event/AccumulationMovement 尚未一一对照 |
|
||||
| Protocol side effects | PARTIAL | `FUNC_MOVE/FUNC_WAIT` 发送和节流有测试;阻止/重复/相机副作用仍未闭合 |
|
||||
@@ -106,6 +106,11 @@
|
||||
Paralysis 是可达代码中的死代码(唯一 setter 零调用点);Sleep 在实际运行中是
|
||||
AFFECT_STUN 的别名,已被当前端 `stunned` 移动门覆盖;Faint 的可达性在现有 40250
|
||||
检出材料下无法证明或证伪,evidence-blocked。三者均非需要修复的移动等价差异。
|
||||
- ~~本地玩家 `set_server_speed()` 对 `moving_speed/100.0` 施加了参考代码没有的
|
||||
`clampf(..., 0.25, 3.0)` 边界~~ **已修复(2026-09-22,
|
||||
`movement.keyboard.motion/server-speed-scale-clamp`,见下方实现轮次)**:现在
|
||||
与 `CInstanceBase::SetMoveSpeed` 和已修复的 `EntityStore::motion_move_speed`
|
||||
一样,只在 `moving_speed > 1100` 时归零,其余按 `moving_speed/100.0` 直接换算。
|
||||
|
||||
### Audit round 2026-09-21
|
||||
|
||||
@@ -274,3 +279,55 @@
|
||||
移动阻断结果无影响,已移交 `combat.affect_status` 既有条目,不重复登记。`Remaining`
|
||||
中对应条目标记为已调查关闭。合同状态维持 `PARTIAL`(根运动/资源事件/同步受击门等
|
||||
仍未闭合),Branch structure 行的 Paralysis/Faint/Sleep 备注移除。
|
||||
|
||||
### Implementation fix round 2026-09-22 — `movement.keyboard.motion/server-speed-scale-clamp`
|
||||
|
||||
**参考链**:`InstanceBaseMovement.cpp:CInstanceBase::SetMoveSpeed(UINT uMovSpd)`——
|
||||
`if (uMovSpd > 1100) uMovSpd = 0; m_GraphicThingInstance.SetMoveSpeed(uMovSpd/100.0f);`。
|
||||
除 1100 冻结门外没有其他上下限。
|
||||
|
||||
**当前链(修复前)**:`player_controller.gd::set_server_speed(moving_speed)` 把
|
||||
`moving_speed/100.0` 塞进 `clampf(..., 0.25, 3.0)`,即 `moving_speed<25` 会被强行拉高到
|
||||
0.25 倍速、`moving_speed>300` 会被强行压低到 3.0 倍速——这个区间在参考代码、
|
||||
`InstanceBase.cpp` 或本项目已修复的远端实现 `EntityStore::motion_move_speed`
|
||||
(`extension/src/net/entity_store.cpp`,只有 `moving_speed>1100→0` 和
|
||||
`mount_vnum!=0→0` 两个门)中都找不到依据,是无参考支持的本地私有夹钳:叠了减速/
|
||||
加速状态的本地玩家会和其他人看到的自己不一致。
|
||||
|
||||
调查过程中还确认 `advance_walk_by_motion`(远端实体)和本地 `_process()` 的位移积分
|
||||
在**种类**上是同构的(都是恒速 `speed*dt` 直线插值,都从 `get_move_motion_speeds()`
|
||||
取 `.msa` 基准速度),排除了「根运动 vs 连续速度」这个更大的假设——真正的差异只在
|
||||
速度缩放公式的边界,不涉及积分模型本身。另确认 `CInstanceBase::SHORSE::SetMoveSpeed`
|
||||
是坐骑上玩家的另一套速度设定(`InstanceBase.cpp:40-135`),只在 `IsMounting()` 时生效;
|
||||
本地玩家的动作模式已经在 `net_play.gd::motion_mode_for()` 里按骑乘切到
|
||||
`MOTION_MODE_HORSE`,而远端实体对 `mount_vnum!=0` 直接归零处理——这是坐骑速度的独立
|
||||
细节,本轮不下定论,留给未来一轮单独核实是否构成差异。
|
||||
|
||||
**修复**:`project/player_controller.gd::set_server_speed()` 把
|
||||
|
||||
```gdscript
|
||||
server_speed_scale = clampf(float(moving_speed) / 100.0, 0.25, 3.0)
|
||||
```
|
||||
|
||||
改为
|
||||
|
||||
```gdscript
|
||||
server_speed_scale = 0.0 if moving_speed > 1100 else float(moving_speed) / 100.0
|
||||
```
|
||||
|
||||
`moving_speed <= 0` 提前 return 的既有保护(防止出生前/畸形值冻结本地预测)保留不变。
|
||||
两处调用方(`net_world.gd:795-796`、`net_play.gd:921-924`)均不额外夹钳,改动影响面
|
||||
只限 `player_controller.gd` 本体。
|
||||
|
||||
**测试**:新增 `keyboard_motion_timeline_test.gd` 末尾的 `set_server_speed` 断言
|
||||
(`moving_speed=10→0.1`、`500→5.0`、`1200→0.0`、`100→1.0`,覆盖旧 [0.25,3.0] 边界内外和
|
||||
1100 冻结门),随同下列既有回归一并执行,全部 PASS:
|
||||
`keyboard_motion_timeline_test.gd`、`test_wasd_steering_parity.gd`、
|
||||
`test_no_auto_move_regression.gd`、`game_camera_test.gd`、`movement_parity_test.gd`、
|
||||
`player_move_test.gd`、`mouse_controller_test.gd`、`test_alignment_parity.gd`、
|
||||
`netplay_test.gd`(`netplay_test.gd` 里的同名 mock `set_server_speed` 是独立测试替身,
|
||||
不含旧夹钳逻辑,未受影响)。`git diff --check` 无空白错误。
|
||||
|
||||
**Equivalence**:`Constants/units` 行的 `movSpd` 缩放边界差异关闭;合同状态维持
|
||||
`PARTIAL`(固定 300 像素 Dst/根运动适配层、资源与网络事件完整顺序、坐骑速度细节等
|
||||
仍未闭合)。
|
||||
|
||||
Reference in New Issue
Block a user