fix: 物理录制器区分「被服务端推回」与「输入没进物理」

原来 frozenTicks 只看「有输入 + tick 级无位移 + 物理没报告碰撞」,
但服务端推回发生在 tick 之间,tick 级位移同样是 0 —— 实测大厅里就是这个形态:
collidedHorizontally = false、frozenTicks = 194,而物理其实每 tick 都在动。

现在再按水平速度是否非零细分:
- pushedBackTicks:速度非零 → 物理确实动了,位移被服务端位置包抹掉;
- frozenTicks:速度也是 0 → 这才是「输入根本没进物理」。

类注释里的判定表也同步改成三分法(被挡住 / 被推回 / 输入没生效)。

测试 469 → 470。
这个提交包含在:
lyizai
2026-10-01 16:28:14 +08:00
父节点 468c719e37
当前提交 5513ef9f5f
共修改 5 个文件,包含 57 行新增和 7 行删除
+18
查看文件
@@ -91,6 +91,24 @@ test('有输入但没位移且物理没报告碰撞 → 记为「输入没进物
assert.strictEqual(snap.blockedTicks, 0, '没报告碰撞就不算「被挡住」');
});
test('有输入、没位移、没碰撞,但水平速度非零 → 记为「被服务端推回」', () => {
// 实测形态:大厅里物理每 tick 都在动,位移却被服务端的位置包抹掉
// (推回发生在 tick 之间,所以 tick 级位移为 0、也没有方块碰撞)
const { bot, recorder } = setup();
recorder.start();
bot.setControlState('forward', true);
bot.entity.velocity.set(0, -0.0784, 0.02319);
tick(bot, { isCollidedHorizontally: false });
tick(bot, { isCollidedHorizontally: false });
const snap = recorder.snapshot();
assert.strictEqual(snap.inputTicks, 2);
assert.strictEqual(snap.inputMovedTicks, 0);
assert.strictEqual(snap.pushedBackTicks, 2);
assert.strictEqual(snap.frozenTicks, 0, '速度非零就不该算「输入没进物理」');
assert.strictEqual(snap.blockedTicks, 0);
});
test('没有输入时不计入 inputTicks', () => {
const { bot, recorder } = setup();
recorder.start();