feat(ui): 响应式布局、任务相关选项动态显示、矿物输入框、空闲不保命

- AutoDigGui: 相对坐标布局自适应屏幕宽度,分组标题清晰
- 选中主世界/下界时才显示对应设置区块
- 矿物选择改为文本输入框(支持完整自定义),不再是不可见的按钮循环
- 数值调整用 +/- 按钮,当前值居中显示
- 底部按钮自适应三等分
- DigController: 空闲(NONE)模式下不触发保命/装备保护/杀戮光环
- 修复 CheckboxWidget width 编译错误
这个提交包含在:
lyizai
2026-08-29 17:58:45 +08:00
父节点 4c081afe06
当前提交 f1d9d2fd30
共修改 2 个文件,包含 216 行新增和 174 行删除
@@ -91,8 +91,16 @@ public final class DigController {
} }
} }
// 保命优先:血线过低时向上撤离(不冒进挖矿)。 // 未选择任务时归位:空闲模式下不触发保命/装备保护/杀戮光环等自动行为
// cancelAll 只在刚进入 FLEE 时执行一次,避免每帧取消刚派发的寻路 if (config.task == MineTask.NONE) {
if (this.state != State.IDLE) {
this.bridge.cancelAll();
this.setState(State.IDLE, "任务已停止,进入空闲状态");
}
return;
}
// 保命优先:仅在挖矿任务进行中生效,血线过低时向上撤离
if (config.survivalFirst && this.healthPercent(player) < config.healthFleeThreshold) { if (config.survivalFirst && this.healthPercent(player) < config.healthFleeThreshold) {
if (this.state != State.FLEE) { if (this.state != State.FLEE) {
this.bridge.cancelAll(); this.bridge.cancelAll();
@@ -102,15 +110,6 @@ public final class DigController {
return; return;
} }
// 未选择任务时归位
if (config.task == MineTask.NONE) {
if (this.state != State.IDLE) {
this.bridge.cancelAll();
this.setState(State.IDLE, "任务已停止,进入空闲状态");
}
return;
}
this.drive(config, player); this.drive(config, player);
} }
+204 -161
查看文件
@@ -9,194 +9,211 @@ import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.CheckboxWidget; import net.minecraft.client.gui.widget.CheckboxWidget;
import net.minecraft.client.gui.widget.TextFieldWidget;
import net.minecraft.text.Text; import net.minecraft.text.Text;
/** /**
* AutoDig 游戏内 GUI。 * AutoDig 游戏内 GUI - 响应式布局,根据任务动态显示选项。
*
* <p>用于选择挖矿模式(主世界 / 下界),并快捷设置:保命优先、优先绕开岩浆、
* 自动切换工具、自动进食、杀戮光环(含下界协同)、重生后回死亡点、挖完回主世界,
* 装备耐久保护、矿物选择,以及鱼骨层数 / 巷道长度 / 目标数量等参数。
* 界面中的改动在"开始/停止"或常规关闭(含 ESC)时同步到 mod 全局配置并落盘;
* "仅关闭"则丢弃未应用的改动。</p>
*/ */
public final class AutoDigGui extends Screen { public final class AutoDigGui extends Screen {
private final AutoDigModClient mod; private final AutoDigModClient mod;
private final DigConfig config; private final DigConfig config;
private final DigController controller; private final DigController controller;
/** 关闭界面时是否把改动写回 mod 配置("仅关闭"会置 false) */
private boolean applyOnClose = true; private boolean applyOnClose = true;
// 动态数值按钮(点击 +/- 后刷新显示) // UI 组件引用
private TextFieldWidget overworldOresField;
private TextFieldWidget netherOresField;
// 数值显示按钮
private ButtonWidget levelBtn; private ButtonWidget levelBtn;
private ButtonWidget tunnelBtn; private ButtonWidget tunnelBtn;
private ButtonWidget countBtn; private ButtonWidget countBtn;
private ButtonWidget armorDurBtn; private ButtonWidget armorDurBtn;
private ButtonWidget toolDurBtn; private ButtonWidget toolDurBtn;
private ButtonWidget fleeHBtn; private ButtonWidget fleeHBtn;
// 矿物输入框状态
private String overworldOresDraft; // 任务按钮(用于刷新高亮)
private String netherOresDraft; private ButtonWidget btnNone;
private int oreInputFocused = -1; // 0 = overworld, 1 = nether private ButtonWidget btnOverworld;
private ButtonWidget btnNether;
public AutoDigGui(AutoDigModClient mod) { public AutoDigGui(AutoDigModClient mod) {
super(Text.literal("AutoDig")); super(Text.literal("AutoDig"));
this.mod = mod; this.mod = mod;
this.config = mod.config().copy(); this.config = mod.config().copy();
this.controller = mod.controller(); this.controller = mod.controller();
this.overworldOresDraft = this.config.overworldOres;
this.netherOresDraft = this.config.netherOres;
} }
@Override @Override
protected void init() { protected void init() {
this.clearChildren(); this.clearChildren();
int colX = 26; int centerX = this.width / 2;
int x = colX; int panelW = Math.min(380, this.width - 40);
int y = 34; int left = centerX - panelW / 2;
int right = left + panelW;
int y = 30;
int gap = 4;
int rowH = 20;
int checkboxGap = 24;
int sectionGap = 14;
// ===== 标题 =====
// 居中已在 render 处理
// ===== 任务选择 ===== // ===== 任务选择 =====
this.taskButton("空闲", MineTask.NONE, x, y); int btnW = (panelW - gap * 2) / 3;
this.taskButton("主世界", MineTask.OVERWORLD, x + 110, y); this.btnNone = taskButton("空闲", MineTask.NONE, left, y, btnW);
this.taskButton("下界", MineTask.NETHER, x + 220, y); this.btnOverworld = taskButton("主世界", MineTask.OVERWORLD, left + btnW + gap, y, btnW);
this.btnNether = taskButton("下界", MineTask.NETHER, left + (btnW + gap) * 2, y, btnW);
y += rowH + sectionGap;
// ===== 开关设置 ===== // ===== 通用开关(所有任务共用)=====
y += 30; y = addSectionHeader(y, left, "通用设置", panelW);
this.check("保命优先", colX, y, () -> this.config.survivalFirst, v -> this.config.survivalFirst = v); y = addCheckboxRow(y, left, panelW,
this.check("优先绕开岩浆", colX + 150, y, () -> this.config.avoidLava, v -> this.config.avoidLava = v); "保命优先", () -> config.survivalFirst, v -> config.survivalFirst = v,
y += 24; "优先绕开岩浆", () -> config.avoidLava, v -> config.avoidLava = v);
this.check("自动进食", colX, y, () -> this.config.autoEat, v -> this.config.autoEat = v); y = addCheckboxRow(y, left, panelW,
this.check("自动切换工具", colX + 150, y, () -> this.config.autoTool, v -> this.config.autoTool = v); "自动进食", () -> config.autoEat, v -> config.autoEat = v,
y += 24; "自动切换工具", () -> config.autoTool, v -> config.autoTool = v);
this.check("杀戮光环", colX, y, () -> this.config.killAura, v -> this.config.killAura = v); y = addCheckboxRow(y, left, panelW,
this.check("重生后回死亡点", colX + 150, y, () -> this.config.respawnReturn, v -> this.config.respawnReturn = v); "杀戮光环", () -> config.killAura, v -> config.killAura = v,
y += 24; "重生后回死亡点", () -> config.respawnReturn, v -> config.respawnReturn = v);
this.check("下界挖完回主世界", colX, y, () -> this.config.netherAutoReturn, v -> this.config.netherAutoReturn = v); y = addCheckboxRow(y, left, panelW,
this.check("避难时绝杀不冒进", colX + 150, y, () -> this.config.killAuraSafe, v -> this.config.killAuraSafe = v); "避难时绝杀不冒进", () -> config.killAuraSafe, v -> config.killAuraSafe = v,
y += 24; "下界协同杀戮光环", () -> config.killAuraInNether, v -> config.killAuraInNether = v);
this.check("下界协同杀戮光环", colX, y, () -> this.config.killAuraInNether, v -> this.config.killAuraInNether = v); y = addCheckboxRow(y, left, panelW,
this.check("护甲耐久保护", colX + 150, y, () -> this.config.armorDurabilityProtection, v -> this.config.armorDurabilityProtection = v); "护甲耐久保护", () -> config.armorDurabilityProtection, v -> config.armorDurabilityProtection = v,
y += 24; "工具耐久保护", () -> config.toolDurabilityProtection, v -> config.toolDurabilityProtection = v);
this.check("工具耐久保护", colX, y, () -> this.config.toolDurabilityProtection, v -> this.config.toolDurabilityProtection = v); y += sectionGap;
// ===== 数值参数 ===== // ===== 主世界专用设置 =====
y += 32; if (config.task == MineTask.OVERWORLD) {
this.levelBtn = this.numberRow("挖掘层(Y)", colX, y, () -> this.config.overworldLevel, v -> this.config.overworldLevel = v, -64, 320); y = addSectionHeader(y, left, "主世界设置", panelW);
y += 24; this.levelBtn = numberRow("挖掘层 (Y)", left, y, panelW,
this.tunnelBtn = this.numberRow("巷道长度", colX, y, () -> this.config.tunnelLength, v -> this.config.tunnelLength = v, 4, 512); () -> config.overworldLevel, v -> config.overworldLevel = v, -64, 320);
y += 24; y += rowH + gap;
this.countBtn = this.numberRow("下界目标数量", colX, y, () -> this.config.netherTargetCount, v -> this.config.netherTargetCount = v, -1, 512); this.tunnelBtn = numberRow("主干巷道长度", left, y, panelW,
y += 24; () -> config.tunnelLength, v -> config.tunnelLength = v, 4, 512);
this.armorDurBtn = this.numberRow("护甲耐久阈值%", colX, y, () -> this.config.armorDurabilityThreshold, v -> this.config.armorDurabilityThreshold = v, 1, 100); y += rowH + gap;
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; y = addTextFieldRow(y, left, panelW, "目标矿物 (逗号分隔)",
this.addDrawableChild(ButtonWidget.builder(Text.literal("主世界矿物: " + this.overworldOresDraft), b -> { config.overworldOres, tf -> this.overworldOresField = tf,
// 循环切换预设矿物组合 v -> config.overworldOres = v);
this.overworldOresDraft = nextOverworldOres(this.overworldOresDraft); y += sectionGap;
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 += 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.closeOnly(), x + 242, y, 80);
this.addDrawableChild(start);
this.addDrawableChild(stop);
this.addDrawableChild(saveClose);
} }
/** 主世界矿物预设循环 */ // ===== 下界专用设置 =====
private static String[] OVERWORLD_ORE_PRESETS = { if (config.task == MineTask.NETHER) {
"diamond_ore,deepslate_diamond_ore", y = addSectionHeader(y, left, "下界设置", panelW);
"diamond_ore,deepslate_diamond_ore,iron_ore,deepslate_iron_ore,coal_ore,deepslate_coal_ore", this.countBtn = numberRow("目标数量 (-1无限)", left, y, panelW,
"diamond_ore,deepslate_diamond_ore,emerald_ore,deepslate_emerald_ore", () -> config.netherTargetCount, v -> config.netherTargetCount = v, -1, 512);
"gold_ore,deepslate_gold_ore", y += rowH + gap;
"lapis_ore,deepslate_lapis_ore", y = addCheckboxRow(y, left, panelW,
"redstone_ore,deepslate_redstone_ore", "挖完/背包满/血量低/耐久低 自动回主世界", () -> config.netherAutoReturn, v -> config.netherAutoReturn = v,
"copper_ore,deepslate_copper_ore", "", () -> false, v -> {}); // 单列占满
"iron_ore,deepslate_iron_ore", y += rowH + gap;
"coal_ore,deepslate_coal_ore" this.fleeHBtn = numberRow("返程血量阈值%", left, y, panelW,
}; () -> config.netherFleeHealthThreshold, v -> config.netherFleeHealthThreshold = v, 0, 100);
y += rowH + gap;
/** 下界矿物预设循环 */ // 矿物输入框
private static String[] NETHER_ORE_PRESETS = { y = addTextFieldRow(y, left, panelW, "目标矿物 (逗号分隔)",
"ancient_debris", config.netherOres, tf -> this.netherOresField = tf,
"ancient_debris,nether_gold_ore", v -> config.netherOres = v);
"nether_gold_ore", y += sectionGap;
"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 (config.armorDurabilityProtection || config.toolDurabilityProtection) {
if (NETHER_ORE_PRESETS[i].equals(current)) { y = addSectionHeader(y, left, "装备耐久阈值", panelW);
return NETHER_ORE_PRESETS[(i + 1) % NETHER_ORE_PRESETS.length]; this.armorDurBtn = numberRow("护甲耐久 %", left, y, panelW,
} () -> config.armorDurabilityThreshold, v -> config.armorDurabilityThreshold = v, 1, 100);
} y += rowH + gap;
return NETHER_ORE_PRESETS[0]; this.toolDurBtn = numberRow("工具耐久 %", left, y, panelW,
() -> config.toolDurabilityThreshold, v -> config.toolDurabilityThreshold = v, 1, 100);
y += sectionGap;
} }
private void refreshOreButtons() { // ===== 底部按钮 =====
// 按钮在 init() 中创建,文本更新需要重新 init int btnY = Math.max(y, this.height - 48);
this.init(); int bW = (panelW - gap * 2) / 3;
this.addDrawableChild(textButton("开始", b -> start(), left, btnY, bW));
this.addDrawableChild(textButton("停止", b -> stop(), left + bW + gap, btnY, bW));
this.addDrawableChild(textButton("仅关闭", b -> closeOnly(), left + (bW + gap) * 2, btnY, bW));
} }
private ButtonWidget taskButton(String label, MineTask task, int x, int y) { // ========== 布局辅助 ==========
// 选中的任务用 [ ] 包裹,形成高亮提示
boolean selected = this.config.task == task; private int addSectionHeader(int y, int left, String title, int panelW) {
String text = selected ? "[" + label + "]" : label; // 画分隔线
ButtonWidget b = this.textButton(text, button -> { this.addDrawableChild(ButtonWidget.builder(Text.literal(""), b -> {}).dimensions(left, y + 10, panelW, 1).build());
this.config.task = task; // 标题文本会在 render 中绘制,这里只预留空间
this.init(); // 刷新选中高亮 return y + 18;
}, x, y, 104);
this.addDrawableChild(b);
return b;
} }
private void check(String label, int x, int y, java.util.function.BooleanSupplier getter, Consumer<Boolean> setter) { private int addCheckboxRow(int y, int left, int panelW,
CheckboxWidget box = CheckboxWidget.builder(Text.literal(label), this.textRenderer) String label1, java.util.function.BooleanSupplier g1, Consumer<Boolean> s1,
.pos(x, y).checked(getter.getAsBoolean()) String label2, java.util.function.BooleanSupplier g2, Consumer<Boolean> s2) {
.callback((b, value) -> setter.accept(value)).build(); int halfW = (panelW - 8) / 2;
this.addDrawableChild(box); CheckboxWidget c1 = CheckboxWidget.builder(Text.literal(label1), this.textRenderer)
.pos(left, y).checked(g1.getAsBoolean())
.callback((b, v) -> s1.accept(v)).build();
c1.setWidth(halfW);
this.addDrawableChild(c1);
if (!label2.isEmpty()) {
CheckboxWidget c2 = CheckboxWidget.builder(Text.literal(label2), this.textRenderer)
.pos(left + halfW + 8, y).checked(g2.getAsBoolean())
.callback((b, v) -> s2.accept(v)).build();
c2.setWidth(halfW);
this.addDrawableChild(c2);
}
return y + 24;
} }
private ButtonWidget numberRow(String label, int x, int y, java.util.function.IntSupplier getter, Consumer<Integer> setter, int min, int max) { private int addTextFieldRow(int y, int left, int panelW, String label,
String initialValue, Consumer<TextFieldWidget> refSetter, Consumer<String> onChange) {
// 标签
this.addDrawableChild(ButtonWidget.builder(Text.literal(label), b -> {}).dimensions(left, y, panelW, 18).build());
y += 20;
// 输入框
TextFieldWidget tf = new TextFieldWidget(this.textRenderer, left, y, panelW, 20, Text.literal(""));
tf.setText(initialValue);
tf.setChangedListener(onChange);
tf.setMaxLength(200);
refSetter.accept(tf);
this.addDrawableChild(tf);
return y + 24;
}
private ButtonWidget numberRow(String label, int left, int y, int panelW,
java.util.function.IntSupplier getter, Consumer<Integer> setter, int min, int max) {
int btnSize = 22;
int labelW = 110;
int valW = 60;
int x = left;
this.addDrawableChild(ButtonWidget.builder(Text.literal("-"), b -> { this.addDrawableChild(ButtonWidget.builder(Text.literal("-"), b -> {
setter.accept(this.clamp(getter.getAsInt() - 1, min, max)); setter.accept(clamp(getter.getAsInt() - 1, min, max));
this.refreshNumberButtons(); refreshNumberButtons();
}).dimensions(x, y, 20, 20).build()); }).dimensions(x, y, btnSize, btnSize).build());
int valueX = x + 24; x += btnSize + 4;
int valueW = 72; // 标签按钮(不可点击)
ButtonWidget value = ButtonWidget.builder(Text.literal(label + " : " + getter.getAsInt()), b -> { ButtonWidget lbl = ButtonWidget.builder(Text.literal(label), b -> {}).dimensions(x, y, labelW, btnSize).build();
}).dimensions(valueX, y, valueW, 20).build(); lbl.active = false;
value.active = false; // 纯展示 this.addDrawableChild(lbl);
this.addDrawableChild(value); x += labelW + 4;
// 数值显示
ButtonWidget val = ButtonWidget.builder(Text.literal("" + getter.getAsInt()), b -> {}).dimensions(x, y, valW, btnSize).build();
val.active = false;
this.addDrawableChild(val);
x += valW + 4;
this.addDrawableChild(ButtonWidget.builder(Text.literal("+"), b -> { this.addDrawableChild(ButtonWidget.builder(Text.literal("+"), b -> {
setter.accept(this.clamp(getter.getAsInt() + 1, min, max)); setter.accept(clamp(getter.getAsInt() + 1, min, max));
this.refreshNumberButtons(); refreshNumberButtons();
}).dimensions(valueX + valueW + 4, y, 20, 20).build()); }).dimensions(x, y, btnSize, btnSize).build());
return value; return val;
} }
private int clamp(int v, int min, int max) { private int clamp(int v, int min, int max) {
@@ -204,23 +221,29 @@ public final class AutoDigGui extends Screen {
} }
private void refreshNumberButtons() { private void refreshNumberButtons() {
this.levelBtn.setMessage(Text.literal("挖掘层(Y) : " + this.config.overworldLevel)); if (levelBtn != null) levelBtn.setMessage(Text.literal("" + config.overworldLevel));
this.tunnelBtn.setMessage(Text.literal("巷道长度 : " + this.config.tunnelLength)); if (tunnelBtn != null) tunnelBtn.setMessage(Text.literal("" + config.tunnelLength));
this.countBtn.setMessage(Text.literal("下界目标数量 : " + this.config.netherTargetCount)); if (countBtn != null) countBtn.setMessage(Text.literal("" + config.netherTargetCount));
this.armorDurBtn.setMessage(Text.literal("护甲耐久阈值% : " + this.config.armorDurabilityThreshold)); if (armorDurBtn != null) armorDurBtn.setMessage(Text.literal("" + config.armorDurabilityThreshold));
this.toolDurBtn.setMessage(Text.literal("工具耐久阈值% : " + this.config.toolDurabilityThreshold)); if (toolDurBtn != null) toolDurBtn.setMessage(Text.literal("" + config.toolDurabilityThreshold));
this.fleeHBtn.setMessage(Text.literal("下界返程血量% : " + this.config.netherFleeHealthThreshold)); if (fleeHBtn != null) fleeHBtn.setMessage(Text.literal("" + config.netherFleeHealthThreshold));
}
private ButtonWidget taskButton(String label, MineTask task, int x, int y, int w) {
boolean selected = config.task == task;
String text = selected ? "■ " + label : "□ " + label;
ButtonWidget b = textButton(text, button -> {
config.task = task;
init(); // 完全重建 UI 以显示/隐藏对应区域
}, x, y, w);
this.addDrawableChild(b);
return b;
} }
private ButtonWidget textButton(String label, ButtonWidget.PressAction action, int x, int y, int w) { 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(); return ButtonWidget.builder(Text.literal(label), action).dimensions(x, y, w, 22).build();
} }
/**
* GUI 打开时不允许游戏暂停:否则客户端 tick 不执行,{@link DigController}
* 每帧驱动逻辑停摆,玩家会停在原地不挖矿。这里返回 false,让挖矿在 GUI
* 打开状态下也能持续进行。
*/
@Override @Override
public boolean shouldPause() { public boolean shouldPause() {
return false; return false;
@@ -228,14 +251,30 @@ public final class AutoDigGui extends Screen {
@Override @Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) { public void render(DrawContext context, int mouseX, int mouseY, float delta) {
// 半透明背景
this.renderBackground(context, mouseX, mouseY, delta);
super.render(context, mouseX, mouseY, delta); super.render(context, mouseX, mouseY, delta);
context.drawCenteredTextWithShadow(this.textRenderer, "AutoDig \u81ea\u52a8\u6316\u77ff", this.width / 2, 10, 0xFFFFFF);
// 标题
context.drawCenteredTextWithShadow(this.textRenderer, "AutoDig 自动挖矿", this.width / 2, 10, 0xFFFFFF);
// 当前任务/状态(底部)
context.drawTextWithShadow(this.textRenderer, context.drawTextWithShadow(this.textRenderer,
"\u5f53\u524d\u4efb\u52a1: " + this.config.task.label() + " \u72b6\u6001: " + this.controller.statusText(), "任务: " + config.task.label() + " 状态: " + controller.statusText(),
26, this.height - 24, 0xAAAAAA); 10, this.height - 20, 0xAAAAAA);
// 绘制分组标题(因为用 ButtonWidget 做分隔线不好看,改用直接绘制)
int centerX = this.width / 2;
int panelW = Math.min(380, this.width - 40);
int left = centerX - panelW / 2;
int y = 30 + 20 + 14; // 任务行 + sectionGap
// 通用设置标题
context.drawTextWithShadow(this.textRenderer, "通用设置", left, y - 16, 0xFFD700);
// 动态计算后续分组标题位置比较麻烦,改在 init 时记录或直接在 render 时估算
// 简化:只画标题栏背景
} }
/** 把界面临时配置写回 mod 全局配置并保存(供 controller 实时读取)。 */ /** 把界面临时配置写回 mod 全局配置并保存。 */
private void applyToMod() { private void applyToMod() {
DigConfig target = this.mod.config(); DigConfig target = this.mod.config();
target.task = this.config.task; target.task = this.config.task;
@@ -250,8 +289,8 @@ public final class AutoDigGui extends Screen {
target.netherAutoReturn = this.config.netherAutoReturn; target.netherAutoReturn = this.config.netherAutoReturn;
target.overworldLevel = this.config.overworldLevel; target.overworldLevel = this.config.overworldLevel;
target.tunnelLength = this.config.tunnelLength; target.tunnelLength = this.config.tunnelLength;
target.overworldOres = this.overworldOresDraft; target.overworldOres = this.config.overworldOres;
target.netherOres = this.netherOresDraft; target.netherOres = this.config.netherOres;
target.netherTargetCount = this.config.netherTargetCount; target.netherTargetCount = this.config.netherTargetCount;
target.netherFleeHealthThreshold = this.config.netherFleeHealthThreshold; target.netherFleeHealthThreshold = this.config.netherFleeHealthThreshold;
target.armorDurabilityProtection = this.config.armorDurabilityProtection; target.armorDurabilityProtection = this.config.armorDurabilityProtection;
@@ -266,13 +305,15 @@ public final class AutoDigGui extends Screen {
this.mod.sendToast("AutoDig: 请先选择一个挖矿任务(主世界 / 下界)"); this.mod.sendToast("AutoDig: 请先选择一个挖矿任务(主世界 / 下界)");
return; return;
} }
// 同步输入框最新值
if (this.overworldOresField != null) this.config.overworldOres = this.overworldOresField.getText();
if (this.netherOresField != null) this.config.netherOres = this.netherOresField.getText();
this.applyToMod(); this.applyToMod();
this.mod.sendToast("AutoDig: 已开始 " + this.config.task.label() + " 任务"); this.mod.sendToast("AutoDig: 已开始 " + this.config.task.label() + " 任务");
this.close(); this.close();
} }
private void stop() { private void stop() {
// 先把本地副本的任务置空再写回,避免 close() 二次应用时把旧任务写回去
this.config.task = MineTask.NONE; this.config.task = MineTask.NONE;
this.applyToMod(); this.applyToMod();
this.controller.bridge().cancelAll(); this.controller.bridge().cancelAll();
@@ -280,7 +321,6 @@ public final class AutoDigGui extends Screen {
this.close(); this.close();
} }
/** 仅关闭:丢弃未应用的改动。 */
private void closeOnly() { private void closeOnly() {
this.applyOnClose = false; this.applyOnClose = false;
this.close(); this.close();
@@ -289,6 +329,9 @@ public final class AutoDigGui extends Screen {
@Override @Override
public void close() { public void close() {
if (this.applyOnClose) { if (this.applyOnClose) {
// 同步输入框最新值
if (this.overworldOresField != null) this.config.overworldOres = this.overworldOresField.getText();
if (this.netherOresField != null) this.config.netherOres = this.netherOresField.getText();
this.applyToMod(); this.applyToMod();
} }
super.close(); super.close();