v1.2.4: 连续寻路超时超过1分钟自动发送/u return回城,传送后从最高优先级区块重新扩地
这个提交包含在:
@@ -31,6 +31,12 @@ public class ExpansionConfig {
|
||||
/** 超时后的最大重试次数 */
|
||||
public int retries = 2;
|
||||
|
||||
/** 连续寻路超时累计达到该秒数后,发送 /u return 回城传送并重新开始(默认 60 秒) */
|
||||
public int returnThresholdSeconds = 60;
|
||||
|
||||
/** 发送 /u return 后等待传送完成的时间(秒);默认 12 秒,覆盖 10 秒传送延迟并留余量 */
|
||||
public int returnWaitSeconds = 12;
|
||||
|
||||
/** 区域扩地策略的中心 X 坐标(区块) */
|
||||
public int regionCenterX;
|
||||
|
||||
@@ -94,6 +100,8 @@ public class ExpansionConfig {
|
||||
c.targetCount = this.targetCount;
|
||||
c.waitTimeoutSeconds = this.waitTimeoutSeconds;
|
||||
c.retries = this.retries;
|
||||
c.returnThresholdSeconds = this.returnThresholdSeconds;
|
||||
c.returnWaitSeconds = this.returnWaitSeconds;
|
||||
c.regionCenterX = this.regionCenterX;
|
||||
c.regionCenterZ = this.regionCenterZ;
|
||||
c.regionRadius = this.regionRadius;
|
||||
|
||||
@@ -95,6 +95,10 @@ implements SubtitleChatMonitor.Listener, BaritoneBridge.PathListener {
|
||||
private volatile boolean pathCalcFailed;
|
||||
/** 等待开拓时段自动开始:不在 11:00-22:00 时点击开始会暂存配置,进入时段后自动启动(null 表示无等待任务) */
|
||||
private ExpansionConfig pendingStart;
|
||||
/** 连续寻路超时累计时长(毫秒):多次寻路超时逐次累加,达到阈值触发 /u return 回城传送 */
|
||||
private long consecutiveTimeoutMillis;
|
||||
/** 发送 /u return 回城指令的时间戳(RETURNING 状态使用,用于等待传送完成) */
|
||||
private long returnStartMillis;
|
||||
|
||||
public ExpansionController(TerritoryDataService dataService) {
|
||||
this.dataService = dataService;
|
||||
@@ -211,6 +215,7 @@ implements SubtitleChatMonitor.Listener, BaritoneBridge.PathListener {
|
||||
}
|
||||
this.completedClaims = 0;
|
||||
this.retryCount = 0;
|
||||
this.consecutiveTimeoutMillis = 0L;
|
||||
this.queue.clear();
|
||||
this.claimedSet.clear();
|
||||
this.target = null;
|
||||
@@ -298,6 +303,10 @@ implements SubtitleChatMonitor.Listener, BaritoneBridge.PathListener {
|
||||
this.tickNext();
|
||||
break;
|
||||
}
|
||||
case 7: {
|
||||
this.tickReturning();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,6 +388,8 @@ implements SubtitleChatMonitor.Listener, BaritoneBridge.PathListener {
|
||||
}
|
||||
if (this.playerChunk.equals(this.target)) {
|
||||
this.baritoneBridge.cancel();
|
||||
// 成功到达目标:寻路不再卡死,清零连续超时计数
|
||||
this.consecutiveTimeoutMillis = 0L;
|
||||
this.stageStartedMillis = System.currentTimeMillis();
|
||||
this.setState(State.WAITING, "\u5df2\u5230\u8fbe\uff0c\u7b49\u5f85\u9886\u5730\u5f00\u62d3");
|
||||
this.log("\u5df2\u5230\u8fbe\u76ee\u6807 " + this.target.x() + "," + this.target.z() + "\uff0c\u5f00\u59cb\u7b49\u5f85\u5f00\u57a6");
|
||||
@@ -389,7 +400,12 @@ implements SubtitleChatMonitor.Listener, BaritoneBridge.PathListener {
|
||||
++this.retryCount;
|
||||
// 主动刷新地图,尽快同步最新领土状态
|
||||
this.dataService.refreshAsync();
|
||||
if (this.retryCount >= this.config.retries) {
|
||||
// 累计"连续寻路超时"时长:连续多次寻路都超时说明玩家被地形/缝隙卡死走不到目标,
|
||||
// 累计达到阈值后发送 /u return 回城(约 10 秒后传送到可寻路位置),传送后重新规划。
|
||||
this.consecutiveTimeoutMillis += (long)this.config.waitTimeoutSeconds * 1000L;
|
||||
if (this.consecutiveTimeoutMillis >= (long)this.config.returnThresholdSeconds * 1000L) {
|
||||
this.sendReturnCommand();
|
||||
} else if (this.retryCount >= this.config.retries) {
|
||||
// 重试耗尽:跳过当前目标(不再回城),交给下一个目标
|
||||
this.log("\u5bfb\u8def\u8d85\u65f6\uff0c\u8df3\u8fc7 " + this.target.x() + "," + this.target.z());
|
||||
this.setState(State.FAIL, "\u5bfb\u8def\u8d85\u65f6");
|
||||
@@ -401,6 +417,43 @@ implements SubtitleChatMonitor.Listener, BaritoneBridge.PathListener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 连续寻路超时达到阈值时触发回城:
|
||||
* 取消当前寻路,向服务器发送 /u return 指令(约 10 秒后自动传送回可寻路的安全位置),
|
||||
* 随后进入 RETURNING 状态等待传送完成,传送后由 {@link #tickReturning()} 重新规划并从头开始。
|
||||
*/
|
||||
private void sendReturnCommand() {
|
||||
this.baritoneBridge.cancel();
|
||||
MinecraftClient client = MinecraftClient.getInstance();
|
||||
if (client != null && client.player != null) {
|
||||
this.log("\u8fde\u7eed\u5bfb\u8def\u8d85\u65f6\u8d85\u8fc7 " + this.config.returnThresholdSeconds + " \u79d2\uff0c\u53d1\u9001 /u return \u56de\u57ce\uff0c10 \u79d2\u540e\u81ea\u52a8\u4f20\u9001");
|
||||
// 通过玩家网络处理器发送聊天指令 /u return(Yarn 映射:sendChatCommand 自动带上前缀斜杠)
|
||||
client.player.networkHandler.sendChatCommand("u return");
|
||||
client.player.sendMessage(Text.literal("[AutoStore] \u8fde\u7eed\u5bfb\u8def\u8d85\u65f6\uff0c\u5df2\u53d1\u9001 /u return\uff0c\u7b49\u5f85\u4f20\u9001\u540e\u91cd\u65b0\u6269\u5730"), false);
|
||||
} else {
|
||||
this.log("\u8fde\u7eed\u5bfb\u8def\u8d85\u65f6\uff0c\u4f46\u73a9\u5bb6\u4e0d\u5728\u4e16\u754c\uff0c\u8df3\u8fc7");
|
||||
}
|
||||
this.returnStartMillis = System.currentTimeMillis();
|
||||
this.setState(State.RETURNING, "\u7b49\u5f85\u56de\u57ce\u4f20\u9001\uff0810 \u79d2\u540e\u81ea\u52a8\u4f20\u9001\uff09");
|
||||
}
|
||||
|
||||
/**
|
||||
* 回城传送等待阶段每帧逻辑:
|
||||
* 发送 /u return 后服务器约 10 秒把玩家传送回安全位置。等待 {@code returnWaitSeconds}
|
||||
* 秒(覆盖传送延迟并留余量)后,清零连续超时计数并重新规划扩地计划,
|
||||
* 从最高优先级区块(队首)重新开始寻路。
|
||||
*/
|
||||
private void tickReturning() {
|
||||
long elapsedMillis = System.currentTimeMillis() - this.returnStartMillis;
|
||||
if (elapsedMillis < (long)this.config.returnWaitSeconds * 1000L) {
|
||||
return;
|
||||
}
|
||||
this.consecutiveTimeoutMillis = 0L;
|
||||
this.log("\u56de\u57ce\u4f20\u9001\u5b8c\u6210\uff0c\u91cd\u65b0\u89c4\u5212\u5e76\u4ece\u6700\u9ad8\u4f18\u5148\u7ea7\u533a\u5757\u5f00\u59cb");
|
||||
// 重新规划:清空队列重新生成计划,从队首(最高优先级)区块开始寻路
|
||||
this.plan();
|
||||
}
|
||||
|
||||
/** 等待开垦阶段每帧逻辑:玩家离开目标区块则重新寻路;等待超时则重试或跳过当前目标 */
|
||||
private void tickWaiting() {
|
||||
if (this.target == null) {
|
||||
@@ -622,6 +675,8 @@ implements SubtitleChatMonitor.Listener, BaritoneBridge.PathListener {
|
||||
// 缩短"会话占领等待确认"窗口,避免假占领长时间残留
|
||||
this.dataService.refreshAsync();
|
||||
++this.completedClaims;
|
||||
// 开垦成功:寻路/等待恢复正常,清零连续超时计数
|
||||
this.consecutiveTimeoutMillis = 0L;
|
||||
this.target = chunk;
|
||||
this.lastProgress = 100;
|
||||
this.log("\u5360\u9886\u6210\u529f " + chunk.x() + "," + chunk.z() + "\uff08\u533a\u5757 " + chunk.x() + "," + chunk.z() + " / \u4e16\u754c " + blockX + "," + blockZ + "\uff09");
|
||||
@@ -652,6 +707,8 @@ implements SubtitleChatMonitor.Listener, BaritoneBridge.PathListener {
|
||||
// 占领成功后立即触发一次地图刷新,尽快确认该区块
|
||||
this.dataService.refreshAsync();
|
||||
++this.completedClaims;
|
||||
// 开垦成功:寻路/等待恢复正常,清零连续超时计数
|
||||
this.consecutiveTimeoutMillis = 0L;
|
||||
this.lastProgress = 100;
|
||||
this.log("\u5360\u9886\u6210\u529f " + this.target.x() + "," + this.target.z());
|
||||
this.setState(State.SUCCESS, "\u7586\u571f\u5df2\u5f00\u62d3 " + this.target.x() + "," + this.target.z());
|
||||
@@ -826,6 +883,7 @@ implements SubtitleChatMonitor.Listener, BaritoneBridge.PathListener {
|
||||
SUCCESS,
|
||||
FAIL,
|
||||
NEXT,
|
||||
RETURNING,
|
||||
COMPLETE,
|
||||
STOPPED;
|
||||
|
||||
|
||||
在新工单中引用
屏蔽一个用户