From 522df4551440af8482280286817444976d2205f6 Mon Sep 17 00:00:00 2001 From: Frederik van der Els Date: Wed, 30 Sep 2026 01:10:24 +0200 Subject: [PATCH] [WIP] Add the ability to add custom names to configs --- .../dev/xpple/betterconfig/api/Config.java | 17 +++++++++++++++ .../dev/xpple/betterconfig/api/ModConfig.java | 11 ++++++++-- .../command/AbstractConfigCommand.java | 4 +++- .../impl/BetterConfigInternals.java | 15 ++++++++++--- .../betterconfig/impl/ModConfigImpl.java | 21 +++++++++++++++++-- fabric/build.gradle | 5 +++++ .../java/dev/xpple/betterconfig/Configs.java | 3 +++ gradle.properties | 8 +++---- .../java/dev/xpple/betterconfig/Configs.java | 3 +++ 9 files changed, 75 insertions(+), 12 deletions(-) diff --git a/common/src/main/java/dev/xpple/betterconfig/api/Config.java b/common/src/main/java/dev/xpple/betterconfig/api/Config.java index cd8702c..fcac79a 100644 --- a/common/src/main/java/dev/xpple/betterconfig/api/Config.java +++ b/common/src/main/java/dev/xpple/betterconfig/api/Config.java @@ -95,6 +95,23 @@ */ String comment() default ""; + // TODO the command suggestions do not work as described + /// A custom name that will be used as command literal in place of the name of the config field. This essentially configures + /// a custom user-facing name, without having to change the name of the config field. This is particularly useful because of + /// the way command suggestions work in Minecraft. When a suggested string contains any of `._/`, the string will be split + /// up at those characters. Each part of the string is then matched individually to the input string. If any of them match, + /// the entire string will be suggested. Below is an example: + /// {@snippet lang = java: + /// @Config(customName = "custom_name") + /// public static String customName = ""; + /// } + /// Without the custom name, the config will only be suggested when typing `c`. With the custom name, the config will also be + /// suggested when typing `n`. + /// + /// The caller has to verify themselves that the custom name is a valid command literal, and that it is unique. + /// @return the custom name + String customName() default ""; + /** * A method name that will be used to represent the config value in the chat. The method should have no parameters and return * a chat {@code Component}, which is {@link net.minecraft.network.chat.Component} on Fabric and {@link net.kyori.adventure.text.Component} diff --git a/common/src/main/java/dev/xpple/betterconfig/api/ModConfig.java b/common/src/main/java/dev/xpple/betterconfig/api/ModConfig.java index afbee6d..7ba3048 100644 --- a/common/src/main/java/dev/xpple/betterconfig/api/ModConfig.java +++ b/common/src/main/java/dev/xpple/betterconfig/api/ModConfig.java @@ -1,6 +1,7 @@ package dev.xpple.betterconfig.api; import com.mojang.brigadier.exceptions.CommandSyntaxException; +import org.jspecify.annotations.Nullable; import java.nio.file.Path; import java.util.Set; @@ -33,9 +34,15 @@ public interface ModConfig

{ /// Get the comment for a config. /// @param config the config's key - /// @return the config comment + /// @return the config comment or `null` if none has been configured /// @throws IllegalArgumentException when there is no config associated to this key - P getComment(String config); + @Nullable P getComment(String config); + + /// Get the custom name for a config. + /// @param config the config's key + /// @return the custom name or `null` if none has been configured + /// @throws IllegalArgumentException when there is no config associated to this key + @Nullable String getCustomName(String config); /// Get a config value based on the key. /// @param config the config's key diff --git a/common/src/main/java/dev/xpple/betterconfig/command/AbstractConfigCommand.java b/common/src/main/java/dev/xpple/betterconfig/command/AbstractConfigCommand.java index 912fe3f..86feb4f 100644 --- a/common/src/main/java/dev/xpple/betterconfig/command/AbstractConfigCommand.java +++ b/common/src/main/java/dev/xpple/betterconfig/command/AbstractConfigCommand.java @@ -30,8 +30,10 @@ protected final LiteralArgumentBuilder create(Collection modConfig : modConfigs) { LiteralArgumentBuilder identifierLiteral = LiteralArgumentBuilder.literal(modConfig.getModId()); for (String config : modConfig.getConfigs().keySet()) { + String customName = modConfig.getCustomNames().get(config); + String commandLiteral = customName != null ? customName : config; Predicate condition = modConfig.getConditions().get(config); - LiteralArgumentBuilder configLiteral = LiteralArgumentBuilder.literal(config).requires(condition); + LiteralArgumentBuilder configLiteral = LiteralArgumentBuilder.literal(commandLiteral).requires(condition); configLiteral.then(LiteralArgumentBuilder.literal("get").executes(ctx -> get(ctx.getSource(), modConfig, config))); Config annotation = modConfig.getAnnotations().get(config); diff --git a/common/src/main/java/dev/xpple/betterconfig/impl/BetterConfigInternals.java b/common/src/main/java/dev/xpple/betterconfig/impl/BetterConfigInternals.java index 8599aa8..0d1df87 100644 --- a/common/src/main/java/dev/xpple/betterconfig/impl/BetterConfigInternals.java +++ b/common/src/main/java/dev/xpple/betterconfig/impl/BetterConfigInternals.java @@ -76,6 +76,8 @@ public static void init(ModConfigImpl modConfig) { } } + initCustomName(modConfig, annotation.customName(), fieldName); + initCondition(modConfig, annotation.condition(), fieldName); initChatRepresentation(modConfig, field, annotation.chatRepresentation()); @@ -163,9 +165,16 @@ private static void initChatRepresentation(ModConfigImpl modConfig, Fie }); } + private static void initCustomName(ModConfigImpl modConfig, String customName, String fieldName) { + if (customName.isEmpty()) { + return; + } + modConfig.getCustomNames().put(fieldName, customName); + } + private static void initCondition(ModConfigImpl modConfig, String condition, String fieldName) { if (condition.isEmpty()) { - modConfig.getConditions().put(fieldName, source -> true); + modConfig.getConditions().put(fieldName, _ -> true); return; } Method predicateMethod; @@ -200,7 +209,7 @@ private static void initCondition(ModConfigImpl modConfig, String condi } }); } else { - modConfig.getConditions().put(fieldName, source -> { + modConfig.getConditions().put(fieldName, _ -> { try { return (Boolean) predicateMethod_f.invoke(null); } catch (ReflectiveOperationException e) { @@ -212,7 +221,7 @@ private static void initCondition(ModConfigImpl modConfig, String condi private static BiConsumer initOnChange(ModConfigImpl modConfig, Field field, String onChangeMethodName) { if (onChangeMethodName.isEmpty()) { - BiConsumer onChange = (oldValue, newValue) -> {}; + BiConsumer onChange = (_, _) -> {}; modConfig.getOnChangeCallbacks().put(field.getName(), onChange); return onChange; } diff --git a/common/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java b/common/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java index ddcdd22..f902058 100644 --- a/common/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java +++ b/common/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java @@ -17,6 +17,7 @@ import dev.xpple.betterconfig.api.ModConfig; import dev.xpple.betterconfig.util.CheckedBiConsumer; import dev.xpple.betterconfig.util.CheckedConsumer; +import org.jspecify.annotations.Nullable; import java.io.BufferedWriter; import java.io.IOException; @@ -53,6 +54,7 @@ public class ModConfigImpl implements ModConfig

{ private final Map configs = new HashMap<>(); private final Map annotations = new HashMap<>(); + private final Map customNames = new HashMap<>(); private final Map defaults = new HashMap<>(); private final Map> comments = new HashMap<>(); private final Map> conditions = new HashMap<>(); @@ -105,6 +107,10 @@ public Map getAnnotations() { return this.annotations; } + public Map getCustomNames() { + return this.customNames; + } + Map getDefaults() { return this.defaults; } @@ -170,14 +176,25 @@ public Object getDefault(String config) { } @Override - public P getComment(String config) { + public @Nullable P getComment(String config) { + if (!this.configs.containsKey(config)) { + throw new IllegalArgumentException(); + } Supplier

comment = this.comments.get(config); if (comment == null) { - throw new IllegalArgumentException(); + return null; } return comment.get(); } + @Override + public @Nullable String getCustomName(String config) { + if (!this.configs.containsKey(config)) { + throw new IllegalArgumentException(); + } + return this.customNames.get(config); + } + @Override public Object get(String config) { Field field = this.configs.get(config); diff --git a/fabric/build.gradle b/fabric/build.gradle index 63f3771..c88c9cd 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -14,6 +14,11 @@ loom { splitEnvironmentSourceSets() } +loom.runs.configureEach { + jvmArguments.add("-enableassertions") + systemProperties.put("fabric.loom.suppressNarratorError", "true") +} + sourceSets { testmod { compileClasspath += main.compileClasspath diff --git a/fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java b/fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java index 28aa20b..563b848 100644 --- a/fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java +++ b/fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java @@ -118,4 +118,7 @@ private static Component customChatRepresentation() { private static boolean isClient(SharedSuggestionProvider source) { return !(source instanceof CommandSourceStack); } + + @Config(customName = "example_custom_name") + public static String exampleCustomName = ""; } diff --git a/gradle.properties b/gradle.properties index 0ab4aba..ea845cd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,17 +8,17 @@ maven_group=dev.xpple archives_base_name=betterconfig # Minecraft properties -minecraft_version=26.3-rc-1 +minecraft_version=26.3 minecraft_dependency=>=26.3-rc.1 <26.4 # Fabric Properties # check these on https://fabricmc.net/develop -fabric_api_version=0.160.3+26.3 +fabric_api_version=0.161.0+26.3 fabric_loader_version=0.19.5 -fabric_loom_version=1.17-SNAPSHOT +fabric_loom_version=1.18-SNAPSHOT devauth_version=1.2.2 # Paper Properties -paper_api_version=26.3-pre-2.build.0-alpha +paper_api_version=26.3.build.49-alpha plugin_yml_paper_api_version=26.3 diff --git a/paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java b/paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java index 72b2c55..1bc21e4 100644 --- a/paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java +++ b/paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java @@ -113,4 +113,7 @@ private static Component customChatRepresentation() { }) .toList())); } + + @Config(customName = "example_custom_name") + public static String exampleCustomName = ""; }