diff --git a/README.md b/README.md index e62b618..4540e48 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,8 @@ - 自动进食(饥饿时自动吃背包食物) - 自动攻击敌对生物:扩地途中自动面向并攻击索敌范围内的敌对生物(满蓄力出手、不追击、不打断寻路);严格豁免不会主动攻击玩家的中立生物——铁傀儡、僵尸猪灵永不攻击,末影人(仅被激怒)、蜘蛛(仅黑暗中)、猪灵(仅玩家未穿金甲)按原版敌对条件反击,狼、蜜蜂、羊驼等其它中立生物一律不打 - 耐久保护回城:每 2 秒检查主手/副手/四件盔甲耐久,任意一件剩余耐久低于阈值(默认 15%,可在 GUI 调整)时自动发送 `/u return` 回城并停止扩地,防止装备被怪物磨没 -- 自动用船过水:扩地途中若路径前方出现开阔水域(默认宽度 ≥ 4 格、长度 ≥ 6 格),自动切到主手放船并登船;前方出现岸边时自动蹲伏下船并攻击船实体回收船(仅背包有任意 `*_boat`/`*_chest_boat` 时生效;不打断 Baritone 寻路) +- 自动用船过水:扩地途中遇开阔水域(默认宽度 ≥ 4 格、长度 ≥ 6 格)自动切到主手放船并登船,坐船朝目标区块航行;靠岸前自动下船并攻击船实体回收船。水面游泳时也能直接登船,用船期间暂停 Baritone 寻路、结束后自动恢复(仅背包有任意 `*_boat`/`*_chest_boat` 时生效) +- 自动游泳防溺水:玩家在水中(含 Baritone 寻路期间)持续按住跳跃键上浮,不会沉入水中越沉越深;坐上船或进入用船流程时自动松开,避免与航行/登船冲突 - 实时地图 GUI(通过 Ctrl+R 打开) - 监听聊天/字幕消息判断开垦结果 - 刷新地图时与最新 `markers.json` 核对已占领区块,丢弃地图未确认的超期假占领,避免高地扩地残留空洞 @@ -29,7 +30,7 @@ ## 安装 1. 安装 Fabric Loader 0.16.14+ 和 Fabric API -2. 将 `autostore-1.3.0.jar` 放入 `.minecraft/mods/` 目录 +2. 将 `autostore-1.3.1.jar` 放入 `.minecraft/mods/` 目录 3. 启动游戏,按 `Ctrl+R` 打开 GUI ## 构建 @@ -39,7 +40,7 @@ ./build_mod.sh ``` -输出文件:`autostore-1.3.0.jar` +输出文件:`autostore-1.3.1.jar` ## 赞助支持 diff --git a/gradle.properties b/gradle.properties index 3170488..5ab81ef 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=1.3.0 +mod_version=1.3.1 maven_group=autostore archives_base_name=autostore diff --git a/src/main/java/autostore/client/controller/ExpansionController.java b/src/main/java/autostore/client/controller/ExpansionController.java index 92bcf59..e4e12cf 100644 --- a/src/main/java/autostore/client/controller/ExpansionController.java +++ b/src/main/java/autostore/client/controller/ExpansionController.java @@ -320,7 +320,8 @@ implements SubtitleChatMonitor.Listener, BaritoneBridge.PathListener { client.player.sendMessage(Text.literal("[AutoStore] \u5df2\u5230\u5f00\u62d3\u65f6\u9650\u5916\uff0811:00-22:00\uff09\uff0c\u4efb\u52a1\u505c\u6b62"), false); return; } - if (this.tickAutoFood(client)) { + // 自动用船流程进行中:暂停自动进食,避免进食中断航行/游泳按键(吃食物占用主手动画) + if (!this.autoBoat.isActive() && this.tickAutoFood(client)) { return; } // 耐久保护优先于一切寻路/战斗:装备耐久过低时先回城,防止装备被怪物磨没 @@ -328,15 +329,17 @@ implements SubtitleChatMonitor.Listener, BaritoneBridge.PathListener { return; } this.tickAutoSwim(client); - // 自动用船过水:开阔水域自动放船登船、上岸前自动下船回收 + // 自动用船过水:开阔水域自动放船登船、坐船朝目标航行、上岸前自动下船回收 this.tickAutoBoat(client); // 处于"往边上走两步"阶段:每帧驱动手动横向行走,走开后自动重试原目标(该阶段不自动攻击,避免抢方向键) if (this.sideStepping) { this.tickSideStep(); return; } - // 自动攻击:面向并攻击范围内的敌对生物(不追击,不打断寻路状态机) - this.tickAutoAttack(client); + // 自动攻击:面向并攻击范围内的敌对生物(不追击,不打断寻路状态机;用船期间不攻击,避免抢转向) + if (!this.autoBoat.isActive()) { + this.tickAutoAttack(client); + } switch (this.state) { case PLANNING: { this.plan(); @@ -431,6 +434,21 @@ implements SubtitleChatMonitor.Listener, BaritoneBridge.PathListener { if (this.skipIfTargetClaimed("\u76ee\u6807\u5df2\u88ab\u5360\u9886")) { return; } + // 已到达目标区块:寻路完成(无论是否在用船,都立即进入等待开垦) + 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"); + return; + } + // 自动用船流程进行中:移动由船导航接管(到达判定已在上方完成), + // 跳过超时/重试/路径失败处理,避免与船流程抢按键或误判 + if (this.autoBoat.isActive()) { + return; + } // Baritone 报告路径计算失败(目标不可达,如被悬崖/高山/水体完全隔断)。 // 不立即跳过:CALC_FAILED 常因瞬时能力限制或起点卡位误报,先重新寻路一次 //(相当于“往边上走两步再算一遍”),重试耗尽才跳过当前目标。 @@ -898,10 +916,11 @@ implements SubtitleChatMonitor.Listener, BaritoneBridge.PathListener { /** * 自动游泳逻辑(每帧调用): - * 仅在玩家处于水中(含没入 / 水面 / 浅水)、Baritone 未接管寻路、玩家不在船中时, - * 持续按住跳跃键,使玩家不断浮到水面,避免溺水。 - * 任务停止、离开水、Baritone 开始寻路、坐上船等条件触发时立即释放跳跃键, - * 避免干扰 Baritone 与其它流程。 + * 只要玩家处于水中(含没入 / 水面 / 浅水)、不在船中、无自动用船流程、未在手动走两步, + * 就持续按住跳跃键,使玩家不断浮到水面,避免溺水。 + * 之前"只在 Baritone 未接管时按空格"会在 Baritone 寻路期间松手,导致玩家在水里越沉越深; + * 现在即使 Baritone 正在寻路也持续按空格,保证玩家始终浮在水面附近。 + * 任务停止、离开水、坐上船、进入用船流程等条件触发时立即释放跳跃键,避免干扰其它流程。 */ private void tickAutoSwim(MinecraftClient client) { if (!this.isRunning() || client.player == null) { @@ -909,11 +928,10 @@ implements SubtitleChatMonitor.Listener, BaritoneBridge.PathListener { return; } PlayerEntity player = client.player; - // 水中 + Baritone 未接管 + 玩家不在船中(船里前进靠船自身,不需要自动跳)→ 持续按住空格 + // 水中 + 不在船中(船里前进靠船自身,不需要自动跳)+ 无自动用船流程 + 未在手动走两步 → 持续按住空格 boolean inWater = player.isTouchingWater(); - boolean baritoneControlling = this.baritoneBridge.isPathing(); boolean inBoat = player.getVehicle() instanceof AbstractBoatEntity; - if (inWater && !baritoneControlling && !inBoat) { + if (inWater && !inBoat && !this.autoBoat.isActive() && !this.sideStepping) { this.pressJump(client); } else { this.releaseJump(client); @@ -962,17 +980,31 @@ implements SubtitleChatMonitor.Listener, BaritoneBridge.PathListener { /** * 自动用船过水(每帧调用): - * 在岸上且朝向方向前方出现开阔水域时,自动放船并登船; - * 在船中且前方出现岸边时,自动下船并攻击船实体回收船。 - * 仅在扩地任务运行中、配置 autoBoat 开启时生效;不打断 Baritone 寻路。 + * 在开阔水域朝目标方向自动放船登船、坐船朝目标航行、上岸前自动下船回收船。 + * 仅在扩地任务运行中、配置 autoBoat 开启、且处于"寻路前往目标"阶段时开启新的用船流程; + * 用船流程进行中暂停 Baritone 寻路(船由 AutoBoatController 手动导航,避免按键/方向冲突), + * 流程结束后自动恢复 Baritone 寻路。 */ private void tickAutoBoat(MinecraftClient client) { - this.autoBoat.tick(client, this.config, this.isRunning()); + boolean wasActive = this.autoBoat.isActive(); + // 仅在"寻路前往目标"阶段允许开启新的用船流程;走两步阶段手动控制方向键,不抢路 + boolean canStartFlow = this.state == State.PATHING && !this.sideStepping && this.target != null; + this.autoBoat.tick(client, this.config, this.isRunning(), canStartFlow, this.target); if (this.autoBoat.isActive()) { + // 自动用船流程接管移动:取消 Baritone 寻路,避免与船的按键/方向冲突 + this.baritoneBridge.cancel(); String desc = this.autoBoat.describe(); if (desc != null) { this.status = desc; } + } else if (wasActive) { + // 用船流程刚结束:若仍处于寻路阶段且未到达目标,恢复 Baritone 寻路 + if (this.state == State.PATHING && this.target != null + && !this.playerChunk.equals(this.target) && !this.sideStepping) { + this.stageStartedMillis = System.currentTimeMillis(); + this.baritoneBridge.pathTo(this.target); + this.log("\u81ea\u52a8\u7528\u8239\u7ed3\u675f\uff0c\u6062\u590d Baritone \u5bfb\u8def"); + } } } diff --git a/src/main/java/autostore/client/navigation/AutoBoatController.java b/src/main/java/autostore/client/navigation/AutoBoatController.java index 3defd27..8345e3f 100644 --- a/src/main/java/autostore/client/navigation/AutoBoatController.java +++ b/src/main/java/autostore/client/navigation/AutoBoatController.java @@ -19,6 +19,7 @@ package autostore.client.navigation; import autostore.client.config.ExpansionConfig; +import autostore.client.territory.ChunkPos; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.block.Blocks; @@ -90,42 +91,66 @@ public final class AutoBoatController { private static final int FLOW_ENTER = 1; /** 当前是上岸流程 */ private static final int FLOW_EXIT = 2; + /** 当前是坐船航行流程(自动朝目标区块航行) */ + private static final int FLOW_SAIL = 3; private int flow = IDLE; + /** 登船失败冷却时长(tick,80 tick ≈ 4 秒):失败后一段时间内不再尝试,避免每帧重试刷屏 */ + private static final int BOARD_FAIL_COOLDOWN_TICKS = 80; + /** 已到达目标区块后仍未靠岸、强制下船的等待时长(tick,100 tick ≈ 5 秒) */ + private static final int ARRIVED_FORCE_DISEMBARK_TICKS = 100; + /** 坐船航行时是否正在按住前进键 */ + private boolean holdingForward; + /** 登船失败后的冷却 tick 数(>0 时不触发登船) */ + private int failCooldownTicks; + /** 已到达目标区块后继续找岸边的 tick 数(超时则直接下船) */ + private int arrivedTicks; + /** - * 每帧调用入口:根据当前玩家状态决定是否触发登船或上岸流程; + * 每帧调用入口:根据当前玩家状态决定是否触发登船 / 坐船航行 / 上岸流程; * 已经处于某个流程中时推进阶段。 * - * @param client 客户端 - * @param config 扩地配置(用于读取 autoBoat/最小宽度/最短长度) - * @param isRunning 当前扩地任务是否在运行(PAUSE/COMPLETE/STOPPED 时跳过) + * @param client 客户端 + * @param config 扩地配置(用于读取 autoBoat/最小宽度/最短长度) + * @param isRunning 当前扩地任务是否在运行(PAUSE/COMPLETE/STOPPED 时跳过) + * @param canStartFlow 是否允许开启新的用船流程(仅"寻路前往目标"阶段为 true; + * 走两步/等待开垦等阶段不抢路) + * @param target 当前寻路目标区块(坐船航行时朝它前进) */ - public void tick(MinecraftClient client, ExpansionConfig config, boolean isRunning) { + public void tick(MinecraftClient client, ExpansionConfig config, boolean isRunning, boolean canStartFlow, ChunkPos target) { if (client == null || client.player == null || client.world == null || client.interactionManager == null) { return; } - // 配置未启用或任务未运行:清理状态(如有进行中的流程,强行取消并释放蹲伏键) + // 登船失败冷却计时 + if (this.failCooldownTicks > 0) { + --this.failCooldownTicks; + } + // 配置未启用或任务未运行:清理状态(如有进行中的流程,强行取消并释放按键) if (!isRunning || !config.autoBoat) { this.reset(client, false); return; } - // 自动攻击、自动进食、自动游泳、走两步期间:让位(避免按键冲突) if (this.flow == IDLE) { - // 无进行中流程:根据玩家状态决定是否需要登船 / 上岸 + // 无进行中流程:根据玩家状态决定是否需要登船 / 航行 / 上岸 Entity vehicle = client.player.getVehicle(); if (vehicle instanceof AbstractBoatEntity) { - // 已在船中:检测前方是否即将到达岸边 + // 已在船中:优先靠岸下船;未靠岸且处于寻路阶段则接管航行朝目标前进,否则立即下船 if (this.shouldDisembark(client, config)) { this.beginDisembark(client, (AbstractBoatEntity) vehicle); + } else if (canStartFlow) { + this.beginSail(client); + } else { + this.beginDisembark(client, (AbstractBoatEntity) vehicle); } - } else if (this.shouldBoardBoat(client, config)) { - // 在岸上且前方有开阔水域:尝试登船 + } else if (canStartFlow && this.shouldBoardBoat(client, config)) { + // 在岸上/水面且前方有开阔水域:尝试登船 this.beginBoard(client); } return; } // 有进行中流程:推进阶段 switch (this.flow) { + case FLOW_SAIL -> this.tickSail(client, config, target); case FLOW_ENTER -> this.tickEnter(client); case FLOW_EXIT -> this.tickExit(client); } @@ -133,14 +158,19 @@ public final class AutoBoatController { /** 强制停止所有动作(如任务被手动停止时) */ public void reset(MinecraftClient client, boolean silent) { - if (this.flow == IDLE) { - return; - } // 释放蹲伏键(避免卡住"按住"状态) if (this.holdingSneak) { this.releaseSneak(client); this.holdingSneak = false; } + // 释放前进键(坐船航行时按住,避免流程结束后玩家一直往前走) + if (this.holdingForward) { + this.releaseForward(client); + this.holdingForward = false; + } + if (this.flow == IDLE) { + return; + } // 还原主手槽位(如有暂存) this.restoreSelectedSlot(client); this.flow = IDLE; @@ -149,6 +179,7 @@ public final class AutoBoatController { this.placeTarget = null; this.boardTargetEntityId = -1; this.boatEntityId = -1; + this.arrivedTicks = 0; this.lastLoggedPhase = null; } @@ -161,6 +192,7 @@ public final class AutoBoatController { public String describe() { return switch (this.flow) { case FLOW_ENTER -> "正在自动登船"; + case FLOW_SAIL -> "正在坐船航行"; case FLOW_EXIT -> "正在上岸回收船"; default -> null; }; @@ -176,11 +208,17 @@ public final class AutoBoatController { */ private boolean shouldBoardBoat(MinecraftClient client, ExpansionConfig config) { PlayerEntity player = client.player; - // 玩家完全没入水中:暂不处理,等 Baritone 处理上岸(或玩家主动下船) - if (player.isSubmergedInWater()) { + // 登船失败冷却中:不重复尝试(避免每帧重试刷屏/浪费物品) + if (this.failCooldownTicks > 0) { return false; } - // 玩家脚下为水方块(浅水行走)或睡莲:也允许尝试放船 + // 玩家没入深水(脚部上方 2 格仍是水,即已沉到水面以下 2 格以上): + // 先由自动游泳把玩家浮到水面附近再放船登船,避免把船放在头顶够不到的水里。 + // 注意:水面正常游泳(潜水/漂浮)是允许登船的——这正是"开阔水面自动用船"的关键。 + if (this.isWaterAt(client.world, player.getBlockPos().up(2))) { + return false; + } + // 玩家脚下为水方块(浅水/水面游泳)或睡莲:也允许尝试放船 BlockPos playerPos = player.getBlockPos(); if (!isStandable(client.world, playerPos) && !this.isWaterAt(client.world, playerPos) && !client.world.getBlockState(playerPos).isOf(Blocks.LILY_PAD)) { @@ -345,9 +383,12 @@ public final class AutoBoatController { this.lastLoggedPhase = null; // 暂存当前主手槽位,结束后还原 this.savedSelectedSlot = client.player.getInventory().selectedSlot; - // 按住蹲伏键以阻止 Baritone 把玩家推进水里(也避免登船后立即被推动离开船) - this.pressSneak(client); - this.holdingSneak = true; + // 在岸上时按住蹲伏键阻止 Baritone 把玩家推进水里;水面游泳登船时不按蹲伏 + //(蹲伏会让角色下沉,反而不利),且 ExpansionController 已在用船期间取消 Baritone。 + if (!client.player.isTouchingWater()) { + this.pressSneak(client); + this.holdingSneak = true; + } } private void tickEnter(MinecraftClient client) { @@ -369,13 +410,13 @@ public final class AutoBoatController { // 若玩家当前站在陆地:仍允许(船会被放在脚前的水方块上) BlockPos waterPos = this.placeTarget != null ? this.placeTarget : player.getBlockPos(); if (!this.isWaterAt(client.world, waterPos)) { - // 没有合适的水方块 → 取消 - this.reset(client, true); + // 没有合适的水方块 → 取消(进入冷却,避免每帧重试) + this.cancelEnter(client, "没有合适的水面,取消登船"); return; } int slot = this.findBoatSlot(player); if (slot < 0) { - this.reset(client, true); + this.cancelEnter(client, "背包里没有船,取消登船"); return; } // 切换主手到船物品并放置 @@ -401,9 +442,8 @@ public final class AutoBoatController { // 在附近寻找新放置的船 AbstractBoatEntity boat = this.findNearbyBoat(client, 6.0); if (boat == null) { - // 没找到:可能服务器拒收 / 反作弊拦截 → 取消 - this.logPhaseOnce(client, "放船后未找到船实体,取消登船"); - this.reset(client, true); + // 没找到:可能服务器拒收 / 反作弊拦截 → 取消(进入冷却) + this.cancelEnter(client, "放船后未找到船实体,取消登船"); return; } this.boardTargetEntityId = boat.getId(); @@ -418,7 +458,7 @@ public final class AutoBoatController { // 实体可能已被销毁:再扫一次附近 boat = this.findNearbyBoat(client, 4.0); if (boat == null) { - this.reset(client, true); + this.cancelEnter(client, "登船目标丢失,取消登船"); return; } this.boardTargetEntityId = boat.getId(); @@ -437,21 +477,29 @@ public final class AutoBoatController { return; } if (!(client.player.getVehicle() instanceof AbstractBoatEntity)) { - // 登船失败 → 取消 - this.reset(client, true); + // 登船失败 → 取消(进入冷却) + this.cancelEnter(client, "登船失败,取消登船"); return; } - // 释放蹲伏键,Baritone 恢复自动寻路(此时玩家在船中,按 W 即可让船前进) + // 释放蹲伏键,进入坐船航行阶段(船由本类手动朝目标导航,Baritone 已取消) this.releaseSneak(client); this.holdingSneak = false; - this.logPhaseOnce(client, "自动登船完成,开始过水"); - this.flow = IDLE; + // 还原主手槽位(船航行不依赖主手) + this.restoreSelectedSlot(client); + this.logPhaseOnce(client, "自动登船完成,开始过水航行"); + this.flow = FLOW_SAIL; this.phase = PHASE_PLACE; this.phaseTicks = 0; this.placeTarget = null; this.boardTargetEntityId = -1; - // 还原主手槽位(让 Baritone 自由切回所需工具) - this.restoreSelectedSlot(client); + this.arrivedTicks = 0; + } + + /** 登船流程失败:记录日志、进入失败冷却(避免每帧重试刷屏)、清理流程状态 */ + private void cancelEnter(MinecraftClient client, String message) { + this.logPhaseOnce(client, message); + this.failCooldownTicks = BOARD_FAIL_COOLDOWN_TICKS; + this.reset(client, true); } /** 玩家正前方 1 格内的水面方块(脚下优先);找不到返回 null */ @@ -501,6 +549,79 @@ public final class AutoBoatController { this.savedSelectedSlot = -1; } + // =========================== 坐船航行 =========================== + + /** 开启坐船航行流程:接管船的移动,朝目标区块方向前进(Baritone 已由控制器取消) */ + private void beginSail(MinecraftClient client) { + if (this.flow != IDLE) { + return; + } + this.flow = FLOW_SAIL; + this.arrivedTicks = 0; + this.lastLoggedPhase = null; + this.logPhaseOnce(client, "开始坐船航行"); + } + + /** 航行中每帧:靠岸或到达目标区块附近则下船回收;否则面向目标按住前进键 */ + private void tickSail(MinecraftClient client, ExpansionConfig config, ChunkPos target) { + PlayerEntity player = client.player; + if (!(player.getVehicle() instanceof AbstractBoatEntity)) { + // 船已消失(被销毁 / 玩家被踢出):结束航行,交给 ExpansionController 恢复寻路 + this.logPhaseOnce(client, "航行中船已消失,结束用船"); + this.finishSail(client, false); + return; + } + // 前方即将靠岸:下船回收 + if (this.shouldDisembark(client, config)) { + this.finishSail(client, true); + return; + } + // 已到达目标区块:再航一会儿找岸边;超时仍未靠岸则直接下船(自动游泳会接管漂浮) + if (this.reachedTarget(player, target)) { + if (++this.arrivedTicks > ARRIVED_FORCE_DISEMBARK_TICKS) { + this.logPhaseOnce(client, "已到达目标区块,直接下船"); + this.finishSail(client, true); + return; + } + } + // 面向目标航行 + this.steerTowardTarget(client, target); + this.pressForward(client); + } + + /** 结束航行流程:释放前进键;需要下船时进入上岸流程,否则直接恢复寻路 */ + private void finishSail(MinecraftClient client, boolean disembark) { + this.releaseForward(client); + if (disembark && client.player.getVehicle() instanceof AbstractBoatEntity boat) { + this.beginDisembark(client, boat); + return; + } + this.flow = IDLE; + this.arrivedTicks = 0; + this.lastLoggedPhase = null; + } + + /** 玩家当前区块是否已到达目标区块 */ + private boolean reachedTarget(PlayerEntity player, ChunkPos target) { + return target != null && ChunkPos.fromBlock(player.getBlockX(), player.getBlockZ()).equals(target); + } + + /** 把玩家朝向对准目标区块中心(水平方向),船会沿视线方向前进 */ + private void steerTowardTarget(MinecraftClient client, ChunkPos target) { + if (target == null || client.player == null) { + return; + } + PlayerEntity player = client.player; + double dx = target.centerBlockX() + 0.5 - player.getX(); + double dz = target.centerBlockZ() + 0.5 - player.getZ(); + if (dx * dx + dz * dz < 1.0e-6) { + return; + } + // Minecraft yaw 约定:yaw=0 面向 +Z(南),x 分量 = -sin(yaw) + float yaw = (float) Math.toDegrees(Math.atan2(-dx, dz)); + player.setYaw(yaw); + } + // =========================== 上岸流程 =========================== private void beginDisembark(MinecraftClient client, AbstractBoatEntity boat) { @@ -612,6 +733,24 @@ public final class AutoBoatController { sneak.setPressed(false); } + /** 按下前进键(坐船航行时持续按住,使船沿视线方向前进) */ + private void pressForward(MinecraftClient client) { + if (client.player == null) return; + if (!this.holdingForward) { + client.options.forwardKey.setPressed(true); + this.holdingForward = true; + } + } + + /** 释放前进键 */ + private void releaseForward(MinecraftClient client) { + if (client.player == null) return; + if (this.holdingForward) { + client.options.forwardKey.setPressed(false); + this.holdingForward = false; + } + } + /** 在指定半径内查找最接近玩家的船实体 */ private AbstractBoatEntity findNearbyBoat(MinecraftClient client, double radius) { Vec3d center = client.player.getPos(); diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 95871f1..e8d7856 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -1 +1 @@ -{"schemaVersion":1,"id":"autostore","version":"1.3.0","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"}]} \ No newline at end of file +{"schemaVersion":1,"id":"autostore","version":"1.3.1","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"}]} \ No newline at end of file