From aa840a6c0dc9d977b576d0438e748b1aba0d44a1 Mon Sep 17 00:00:00 2001 From: Frederik van der Els Date: Sun, 15 Jun 2025 15:44:14 +0200 Subject: [PATCH 1/2] Change type of comments to Components + add API methods for default values and comments --- .../dev/xpple/betterconfig/api/Config.java | 12 +++++-- .../dev/xpple/betterconfig/api/ModConfig.java | 17 ++++++++++ .../command/AbstractConfigCommand.java | 7 ++-- .../impl/BetterConfigInternals.java | 33 +++++++++++++++++-- .../betterconfig/impl/ModConfigImpl.java | 22 +++++++++++-- .../command/client/ConfigCommandClient.java | 4 +-- .../betterconfig/command/ConfigCommand.java | 4 +-- .../java/dev/xpple/betterconfig/Configs.java | 6 +++- .../betterconfig/command/ConfigCommand.java | 4 +-- .../java/dev/xpple/betterconfig/Configs.java | 7 +++- 10 files changed, 98 insertions(+), 18 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 b9afd4b..cd8702c 100644 --- a/common/src/main/java/dev/xpple/betterconfig/api/Config.java +++ b/common/src/main/java/dev/xpple/betterconfig/api/Config.java @@ -82,8 +82,16 @@ @Retention(RetentionPolicy.RUNTIME) public @interface Config { /** - * An explanatory comment about the config. This value will be used in the {@code comment} subcommand of the config command. - * @return the comment + * A method name that will be used to display an explanatory comment about the config. The method should have no parameters + * and return the chat component type: {@link net.minecraft.network.chat.Component} on Fabric and {@link net.kyori.adventure.text.Component} + * on Paper. This value will be used in the {@code comment} subcommand of the config command. Below is an example for Fabric: + * {@snippet lang = java: + * @Config(comment = "comment") + * public static Component comment() { + * return Component.literal("This should be helpful!"); + * } + * } + * @return the method name */ String comment() default ""; 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 e7d3ef3..7bb353c 100644 --- a/common/src/main/java/dev/xpple/betterconfig/api/ModConfig.java +++ b/common/src/main/java/dev/xpple/betterconfig/api/ModConfig.java @@ -27,6 +27,23 @@ public interface ModConfig

{ */ Path getConfigsPath(); + /** + * Get the default (initial) value for a config. Note that the returned value is a + * deep copy of the config's default value. + * @param config the config's key + * @return (a deep copy of) the default value + * @throws IllegalArgumentException when there is no config associated to this key + */ + Object getDefault(String config); + + /** + * Get the comment for a config. + * @param config the config's key + * @return the config comment + * @throws IllegalArgumentException when there is no config associated to this key + */ + P getComment(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 c7c453a..912fe3f 100644 --- a/common/src/main/java/dev/xpple/betterconfig/command/AbstractConfigCommand.java +++ b/common/src/main/java/dev/xpple/betterconfig/command/AbstractConfigCommand.java @@ -13,6 +13,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.function.Predicate; +import java.util.function.Supplier; import static com.mojang.brigadier.arguments.StringArgumentType.*; @@ -38,9 +39,9 @@ protected final LiteralArgumentBuilder create(Collectionliteral("reset").executes(ctx -> reset(ctx.getSource(), modConfig, config))); } - String comment = modConfig.getComments().get(config); + Supplier

comment = modConfig.getComments().get(config); if (comment != null) { - configLiteral.then(LiteralArgumentBuilder.literal("comment").executes(ctx -> comment(ctx.getSource(), config, comment))); + configLiteral.then(LiteralArgumentBuilder.literal("comment").executes(ctx -> comment(ctx.getSource(), config, comment.get()))); } if (modConfig.getSetters().containsKey(config)) { @@ -148,7 +149,7 @@ protected final LiteralArgumentBuilder create(Collection modConfig, String 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 30f3d2d..8599aa8 100644 --- a/common/src/main/java/dev/xpple/betterconfig/impl/BetterConfigInternals.java +++ b/common/src/main/java/dev/xpple/betterconfig/impl/BetterConfigInternals.java @@ -58,9 +58,7 @@ public static void init(ModConfigImpl modConfig) { throw new AssertionError(e); } - if (!annotation.comment().isEmpty()) { - modConfig.getComments().put(fieldName, annotation.comment()); - } + initComment(modConfig, annotation.comment(), fieldName); if (!annotation.temporary()) { try { @@ -107,6 +105,35 @@ public static void init(ModConfigImpl modConfig) { } } + private static void initComment(ModConfigImpl modConfig, String commentMethodName, String fieldName) { + if (commentMethodName.isEmpty()) { + return; + } + Method commentMethod; + try { + commentMethod = modConfig.getConfigsClass().getDeclaredMethod(commentMethodName); + } catch (ReflectiveOperationException e) { + throw new AssertionError(e); + } + Class componentClass = Platform.current.getComponentClass(); + if (commentMethod.getReturnType() != componentClass) { + throw new AssertionError("Comment method '" + commentMethodName + "' does not return Component"); + } + if (!Modifier.isStatic(commentMethod.getModifiers())) { + throw new AssertionError("Comment method '" + commentMethodName + "' is not static"); + } + commentMethod.setAccessible(true); + + //noinspection rawtypes, unchecked + modConfig.getComments().put(fieldName, (Supplier) () -> { + try { + return commentMethod.invoke(null); + } catch (ReflectiveOperationException e) { + throw new AssertionError(e); + } + }); + } + private static void initChatRepresentation(ModConfigImpl modConfig, Field field, String chatRepresentationMethodName) { if (chatRepresentationMethodName.isEmpty()) { return; 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 9619c64..59f99ab 100644 --- a/common/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java +++ b/common/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java @@ -52,7 +52,7 @@ public class ModConfigImpl implements ModConfig

{ private final Map configs = new HashMap<>(); private final Map annotations = new HashMap<>(); private final Map defaults = new HashMap<>(); - private final Map comments = new HashMap<>(); + private final Map> comments = new HashMap<>(); private final Map> conditions = new HashMap<>(); private final Map> chatRepresentations = new HashMap<>(); private final Map> setters = new HashMap<>(); @@ -105,7 +105,7 @@ Map getDefaults() { return this.defaults; } - public Map getComments() { + public Map> getComments() { return this.comments; } @@ -151,6 +151,24 @@ public Path getConfigsPath() { return Platform.current.getConfigsPath(this.modId); } + @Override + public Object getDefault(String config) { + Field field = this.configs.get(config); + if (field == null) { + throw new IllegalArgumentException(); + } + return this.deepCopy(this.defaults.get(config), field.getGenericType()); + } + + @Override + public P getComment(String config) { + Supplier

comment = this.comments.get(config); + if (comment == null) { + throw new IllegalArgumentException(); + } + return comment.get(); + } + @Override public Object get(String config) { Field field = this.configs.get(config); diff --git a/fabric/src/client/java/dev/xpple/betterconfig/command/client/ConfigCommandClient.java b/fabric/src/client/java/dev/xpple/betterconfig/command/client/ConfigCommandClient.java index d49c047..1a35d4a 100644 --- a/fabric/src/client/java/dev/xpple/betterconfig/command/client/ConfigCommandClient.java +++ b/fabric/src/client/java/dev/xpple/betterconfig/command/client/ConfigCommandClient.java @@ -22,9 +22,9 @@ public static void register(CommandDispatcher dispatc } @Override - protected int comment(FabricClientCommandSource source, String config, String comment) { + protected int comment(FabricClientCommandSource source, String config, Component comment) { source.sendFeedback(Component.translatable("betterconfig.commands.config.comment", config)); - source.sendFeedback(Component.literal(comment)); + source.sendFeedback(comment); return Command.SINGLE_SUCCESS; } diff --git a/fabric/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java b/fabric/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java index f1d2080..cddd644 100644 --- a/fabric/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java +++ b/fabric/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java @@ -21,9 +21,9 @@ public static void register(CommandDispatcher dispatcher, Co } @Override - protected int comment(CommandSourceStack source, String config, String comment) { + protected int comment(CommandSourceStack source, String config, Component comment) { source.sendSuccess(() -> Component.translatableWithFallback("betterconfig.commands.config.comment", "Comment for %s:", config), false); - source.sendSuccess(() -> Component.literal(comment), false); + source.sendSuccess(() -> comment, false); return Command.SINGLE_SUCCESS; } diff --git a/fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java b/fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java index a9a01b6..28aa20b 100644 --- a/fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java +++ b/fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java @@ -2,6 +2,7 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import dev.xpple.betterconfig.api.Config; +import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.SharedSuggestionProvider; @@ -83,8 +84,11 @@ private static void privateSetter(String string) { examplePrivateSetter = string + '!'; } - @Config(comment = "This is a mysterious object") + @Config(comment = "comment") public static Object exampleComment = null; + private static Component comment() { + return Component.literal("This is a mysterious object").withStyle(ChatFormatting.OBFUSCATED); + } @Config public static BlockInput exampleRegistryAccess = new BlockInput(Blocks.COMPOSTER.defaultBlockState(), Collections.emptySet(), null); diff --git a/paper/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java b/paper/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java index 0971152..570568f 100644 --- a/paper/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java +++ b/paper/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java @@ -21,9 +21,9 @@ public static LiteralCommandNode build() { } @Override - protected int comment(CommandSourceStack source, String config, String comment) { + protected int comment(CommandSourceStack source, String config, Component comment) { source.getSender().sendMessage(Component.translatable("betterconfig.commands.config.comment", "Comment for %s:", Component.text(config))); - source.getSender().sendMessage(Component.text(comment)); + source.getSender().sendMessage(comment); return Command.SINGLE_SUCCESS; } diff --git a/paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java b/paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java index a3f99bd..72b2c55 100644 --- a/paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java +++ b/paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java @@ -5,6 +5,8 @@ import io.papermc.paper.command.brigadier.CommandSourceStack; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.JoinConfiguration; +import net.kyori.adventure.text.format.Style; +import net.kyori.adventure.text.format.TextDecoration; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.block.BlockState; @@ -80,8 +82,11 @@ private static void privateSetter(String string) { examplePrivateSetter = string + '!'; } - @Config(comment = "This is a mysterious object") + @Config(comment = "comment") public static Object exampleComment = null; + private static Component comment() { + return Component.text("This is a mysterious object").style(Style.style(TextDecoration.OBFUSCATED)); + } @Config public static BlockState exampleNativeArgumentType = Material.COMPOSTER.createBlockData().createBlockState(); From cb9e8003d3e4aa1ae1251b744185b0c5ea7f1a9a Mon Sep 17 00:00:00 2001 From: Frederik van der Els Date: Sun, 15 Jun 2025 15:56:10 +0200 Subject: [PATCH 2/2] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5a5e9e3..e853293 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ field should not be final. Mark this field with the annotation `@Config`. The in default (fallback) value. You can add a comment by setting the `comment` attribute. ```java public class Configs { - @Config(comment = "This is an example!") + @Config public static String exampleString = "default"; } ```