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
这个提交包含在:
lyizai
2026-08-29 13:23:43 +08:00
父节点 95c4e97db0
当前提交 4c081afe06
共修改 17 个文件,包含 864 行新增和 299 行删除
+147 -25
查看文件
@@ -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();
}
}