feat: 重构挖矿模式为主世界/下界,新增装备耐久保护与自定义矿物
- MineTask: DIAMOND->OVERWORLD, ANCIENT_DEBRIS->NETHER, 移除钻石/远古残骸硬编码 - DigConfig: 新增主世界/下界可选矿物列表、护甲/工具耐久保护阈值、下界返程血量阈值、目标数量 - AutoDigCommands: 支持 overworld/nether/none 任务名 - OverworldMiner: 重命名自 FishboneMiner, 支持配置矿物列表 - NetherMiner: 重命名自 DebrisHandler, 支持配置矿物、血量/耐久/背包满自动返程 - DigController: 新增 GEAR_PROTECTION 状态, 装备耐久过低暂停挖矿/触发下界返程 - AutoDigGui: 更新任务按钮、矿物预设循环、装备耐久/返程阈值设置 - ConfigStore: 扩展 sanitize 校验新字段 - 版本升级: 1.0.0 -> 2.0.0
这个提交包含在:
@@ -14,27 +14,39 @@ import net.minecraft.text.Text;
|
||||
/**
|
||||
* AutoDig 游戏内 GUI。
|
||||
*
|
||||
* <p>用于选择挖什么(钻石 / 远古残骸),并快捷设置:保命优先、优先绕开岩浆、
|
||||
* 自动切换工具、自动进食、杀戮光环、重生后回死亡点、挖完回主世界,
|
||||
* 以及钻石层数 / 巷道长度 / 残骸数量等参数。界面中的改动在"开始/停止/关闭"时
|
||||
* 同步到 mod 全局配置并落盘。</p>
|
||||
* <p>用于选择挖矿模式(主世界 / 下界),并快捷设置:保命优先、优先绕开岩浆、
|
||||
* 自动切换工具、自动进食、杀戮光环(含下界协同)、重生后回死亡点、挖完回主世界,
|
||||
* 装备耐久保护、矿物选择,以及鱼骨层数 / 巷道长度 / 目标数量等参数。
|
||||
* 界面中的改动在"开始/停止"或常规关闭(含 ESC)时同步到 mod 全局配置并落盘;
|
||||
* "仅关闭"则丢弃未应用的改动。</p>
|
||||
*/
|
||||
public final class AutoDigGui extends Screen {
|
||||
|
||||
private final AutoDigModClient mod;
|
||||
private final DigConfig config;
|
||||
private final DigController controller;
|
||||
/** 关闭界面时是否把改动写回 mod 配置("仅关闭"会置 false) */
|
||||
private boolean applyOnClose = true;
|
||||
|
||||
// 动态数值按钮(点击 +/- 后刷新显示)
|
||||
private ButtonWidget levelBtn;
|
||||
private ButtonWidget tunnelBtn;
|
||||
private ButtonWidget debrisBtn;
|
||||
private ButtonWidget countBtn;
|
||||
private ButtonWidget armorDurBtn;
|
||||
private ButtonWidget toolDurBtn;
|
||||
private ButtonWidget fleeHBtn;
|
||||
// 矿物输入框状态
|
||||
private String overworldOresDraft;
|
||||
private String netherOresDraft;
|
||||
private int oreInputFocused = -1; // 0 = overworld, 1 = nether
|
||||
|
||||
public AutoDigGui(AutoDigModClient mod) {
|
||||
super(Text.literal("AutoDig"));
|
||||
this.mod = mod;
|
||||
this.config = mod.config().copy();
|
||||
this.controller = mod.controller();
|
||||
this.overworldOresDraft = this.config.overworldOres;
|
||||
this.netherOresDraft = this.config.netherOres;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -45,8 +57,8 @@ public final class AutoDigGui extends Screen {
|
||||
int y = 34;
|
||||
// ===== 任务选择 =====
|
||||
this.taskButton("空闲", MineTask.NONE, x, y);
|
||||
this.taskButton("钻石(鱼骨)", MineTask.DIAMOND, x + 110, y);
|
||||
this.taskButton("远古残骸", MineTask.ANCIENT_DEBRIS, x + 220, y);
|
||||
this.taskButton("主世界", MineTask.OVERWORLD, x + 110, y);
|
||||
this.taskButton("下界", MineTask.NETHER, x + 220, y);
|
||||
|
||||
// ===== 开关设置 =====
|
||||
y += 30;
|
||||
@@ -59,29 +71,102 @@ public final class AutoDigGui extends Screen {
|
||||
this.check("杀戮光环", colX, y, () -> this.config.killAura, v -> this.config.killAura = v);
|
||||
this.check("重生后回死亡点", colX + 150, y, () -> this.config.respawnReturn, v -> this.config.respawnReturn = v);
|
||||
y += 24;
|
||||
this.check("挖完回主世界", colX, y, () -> this.config.debrisReturnHome, v -> this.config.debrisReturnHome = v);
|
||||
this.check("下界挖完回主世界", colX, y, () -> this.config.netherAutoReturn, v -> this.config.netherAutoReturn = v);
|
||||
this.check("避难时绝杀不冒进", colX + 150, y, () -> this.config.killAuraSafe, v -> this.config.killAuraSafe = v);
|
||||
y += 24;
|
||||
this.check("下界协同杀戮光环", colX, y, () -> this.config.killAuraInNether, v -> this.config.killAuraInNether = v);
|
||||
this.check("护甲耐久保护", colX + 150, y, () -> this.config.armorDurabilityProtection, v -> this.config.armorDurabilityProtection = v);
|
||||
y += 24;
|
||||
this.check("工具耐久保护", colX, y, () -> this.config.toolDurabilityProtection, v -> this.config.toolDurabilityProtection = v);
|
||||
|
||||
// ===== 数值参数 =====
|
||||
y += 32;
|
||||
this.levelBtn = this.numberRow("钻石层(Y)", colX, y, () -> this.config.diamondLevel, v -> this.config.diamondLevel = v);
|
||||
this.levelBtn = this.numberRow("挖掘层(Y)", colX, y, () -> this.config.overworldLevel, v -> this.config.overworldLevel = v, -64, 320);
|
||||
y += 24;
|
||||
this.tunnelBtn = this.numberRow("巷道长度", colX, y, () -> this.config.tunnelLength, v -> this.config.tunnelLength = v);
|
||||
this.tunnelBtn = this.numberRow("巷道长度", colX, y, () -> this.config.tunnelLength, v -> this.config.tunnelLength = v, 4, 512);
|
||||
y += 24;
|
||||
this.debrisBtn = this.numberRow("残骸数量", colX, y, () -> this.config.debrisCount, v -> this.config.debrisCount = v);
|
||||
this.countBtn = this.numberRow("下界目标数量", colX, y, () -> this.config.netherTargetCount, v -> this.config.netherTargetCount = v, -1, 512);
|
||||
y += 24;
|
||||
this.armorDurBtn = this.numberRow("护甲耐久阈值%", colX, y, () -> this.config.armorDurabilityThreshold, v -> this.config.armorDurabilityThreshold = v, 1, 100);
|
||||
y += 24;
|
||||
this.toolDurBtn = this.numberRow("工具耐久阈值%", colX, y, () -> this.config.toolDurabilityThreshold, v -> this.config.toolDurabilityThreshold = v, 1, 100);
|
||||
y += 24;
|
||||
this.fleeHBtn = this.numberRow("下界返程血量%", colX, y, () -> this.config.netherFleeHealthThreshold, v -> this.config.netherFleeHealthThreshold = v, 0, 100);
|
||||
|
||||
// ===== 矿物选择 =====
|
||||
y += 32;
|
||||
this.addDrawableChild(ButtonWidget.builder(Text.literal("主世界矿物: " + this.overworldOresDraft), b -> {
|
||||
// 循环切换预设矿物组合
|
||||
this.overworldOresDraft = nextOverworldOres(this.overworldOresDraft);
|
||||
this.refreshOreButtons();
|
||||
}).dimensions(colX, y, 300, 20).build());
|
||||
y += 24;
|
||||
this.addDrawableChild(ButtonWidget.builder(Text.literal("下界矿物: " + this.netherOresDraft), b -> {
|
||||
// 循环切换预设矿物组合
|
||||
this.netherOresDraft = nextNetherOres(this.netherOresDraft);
|
||||
this.refreshOreButtons();
|
||||
}).dimensions(colX, y, 300, 20).build());
|
||||
|
||||
// ===== 底部操作按钮 =====
|
||||
y += 40;
|
||||
y += 32;
|
||||
ButtonWidget start = this.textButton("开始 (保存并运行)", b -> this.start(), x, y, 140);
|
||||
ButtonWidget stop = this.textButton("停止", b -> this.stop(), x + 146, y, 90);
|
||||
ButtonWidget saveClose = this.textButton("仅关闭", b -> this.close(), x + 242, y, 80);
|
||||
ButtonWidget saveClose = this.textButton("仅关闭", b -> this.closeOnly(), x + 242, y, 80);
|
||||
this.addDrawableChild(start);
|
||||
this.addDrawableChild(stop);
|
||||
this.addDrawableChild(saveClose);
|
||||
}
|
||||
|
||||
/** 主世界矿物预设循环 */
|
||||
private static String[] OVERWORLD_ORE_PRESETS = {
|
||||
"diamond_ore,deepslate_diamond_ore",
|
||||
"diamond_ore,deepslate_diamond_ore,iron_ore,deepslate_iron_ore,coal_ore,deepslate_coal_ore",
|
||||
"diamond_ore,deepslate_diamond_ore,emerald_ore,deepslate_emerald_ore",
|
||||
"gold_ore,deepslate_gold_ore",
|
||||
"lapis_ore,deepslate_lapis_ore",
|
||||
"redstone_ore,deepslate_redstone_ore",
|
||||
"copper_ore,deepslate_copper_ore",
|
||||
"iron_ore,deepslate_iron_ore",
|
||||
"coal_ore,deepslate_coal_ore"
|
||||
};
|
||||
|
||||
/** 下界矿物预设循环 */
|
||||
private static String[] NETHER_ORE_PRESETS = {
|
||||
"ancient_debris",
|
||||
"ancient_debris,nether_gold_ore",
|
||||
"nether_gold_ore",
|
||||
"nether_quartz_ore",
|
||||
"ancient_debris,nether_gold_ore,nether_quartz_ore"
|
||||
};
|
||||
|
||||
private String nextOverworldOres(String current) {
|
||||
for (int i = 0; i < OVERWORLD_ORE_PRESETS.length; i++) {
|
||||
if (OVERWORLD_ORE_PRESETS[i].equals(current)) {
|
||||
return OVERWORLD_ORE_PRESETS[(i + 1) % OVERWORLD_ORE_PRESETS.length];
|
||||
}
|
||||
}
|
||||
return OVERWORLD_ORE_PRESETS[0];
|
||||
}
|
||||
|
||||
private String nextNetherOres(String current) {
|
||||
for (int i = 0; i < NETHER_ORE_PRESETS.length; i++) {
|
||||
if (NETHER_ORE_PRESETS[i].equals(current)) {
|
||||
return NETHER_ORE_PRESETS[(i + 1) % NETHER_ORE_PRESETS.length];
|
||||
}
|
||||
}
|
||||
return NETHER_ORE_PRESETS[0];
|
||||
}
|
||||
|
||||
private void refreshOreButtons() {
|
||||
// 按钮在 init() 中创建,文本更新需要重新 init
|
||||
this.init();
|
||||
}
|
||||
|
||||
private ButtonWidget taskButton(String label, MineTask task, int x, int y) {
|
||||
ButtonWidget b = this.textButton(label, button -> {
|
||||
// 选中的任务用 [ ] 包裹,形成高亮提示
|
||||
boolean selected = this.config.task == task;
|
||||
String text = selected ? "[" + label + "]" : label;
|
||||
ButtonWidget b = this.textButton(text, button -> {
|
||||
this.config.task = task;
|
||||
this.init(); // 刷新选中高亮
|
||||
}, x, y, 104);
|
||||
@@ -96,9 +181,9 @@ public final class AutoDigGui extends Screen {
|
||||
this.addDrawableChild(box);
|
||||
}
|
||||
|
||||
private ButtonWidget numberRow(String label, int x, int y, java.util.function.IntSupplier getter, Consumer<Integer> setter) {
|
||||
private ButtonWidget numberRow(String label, int x, int y, java.util.function.IntSupplier getter, Consumer<Integer> setter, int min, int max) {
|
||||
this.addDrawableChild(ButtonWidget.builder(Text.literal("-"), b -> {
|
||||
setter.accept(getter.getAsInt() - 1);
|
||||
setter.accept(this.clamp(getter.getAsInt() - 1, min, max));
|
||||
this.refreshNumberButtons();
|
||||
}).dimensions(x, y, 20, 20).build());
|
||||
int valueX = x + 24;
|
||||
@@ -108,22 +193,39 @@ public final class AutoDigGui extends Screen {
|
||||
value.active = false; // 纯展示
|
||||
this.addDrawableChild(value);
|
||||
this.addDrawableChild(ButtonWidget.builder(Text.literal("+"), b -> {
|
||||
setter.accept(getter.getAsInt() + 1);
|
||||
setter.accept(this.clamp(getter.getAsInt() + 1, min, max));
|
||||
this.refreshNumberButtons();
|
||||
}).dimensions(valueX + valueW + 4, y, 20, 20).build());
|
||||
return value;
|
||||
}
|
||||
|
||||
private int clamp(int v, int min, int max) {
|
||||
return Math.max(min, Math.min(max, v));
|
||||
}
|
||||
|
||||
private void refreshNumberButtons() {
|
||||
this.levelBtn.setMessage(Text.literal("钻石层(Y) : " + this.config.diamondLevel));
|
||||
this.levelBtn.setMessage(Text.literal("挖掘层(Y) : " + this.config.overworldLevel));
|
||||
this.tunnelBtn.setMessage(Text.literal("巷道长度 : " + this.config.tunnelLength));
|
||||
this.debrisBtn.setMessage(Text.literal("残骸数量 : " + this.config.debrisCount));
|
||||
this.countBtn.setMessage(Text.literal("下界目标数量 : " + this.config.netherTargetCount));
|
||||
this.armorDurBtn.setMessage(Text.literal("护甲耐久阈值% : " + this.config.armorDurabilityThreshold));
|
||||
this.toolDurBtn.setMessage(Text.literal("工具耐久阈值% : " + this.config.toolDurabilityThreshold));
|
||||
this.fleeHBtn.setMessage(Text.literal("下界返程血量% : " + this.config.netherFleeHealthThreshold));
|
||||
}
|
||||
|
||||
private ButtonWidget textButton(String label, ButtonWidget.PressAction action, int x, int y, int w) {
|
||||
return ButtonWidget.builder(Text.literal(label), action).dimensions(x, y, w, 20).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* GUI 打开时不允许游戏暂停:否则客户端 tick 不执行,{@link DigController}
|
||||
* 每帧驱动逻辑停摆,玩家会停在原地不挖矿。这里返回 false,让挖矿在 GUI
|
||||
* 打开状态下也能持续进行。
|
||||
*/
|
||||
@Override
|
||||
public boolean shouldPause() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||
super.render(context, mouseX, mouseY, delta);
|
||||
@@ -143,32 +245,52 @@ public final class AutoDigGui extends Screen {
|
||||
target.autoTool = this.config.autoTool;
|
||||
target.killAura = this.config.killAura;
|
||||
target.killAuraSafe = this.config.killAuraSafe;
|
||||
target.killAuraInNether = this.config.killAuraInNether;
|
||||
target.respawnReturn = this.config.respawnReturn;
|
||||
target.debrisReturnHome = this.config.debrisReturnHome;
|
||||
target.diamondLevel = this.config.diamondLevel;
|
||||
target.netherAutoReturn = this.config.netherAutoReturn;
|
||||
target.overworldLevel = this.config.overworldLevel;
|
||||
target.tunnelLength = this.config.tunnelLength;
|
||||
target.debrisCount = this.config.debrisCount;
|
||||
target.overworldOres = this.overworldOresDraft;
|
||||
target.netherOres = this.netherOresDraft;
|
||||
target.netherTargetCount = this.config.netherTargetCount;
|
||||
target.netherFleeHealthThreshold = this.config.netherFleeHealthThreshold;
|
||||
target.armorDurabilityProtection = this.config.armorDurabilityProtection;
|
||||
target.armorDurabilityThreshold = this.config.armorDurabilityThreshold;
|
||||
target.toolDurabilityProtection = this.config.toolDurabilityProtection;
|
||||
target.toolDurabilityThreshold = this.config.toolDurabilityThreshold;
|
||||
this.mod.saveConfig();
|
||||
}
|
||||
|
||||
private void start() {
|
||||
if (this.config.task == MineTask.NONE) {
|
||||
this.mod.sendToast("AutoDig: 请先选择一个挖矿任务(主世界 / 下界)");
|
||||
return;
|
||||
}
|
||||
this.applyToMod();
|
||||
this.mod.sendToast("AutoDig: 已开始 " + this.config.task.label() + " 任务");
|
||||
this.close();
|
||||
}
|
||||
|
||||
private void stop() {
|
||||
// 先把本地副本的任务置空再写回,避免 close() 二次应用时把旧任务写回去
|
||||
this.config.task = MineTask.NONE;
|
||||
this.applyToMod();
|
||||
this.mod.config().task = MineTask.NONE;
|
||||
this.mod.saveConfig();
|
||||
this.controller.bridge().cancelAll();
|
||||
this.mod.sendToast("AutoDig: 已停止");
|
||||
this.close();
|
||||
}
|
||||
|
||||
/** 仅关闭:丢弃未应用的改动。 */
|
||||
private void closeOnly() {
|
||||
this.applyOnClose = false;
|
||||
this.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.applyToMod();
|
||||
if (this.applyOnClose) {
|
||||
this.applyToMod();
|
||||
}
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
在新工单中引用
屏蔽一个用户