From 1606646e8750b08ee9c02c48f4056951d7dd318b Mon Sep 17 00:00:00 2001 From: Jaffe2718 Date: Sun, 13 Apr 2025 18:32:35 +0800 Subject: [PATCH 01/12] - fix bug: avoid the crash due to `Identifier` syntax not legitimate. - new feature: multiple expect values for `@Condition` - change: use `net.minecraft.client.gui.widget.CheckboxWidget` for boolean `@Entry` instead of `net.minecraft.client.gui.widget.ButtonWidget` - misc: cleanup for `en_us.json` and example code & bump version --- .../lib/config/MidnightConfig.java | 32 +++++++++---------- gradle.properties | 2 +- .../example/config/MidnightConfigExample.java | 8 ++++- .../resources/assets/modid/lang/en_us.json | 7 ---- 4 files changed, 24 insertions(+), 25 deletions(-) diff --git a/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java b/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java index 4487db3..65eafca 100755 --- a/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java +++ b/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java @@ -97,7 +97,7 @@ public abstract class MidnightConfig { this.conditionsMet = false; String requiredOption = condition.requiredOption().contains(":") ? condition.requiredOption() : (this.modid + ":" + condition.requiredOption()); if (entries.get(requiredOption) instanceof EntryInfo info) - this.conditionsMet &= condition.requiredValue().equals(info.tempValue); + this.conditionsMet &= List.of(condition.requiredValue()).contains(info.tempValue); if (!this.conditionsMet) break; } if (prevConditionState != this.conditionsMet) reloadScreen = true; @@ -162,10 +162,7 @@ public abstract class MidnightConfig { else if (info.dataType == double.class) textField(info, Double::parseDouble, DECIMAL_ONLY, e.min(), e.max(), false); else if (info.dataType == String.class || info.dataType == Identifier.class) textField(info, String::length, null, Math.min(e.min(), 0), Math.max(e.max(), 1), true); else if (info.dataType == boolean.class) { - Function func = value -> Text.translatable((Boolean) value ? "gui.yes" : "gui.no").formatted((Boolean) value ? Formatting.GREEN : Formatting.RED); - info.function = new AbstractMap.SimpleEntry>(button -> { - info.setValue(!(Boolean) info.value); button.setMessage(func.apply(info.value)); - }, func); + info.function = (CheckboxWidget.Callback) (ch, b) -> info.setValue(b); } else if (info.dataType.isEnum()) { List values = Arrays.asList(field.getType().getEnumConstants()); Function func = value -> { @@ -215,7 +212,11 @@ public abstract class MidnightConfig { b.active = entries.values().stream().allMatch(e -> e.inLimits); if (inLimits) { - if (info.dataType == Identifier.class) info.setValue(Identifier.tryParse(s)); + if (info.dataType == Identifier.class) { // avoid the crash due to Identifier syntax not legitimate + Identifier id = Identifier.tryParse(s); + if (id == null) return false; + info.setValue(Identifier.tryParse(s)); + } else info.setValue(isNumber ? value : s); } @@ -296,7 +297,7 @@ public abstract class MidnightConfig { if (entry.buttons.get(0) instanceof ClickableWidget widget) if (widget.isFocused() || widget.isHovered()) widget.setTooltip(getTooltip(entry.info, true)); if (entry.buttons.get(1) instanceof ButtonWidget button) - button.active = !Objects.equals(entry.info.value.toString(), entry.info.defaultValue.toString()); + button.active = !Objects.equals(String.valueOf(entry.info.value), String.valueOf(entry.info.defaultValue)); }}}} @Override public boolean keyPressed(int keyCode, int scanCode, int modifiers) { @@ -354,17 +355,16 @@ public abstract class MidnightConfig { if (info.function != null) { ClickableWidget widget; Entry e = info.entry; - - if (info.function instanceof Map.Entry) { // Enums & booleans + if (info.dataType == boolean.class) { + widget = CheckboxWidget.builder(Text.empty(), textRenderer).pos(width - 185, 0).callback((CheckboxWidget.Callback) info.function).checked((boolean) info.value).build(); + } else if (info.dataType.isEnum()) { var values = (Map.Entry>) info.function; - if (info.dataType.isEnum()) - values.setValue(value -> Text.translatable(translationPrefix + "enum." + info.dataType.getSimpleName() + "." + info.value.toString())); + values.setValue(value -> Text.translatable(translationPrefix + "enum." + info.dataType.getSimpleName() + "." + info.value.toString())); widget = ButtonWidget.builder(values.getValue().apply(info.value), values.getKey()).dimensions(width - 185, 0, 150, 20).tooltip(getTooltip(info, true)).build(); - } - else if (e.isSlider()) + } else if (e.isSlider()) widget = new MidnightSliderWidget(width - 185, 0, 150, 20, Text.of(info.tempValue), (Double.parseDouble(info.tempValue) - e.min()) / (e.max() - e.min()), info); - else widget = new TextFieldWidget(textRenderer, width - 185, 0, 150, 20, Text.empty()); - + else + widget = new TextFieldWidget(textRenderer, width - 185, 0, 150, 20, Text.empty()); if (widget instanceof TextFieldWidget textField) { textField.setMaxLength(e.width()); textField.setText(info.tempValue); Predicate processor = ((BiFunction>) info.function).apply(textField, done); @@ -589,7 +589,7 @@ public abstract class MidnightConfig { public @interface Condition { String requiredModId() default ""; String requiredOption() default ""; - String requiredValue() default "true"; + String[] requiredValue() default {"true"}; boolean visibleButLocked() default false; } diff --git a/gradle.properties b/gradle.properties index 6903179..b847844 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ yarn_mappings=1.21.4+build.1 enabled_platforms=fabric,neoforge archives_base_name=midnightlib -mod_version=1.7.1 +mod_version=1.7.2-rc.1 maven_group=eu.midnightdust release_type=release curseforge_id=488090 diff --git a/test-fabric/src/main/java/eu/midnightdust/fabric/example/config/MidnightConfigExample.java b/test-fabric/src/main/java/eu/midnightdust/fabric/example/config/MidnightConfigExample.java index ec599de..512f7a3 100644 --- a/test-fabric/src/main/java/eu/midnightdust/fabric/example/config/MidnightConfigExample.java +++ b/test-fabric/src/main/java/eu/midnightdust/fabric/example/config/MidnightConfigExample.java @@ -74,7 +74,7 @@ public class MidnightConfigExample extends MidnightConfig { @Entry(category = CONDITIONS, name="Turn me on!") public static boolean turnMeOn = false; @Condition(requiredOption = "modid:turnMeOn", visibleButLocked = true) - @Entry(category = CONDITIONS, name="Turn me off (locked if modid:turnMeOn is false)!") + @Entry(category = CONDITIONS, name="Turn me off (locked)!") public static Boolean turnMeOff = true; @Condition(requiredOption = "turnMeOn") // You can also use multiple conditions for the same entry @Condition(requiredOption = "modid:turnMeOff", requiredValue = "false") @@ -101,6 +101,12 @@ public class MidnightConfigExample extends MidnightConfig { @Comment(category = CONDITIONS, name="⭐ Correct! Quilt (and Fabric) are the best!", centered = true) public static Comment answerQuilt; + @Entry(category = CONDITIONS, name="Enter any prime number below 10") + public static int primeNumber = 0; + @Comment(category = CONDITIONS, name="Correct!") + @Condition(requiredOption = "primeNumber", requiredValue = {"2", "3", "5", "7"}) + public static Comment answerPrime; + @Condition(requiredOption = "midnightlib:config_screen_list", requiredValue = "FALSE") // Access options of other mods that are also using MidnightLib @Comment(category = CONDITIONS) public static Comment spaceracer; @Condition(requiredOption = "midnightlib:config_screen_list", requiredValue = "FALSE") diff --git a/test-fabric/src/main/resources/assets/modid/lang/en_us.json b/test-fabric/src/main/resources/assets/modid/lang/en_us.json index b014330..702947c 100644 --- a/test-fabric/src/main/resources/assets/modid/lang/en_us.json +++ b/test-fabric/src/main/resources/assets/modid/lang/en_us.json @@ -11,13 +11,6 @@ "modid.midnightconfig.hello":"I am a limited int!", "modid.midnightconfig.id":"I am an Item Identifier!", "modid.midnightconfig.modPlatform":"I am an enum!", - "modid.midnightconfig.enum.Arch.X86":"X86", - "modid.midnightconfig.enum.Arch.X86_64":"X86_64", - "modid.midnightconfig.enum.Arch.AARCH64":"AARCH64", - "modid.midnightconfig.enum.Arch.RISCV64":"RISCV64", - "modid.midnightconfig.enum.OS.LINUX":"Linux", - "modid.midnightconfig.enum.OS.WINDOWS":"Windows", - "modid.midnightconfig.enum.OS.MAC":"MacOS", "modid.midnightconfig.enum.ModPlatform.FORGE":"Forge", "modid.midnightconfig.enum.ModPlatform.FABRIC":"Fabric", "modid.midnightconfig.enum.ModPlatform.QUILT":"Quilt", From a4ce16482c6ad96ff1c92d16c205e4c84e62ead9 Mon Sep 17 00:00:00 2001 From: Jaffe2718 Date: Sun, 13 Apr 2025 18:42:24 +0800 Subject: [PATCH 02/12] - fix bug+: illegal Identifier cannot input character --- .../main/java/eu/midnightdust/lib/config/MidnightConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java b/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java index 65eafca..04b312e 100755 --- a/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java +++ b/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java @@ -74,12 +74,12 @@ public abstract class MidnightConfig { } public void setValue(Object value) { if (this.field.getType() != List.class) { this.value = value; - this.tempValue = value.toString(); + this.tempValue = value == null ? "" : value.toString(); // fix bug+: illegal Identifier cannot input character } else { writeList(this.listIndex, value); this.tempValue = toTemporaryValue(); } } public String toTemporaryValue() { - if (this.field.getType() != List.class) return this.value.toString(); + if (this.field.getType() != List.class) return this.value == null ? "" : this.value.toString(); // fix bug+: illegal Identifier cannot input character else try { return ((List) this.value).get(this.listIndex).toString(); } catch (Exception ignored) {return "";} } public void updateFieldValue() { From e046463f669ccff32c85294135c26641683092c5 Mon Sep 17 00:00:00 2001 From: Jaffe2718 Date: Mon, 14 Apr 2025 20:00:51 +0800 Subject: [PATCH 03/12] - rollback: boolean field (`CheckboxWidget` -> `ButtonWidget`) --- .../eu/midnightdust/lib/config/MidnightConfig.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java b/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java index 04b312e..1c27dc9 100755 --- a/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java +++ b/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java @@ -162,7 +162,10 @@ public abstract class MidnightConfig { else if (info.dataType == double.class) textField(info, Double::parseDouble, DECIMAL_ONLY, e.min(), e.max(), false); else if (info.dataType == String.class || info.dataType == Identifier.class) textField(info, String::length, null, Math.min(e.min(), 0), Math.max(e.max(), 1), true); else if (info.dataType == boolean.class) { - info.function = (CheckboxWidget.Callback) (ch, b) -> info.setValue(b); + Function func = value -> Text.translatable((Boolean) value ? "gui.yes" : "gui.no").formatted((Boolean) value ? Formatting.GREEN : Formatting.RED); + info.function = new AbstractMap.SimpleEntry>(button -> { + info.setValue(!(Boolean) info.value); button.setMessage(func.apply(info.value)); + }, func); } else if (info.dataType.isEnum()) { List values = Arrays.asList(field.getType().getEnumConstants()); Function func = value -> { @@ -355,11 +358,10 @@ public abstract class MidnightConfig { if (info.function != null) { ClickableWidget widget; Entry e = info.entry; - if (info.dataType == boolean.class) { - widget = CheckboxWidget.builder(Text.empty(), textRenderer).pos(width - 185, 0).callback((CheckboxWidget.Callback) info.function).checked((boolean) info.value).build(); - } else if (info.dataType.isEnum()) { + if (info.function instanceof Map.Entry) { var values = (Map.Entry>) info.function; - values.setValue(value -> Text.translatable(translationPrefix + "enum." + info.dataType.getSimpleName() + "." + info.value.toString())); + if (info.dataType.isEnum()) + values.setValue(value -> Text.translatable(translationPrefix + "enum." + info.dataType.getSimpleName() + "." + info.value.toString())); widget = ButtonWidget.builder(values.getValue().apply(info.value), values.getKey()).dimensions(width - 185, 0, 150, 20).tooltip(getTooltip(info, true)).build(); } else if (e.isSlider()) widget = new MidnightSliderWidget(width - 185, 0, 150, 20, Text.of(info.tempValue), (Double.parseDouble(info.tempValue) - e.min()) / (e.max() - e.min()), info); From 517d3c8a0ee5921d583dcc332f196b751c75b45e Mon Sep 17 00:00:00 2001 From: Jaffe2718 Date: Mon, 14 Apr 2025 20:05:21 +0800 Subject: [PATCH 04/12] - adjust: optimize code & add comment --- .../main/java/eu/midnightdust/lib/config/MidnightConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java b/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java index 1c27dc9..34ad33b 100755 --- a/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java +++ b/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java @@ -218,7 +218,7 @@ public abstract class MidnightConfig { if (info.dataType == Identifier.class) { // avoid the crash due to Identifier syntax not legitimate Identifier id = Identifier.tryParse(s); if (id == null) return false; - info.setValue(Identifier.tryParse(s)); + info.setValue(id); } else info.setValue(isNumber ? value : s); } @@ -358,7 +358,7 @@ public abstract class MidnightConfig { if (info.function != null) { ClickableWidget widget; Entry e = info.entry; - if (info.function instanceof Map.Entry) { + if (info.function instanceof Map.Entry) { // Enums & booleans var values = (Map.Entry>) info.function; if (info.dataType.isEnum()) values.setValue(value -> Text.translatable(translationPrefix + "enum." + info.dataType.getSimpleName() + "." + info.value.toString())); From dcf0dbcaabae15e61335a36ed8eb0cb4f3081bc2 Mon Sep 17 00:00:00 2001 From: Martin Prokoph Date: Mon, 14 Apr 2025 17:47:11 +0200 Subject: [PATCH 05/12] fix: improve identifier crash fix Now uses Minecraft's built-in Identifier.validate function to check validity before applying changes --- .../midnightdust/lib/config/MidnightConfig.java | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java b/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java index 34ad33b..2f706a1 100755 --- a/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java +++ b/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java @@ -66,20 +66,18 @@ public abstract class MidnightConfig { this.entry = field.getAnnotation(Entry.class); this.comment = field.getAnnotation(Comment.class); this.conditions = field.getAnnotationsByType(Condition.class); - } else { - this.fieldName = ""; this.dataType = null; - } + } else { this.fieldName = ""; this.dataType = null; } if (entry != null && !entry.name().isEmpty()) this.name = Text.translatable(entry.name()); else if (comment != null && !comment.name().isEmpty()) this.name = Text.translatable(comment.name()); } public void setValue(Object value) { if (this.field.getType() != List.class) { this.value = value; - this.tempValue = value == null ? "" : value.toString(); // fix bug+: illegal Identifier cannot input character + this.tempValue = value.toString(); } else { writeList(this.listIndex, value); this.tempValue = toTemporaryValue(); } } public String toTemporaryValue() { - if (this.field.getType() != List.class) return this.value == null ? "" : this.value.toString(); // fix bug+: illegal Identifier cannot input character + if (this.field.getType() != List.class) return this.value.toString(); else try { return ((List) this.value).get(this.listIndex).toString(); } catch (Exception ignored) {return "";} } public void updateFieldValue() { @@ -197,7 +195,8 @@ public abstract class MidnightConfig { boolean isNumber = pattern != null; info.function = (BiFunction>) (t, b) -> s -> { s = s.trim(); - if (!(s.isEmpty() || !isNumber || pattern.matcher(s).matches())) return false; + if (!(s.isEmpty() || !isNumber || pattern.matcher(s).matches()) || + (info.dataType == Identifier.class && Identifier.validate(s).isError())) return false; Number value = 0; boolean inLimits = false; info.error = null; if (!(isNumber && s.isEmpty()) && !s.equals("-") && !s.equals(".")) { @@ -215,11 +214,7 @@ public abstract class MidnightConfig { b.active = entries.values().stream().allMatch(e -> e.inLimits); if (inLimits) { - if (info.dataType == Identifier.class) { // avoid the crash due to Identifier syntax not legitimate - Identifier id = Identifier.tryParse(s); - if (id == null) return false; - info.setValue(id); - } + if (info.dataType == Identifier.class) info.setValue(Identifier.tryParse(s)); else info.setValue(isNumber ? value : s); } From 3e6a72cda40bc66050afc3335a9cfafd9824a3c2 Mon Sep 17 00:00:00 2001 From: Martin Prokoph Date: Mon, 14 Apr 2025 17:49:02 +0200 Subject: [PATCH 06/12] feat: checkbox buttons next to boolean yes/no text buttons --- .../java/eu/midnightdust/lib/config/MidnightConfig.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java b/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java index 2f706a1..da71553 100755 --- a/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java +++ b/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java @@ -162,6 +162,9 @@ public abstract class MidnightConfig { else if (info.dataType == boolean.class) { Function func = value -> Text.translatable((Boolean) value ? "gui.yes" : "gui.no").formatted((Boolean) value ? Formatting.GREEN : Formatting.RED); info.function = new AbstractMap.SimpleEntry>(button -> { + if (info.actionButton instanceof CheckboxWidget checkbox && checkbox.isChecked() == (Boolean) info.value) { + checkbox.onPress(); return; + } info.setValue(!(Boolean) info.value); button.setMessage(func.apply(info.value)); }, func); } else if (info.dataType.isEnum()) { @@ -358,10 +361,10 @@ public abstract class MidnightConfig { if (info.dataType.isEnum()) values.setValue(value -> Text.translatable(translationPrefix + "enum." + info.dataType.getSimpleName() + "." + info.value.toString())); widget = ButtonWidget.builder(values.getValue().apply(info.value), values.getKey()).dimensions(width - 185, 0, 150, 20).tooltip(getTooltip(info, true)).build(); + if (info.dataType == boolean.class) info.actionButton = CheckboxWidget.builder(Text.empty(), textRenderer).callback((checkbox, checked) -> values.getKey().onPress((ButtonWidget) widget)).checked((Boolean) info.value).pos(widget.getX(), 1).build(); } else if (e.isSlider()) widget = new MidnightSliderWidget(width - 185, 0, 150, 20, Text.of(info.tempValue), (Double.parseDouble(info.tempValue) - e.min()) / (e.max() - e.min()), info); - else - widget = new TextFieldWidget(textRenderer, width - 185, 0, 150, 20, Text.empty()); + else widget = new TextFieldWidget(textRenderer, width - 185, 0, 150, 20, Text.empty()); if (widget instanceof TextFieldWidget textField) { textField.setMaxLength(e.width()); textField.setText(info.tempValue); Predicate processor = ((BiFunction>) info.function).apply(textField, done); @@ -471,7 +474,7 @@ public abstract class MidnightConfig { } } public void render(DrawContext context, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { - buttons.forEach(b -> { b.setY(y); b.render(context, mouseX, mouseY, tickDelta);}); + buttons.forEach(b -> { b.setY(y + (b instanceof CheckboxWidget ? 1 : 0)); b.render(context, mouseX, mouseY, tickDelta);}); if (title != null) { title.setY(y + 9); title.renderWidget(context, mouseX, mouseY, tickDelta); From 0297d91e703ebac235b95861b290ede23a5a1154 Mon Sep 17 00:00:00 2001 From: Martin Prokoph Date: Mon, 14 Apr 2025 18:02:56 +0200 Subject: [PATCH 07/12] feat: 'visibleButLocked' now applies for all buttons --- .../main/java/eu/midnightdust/lib/config/MidnightConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java b/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java index da71553..c689277 100755 --- a/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java +++ b/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java @@ -298,7 +298,7 @@ public abstract class MidnightConfig { if (entry.buttons.get(0) instanceof ClickableWidget widget) if (widget.isFocused() || widget.isHovered()) widget.setTooltip(getTooltip(entry.info, true)); if (entry.buttons.get(1) instanceof ButtonWidget button) - button.active = !Objects.equals(String.valueOf(entry.info.value), String.valueOf(entry.info.defaultValue)); + button.active = !Objects.equals(String.valueOf(entry.info.value), String.valueOf(entry.info.defaultValue)) && entry.info.conditionsMet; }}}} @Override public boolean keyPressed(int keyCode, int scanCode, int modifiers) { @@ -415,7 +415,6 @@ public abstract class MidnightConfig { explorerButton.setPosition(width - 185, 0); info.actionButton = explorerButton; } - if (!info.conditionsMet) widget.active = false; List widgets = Lists.newArrayList(widget, resetButton); if (info.actionButton != null) { if (IS_SYSTEM_MAC) info.actionButton.active = false; @@ -426,6 +425,7 @@ public abstract class MidnightConfig { widget.setWidth(widget.getWidth() - 22); widget.setX(widget.getX() + 22); widgets.add(cycleButton); } + if (!info.conditionsMet) widgets.forEach(w -> w.active = false); this.list.addButton(widgets, name, info); } else this.list.addButton(List.of(), name, info); } list.setScrollY(scrollProgress); From 5905eed58f5fd4ee79658c0a37b436dae7869afe Mon Sep 17 00:00:00 2001 From: Jaffe2718 Date: Fri, 18 Apr 2025 17:01:35 +0800 Subject: [PATCH 08/12] - feat: add clickable url for `@Comment` - chore: bump version `1.7.2-rc.2` --- .../lib/config/MidnightConfig.java | 29 +++++++++++++++++-- gradle.properties | 2 +- .../example/config/MidnightConfigExample.java | 4 ++- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java b/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java index c689277..f132d45 100755 --- a/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java +++ b/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java @@ -5,7 +5,9 @@ import com.google.gson.*; import com.google.gson.stream.*; import eu.midnightdust.lib.util.PlatformFunctions; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.Element; import net.minecraft.client.gui.Selectable; import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.Element; import net.minecraft.client.gui.Selectable; +import net.minecraft.client.gui.screen.ConfirmLinkScreen; +import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.tab.GridScreenTab; import net.minecraft.client.gui.tab.Tab; import net.minecraft.client.gui.tab.TabManager; import net.minecraft.client.gui.tooltip.Tooltip; import net.minecraft.client.gui.widget.*; import net.minecraft.client.render.RenderLayer; @@ -14,6 +16,7 @@ import net.minecraft.registry.Registries; import net.minecraft.screen.ScreenTexts; import net.minecraft.text.Style; import net.minecraft.text.Text; import net.minecraft.util.Formatting; import net.minecraft.util.Identifier; +import net.minecraft.util.Util; import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.filechooser.FileNameExtensionFilter; @@ -488,6 +491,20 @@ public abstract class MidnightConfig { } } } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + boolean result = super.mouseClicked(mouseX, mouseY, button); + if (this.info != null && this.info.comment != null && !this.info.comment.url().isBlank()) { + Screen parent = MinecraftClient.getInstance().currentScreen; + MinecraftClient.getInstance().setScreen(new ConfirmLinkScreen((confirm)->{ + if (confirm) Util.getOperatingSystem().open(this.info.comment.url()); + MinecraftClient.getInstance().setScreen(parent); + }, this.info.comment.url(), true)); + } + return result; + } + public List children() {return Lists.newArrayList(buttons);} public List selectableChildren() {return Lists.newArrayList(buttons);} } @@ -567,11 +584,19 @@ public abstract class MidnightConfig { */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Hidden {} + /** + * Comment Annotation
+ * - {@link Comment#centered()}: If the comment should be centered (default: false)
+ * - {@link Comment#category()}: The category of the comment in the config screen (default + * "default")
+ * - {@link Comment#name()}: The name of the comment in the config screen (default: "")
+ * - {@link Comment#url()}: The url of the comment in the config screen, empty or blank means no url (default: "")
+ * */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Comment { boolean centered() default false; String category() default "default"; String name() default ""; - @Deprecated String requiredMod() default ""; + String url() default ""; } /** * Condition Annotation
diff --git a/gradle.properties b/gradle.properties index b847844..fcb7bd9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ yarn_mappings=1.21.4+build.1 enabled_platforms=fabric,neoforge archives_base_name=midnightlib -mod_version=1.7.2-rc.1 +mod_version=1.7.2-rc.2 maven_group=eu.midnightdust release_type=release curseforge_id=488090 diff --git a/test-fabric/src/main/java/eu/midnightdust/fabric/example/config/MidnightConfigExample.java b/test-fabric/src/main/java/eu/midnightdust/fabric/example/config/MidnightConfigExample.java index 512f7a3..3ffa54d 100644 --- a/test-fabric/src/main/java/eu/midnightdust/fabric/example/config/MidnightConfigExample.java +++ b/test-fabric/src/main/java/eu/midnightdust/fabric/example/config/MidnightConfigExample.java @@ -10,7 +10,7 @@ import java.util.List; /** Every option in a MidnightConfig class has to be public and static, so we can access it from other classes. * The config class also has to extend MidnightConfig*/ -@SuppressWarnings("unused") +@SuppressWarnings({"unused", "DefaultAnnotationParam"}) public class MidnightConfigExample extends MidnightConfig { public static final String TEXT = "text"; public static final String NUMBERS = "numbers"; @@ -31,6 +31,8 @@ public class MidnightConfigExample extends MidnightConfig { public enum ModPlatform { // Enums allow the user to cycle through predefined options QUILT, FABRIC, FORGE, NEOFORGE, VANILLA } + @Comment(category = TEXT, name = "§nMidnightLib Wiki", centered = true, url = "https://www.midnightdust.eu/wiki/midnightlib/") public static Comment wiki; // Example for a comment with a url + @Entry(category = NUMBERS) public static int fabric = 16777215; // Example for an int option @Entry(category = NUMBERS) public static double world = 1.4D; // Example for a double option @Entry(category = NUMBERS, min=69,max=420) public static int hello = 420; // - The entered number has to be larger than 69 and smaller than 420 From e58c7fc0fdc527d24818211f9c5170f98437774a Mon Sep 17 00:00:00 2001 From: Martin Prokoph Date: Fri, 18 Apr 2025 12:37:46 +0200 Subject: [PATCH 09/12] feat: improve URL handling - Uses the `open` method of `ConfirmLinkScreen` instead of manually instantiating it - Also re-add the `requiredMod` field for `@Comment` to prevent mods that haven't adjusted yet from outright crashing --- .../eu/midnightdust/lib/config/MidnightConfig.java | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java b/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java index f132d45..588b1dd 100755 --- a/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java +++ b/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java @@ -494,15 +494,9 @@ public abstract class MidnightConfig { @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { - boolean result = super.mouseClicked(mouseX, mouseY, button); - if (this.info != null && this.info.comment != null && !this.info.comment.url().isBlank()) { - Screen parent = MinecraftClient.getInstance().currentScreen; - MinecraftClient.getInstance().setScreen(new ConfirmLinkScreen((confirm)->{ - if (confirm) Util.getOperatingSystem().open(this.info.comment.url()); - MinecraftClient.getInstance().setScreen(parent); - }, this.info.comment.url(), true)); - } - return result; + if (this.info != null && this.info.comment != null && !this.info.comment.url().isBlank()) + ConfirmLinkScreen.open(MinecraftClient.getInstance().currentScreen, this.info.comment.url(), true); + return super.mouseClicked(mouseX, mouseY, button); } public List children() {return Lists.newArrayList(buttons);} @@ -597,6 +591,7 @@ public abstract class MidnightConfig { String category() default "default"; String name() default ""; String url() default ""; + @Deprecated String requiredMod() default ""; } /** * Condition Annotation
From 82889b8c061ae6debb21d46506feba1d1ef09482 Mon Sep 17 00:00:00 2001 From: Martin Prokoph Date: Mon, 21 Apr 2025 10:43:40 +0200 Subject: [PATCH 10/12] docs: improve JavaDocs --- .../eu/midnightdust/lib/config/MidnightConfig.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java b/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java index 588b1dd..355e2b8 100755 --- a/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java +++ b/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java @@ -530,7 +530,7 @@ public abstract class MidnightConfig { * - width: The maximum character length of the {@link String}, {@link Identifier} or String/Identifier {@link List<>} field
* - min: The minimum value of the int, float or double field
* - max: The maximum value of the int, float or double field
- * - name: The name of the field in the config screen
+ * - name: Will be used instead of the default translation key, if not empty
* - selectionMode: The selection mode of the file picker button for {@link String} fields, * -1 for none, {@link JFileChooser#FILES_ONLY} for files, {@link JFileChooser#DIRECTORIES_ONLY} for directories, * {@link JFileChooser#FILES_AND_DIRECTORIES} for both (default: -1). Remember to set the translation key @@ -580,11 +580,10 @@ public abstract class MidnightConfig { /** * Comment Annotation
- * - {@link Comment#centered()}: If the comment should be centered (default: false)
- * - {@link Comment#category()}: The category of the comment in the config screen (default - * "default")
- * - {@link Comment#name()}: The name of the comment in the config screen (default: "")
- * - {@link Comment#url()}: The url of the comment in the config screen, empty or blank means no url (default: "")
+ * - {@link Comment#centered()}: If the comment should be centered
+ * - {@link Comment#category()}: The category of the comment in the config screen
+ * - {@link Comment#name()}: Will be used instead of the default translation key, if not empty
+ * - {@link Comment#url()}: The url of the comment should link to in the config screen (none if left empty)
* */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Comment { boolean centered() default false; From 06ef4fdcf77c6a4c02fc6b134a1108d4e4d029ff Mon Sep 17 00:00:00 2001 From: Martin Prokoph Date: Mon, 21 Apr 2025 10:45:02 +0200 Subject: [PATCH 11/12] clean: remove unused import --- .../main/java/eu/midnightdust/lib/config/MidnightConfig.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java b/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java index 355e2b8..3832f0e 100755 --- a/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java +++ b/common/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java @@ -6,8 +6,7 @@ import eu.midnightdust.lib.util.PlatformFunctions; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.Element; import net.minecraft.client.gui.Selectable; -import net.minecraft.client.gui.screen.ConfirmLinkScreen; -import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.ConfirmLinkScreen; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.tab.GridScreenTab; import net.minecraft.client.gui.tab.Tab; import net.minecraft.client.gui.tab.TabManager; import net.minecraft.client.gui.tooltip.Tooltip; import net.minecraft.client.gui.widget.*; import net.minecraft.client.render.RenderLayer; @@ -16,7 +15,6 @@ import net.minecraft.registry.Registries; import net.minecraft.screen.ScreenTexts; import net.minecraft.text.Style; import net.minecraft.text.Text; import net.minecraft.util.Formatting; import net.minecraft.util.Identifier; -import net.minecraft.util.Util; import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.filechooser.FileNameExtensionFilter; From 356064b052f51fd409d5e9f9f9fe459f0b873f48 Mon Sep 17 00:00:00 2001 From: Martin Prokoph Date: Mon, 21 Apr 2025 10:46:02 +0200 Subject: [PATCH 12/12] chore: bump version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index fcb7bd9..13e4aee 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ yarn_mappings=1.21.4+build.1 enabled_platforms=fabric,neoforge archives_base_name=midnightlib -mod_version=1.7.2-rc.2 +mod_version=1.7.2 maven_group=eu.midnightdust release_type=release curseforge_id=488090