v1.2.2: 根治寻路秒CALC_FAILED——删除自定义ChunkGoal(含高度isInGoal),改用Baritone原生GoalXZ到区块中心
这个提交包含在:
@@ -11,13 +11,11 @@ import baritone.api.event.events.PathEvent;
|
|||||||
import baritone.api.event.listener.AbstractGameEventListener;
|
import baritone.api.event.listener.AbstractGameEventListener;
|
||||||
import autostore.client.config.ExpansionConfig;
|
import autostore.client.config.ExpansionConfig;
|
||||||
import autostore.client.territory.ChunkPos;
|
import autostore.client.territory.ChunkPos;
|
||||||
|
import baritone.api.pathing.goals.GoalXZ;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import net.fabricmc.api.EnvType;
|
import net.fabricmc.api.EnvType;
|
||||||
import net.fabricmc.api.Environment;
|
import net.fabricmc.api.Environment;
|
||||||
import net.minecraft.client.MinecraftClient;
|
|
||||||
import net.minecraft.world.Heightmap;
|
|
||||||
import net.minecraft.world.World;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Baritone API 封装(桥接层)。
|
* Baritone API 封装(桥接层)。
|
||||||
@@ -72,7 +70,13 @@ public final class BaritoneBridge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 让 Baritone 寻路前往指定区块(以“到达区块内”为完成条件)。
|
* 让 Baritone 寻路前往指定区块中心。
|
||||||
|
*
|
||||||
|
* <p>使用 Baritone <b>原生</b>{@link GoalXZ}(目标区块中心单格):原生 GoalXZ 对
|
||||||
|
* 可达地形几乎不会误判“目标不可达”,是最好的默认选择。早期用自定义
|
||||||
|
* {@code ChunkGoal}(曾加入高度硬约束)疑似是“平原上一按 W 就能走、Baritone 却秒
|
||||||
|
* CALC_FAILED”的根因——自定义 Goal 在某些站位/边界下会把可达目标判成不可达。
|
||||||
|
* 到达判定仍由控制器 {@code playerChunk.equals(target)} 保证,与 Goal 自身容差无关。</p>
|
||||||
*
|
*
|
||||||
* @param chunk 目标区块
|
* @param chunk 目标区块
|
||||||
*/
|
*/
|
||||||
@@ -81,42 +85,7 @@ public final class BaritoneBridge {
|
|||||||
if (baritone == null) {
|
if (baritone == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 使用自定义 ChunkGoal:完成条件为“玩家脚下方块落在目标区块内地表”,
|
baritone.getCustomGoalProcess().setGoalAndPath(new GoalXZ(chunk.centerBlockX(), chunk.centerBlockZ()));
|
||||||
// 与控制器 playerChunk.equals(target) 的判定一致,并对高度施加约束,
|
|
||||||
// 避免 Baritone 把终点停在地下洞穴/矿坑里。避免 Baritone 自带 GoalXZ
|
|
||||||
//(容差 0,精确到区块中心单格)在中心不可达时停在相邻区块,造成目标区块错位。
|
|
||||||
baritone.getCustomGoalProcess().setGoalAndPath(new ChunkGoal(chunk, this.surfaceY(chunk)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 计算目标区块内地表高度(方块 Y):遍历该区块 16×16 各列,取
|
|
||||||
* “排除树叶的实体地表”高度的<b>中位数</b>,作为高度约束目标。
|
|
||||||
*
|
|
||||||
* <p>用中位数而非最大值:高树/孤峰只是少数列(其树干顶也算 MOTION_BLOCKING_NO_LEAVES),
|
|
||||||
* 取最大值会把整个区块的目标高度拉到无法到达的高柱顶,导致一步之隔的平原区块也
|
|
||||||
* CALC_FAILED(v1.2.2 回归);中位数代表区块“通常地表”,天然可达,而地下矿坑的 y
|
|
||||||
* 仍远低于中位,不会被误判为已到达。</p>
|
|
||||||
*
|
|
||||||
* @param chunk 目标区块
|
|
||||||
* @return 地表高度中位数;≤0 表示暂无法确定(不施加高度约束)
|
|
||||||
*/
|
|
||||||
private int surfaceY(ChunkPos chunk) {
|
|
||||||
MinecraftClient client = MinecraftClient.getInstance();
|
|
||||||
if (client == null || client.world == null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
World world = client.world;
|
|
||||||
int x0 = chunk.x() * 16;
|
|
||||||
int z0 = chunk.z() * 16;
|
|
||||||
int[] ys = new int[256];
|
|
||||||
int n = 0;
|
|
||||||
for (int bx = x0; bx < x0 + 16; ++bx) {
|
|
||||||
for (int bz = z0; bz < z0 + 16; ++bz) {
|
|
||||||
ys[n++] = world.getTopY(Heightmap.Type.MOTION_BLOCKING_NO_LEAVES, bx, bz);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
java.util.Arrays.sort(ys);
|
|
||||||
return ys[128];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 强制取消当前寻路任务。 */
|
/** 强制取消当前寻路任务。 */
|
||||||
|
|||||||
@@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* 本文件为 AutoStore 模组自定义的 Baritone 寻路目标。
|
|
||||||
*/
|
|
||||||
package autostore.client.bridge;
|
|
||||||
|
|
||||||
import autostore.client.territory.ChunkPos;
|
|
||||||
import baritone.api.pathing.goals.Goal;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 以“到达目标区块内”为完成条件的寻路目标。
|
|
||||||
*
|
|
||||||
* <p>完成条件为纯二维:只要玩家脚下方块落在目标区块内即视为到达。
|
|
||||||
* 这样目标区块的可达性与平坦地表相邻区块一致,绝不会因一步之隔、贴边落点、
|
|
||||||
* 或高度起伏被误判为目标不可达(CALC_FAILED 后秒切目标)。</p>
|
|
||||||
*
|
|
||||||
* <p>“避免寻路下到地下矿坑、尽量走地表”改为在启发式中做<b>软引导</b>:
|
|
||||||
* 仅当玩家远低于该区块的地表高度(很有可能是下了矿洞)时,给 heuristic 叠加
|
|
||||||
* 向上的加权,促使 Baritone 优先走地表。它不改变 isInGoal 的完成判定,因此
|
|
||||||
* 不会像“高度硬约束”那样导致本可达的目标被判成不可达。</p>
|
|
||||||
*/
|
|
||||||
public final class ChunkGoal implements Goal {
|
|
||||||
|
|
||||||
/** 目标区块 X 坐标 */
|
|
||||||
private final int targetX;
|
|
||||||
/** 目标区块 Z 坐标 */
|
|
||||||
private final int targetZ;
|
|
||||||
/** 目标区块中心的方块 X 坐标(用于启发式距离估算) */
|
|
||||||
private final int centerX;
|
|
||||||
/** 目标区块中心的方块 Z 坐标(用于启发式距离估算) */
|
|
||||||
private final int centerZ;
|
|
||||||
/**
|
|
||||||
* 目标地表高度(方块 Y):目标区块内 16×16 各列 “排除树叶的实体地表”高度的中位数。
|
|
||||||
* 仅用于启发式软引导(避开矿洞);≤0 表示暂无法确定地表高度,跳过引导。
|
|
||||||
*/
|
|
||||||
private final int targetY;
|
|
||||||
/** 深度容差:低于目标地表超过该值才视为“很可能下了矿洞”,触发向上引导 */
|
|
||||||
private static final int DEPTH_TOLERANCE = 6;
|
|
||||||
|
|
||||||
public ChunkGoal(ChunkPos chunk) {
|
|
||||||
this(chunk, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ChunkGoal(ChunkPos chunk, int targetY) {
|
|
||||||
this.targetX = chunk.x();
|
|
||||||
this.targetZ = chunk.z();
|
|
||||||
this.centerX = chunk.centerBlockX();
|
|
||||||
this.centerZ = chunk.centerBlockZ();
|
|
||||||
this.targetY = targetY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 完成条件:纯二维——玩家脚下方块是否落在目标区块内 */
|
|
||||||
@Override
|
|
||||||
public boolean isInGoal(int x, int y, int z) {
|
|
||||||
return Math.floorDiv(x, 16) == this.targetX && Math.floorDiv(z, 16) == this.targetZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 启发式:到目标区块中心的水平欧几里得距离;深度低于地表时叠加向上软引导 */
|
|
||||||
@Override
|
|
||||||
public double heuristic(int x, int y, int z) {
|
|
||||||
double dx = x - this.centerX;
|
|
||||||
double dz = z - this.centerZ;
|
|
||||||
double h = Math.sqrt(dx * dx + dz * dz);
|
|
||||||
if (this.targetY > 0 && y < this.targetY - DEPTH_TOLERANCE) {
|
|
||||||
// 软引导:还在目标地表下较深处(疑似矿洞),给予越深越高的小幅加权,
|
|
||||||
// 让 Baritone 倾向走地表,但不把它变成 isInGoal 的硬约束(避免误判不可达)。
|
|
||||||
h += (this.targetY - y) * 0.1;
|
|
||||||
}
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
在新工单中引用
屏蔽一个用户