feat: 新增物理 tick 录制,把「走不动」的三种原因切开(1.9.0)

抓包已经证明「手动按键时客户端坐标一字未变、服务端入站位置包为 0」,
问题在 prismarine-physics 这一层;但抓包只能看到「发出去的包」,
看不到物理引擎内部读到了什么输入、算出了什么、有没有真的移动。
本提交补上这最后一块拼图。

新增 src/core/physicsRecorder.js + 控制台接口
(POST /api/bots/:id/physics/start|stop、GET /api/bots/:id/physics):

逐 tick 记录位置增量、速度、onGround、isCollidedHorizontally、控制键快照、
脚下/脚部/头部方块名、physicsEnabled;汇总给出四个判定计数:
- inputTicks        有移动输入的 tick 数
- inputMovedTicks   其中真的产生了水平位移的
- blockedTicks      有输入、没位移、物理报告碰撞  → 被方块挡住(地形)
- frozenTicks       有输入、没位移、物理没报告碰撞 → 输入根本没进物理

即:抓包看「发了什么」,本录制器看「物理读到了什么、动没动」,两者配合即可定位。

细节:
- 录制开始时先取一次当前位置作基线,避免第一个 tick 因「没有上一 tick 可比」
  被误判成「有输入但没动」;
- 滚动缓冲只保留最近 240 个 tick(约 12 秒),只放内存、不写盘;
- 录制全程 try 包裹,诊断自身出异常绝不影响物理循环;
- FakeBot 补上与 mineflayer 一致的 controlState(带 getter 的实时控制键代理)。

测试:451 → 468 个用例(含三种故障判定的回归用例与控制台接口用例),全绿。
这个提交包含在:
lyizai
2026-09-30 21:05:38 +08:00
父节点 0c6700642e
当前提交 b2b0317af7
共修改 12 个文件,包含 764 行新增和 5 行删除
+32
查看文件
@@ -2,6 +2,38 @@
本项目遵循 [约定式提交](https://www.conventionalcommits.org/zh-hans/) 与 [语义化版本](https://semver.org/lang/zh-CN/)。
## [1.9.0] - 2026-09-29
补上诊断「走不动」的最后一块拼图:抓包只能看到「客户端发了什么」,
看不到物理引擎内部读到了什么输入、算出了什么、有没有真的移动。
新增**物理 tick 录制器**,与抓包配合就能把三种完全不同的原因一刀切开。
### 新增
- **物理 tick 录制**(`src/core/physicsRecorder.js` + 控制台接口):
- `POST /api/bots/:id/physics/start`(可带 `seconds`)、`/physics/stop`、
`GET /api/bots/:id/physics`(支持 `?limit=`);
- 逐 tick 记录:位置增量、速度、`onGround`、**`isCollidedHorizontally`**、
控制键快照、脚下 / 脚部 / 头部方块名、`physicsEnabled`;
- 汇总给出三个判定用的计数:`inputTicks`(有移动输入的 tick 数)、
`inputMovedTicks`(其中真的产生了水平位移的)、
`blockedTicks`(有输入、没位移、物理报告碰撞 → **被方块挡住**)、
`frozenTicks`(有输入、没位移、物理没报告碰撞 → **输入根本没进物理**);
- 录制开始时先取一次当前位置作基线,避免第一个 tick 因「没有上一 tick 可比」
被误判成「有输入但没动」;
- 滚动缓冲只保留最近 240 个 tick(约 12 秒),只放内存、不写盘。
### 变更
- `FakeBot` 补上与 mineflayer 一致的 `controlState`(带 getter 的实时控制键代理)——
那正是 mineflayer 传给物理引擎的那个对象。
### 测试
新增 17 个用例(451 → 468):物理录制器的逐 tick 记录、三种故障判定
(被挡住 / 输入没生效 / 正常移动)、滚动缓冲、方块读不到时的容错,
以及控制台物理录制接口的 HTTP 用例。
## [1.8.0] - 2026-09-29
把「走不动」的排查手段补成可复用的诊断能力:能按需录下机器人**真正发出的协议包内容**,