feat: 掉线重连后自动恢复扩地任务(autoResumeAfterReconnect)

本服会周期性把机器人踢下线(实测约 1~6 分钟一次,踢出原因是
"An internal error occurred in your connection"),每次都会走到「世界已退出,任务停止」。
原来的行为是就此停住 —— 机器人虽然能被原点自救送回真实世界(实测 4/4 成功),
却再也不会继续扩地,于是永远停在原地。

现在世界退出时把本次任务的配置记下来(resumeConfig),
重新进入世界后自动 start() 接上;状态文案改为「世界已退出,等待重连后自动恢复」,
并打印「已重新进入世界,自动恢复扩地任务」。

只有因世界退出而停的那次会登记:手动停止 / 到开垦时段外 / 耐久保护停机
都会在 stop() 里清空 resumeConfig,不会被重连重新拉起。
开关 autoResumeAfterReconnect 默认开启,可关。

测试 470 → 473。
这个提交包含在:
lyizai
2026-10-01 16:34:56 +08:00
父节点 5513ef9f5f
当前提交 0bed12e189
共修改 6 个文件,包含 106 行新增和 5 行删除
+10
查看文件
@@ -122,6 +122,15 @@ function defaultConfig() {
durabilityGuard: true,
/** 耐久保护阈值:剩余耐久百分比 ≤ 该值时回城(1-99) */
durabilityThreshold: 15,
/**
* 掉线重连后是否自动恢复被中断的扩地任务。
*
* 本服会周期性把机器人踢下线(实测约 1~6 分钟一次),每次都会触发
* 「世界已退出,任务停止」。若不自动恢复,任务就永远停在那里 ——
* 机器人虽然能被原点自救送回真实世界,却再也不会继续扩地。
* 手动停止 / 到时段外 / 耐久保护停机都不会被自动恢复。
*/
autoResumeAfterReconnect: true,
/** 是否启用自动用船过水 */
autoBoat: false,
/** 触发自动用船的水面最小宽度(格) */
@@ -495,6 +504,7 @@ function validateConfig(config) {
config.claimEndHour = clampInt(config.claimEndHour, 1, 24, 22);
config.eatThreshold = clampInt(config.eatThreshold, 0, 20, 14);
config.durabilityThreshold = clampInt(config.durabilityThreshold, 1, 99, 15);
config.autoResumeAfterReconnect = config.autoResumeAfterReconnect !== false;
config.autoBoatMinWidth = clampInt(config.autoBoatMinWidth, 1, 64, 4);
config.autoBoatMinLength = clampInt(config.autoBoatMinLength, 1, 128, 6);
config.refreshIntervalSeconds = clampInt(config.refreshIntervalSeconds, 10, 3600, 30);
+29 -1
查看文件
@@ -128,6 +128,15 @@ class ExpansionController {
/** 等待开拓时段自动开始:不在时段时点击开始会暂存配置(null 表示无等待任务) */
this.pendingStart = null;
/**
* 被「世界退出」打断的任务配置:重连进入世界后用它自动恢复。
*
* 本服会周期性把机器人踢下线(实测约 1~6 分钟一次),而每次掉线都会走到
* 「世界已退出,任务停止」。没有这个字段的话,机器人虽然能被原点自救送回
* 真实世界,任务却再也不会继续 —— 扩地永远跑不长。
* 手动停止 / 到时段外 / 耐久保护停机都不会写入它。
*/
this.resumeConfig = null;
/** 连续寻路超时累计时长(毫秒) */
this.consecutiveTimeoutMillis = 0;
/** 发送回城指令的时间戳 */
@@ -228,6 +237,8 @@ class ExpansionController {
return false;
}
this.config = requestedConfig;
// 显式启动的任务优先于「掉线待恢复」的那一次
this.resumeConfig = null;
// 现实时间限制:不在允许时段时登记「等待自动开始」,进入时段后由 tick() 自动启动
if (!this.isWithinClaimTime()) {
this.pendingStart = requestedConfig;
@@ -308,6 +319,8 @@ class ExpansionController {
/** 手动停止任务 */
stop() {
const bm = this.botManager;
// 任何显式停止都作废「掉线待恢复」——只有 tick() 里因世界退出而停的那次会重新登记
this.resumeConfig = null;
if (this.pendingStart) {
this.pendingStart = null;
this.setState(State.IDLE, '已取消自动开始');
@@ -335,11 +348,26 @@ class ExpansionController {
if (!this.config) return; // 尚未启动过任务,没有可驱动的状态
if (!bm.isSpawned()) {
if (this.isRunning()) {
// 先记下这次任务的配置:本服会周期性把机器人踢下线,重连回来时若没人管,
// 任务就永远停在这里。stop() 会清空 resumeConfig,所以要在它之后重新登记。
const interrupted = this.config;
this.stop();
this.status = '世界已退出,任务停止';
this.status = '世界已退出,等待重连后自动恢复';
if (interrupted && interrupted.autoResumeAfterReconnect !== false) {
this.resumeConfig = interrupted;
this._log('世界已退出,任务已暂停;重新进入世界后会自动恢复');
}
}
return;
}
// 重新进入世界:把被掉线打断的任务接上
if (this.resumeConfig && !this.isRunning()) {
const resume = this.resumeConfig;
this.resumeConfig = null;
this._log('已重新进入世界,自动恢复扩地任务');
this.start(resume).catch((err) => this._log('自动恢复任务失败:' + err.message, 'error'));
return;
}
this.playerChunk = this._playerChunk();
// 续租当前目标:长距离寻路可能要走几分钟,不能让租约中途过期被别人抢走
if (this.isRunning()) this._renewTargetLease();