diff --git a/README.md b/README.md index e622bfd..0523aa5 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ ## 版本记录 +- **v2.2.5**:下界改为巷道扫描式挖矿(替代 mineByName):在 y=15 层挖直巷逐点推进,主动挖方块暴露远古残骸,不依赖矿物扫描(反作弊下仍有效);巷道挖完未挖够时旋转 90° 转移新区域继续,不再漫无目的乱走;新增下界设置(挖掘层 Y、巷道长度)。 - **v2.2.4**:空闲状态彻底静默——不开挖矿任务时不触发任何自动行为(杀戮光环、自动进食、丢垃圾、搭路、换装全部暂停),完全不干扰玩家正常游玩。 - **v2.2.3**:修复下界多个问题——垃圾清单补充灵魂沙/灵魂土/岩浆块/沙砾/下界砖;进食时不再被工具切换打断(镐子/食物来回切换);下界挖掘重构:挖矿中不再每秒重发指令(解决灵魂沙抽搐/来回折返不挖),寻路失败不再误判"任务完成"回主世界,而是空闲一段时间后自动转移到新矿区继续找矿。 - **v2.2.2**:新增无路自动搭方块(可开关):Baritone 放置方块搭桥/垫脚,自动补给快捷栏搭路方块并喂给 Baritone 可放置物品清单;AutoTrash 不再丢弃快捷栏物品。 diff --git a/gradle.properties b/gradle.properties index a7b0629..f6143e5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,7 +7,7 @@ yarn_mappings=1.21.4+build.8 loader_version=0.19.3 # Mod Properties -mod_version=2.2.4 +mod_version=2.2.5 maven_group=autodig archives_base_name=autodig diff --git a/src/main/java/autodig/client/config/ConfigStore.java b/src/main/java/autodig/client/config/ConfigStore.java index 085ef64..6490614 100644 --- a/src/main/java/autodig/client/config/ConfigStore.java +++ b/src/main/java/autodig/client/config/ConfigStore.java @@ -85,6 +85,8 @@ public final class ConfigStore { if (c.netherOres == null || c.netherOres.isBlank()) { c.netherOres = "ancient_debris"; } + c.netherLevel = clamp(c.netherLevel, -64, 320); + c.netherTunnelLength = clamp(c.netherTunnelLength, 4, 512); c.trashReserve = clamp(c.trashReserve, 0, 2304); if (c.trashItems == null || c.trashItems.isBlank()) { c.trashItems = "cobblestone,cobbled_deepslate,deepslate,tuff,dirt,granite,diorite,andesite,netherrack,blackstone,basalt,soul_sand,soul_soil,magma_block,gravel,nether_bricks"; diff --git a/src/main/java/autodig/client/config/DigConfig.java b/src/main/java/autodig/client/config/DigConfig.java index a92fde9..6e633d7 100644 --- a/src/main/java/autodig/client/config/DigConfig.java +++ b/src/main/java/autodig/client/config/DigConfig.java @@ -79,6 +79,10 @@ public class DigConfig { // ---- 下界模式参数 ---- /** 下界要挖的矿物方块 ID 列表(逗号分隔,如 "ancient_debris,nether_gold_ore") */ public String netherOres = "ancient_debris"; + /** 下界巷道瞄准的 Y 层(远古残骸一般在 8-22,15 附近最密集) */ + public int netherLevel = 15; + /** 下界巷道主干长度(方块) */ + public int netherTunnelLength = 60; /** 挖够数量后自动回主世界(-1 表示无限挖直到背包满/血量低/装备耐久低) */ public int netherTargetCount = 4; /** 下界模式:挖够/背包满/血量低/装备耐久低时自动回主世界 */ @@ -145,7 +149,10 @@ public class DigConfig { c.killAuraInNether = this.killAuraInNether; c.overworldLevel = this.overworldLevel; c.tunnelLength = this.tunnelLength; + c.branchLength = this.branchLength; c.overworldOres = this.overworldOres; + c.netherLevel = this.netherLevel; + c.netherTunnelLength = this.netherTunnelLength; c.netherOres = this.netherOres; c.netherTargetCount = this.netherTargetCount; c.netherAutoReturn = this.netherAutoReturn; diff --git a/src/main/java/autodig/client/controller/DigController.java b/src/main/java/autodig/client/controller/DigController.java index 2b17910..24c1c5b 100644 --- a/src/main/java/autodig/client/controller/DigController.java +++ b/src/main/java/autodig/client/controller/DigController.java @@ -197,7 +197,7 @@ public final class DigController { } } case NETHER -> { - if (this.nether.tick(config)) { + if (this.nether.tick(config, canMineOres)) { if (this.nether.isFull()) { this.finish(config, "背包已满,下界任务已暂停(清空背包后重新开始)"); } else if (this.nether.isFled()) { diff --git a/src/main/java/autodig/client/gui/AutoDigGui.java b/src/main/java/autodig/client/gui/AutoDigGui.java index 1bc0755..25e935b 100644 --- a/src/main/java/autodig/client/gui/AutoDigGui.java +++ b/src/main/java/autodig/client/gui/AutoDigGui.java @@ -177,6 +177,10 @@ public final class AutoDigGui extends Screen { y += 10; } else if (this.config.task == MineTask.NETHER) { y = this.header(y, "下界设置"); + y = this.numberRow(y, "挖掘层 (Y)", () -> this.config.netherLevel, + v -> this.config.netherLevel = v, -64, 320); + y = this.numberRow(y, "巷道长度", () -> this.config.netherTunnelLength, + v -> this.config.netherTunnelLength = v, 4, 512); y = this.numberRow(y, "目标数量 (-1 无限)", () -> this.config.netherTargetCount, v -> this.config.netherTargetCount = v, -1, 512); y = this.checkPair(y, "挖完/背包满/血量低/耐久低 自动回主世界", @@ -432,6 +436,8 @@ public final class AutoDigGui extends Screen { target.tunnelLength = this.config.tunnelLength; target.branchLength = this.config.branchLength; target.overworldOres = this.config.overworldOres; + target.netherLevel = this.config.netherLevel; + target.netherTunnelLength = this.config.netherTunnelLength; target.netherOres = this.config.netherOres; target.netherTargetCount = this.config.netherTargetCount; target.netherFleeHealthThreshold = this.config.netherFleeHealthThreshold; diff --git a/src/main/java/autodig/client/miner/NetherMiner.java b/src/main/java/autodig/client/miner/NetherMiner.java index 31370e9..af3df09 100644 --- a/src/main/java/autodig/client/miner/NetherMiner.java +++ b/src/main/java/autodig/client/miner/NetherMiner.java @@ -2,17 +2,20 @@ package autodig.client.miner; import autodig.client.bridge.BaritoneBridge; import autodig.client.config.DigConfig; +import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.ThreadLocalRandom; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; import net.minecraft.client.MinecraftClient; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.registry.Registries; import net.minecraft.registry.RegistryKey; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; import net.minecraft.world.World; /** @@ -23,6 +26,13 @@ import net.minecraft.world.World; * 死亡重生的返回逻辑由控制器统一处理,本类每次 tick 依据当前所在维度 * 自适应地执行对应阶段。

* + *

挖矿方式:与主世界相同采用巷道扫描式——在配置的 Y 层 + * (远古残骸富集层,默认 15)沿玩家朝向挖直巷,逐点推进;巷道壁两侧 + * 暴露的目标矿物由周期性扫描绕道挖掉。这样不依赖 Baritone 的矿物 + * 远距离扫描,即使服务器反作弊隐藏矿物方块,主动挖巷道也能把路径 + * 上的矿物挖出来。一条巷道挖完仍未挖够目标数量时,方向旋转 90° 转移 + * 到新区域继续挖,避免漫无目的地乱走。

+ * *

下界无死亡不掉落,比主世界更"惜命":血量低或装备耐久低时主动触发返程。 * 背包满采用去抖判定(连续 1 秒都满才算真满),给自动丢垃圾服务留出腾位时间。

*/ @@ -43,12 +53,20 @@ public final class NetherMiner { /** 背包满去抖阈值(tick):连续这么久都满才认定为真满 */ private static final int FULL_DEBOUNCE_TICKS = 20; - /** Baritone 空闲(附近矿已挖完/寻路失败)连续这么久后,转移到新区域继续找(tick) */ - private static final int RELOCATE_TICKS = 60; - /** 转移的随机水平距离(方块) */ - private static final int RELOCATE_DISTANCE = 16; - /** 转移寻路超时(毫秒):超过则放弃转移,原地继续挖 */ + /** 矿物扫描间隔(毫秒) */ + private static final long ORE_SCAN_INTERVAL_MS = 1000; + /** 矿物扫描半径(方块) */ + private static final int ORE_SCAN_RADIUS = 6; + /** 单次绕道超时(tick):超过则放弃该矿点回到巷道计划 */ + private static final int DETOUR_TIMEOUT_TICKS = 400; + /** 同一矿点放弃后的重试冷却(毫秒) */ + private static final long ABANDON_COOLDOWN_MS = 30_000; + /** 巷道目标点不可达超时(毫秒):超过此时间仍未接近,放弃该点跳到下一个 */ + private static final long WAYPOINT_STUCK_MS = 20_000; + /** 转移寻路超时(毫秒):超过则放弃转移,原地重建巷道 */ private static final long RELOCATE_TIMEOUT_MS = 15_000; + /** 转移距离(方块) */ + private static final int RELOCATE_DISTANCE = 12; /** 常见矿物方块 id -> 掉落物品 id(挖掘产物与方块本身不同的情况) */ private static final Map ORE_TO_DROP = Map.ofEntries( @@ -82,8 +100,6 @@ public final class NetherMiner { private boolean gearBroken; /** 外部(控制器)要求的强制返程 */ private boolean forceReturn; - /** 是否已派发过挖矿指令(用于区分「尚未开始」和「已经挖完」) */ - private boolean miningStarted; /** 派发节流 */ private long lastIssue; /** 已挖到的目标矿物数量(按背包产物计数,扣除任务开始时的基线) */ @@ -93,8 +109,35 @@ public final class NetherMiner { private boolean baselineSet; /** 背包满连续持续的 tick 数(去抖) */ private int fullTicks; - /** Baritone 空闲连续持续的 tick 数(用于触发转移新区域) */ - private int idleTicks; + + // ---- 巷道推进状态 ---- + /** 下界巷道计划(直巷,y = config.netherLevel) */ + private List plan = new ArrayList<>(); + /** 当前推进到的计划步数 */ + private int step; + /** 当前巷道方向 */ + private int dirX; + private int dirZ; + /** 上一次打印诊断日志的时间戳(节流) */ + private long lastLog; + /** 上一次成功下发的目标点(避免同一目标反复重发) */ + private BlockPos lastIssuedTarget; + /** 当前巷道目标点的最近进度时间戳与最佳距离(用于超时/不可达放弃) */ + private long lastProgress; + private double bestDist; + + // ---- 矿物绕道状态 ---- + /** 绕道目标;非 null 时优先前往挖掘该矿物 */ + private BlockPos detourTarget; + /** 绕道已持续的 tick 数(超时放弃,避免卡死) */ + private int detourTicks; + /** 上一次扫描附近矿物的时间戳(节流) */ + private long lastOreScan; + /** 上次放弃的绕道点与时间(同一点短时间内不再重试) */ + private BlockPos abandonedTarget; + private long abandonedAt; + + // ---- 转移新区域状态 ---- /** 是否正在转移到新矿区 */ private boolean relocating; /** 转移目标点 */ @@ -114,12 +157,19 @@ public final class NetherMiner { this.fled = false; this.gearBroken = false; this.forceReturn = false; - this.miningStarted = false; this.minedCount = 0; this.baselineCount = 0; this.baselineSet = false; this.fullTicks = 0; - this.idleTicks = 0; + this.plan.clear(); + this.step = 0; + this.lastIssuedTarget = null; + this.lastProgress = System.currentTimeMillis(); + this.bestDist = Double.MAX_VALUE; + this.detourTarget = null; + this.detourTicks = 0; + this.abandonedTarget = null; + this.abandonedAt = 0; this.relocating = false; this.relocateTarget = null; this.relocateStart = 0; @@ -128,10 +178,11 @@ public final class NetherMiner { /** * 每帧推进下界挖矿流转。 * - * @param config 挖矿配置 + * @param config 挖矿配置 + * @param canMineOres 手持工具是否足以挖目标矿物(false 时跳过矿物绕道,避免白挖不掉落) * @return 是否已全部完成(含回到主世界) */ - public boolean tick(DigConfig config) { + public boolean tick(DigConfig config, boolean canMineOres) { MinecraftClient client = MinecraftClient.getInstance(); if (client.player == null || client.world == null) { return this.done; @@ -146,9 +197,8 @@ public final class NetherMiner { && config.netherFleeHealthThreshold > 0 && this.healthPercent(player) < config.netherFleeHealthThreshold) { this.fled = true; - this.miningStarted = false; + this.bridge.cancelAll(); if (config.netherAutoReturn) { - this.bridge.cancelAll(); this.stage = Stage.RETURN_PORTAL; } else { this.done = true; @@ -158,7 +208,6 @@ public final class NetherMiner { // 外部标记(装备耐久过低等):直接进入返程 if (this.forceReturn && inNether && this.stage != Stage.RETURN_PORTAL) { - this.miningStarted = false; this.bridge.cancelAll(); this.stage = Stage.RETURN_PORTAL; } @@ -183,7 +232,6 @@ public final class NetherMiner { if (!inNether) { // 意外回到主世界,重走流程 this.stage = Stage.GO_COMMIT; - this.miningStarted = false; return this.done; } // 记录任务开始时背包已有的产物数量作为基线 @@ -200,7 +248,6 @@ public final class NetherMiner { if (this.fullTicks >= FULL_DEBOUNCE_TICKS) { // 背包已满:期望回程则去传送门;不回程时无处可放,直接结束 this.full = true; - this.miningStarted = false; if (config.netherAutoReturn) { this.stage = Stage.RETURN_PORTAL; } else { @@ -208,16 +255,15 @@ public final class NetherMiner { } } else if (this.minedEnough(config, player)) { // 已挖够目标数量 - this.miningStarted = false; - this.relocating = false; + this.bridge.cancelAll(); if (config.netherAutoReturn) { this.stage = Stage.RETURN_PORTAL; } else { this.done = true; } } else { - // 未挖够目标数量:持续挖矿,绝不因 Baritone 空闲误判"任务完成" - this.mineTick(config, player); + // 未挖够目标数量:巷道推进挖矿,绝不因 Baritone 空闲误判"任务完成" + this.mineTick(config, player, canMineOres); } } case RETURN_PORTAL -> { @@ -241,66 +287,227 @@ public final class NetherMiner { } /** - * 未挖够目标时的挖矿驱动:空闲转移到新矿区、持续派发挖矿指令。 - * - *

关键:Baritone 空闲(附近矿挖完或寻路失败)时,不再把它当成"任务完成" - * 回主世界,而是转移到附近新位置继续找矿;无限目标(-1)下只要没背包满/ - * 血量低/装备耐久低,就一直在下界挖。

+ * 巷道扫描式挖矿:建立/推进直巷计划,途中绕道挖掉暴露的目标矿物。 */ - private void mineTick(DigConfig config, PlayerEntity player) { + private void mineTick(DigConfig config, PlayerEntity player, boolean canMineOres) { + MinecraftClient client = MinecraftClient.getInstance(); + if (client.world == null) { + return; + } + // 尚无巷道计划或刚转移完成:建立新计划 + if (this.plan.isEmpty()) { + this.initTunnel(config, player); + } if (this.relocating) { double d = this.distanceSq(player, this.relocateTarget); if (d <= 4.0) { - // 已到新矿区 + // 已到新矿区,重建巷道 this.relocating = false; this.relocateTarget = null; - this.miningStarted = false; + this.plan.clear(); } else if (System.currentTimeMillis() - this.relocateStart > RELOCATE_TIMEOUT_MS) { - // 转移超时(目标点不可达):放弃转移,原地继续挖 + // 转移超时(目标点不可达):放弃转移,原地重建巷道 this.relocating = false; this.relocateTarget = null; this.bridge.cancelAll(); + this.plan.clear(); } else if (!this.bridge.isActive()) { - // 转移途中寻路失败/停下:重发 this.bridge.gotoBlock(this.relocateTarget); } return; } - if (this.miningStarted && !this.bridge.isActive()) { - // 附近矿已挖完或寻路失败:连续空闲一段时间后转移到新区域继续找 - this.idleTicks++; - if (this.idleTicks >= RELOCATE_TICKS) { - this.idleTicks = 0; - this.miningStarted = false; - this.relocateToNewArea(player); - } + // 先处理矿物绕道(巷道壁暴露的目标矿物优先挖掉) + if (this.handleOreDetour(config, player, canMineOres)) { return; } - if (!this.miningStarted) { - this.idleTicks = 0; - List ores = config.getNetherOreList(); - if (!ores.isEmpty()) { - // 无限目标(-1),实际战果由 minedEnough 计数 - this.bridge.mineByName(-1, ores.toArray(String[]::new)); - this.miningStarted = true; - } + // 巷道走完:方向旋转 90° 转移到新区域继续挖 + if (this.step >= this.plan.size()) { + this.rotateAndRelocate(player); + return; + } + BlockPos target = this.plan.get(this.step); + double dist = this.distanceSq(player, target); + long now = System.currentTimeMillis(); + if (now - this.lastLog > 5000) { + this.lastLog = now; + System.out.println("[AutoDig] nether: step=" + this.step + "/" + this.plan.size() + + " player=" + player.getBlockPos() + " target=" + target + + " dist=" + String.format("%.1f", dist) + " active=" + this.bridge.isActive()); + } + if (dist <= 2.0) { + // 已到达当前目标,推进到下一个 + this.step++; + this.lastIssuedTarget = null; + this.lastProgress = now; + this.bestDist = Double.MAX_VALUE; + return; + } + // 进度跟踪:只要在接近目标就刷新"最近有进展"时间 + if (dist < this.bestDist) { + this.bestDist = dist; + this.lastProgress = now; + } + // 长时间无进展(目标不可达)→ 放弃该点,跳到下一个 + if (now - this.lastProgress > WAYPOINT_STUCK_MS) { + System.out.println("[AutoDig] nether 目标长时间不可达,跳过 step=" + this.step + " target=" + target); + this.bridge.cancelAll(); + this.step++; + this.lastIssuedTarget = null; + this.lastProgress = now; + this.bestDist = Double.MAX_VALUE; + return; + } + // 下发寻路:换了新目标才立即下发;同一目标仅在 Baritone 空闲时低频重试 + if (!target.equals(this.lastIssuedTarget)) { + this.bridge.gotoBlock(target); + this.lastIssuedTarget = target; + this.lastIssue = now; + this.lastProgress = now; + this.bestDist = Double.MAX_VALUE; + } else if (!this.bridge.isActive() && now - this.lastIssue > 2000) { + this.bridge.gotoBlock(target); + this.lastIssue = now; } } - /** 转移到玩家附近的新位置(随机水平偏移),继续找矿。 */ - private void relocateToNewArea(PlayerEntity player) { - int dx = ThreadLocalRandom.current().nextInt(-RELOCATE_DISTANCE, RELOCATE_DISTANCE); - int dz = ThreadLocalRandom.current().nextInt(-RELOCATE_DISTANCE, RELOCATE_DISTANCE); - this.relocateTarget = player.getBlockPos().add(dx, 0, dz); + /** 建立一条直巷计划:以玩家水平坐标为起点,y = config.netherLevel,沿当前朝向推进。 */ + private void initTunnel(DigConfig config, PlayerEntity player) { + Direction facing = player.getHorizontalFacing(); + int axis = facing.getAxis() == Direction.Axis.X ? 0 : 1; + int sign = axis == 0 ? facing.getOffsetX() : facing.getOffsetZ(); + this.dirX = axis == 0 ? sign : 0; + this.dirZ = axis == 0 ? 0 : sign; + BlockPos start = new BlockPos(player.getBlockPos().getX(), config.netherLevel, player.getBlockPos().getZ()); + this.plan = new ArrayList<>(); + for (int t = 0; t <= config.netherTunnelLength; t++) { + this.plan.add(start.add(this.dirX * t, 0, this.dirZ * t)); + } + this.step = 0; + this.lastIssuedTarget = null; + this.lastProgress = System.currentTimeMillis(); + this.bestDist = Double.MAX_VALUE; + System.out.println("[AutoDig] nether 巷道建立: y=" + config.netherLevel + + " 方向=(" + this.dirX + "," + this.dirZ + ") 长度=" + config.netherTunnelLength); + } + + /** 巷道挖完仍未挖够:方向旋转 90°,转移到侧方新区域继续挖。 */ + private void rotateAndRelocate(PlayerEntity player) { + int nx = -this.dirZ; + int nz = this.dirX; + this.dirX = nx; + this.dirZ = nz; + this.relocateTarget = player.getBlockPos().add(this.dirX * RELOCATE_DISTANCE, 0, this.dirZ * RELOCATE_DISTANCE); this.relocateStart = System.currentTimeMillis(); this.relocating = true; + this.plan.clear(); this.bridge.gotoBlock(this.relocateTarget); + System.out.println("[AutoDig] nether 巷道挖完,转移到新区域: " + this.relocateTarget); + } + + /** + * 处理矿物绕道挖掘。 + * + * @return true 表示当前正在绕道挖矿(调用方应暂停巷道推进) + */ + private boolean handleOreDetour(DigConfig config, PlayerEntity player, boolean canMineOres) { + MinecraftClient client = MinecraftClient.getInstance(); + if (client.world == null) { + return false; + } + long now = System.currentTimeMillis(); + if (this.detourTarget != null) { + BlockState state = client.world.getBlockState(this.detourTarget); + if (!this.isTargetOre(config, state)) { + // 已挖掉或目标失效:回到巷道计划 + this.detourTarget = null; + return false; + } + this.detourTicks++; + if (this.detourTicks > DETOUR_TIMEOUT_TICKS) { + // 太久没挖到(不可达等):放弃该点并冷却 + this.abandonedTarget = this.detourTarget; + this.abandonedAt = now; + this.detourTarget = null; + return false; + } + // 仅在 Baritone 空闲时低频重发,避免打断正在规划的路线 + if (!this.bridge.isActive() && now - this.lastIssue > 1000) { + this.bridge.gotoBlock(this.detourTarget); + this.lastIssue = now; + } + return true; + } + // 节流扫描附近目标矿物 + if (!canMineOres || now - this.lastOreScan < ORE_SCAN_INTERVAL_MS) { + return false; + } + this.lastOreScan = now; + BlockPos ore = this.findNearbyOre(config, client, player); + if (ore != null) { + this.detourTarget = ore; + this.detourTicks = 0; + this.bridge.gotoBlock(ore); + this.lastIssue = now; + System.out.println("[AutoDig] nether 发现目标矿物,绕道挖掘: " + ore); + return true; + } + return false; + } + + /** 在玩家周围扫描最近的目标矿物方块。 */ + private BlockPos findNearbyOre(DigConfig config, MinecraftClient client, PlayerEntity player) { + Set targets = this.targetOrePaths(config); + if (targets.isEmpty()) { + return null; + } + BlockPos best = null; + double bestDist = Double.MAX_VALUE; + for (BlockPos pos : BlockPos.iterateOutwards(player.getBlockPos(), + ORE_SCAN_RADIUS, ORE_SCAN_RADIUS, ORE_SCAN_RADIUS)) { + String path = Registries.BLOCK.getId(client.world.getBlockState(pos).getBlock()).getPath(); + if (!targets.contains(path)) { + continue; + } + // 最近放弃过的矿点在冷却期内不再尝试 + if (pos.equals(this.abandonedTarget) + && System.currentTimeMillis() - this.abandonedAt < ABANDON_COOLDOWN_MS) { + continue; + } + double d = pos.getSquaredDistance(player.getBlockPos()); + if (d < bestDist) { + bestDist = d; + best = pos.toImmutable(); + } + } + return best; + } + + /** 判断方块状态是否为配置中的目标矿物(按 path 匹配,兼容命名空间前缀)。 */ + private boolean isTargetOre(DigConfig config, BlockState state) { + if (state.isOf(Blocks.AIR)) { + return false; + } + String path = Registries.BLOCK.getId(state.getBlock()).getPath(); + return this.targetOrePaths(config).contains(path); + } + + /** 目标矿物 path 集合(去命名空间,兼容 "minecraft:" 前缀写法)。 */ + private Set targetOrePaths(DigConfig config) { + Set set = new HashSet<>(); + for (String ore : config.getNetherOreList()) { + String path = ore.contains(":") ? ore.substring(ore.indexOf(':') + 1) : ore; + if (!path.isBlank()) { + set.add(path); + } + } + return set; } private double distanceSq(PlayerEntity player, BlockPos target) { double dx = player.getX() - (target.getX() + 0.5); double dz = player.getZ() - (target.getZ() + 0.5); - return dx * dx + dz * dz; + double dy = player.getY() - (target.getY() + 0.5); + return dx * dx + dy * dy + dz * dz; } /** 统计背包中目标矿物产物的总数量(方块 id 映射到掉落物 id)。 */ @@ -374,11 +581,11 @@ public final class NetherMiner { public void markGearBroken() { this.gearBroken = true; this.forceReturn = true; - this.miningStarted = false; + this.bridge.cancelAll(); } /** @return 本次任务新挖到的目标矿物数量 */ public int getMinedCount() { return this.minedCount; } -} \ No newline at end of file +}