v1.2.4: 连续寻路超时超过1分钟自动发送/u return回城,传送后从最高优先级区块重新扩地

这个提交包含在:
lyizai
2026-08-21 16:10:02 +08:00
父节点 a9c71861f5
当前提交 08e15ffc9b
共修改 5 个文件,包含 72 行新增和 5 行删除
+3 -2
查看文件
@@ -8,6 +8,7 @@
- 四种扩地策略:方形外扩、区域扩地、玩家周围、绕国一圈 - 四种扩地策略:方形外扩、区域扩地、玩家周围、绕国一圈
- 区域扩地采用 S 形扫描:从与己方领土接壤的区块开始,横向/纵向 S 形扫过整个矩形,不沿邦国边界,但保证每个新占领区块都与**己方领土**接壤(仅四个正方向,不把其他邦国领土计入接壤) - 区域扩地采用 S 形扫描:从与己方领土接壤的区块开始,横向/纵向 S 形扫过整个矩形,不沿邦国边界,但保证每个新占领区块都与**己方领土**接壤(仅四个正方向,不把其他邦国领土计入接壤)
- 自动寻路(Baritone)前往目标区块;监听 Baritone 路径事件,目标不可达(CALC_FAILED,如被悬崖/高山/水体隔断)时立即跳过;寻路超时则重新寻路(不立即回城),重试耗尽才跳过当前目标 - 自动寻路(Baritone)前往目标区块;监听 Baritone 路径事件,目标不可达(CALC_FAILED,如被悬崖/高山/水体隔断)时立即跳过;寻路超时则重新寻路(不立即回城),重试耗尽才跳过当前目标
- 连续寻路超时回城:连续寻路超时累计超过 1 分钟(可配置)时自动发送 `/u return`,约 10 秒后传送到可寻路位置,随后重新规划并从最高优先级区块重新开始扩地
- 运行时接壤校验:寻路/等待阶段每帧校验目标是否仍与己方领土接壤,地图刷新导致边界变化时立即跳过 - 运行时接壤校验:寻路/等待阶段每帧校验目标是否仍与己方领土接壤,地图刷新导致边界变化时立即跳过
- 目标有效性校验:目标若已被其他邦国占领则立即跳过 - 目标有效性校验:目标若已被其他邦国占领则立即跳过
- 现实时间限制:仅 11:00-22:00(本地现实时间)允许开拓,其余时段启动会被拒绝、运行中到点自动停止 - 现实时间限制:仅 11:00-22:00(本地现实时间)允许开拓,其余时段启动会被拒绝、运行中到点自动停止
@@ -24,7 +25,7 @@
## 安装 ## 安装
1. 安装 Fabric Loader 0.16.14+ 和 Fabric API 1. 安装 Fabric Loader 0.16.14+ 和 Fabric API
2. 将 `autostore-1.2.3.jar` 放入 `.minecraft/mods/` 目录 2. 将 `autostore-1.2.4.jar` 放入 `.minecraft/mods/` 目录
3. 启动游戏,按 `Ctrl+R` 打开 GUI 3. 启动游戏,按 `Ctrl+R` 打开 GUI
## 构建 ## 构建
@@ -34,7 +35,7 @@
./build_mod.sh ./build_mod.sh
``` ```
输出文件:`autostore-1.2.3.jar` 输出文件:`autostore-1.2.4.jar`
## 赞助支持 ## 赞助支持
+1 -1
查看文件
@@ -7,7 +7,7 @@ yarn_mappings=1.21.4+build.8
loader_version=0.19.3 loader_version=0.19.3
# Mod Properties # Mod Properties
mod_version=1.2.3 mod_version=1.2.4
maven_group=autostore maven_group=autostore
archives_base_name=autostore archives_base_name=autostore
@@ -31,6 +31,12 @@ public class ExpansionConfig {
/** 超时后的最大重试次数 */ /** 超时后的最大重试次数 */
public int retries = 2; public int retries = 2;
/** 连续寻路超时累计达到该秒数后,发送 /u return 回城传送并重新开始(默认 60 秒) */
public int returnThresholdSeconds = 60;
/** 发送 /u return 后等待传送完成的时间(秒);默认 12 秒,覆盖 10 秒传送延迟并留余量 */
public int returnWaitSeconds = 12;
/** 区域扩地策略的中心 X 坐标(区块) */ /** 区域扩地策略的中心 X 坐标(区块) */
public int regionCenterX; public int regionCenterX;
@@ -94,6 +100,8 @@ public class ExpansionConfig {
c.targetCount = this.targetCount; c.targetCount = this.targetCount;
c.waitTimeoutSeconds = this.waitTimeoutSeconds; c.waitTimeoutSeconds = this.waitTimeoutSeconds;
c.retries = this.retries; c.retries = this.retries;
c.returnThresholdSeconds = this.returnThresholdSeconds;
c.returnWaitSeconds = this.returnWaitSeconds;
c.regionCenterX = this.regionCenterX; c.regionCenterX = this.regionCenterX;
c.regionCenterZ = this.regionCenterZ; c.regionCenterZ = this.regionCenterZ;
c.regionRadius = this.regionRadius; c.regionRadius = this.regionRadius;
@@ -95,6 +95,10 @@ implements SubtitleChatMonitor.Listener, BaritoneBridge.PathListener {
private volatile boolean pathCalcFailed; private volatile boolean pathCalcFailed;
/** 等待开拓时段自动开始:不在 11:00-22:00 时点击开始会暂存配置,进入时段后自动启动(null 表示无等待任务) */ /** 等待开拓时段自动开始:不在 11:00-22:00 时点击开始会暂存配置,进入时段后自动启动(null 表示无等待任务) */
private ExpansionConfig pendingStart; private ExpansionConfig pendingStart;
/** 连续寻路超时累计时长(毫秒):多次寻路超时逐次累加,达到阈值触发 /u return 回城传送 */
private long consecutiveTimeoutMillis;
/** 发送 /u return 回城指令的时间戳(RETURNING 状态使用,用于等待传送完成) */
private long returnStartMillis;
public ExpansionController(TerritoryDataService dataService) { public ExpansionController(TerritoryDataService dataService) {
this.dataService = dataService; this.dataService = dataService;
@@ -211,6 +215,7 @@ implements SubtitleChatMonitor.Listener, BaritoneBridge.PathListener {
} }
this.completedClaims = 0; this.completedClaims = 0;
this.retryCount = 0; this.retryCount = 0;
this.consecutiveTimeoutMillis = 0L;
this.queue.clear(); this.queue.clear();
this.claimedSet.clear(); this.claimedSet.clear();
this.target = null; this.target = null;
@@ -298,6 +303,10 @@ implements SubtitleChatMonitor.Listener, BaritoneBridge.PathListener {
this.tickNext(); this.tickNext();
break; break;
} }
case 7: {
this.tickReturning();
break;
}
} }
} }
@@ -379,6 +388,8 @@ implements SubtitleChatMonitor.Listener, BaritoneBridge.PathListener {
} }
if (this.playerChunk.equals(this.target)) { if (this.playerChunk.equals(this.target)) {
this.baritoneBridge.cancel(); this.baritoneBridge.cancel();
// 成功到达目标:寻路不再卡死,清零连续超时计数
this.consecutiveTimeoutMillis = 0L;
this.stageStartedMillis = System.currentTimeMillis(); this.stageStartedMillis = System.currentTimeMillis();
this.setState(State.WAITING, "\u5df2\u5230\u8fbe\uff0c\u7b49\u5f85\u9886\u5730\u5f00\u62d3"); 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"); 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.retryCount;
// 主动刷新地图,尽快同步最新领土状态 // 主动刷新地图,尽快同步最新领土状态
this.dataService.refreshAsync(); 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.log("\u5bfb\u8def\u8d85\u65f6\uff0c\u8df3\u8fc7 " + this.target.x() + "," + this.target.z());
this.setState(State.FAIL, "\u5bfb\u8def\u8d85\u65f6"); 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() { private void tickWaiting() {
if (this.target == null) { if (this.target == null) {
@@ -622,6 +675,8 @@ implements SubtitleChatMonitor.Listener, BaritoneBridge.PathListener {
// 缩短"会话占领等待确认"窗口,避免假占领长时间残留 // 缩短"会话占领等待确认"窗口,避免假占领长时间残留
this.dataService.refreshAsync(); this.dataService.refreshAsync();
++this.completedClaims; ++this.completedClaims;
// 开垦成功:寻路/等待恢复正常,清零连续超时计数
this.consecutiveTimeoutMillis = 0L;
this.target = chunk; this.target = chunk;
this.lastProgress = 100; 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"); 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.dataService.refreshAsync();
++this.completedClaims; ++this.completedClaims;
// 开垦成功:寻路/等待恢复正常,清零连续超时计数
this.consecutiveTimeoutMillis = 0L;
this.lastProgress = 100; this.lastProgress = 100;
this.log("\u5360\u9886\u6210\u529f " + this.target.x() + "," + this.target.z()); 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()); 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, SUCCESS,
FAIL, FAIL,
NEXT, NEXT,
RETURNING,
COMPLETE, COMPLETE,
STOPPED; STOPPED;
+1 -1
查看文件
@@ -1 +1 @@
{"schemaVersion":1,"id":"autostore","version":"1.2.3","name":"AutoStore","description":"","authors":[],"contact":{},"license":"All-Rights-Reserved","environment":"client","entrypoints":{"fabric-datagen":["autostore.client.AutoStoreModDataGenerator"],"client":["autostore.client.AutoStoreModClient"],"main":["autostore.AutoStoreMod"]},"mixins":["autostore.mixins.json",{"config":"autostore.client.mixins.json","environment":"client"}],"depends":{"fabricloader":">=0.16.14","fabric-api":"*","minecraft":"1.21.4"},"jars":[{"file":"META-INF/jars/baritone-api-fabric-1.13.1.jar"}]} {"schemaVersion":1,"id":"autostore","version":"1.2.4","name":"AutoStore","description":"","authors":[],"contact":{},"license":"All-Rights-Reserved","environment":"client","entrypoints":{"fabric-datagen":["autostore.client.AutoStoreModDataGenerator"],"client":["autostore.client.AutoStoreModClient"],"main":["autostore.AutoStoreMod"]},"mixins":["autostore.mixins.json",{"config":"autostore.client.mixins.json","environment":"client"}],"depends":{"fabricloader":">=0.16.14","fabric-api":"*","minecraft":"1.21.4"},"jars":[{"file":"META-INF/jars/baritone-api-fabric-1.13.1.jar"}]}