fix: 修正原点(00)两种原因的判断依据 —— 两种情况下脚下都是基岩

用户指出:死亡被卡到 00 时脚下**也是基岩**,所以原来用
lockBelow === 'bedrock' 区分「登录服」和「死亡卡住」是错的,
会把死亡卡住误判成登录服,于是不做自救、只让用户去输验证码。

改成以「服务器有没有要求输入验证码」为唯一可靠信号:
- 要求验证码 -> 判定为登录服,提示人工发验证码(不做无意义的左右移动)
- 没要求验证码 -> 判定为死亡卡住,自动左右移动触发服务器重新传送

自救本身在两种情况下都无害(在登录服里按左右键不会有后果),
所以即使判断错了也不会把事情弄得更糟。

另外:验证码提示往往比 spawn 晚到,所以 _handleAuthPrompt 里也补了一次判断 ——
若提示到达时机器人正好在原点附近,会明确点出「被反复传送刷屏」正是登录服造成的,
把这个因果关系讲清楚,避免用户只看到传送刷屏而不知原因。

同步修正 TODO.md 与 CHANGELOG 里那条错误结论,并标注「不要用基岩做判断依据」。

测试 363 -> 368,全部通过。
这个提交包含在:
lyizai
2026-09-28 20:32:49 +08:00
父节点 9ca80d2f6e
当前提交 0cd65cf9be
共修改 4 个文件,包含 129 行新增和 21 行删除
+24 -13
查看文件
@@ -230,35 +230,38 @@ class BotManager extends EventEmitter {
*
* 邦国崛起这台服务器有两种截然不同的原因会把玩家送到原点附近:
*
* 1. **死亡后被卡在原点** —— 此时左右移动一下就会触发服务器重新传送回正常位置,
* 1. **死亡后被卡在原点** —— 左右移动一下就会触发服务器重新传送回正常位置,
* 机器人可以自救,不需要人工介入;
* 2. **被切到登录服** —— 特征是脚下是基岩、四周是虚空、坐标极小(如 `(-2, -2, -4)`),
* 必须重新输入验证码,而验证码只能人工获取,程序无法代劳。
* 2. **被切到登录服** —— 必须重新输入验证码,而验证码只能人工获取,程序无法代劳。
*
* 这两种情况以前在日志里长得一样(都是「被服务器传送」),
* 所以经常误判成「机器人坏了」。现在区分开并给出对应的处置建议。
* ⚠️ **不能用「脚下是不是基岩」来区分这两种情况 —— 实测两种情况下脚下都是基岩。**
* 唯一可靠的信号是**服务器有没有要求输入验证码**(`_needAuthWarned`),
* 所以这里以它为准;没要求验证码就按「死亡卡住」处理并尝试自救。
* 自救本身是无害的(在登录服里按左右键也不会有什么后果),
* 因此即使判断错了也不会把事情弄得更糟。
*/
_handleZeroPosition() {
const bot = this.bot;
if (!bot || !bot.entity) return;
const pos = bot.entity.position;
// 原点判定:水平方向很近且高度很低(正常地形不会在 y<10 的世界原点附近活动)
// 原点判定:水平方向很近且高度很低(正常地形不会在 y<16 的世界原点附近活动)
const nearOrigin = Math.abs(pos.x) < 48 && Math.abs(pos.z) < 48 && pos.y < 16;
if (!nearOrigin) return;
const below = bot.blockAt ? bot.blockAt(pos.offset(0, -1, 0)) : null;
const isLoginLobby = below && below.name === 'bedrock';
if (isLoginLobby) {
this._log(`机器人位于世界原点附近 (${pos.x.toFixed(0)}, ${pos.y}, ${pos.z.toFixed(0)}),`
+ '脚下是基岩 —— 这是服务器的登录服/验证大厅,不是真实世界', 'warn');
const where = `(${pos.x.toFixed(0)}, ${pos.y.toFixed(0)}, ${pos.z.toFixed(0)})`;
if (this._needAuthWarned) {
this._log(`机器人位于世界原点附近 ${where},且服务器正在要求输入验证码`
+ ' —— 这是被切到了登录服,不是真实世界', 'warn');
this._log('请在控制台的聊天框里把验证码发出去(验证码当聊天内容发送即可,不用加斜杠)。'
+ '待在大厅里还会不断触发「被服务器传送」,看起来像机器人坏了', 'warn');
this.needsVerificationHint = true;
return;
}
this._log(`机器人被卡在世界原点附近 (${pos.x.toFixed(0)}, ${pos.y}, ${pos.z.toFixed(0)}),`
+ '疑似死亡后被卡住 —— 尝试左右移动触发服务器重新传送', 'warn');
this._log(`机器人被卡在世界原点附近 ${where},疑似死亡后卡住`
+ '(若服务器随后要求验证码,则是被切到了登录服)—— 尝试左右移动触发服务器重新传送', 'warn');
this.needsVerificationHint = false;
this._escapeFromOrigin();
}
@@ -738,6 +741,14 @@ class BotManager extends EventEmitter {
this._log('服务器要求先完成账号绑定 / 二次验证(本服为「简幻通」体系):' + message, 'error');
this._log('该验证需要人工完成一次(游戏内扫码,或把验证码当聊天内容直接发出去);'
+ '绑定成功后同一账号即可自动登录。若服务器提供固定验证码,可在配置的「账号绑定指令模板」里填写。', 'warn');
// 如果此刻人在原点附近,那就是被切到了登录服 —— 把这条因果关系讲清楚,
// 否则用户只看到「机器人被反复传送」而不知道真正原因
const pos = this.bot && this.bot.entity ? this.bot.entity.position : null;
if (pos && Math.abs(pos.x) < 48 && Math.abs(pos.z) < 48 && pos.y < 16) {
this.needsVerificationHint = true;
this._log('当前机器人位于世界原点附近,说明它已被切到登录服;'
+ '「被服务器传送」刷屏正是这个原因,输入验证码后即会回到真实世界', 'warn');
}
}
if (server.authCommand) {
this.sendCommand(fillTemplate(server.authCommand, password), { internal: true, immediate: true });