fix: 修复登录按钮死锁,移植旧版 player_input 补包解决「机器人走不动」
控制台登录按钮点不动(致命) - bindEvents() 只在 startApp() 里执行,而 startApp() 只在登录成功后才跑, 未登录时登录按钮根本没绑上事件,形成死锁。现在在 main() 里无条件绑定。 机器人走不动(致命,根因定位并修复) - mineflayer 不发 player_input 包:1.21.2+ 服务端的移动预测依赖它,原版客户端每 tick 都发, 而 mineflayer 只在骑乘/跳下/潜行时发,地面移动的 forward/jump/sprint 完全不发。 带反作弊的服务器判定「没有任何输入却发生位移」,每 tick 把玩家拉回原位置。 实测:修复前入站强制位置同步约 17 次/秒、按方向键 2 秒位移 0.00 格; 修复后入站降到 0 次、位移 0.53~1.40 格。该修复来自旧版机器人(感谢原作者)。 - 同时补发 tick_end(原版每 tick 末尾发送,反作弊用它判定 tick 边界,mineflayer 完全不发) - 资源包未自动接受会卡在加载界面进不了世界,现自动接受 - configure() 每次配置变更都重复注册寻路事件监听,导致同一事件被处理多次 长距离分段寻路 - mineflayer-pathfinder 只能规划已加载区块范围(实测约 8 区块 ≈ 130 格), 扩地目标常在几十个区块外,A* 瞬间 noPath。现在自动拆段:走到已加载范围边缘 → 新区块加载 → 再规划。 段长用 bot.blockAt 对未加载区块返回 null 的特性二分探测,不依赖世界内部结构。 新增 - pathing.thinkTimeoutMs / tickTimeoutMs / searchRadius(负值表示不限制剪枝) - 位置包收发计数、player_input/tick_end 计数、游戏模式、维度、脚下方块、 六向「脚部/头部/地面」与可通行判定等诊断字段 - 手动移动测试按钮(绕开寻路器直接按方向键并回报真实位移) 已知限制 - 机器人当前所在位置 (6759,72,11926) 无法寻路:A* 恒定只展开 47 个节点就 noPath。 已逐项排除挖方块/放方块/跑酷/搭塔/开门/最大下落(试到 64 格)/高度偏好/水域代价/ 搜索半径(试到不限制)/时间预算/依赖版本(与能正常移动的旧机器人完全一致)。 旧机器人日志证明寻路可用(2 次 goal_reached、2 秒走 8.7 格),但它当时在 y=-59, 本机器人被 /spawn 放到了 y=72。下一步需把机器人挪到开阔地再试。 测试 290 -> 308,全部通过。
这个提交包含在:
@@ -247,23 +247,54 @@ pm2 startup systemd -u root --hp /root # 开机自启
|
||||
- **位移正常、但任务报「目标不可达」** → 是规划问题(距离太远、被地形挡住、挖/放方块被 Grim 约束禁用)
|
||||
- **位移 ≈ 0** → 客户端移动被服务端拒绝,属于协议 / 反作弊交互问题,改规划参数没有意义
|
||||
|
||||
配套的诊断数据在 `GET /api/bots/:id/status`:
|
||||
#### 最关键的一条:mineflayer 不发 `player_input`
|
||||
|
||||
这是本项目在真实服务器上「怎么按方向键都不动」的根因,**已在 `GrimCompat` 里自动补发**:
|
||||
|
||||
1.21.2+ 服务端的移动预测依赖 `player_input` 包,原版客户端每 tick 都发;
|
||||
而 mineflayer 只在骑乘 / 跳下 / 潜行时发,地面移动的 forward / jump / sprint **完全不发**。
|
||||
带反作弊的服务器因此判定「没有任何输入却发生了位移」,**每 tick 把玩家拉回原位置**。
|
||||
|
||||
实测对比(同一账号、同一位置、同一时段):
|
||||
|
||||
| | 入站强制位置同步 | 按方向键 2 秒的位移 |
|
||||
| --- | --- | --- |
|
||||
| 不补 `player_input` | ~17 次/秒 | 0.00 格 |
|
||||
| 补 `player_input` + `tick_end` | **0 次** | 0.53 ~ 1.40 格 |
|
||||
|
||||
同时补发的还有 `tick_end`(原版 1.21.2+ 客户端每 tick 末尾发送,反作弊用它判定 tick 边界)。
|
||||
两者可在配置里关掉(`grim.sendPlayerInput` / `grim.sendTickEnd`),但**线上服务器不要关**。
|
||||
|
||||
#### 长距离寻路会被自动拆段
|
||||
|
||||
mineflayer-pathfinder 只能规划**已加载区块**范围(实测本服约 8 区块 ≈ 130 格),
|
||||
而扩地目标常在几十个区块之外,A* 会瞬间返回 noPath。
|
||||
寻路服务会把旅程拆成若干段:走到已加载范围边缘附近 → 新区块加载 → 再规划下一段。
|
||||
段长由 `bot.blockAt` 对未加载区块返回 null 的特性二分探测得出,不依赖世界内部结构。
|
||||
相关配置:`pathing.maxSegmentBlocks`、`pathing.segmentMarginBlocks`。
|
||||
|
||||
#### 配套的诊断数据
|
||||
|
||||
在 `GET /api/bots/:id/status`:
|
||||
|
||||
| 字段 | 含义 |
|
||||
| --- | --- |
|
||||
| `packetStats.inboundPosition` | 服务端下发的强制位置同步次数 |
|
||||
| `packetStats.inboundPosition` | 服务端下发的强制位置同步次数(持续很高 = 被回弹) |
|
||||
| `packetStats.outboundPosition` | 客户端上报的位置包次数 |
|
||||
| `packetStats.playerInput` / `tickEnd` | 每 tick 补发的协议包次数(应约等于 20/秒) |
|
||||
| `packetStats.onGroundFixed` | 出站包中 onGround 被世界数据纠正的次数 |
|
||||
| `onGround` | 客户端当前认为自己在不在空中 |
|
||||
| `gameMode` / `dimension` | 游戏模式与维度(adventure / spectator 会限制移动) |
|
||||
| `world.blockBelow` / `world.surroundings` | 脚下方块与六向实心情况(判断是否被困住) |
|
||||
| `world.blockBelow` / `world.surroundings.exits` | 脚下方块与各方向「脚部 / 头部 / 地面」方块名 + 可通行判定 |
|
||||
| `grim.protocolPackets` | 协议补包是否生效及发送计数 |
|
||||
|
||||
判读方式:
|
||||
|
||||
- 入站高、出站为 0 → 客户端根本没上报位置
|
||||
- 出入都高但位移为 0 → 客户端在报,服务端不认(回弹)
|
||||
- `onGround` 恒为 false 而 `world.blockBelowSolid` 为 true → 客户端上报「站在地上却在空中」,
|
||||
开启 `grim.reportOnGroundFromWorld` 可修正
|
||||
- `onGround` 恒为 false 而 `world.blockBelowSolid` 为 true → 开启 `grim.reportOnGroundFromWorld`
|
||||
- **寻路日志里「已探索节点数」极小(如几十个)就 noPath** → 不是距离问题,是移动生成器
|
||||
从起点就找不到分支:检查 `world.surroundings.exits` 的 `walkable`,或把机器人挪到开阔地
|
||||
|
||||
---
|
||||
|
||||
|
||||
在新工单中引用
屏蔽一个用户