From 0e148556efd6cc28b08873240fa4d9f657f1f2a5 Mon Sep 17 00:00:00 2001 From: xpple Date: Tue, 18 Jul 2023 23:51:05 +0200 Subject: [PATCH 01/28] [TODO] Paper support --- README.md | 4 +- build.gradle | 132 ---------------- common/build.gradle | 34 ++++ .../betterconfig/BetterConfigCommon.java | 11 ++ .../betterconfig/api/AbstractConfig.java | 8 +- .../api/AbstractConfigBuilder.java | 41 ++--- .../dev/xpple/betterconfig/api/Config.java | 0 .../command/ConfigCommandHelper.java | 121 +++++++-------- .../betterconfig/command/package-info.java | 4 + .../AbstractEnumSuggestionProvider.java | 12 ++ .../command/suggestion/package-info.java | 4 + .../betterconfig/impl/AbstractConfigImpl.java | 65 ++++---- .../impl/BetterConfigInternals.java | 87 ++++++----- .../xpple/betterconfig/impl/package-info.java | 0 .../betterconfig/util/CheckedBiConsumer.java | 0 .../betterconfig/util/CheckedBiFunction.java | 0 .../betterconfig/util/CheckedConsumer.java | 0 .../betterconfig/util/CheckedFunction.java | 0 fabric/build.gradle | 146 ++++++++++++++++++ .../betterconfig/BetterConfigClient.java | 0 .../command/client/ConfigCommandClient.java | 72 +++++++++ .../resources/betterconfig.mixins.client.json | 0 .../dev/xpple/betterconfig/BetterConfig.java | 5 - .../betterconfig/api/BetterConfigAPI.java | 0 .../dev/xpple/betterconfig/api/ModConfig.java | 9 ++ .../betterconfig/api/ModConfigBuilder.java | 26 ++++ .../betterconfig/command/ConfigCommand.java | 71 +++++++++ .../suggestion/EnumSuggestionProvider.java | 9 +- .../betterconfig/impl/BetterConfigImpl.java | 4 +- .../betterconfig/impl/ModConfigImpl.java | 36 +++++ .../resources/assets/betterconfig/icon.png | Bin .../assets/betterconfig/lang/en_us.json | 0 .../assets/betterconfig/lang/fr_fr.json | 0 .../main/resources/betterconfig.mixins.json | 0 .../src}/main/resources/fabric.mod.json | 4 +- .../dev/xpple/betterconfig/BlockAdapter.java | 0 .../xpple/betterconfig/BlockArgumentType.java | 0 .../betterconfig/BlockSuggestionProvider.java | 0 .../java/dev/xpple/betterconfig/Configs.java | 0 .../java/dev/xpple/betterconfig/TestEnum.java | 0 .../java/dev/xpple/betterconfig/TestMod.java | 6 +- .../dev/xpple/betterconfig/TestModClient.java | 4 +- .../src}/testmod/resources/fabric.mod.json | 0 gradle.properties | 19 ++- gradle/wrapper/gradle-wrapper.jar | Bin 61574 -> 63375 bytes gradle/wrapper/gradle-wrapper.properties | 1 + gradlew | 16 +- paper/build.gradle | 94 +++++++++++ .../dev/xpple/betterconfig/BetterConfig.java | 25 +++ .../betterconfig/api/BetterConfigAPI.java | 17 ++ .../xpple/betterconfig/api/PluginConfig.java | 9 ++ .../betterconfig/api/PluginConfigBuilder.java | 26 ++++ .../betterconfig/command/ConfigCommand.java | 78 ++++++++++ .../suggestion/EnumSuggestionProvider.java | 39 +++++ .../betterconfig/impl/BetterConfigImpl.java | 27 ++++ .../betterconfig/impl/PluginConfigImpl.java | 36 +++++ paper/src/main/resources/plugin.yml | 23 +++ settings.gradle | 7 +- .../command/client/ConfigCommandClient.java | 56 ------- .../betterconfig/command/ConfigCommand.java | 55 ------- 60 files changed, 986 insertions(+), 457 deletions(-) delete mode 100644 build.gradle create mode 100644 common/build.gradle create mode 100644 common/src/main/java/dev/xpple/betterconfig/BetterConfigCommon.java rename src/main/java/dev/xpple/betterconfig/api/ModConfig.java => common/src/main/java/dev/xpple/betterconfig/api/AbstractConfig.java (94%) rename src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java => common/src/main/java/dev/xpple/betterconfig/api/AbstractConfigBuilder.java (55%) rename {src => common/src}/main/java/dev/xpple/betterconfig/api/Config.java (100%) rename {src => common/src}/main/java/dev/xpple/betterconfig/command/ConfigCommandHelper.java (60%) create mode 100644 common/src/main/java/dev/xpple/betterconfig/command/package-info.java create mode 100644 common/src/main/java/dev/xpple/betterconfig/command/suggestion/AbstractEnumSuggestionProvider.java create mode 100644 common/src/main/java/dev/xpple/betterconfig/command/suggestion/package-info.java rename src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java => common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java (62%) rename {src => common/src}/main/java/dev/xpple/betterconfig/impl/BetterConfigInternals.java (76%) rename {src => common/src}/main/java/dev/xpple/betterconfig/impl/package-info.java (100%) rename {src => common/src}/main/java/dev/xpple/betterconfig/util/CheckedBiConsumer.java (100%) rename {src => common/src}/main/java/dev/xpple/betterconfig/util/CheckedBiFunction.java (100%) rename {src => common/src}/main/java/dev/xpple/betterconfig/util/CheckedConsumer.java (100%) rename {src => common/src}/main/java/dev/xpple/betterconfig/util/CheckedFunction.java (100%) create mode 100644 fabric/build.gradle rename {src => fabric/src}/client/java/dev/xpple/betterconfig/BetterConfigClient.java (100%) create mode 100644 fabric/src/client/java/dev/xpple/betterconfig/command/client/ConfigCommandClient.java rename {src => fabric/src}/client/resources/betterconfig.mixins.client.json (100%) rename {src => fabric/src}/main/java/dev/xpple/betterconfig/BetterConfig.java (83%) rename {src => fabric/src}/main/java/dev/xpple/betterconfig/api/BetterConfigAPI.java (100%) create mode 100644 fabric/src/main/java/dev/xpple/betterconfig/api/ModConfig.java create mode 100644 fabric/src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java create mode 100644 fabric/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java rename {src => fabric/src}/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java (66%) rename {src => fabric/src}/main/java/dev/xpple/betterconfig/impl/BetterConfigImpl.java (80%) create mode 100644 fabric/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java rename {src => fabric/src}/main/resources/assets/betterconfig/icon.png (100%) rename {src => fabric/src}/main/resources/assets/betterconfig/lang/en_us.json (100%) rename {src => fabric/src}/main/resources/assets/betterconfig/lang/fr_fr.json (100%) rename {src => fabric/src}/main/resources/betterconfig.mixins.json (100%) rename {src => fabric/src}/main/resources/fabric.mod.json (91%) rename {src => fabric/src}/testmod/java/dev/xpple/betterconfig/BlockAdapter.java (100%) rename {src => fabric/src}/testmod/java/dev/xpple/betterconfig/BlockArgumentType.java (100%) rename {src => fabric/src}/testmod/java/dev/xpple/betterconfig/BlockSuggestionProvider.java (100%) rename {src => fabric/src}/testmod/java/dev/xpple/betterconfig/Configs.java (100%) rename {src => fabric/src}/testmod/java/dev/xpple/betterconfig/TestEnum.java (100%) rename {src => fabric/src}/testmod/java/dev/xpple/betterconfig/TestMod.java (84%) rename {src => fabric/src}/testmod/java/dev/xpple/betterconfig/TestModClient.java (77%) rename {src => fabric/src}/testmod/resources/fabric.mod.json (100%) create mode 100644 paper/build.gradle create mode 100644 paper/src/main/java/dev/xpple/betterconfig/BetterConfig.java create mode 100644 paper/src/main/java/dev/xpple/betterconfig/api/BetterConfigAPI.java create mode 100644 paper/src/main/java/dev/xpple/betterconfig/api/PluginConfig.java create mode 100644 paper/src/main/java/dev/xpple/betterconfig/api/PluginConfigBuilder.java create mode 100644 paper/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java create mode 100644 paper/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java create mode 100644 paper/src/main/java/dev/xpple/betterconfig/impl/BetterConfigImpl.java create mode 100644 paper/src/main/java/dev/xpple/betterconfig/impl/PluginConfigImpl.java create mode 100644 paper/src/main/resources/plugin.yml delete mode 100644 src/client/java/dev/xpple/betterconfig/command/client/ConfigCommandClient.java delete mode 100644 src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java diff --git a/README.md b/README.md index d55ecc7..745a790 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ new ModConfigBuilder(, Configs.class) .build(); ``` where `BlockAdapter` extends `TypeAdapter` and `BlockArgumentType` implements `ArgumentType`. See -[these tests](src/testmod/java/dev/xpple/betterconfig) for a complete picture. +[these tests](fabric/src/testmod/java/dev/xpple/betterconfig) for a complete picture. Furthermore, you can completely change the behaviour of updating your config values by creating your own methods. Simply add one or more of `setter`, `adder`, `putter` or `remover` as attribute to your `@Config` annotation. A great use for @@ -48,7 +48,7 @@ public static void customMapAdder(String string) { ``` The value of `"none"` for the putter indicates that no putter will be available. This way, you can use this `Map` in your code like usual, and add values to it using `/(c)config exampleMapAdder add `. For more details, see -[the JavaDocs for `@Config`](src/main/java/dev/xpple/betterconfig/api/Config.java). +[the JavaDocs for `@Config`](fabric/src/main/java/dev/xpple/betterconfig/api/Config.java). The parameters of the update method can also be customised. ```java diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 2b2a77c..0000000 --- a/build.gradle +++ /dev/null @@ -1,132 +0,0 @@ -plugins { - id 'fabric-loom' version '1.2-SNAPSHOT' - id 'maven-publish' -} - -sourceCompatibility = JavaVersion.VERSION_17 -targetCompatibility = JavaVersion.VERSION_17 - -archivesBaseName = project.archives_base_name -version = project.mod_version -group = project.maven_group - -loom { - splitEnvironmentSourceSets() -} - -sourceSets { - testmod { - compileClasspath += main.compileClasspath - runtimeClasspath += main.runtimeClasspath - - compileClasspath += client.compileClasspath - runtimeClasspath += client.runtimeClasspath - } -} - -loom { - mods { - betterconfig { - sourceSet sourceSets.main - sourceSet sourceSets.client - } - testmod { - sourceSet sourceSets.testmod - } - } - - runs { - testmodClient { - client() - name = "Test Mod Client" - source sourceSets.testmod - } - testmodServer { - server() - name = "Test Mod Server" - source sourceSets.testmod - } - } -} - -repositories { - // Add repositories to retrieve artifacts from in here. - // You should only use this when depending on other mods because - // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. - // See https://docs.gradle.org/current/userguide/declaring_repositories.html - // for more information about repositories. -} - -dependencies { - // To change the versions see the gradle.properties file - minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - - // Fabric API. This is technically optional, but you probably want it anyway. - modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" - - // Uncomment the following line to enable the deprecated Fabric API modules. - // These are included in the Fabric API production distribution and allow you to update your mod to the latest modules at a later more convenient time. - - // modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}" -} - -processResources { - inputs.property "version", project.version - - filesMatching("fabric.mod.json") { - expand "version": project.version - } -} - -tasks.withType(JavaCompile).configureEach { - it.options.release = 17 -} - -java { - // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task - // if it is present. - // If you remove this line, sources will not be generated. - withSourcesJar() -} - -jar { - from("LICENSE") { - rename {"${it}_${project.archivesBaseName}"} - } -} - -// configure the maven publication -publishing { - publications { - mavenJava(MavenPublication) { - artifactId project.archivesBaseName - from components.java - } - } - - // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. - repositories { - // Add repositories to publish to here. - // Notice: This block does NOT have the same function as the block in the top level. - // The repositories here will be used for publishing your artifact, not for - // retrieving dependencies. - maven { - name = "xpple" - url = "sftp://xpple.dev:22/maven.xpple.dev/maven2" - credentials { - username = System.getenv("MAVEN_USER") - password = System.getenv("MAVEN_PASS") - } - } - maven { - name = "GitHubPackages" - url = "https://maven.pkg.github.com/xpple/BetterConfig" - credentials { - username = System.getenv("GITHUB_ACTOR") - password = System.getenv("GITHUB_TOKEN") - } - } - } -} diff --git a/common/build.gradle b/common/build.gradle new file mode 100644 index 0000000..abf0822 --- /dev/null +++ b/common/build.gradle @@ -0,0 +1,34 @@ +plugins { + id 'fabric-loom' version '1.2-SNAPSHOT' +} + +sourceCompatibility = JavaVersion.VERSION_17 +targetCompatibility = JavaVersion.VERSION_17 + +archivesBaseName = project.archives_base_name +version = project.base_version +group = project.maven_group + +repositories { + // Add repositories to retrieve artifacts from in here. + // You should only use this when depending on other mods because + // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. + // See https://docs.gradle.org/current/userguide/declaring_repositories.html + // for more information about repositories. +} + +dependencies { + // To change the versions see the gradle.properties file + minecraft "com.mojang:minecraft:${project.minecraft_version}" + mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" +} + +tasks.withType(JavaCompile).configureEach { + it.options.release = 17 +} + +jar { + from("LICENSE") { + rename {"${it}_${project.archivesBaseName}"} + } +} diff --git a/common/src/main/java/dev/xpple/betterconfig/BetterConfigCommon.java b/common/src/main/java/dev/xpple/betterconfig/BetterConfigCommon.java new file mode 100644 index 0000000..1a06657 --- /dev/null +++ b/common/src/main/java/dev/xpple/betterconfig/BetterConfigCommon.java @@ -0,0 +1,11 @@ +package dev.xpple.betterconfig; + +import org.jetbrains.annotations.ApiStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@ApiStatus.Internal +public class BetterConfigCommon { + public static final String BASE_ID = "betterconfig"; + public static final Logger LOGGER = LoggerFactory.getLogger(BASE_ID); +} diff --git a/src/main/java/dev/xpple/betterconfig/api/ModConfig.java b/common/src/main/java/dev/xpple/betterconfig/api/AbstractConfig.java similarity index 94% rename from src/main/java/dev/xpple/betterconfig/api/ModConfig.java rename to common/src/main/java/dev/xpple/betterconfig/api/AbstractConfig.java index 2dbe603..67a43a9 100644 --- a/src/main/java/dev/xpple/betterconfig/api/ModConfig.java +++ b/common/src/main/java/dev/xpple/betterconfig/api/AbstractConfig.java @@ -4,13 +4,7 @@ import java.nio.file.Path; -public interface ModConfig { - /** - * Get the identifier of the mod of this configuration. - * @return the mod's identifier - */ - String getModId(); - +public interface AbstractConfig { /** * Get the class where all the configurations for this mod are defined. * @return the class with all configurations diff --git a/src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java b/common/src/main/java/dev/xpple/betterconfig/api/AbstractConfigBuilder.java similarity index 55% rename from src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java rename to common/src/main/java/dev/xpple/betterconfig/api/AbstractConfigBuilder.java index d073684..abe2281 100644 --- a/src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java +++ b/common/src/main/java/dev/xpple/betterconfig/api/AbstractConfigBuilder.java @@ -6,28 +6,22 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.suggestion.SuggestionProvider; -import dev.xpple.betterconfig.impl.BetterConfigImpl; -import dev.xpple.betterconfig.impl.BetterConfigInternals; -import dev.xpple.betterconfig.impl.ModConfigImpl; import dev.xpple.betterconfig.util.CheckedBiFunction; -import net.minecraft.command.CommandSource; -import net.minecraft.util.Pair; +import org.apache.commons.lang3.tuple.Pair; import java.util.HashMap; import java.util.Map; import java.util.function.Supplier; -public class ModConfigBuilder { +public abstract class AbstractConfigBuilder { - final String modId; final Class configsClass; final GsonBuilder builder = new GsonBuilder().serializeNulls().enableComplexMapKeySerialization(); final Map, Pair> arguments = new HashMap<>(); final Map, Pair> suggestors = new HashMap<>(); - public ModConfigBuilder(String modId, Class configsClass) { - this.modId = modId; + public AbstractConfigBuilder(Class configsClass) { this.configsClass = configsClass; } @@ -38,12 +32,12 @@ public ModConfigBuilder(String modId, Class configsClass) { * @param argument a brigadier argument pair * @param the type * @return the current builder instance - * @implNote On servers, consider using {@link ModConfigBuilder#registerTypeHierarchyWithSuggestor} + * @implNote On servers, consider using {@link AbstractConfigBuilder#registerTypeHierarchyWithSuggestor} * instead. To use this method on servers, operators need to register the brigadier argument type * as well. - * @see ModConfigBuilder#registerTypeHierarchyWithArgument + * @see AbstractConfigBuilder#registerTypeHierarchyWithArgument */ - public ModConfigBuilder registerTypeWithArgument(Class type, TypeAdapter adapter, Pair>, CheckedBiFunction, String, T, CommandSyntaxException>> argument) { + public AbstractConfigBuilder registerTypeWithArgument(Class type, TypeAdapter adapter, Pair>, CheckedBiFunction, String, T, CommandSyntaxException>> argument) { this.builder.registerTypeAdapter(type, adapter); this.arguments.put(type, argument); return this; @@ -56,11 +50,11 @@ public ModConfigBuilder registerTypeWithArgument(Class type, TypeAdapter< * @param argument a pair of a brigadier argument and parser * @param the type * @return the current builder instance - * @implNote On servers, consider using {@link ModConfigBuilder#registerTypeHierarchyWithSuggestor} + * @implNote On servers, consider using {@link AbstractConfigBuilder#registerTypeHierarchyWithSuggestor} * instead. To use this method on servers, operators need to register the brigadier argument type * as well. */ - public ModConfigBuilder registerTypeHierarchyWithArgument(Class type, TypeAdapter adapter, Pair>, CheckedBiFunction, String, T, CommandSyntaxException>> argument) { + public AbstractConfigBuilder registerTypeHierarchyWithArgument(Class type, TypeAdapter adapter, Pair>, CheckedBiFunction, String, T, CommandSyntaxException>> argument) { this.builder.registerTypeHierarchyAdapter(type, adapter); this.arguments.put(type, argument); return this; @@ -73,10 +67,10 @@ public ModConfigBuilder registerTypeHierarchyWithArgument(Class type, Typ * @param suggestor a pair of a custom suggestions provider and parser * @param the type * @return the current builder instance - * @implNote On clients, consider using {@link ModConfigBuilder#registerTypeWithArgument} instead. - * @see ModConfigBuilder#registerTypeHierarchyWithSuggestor + * @implNote On clients, consider using {@link AbstractConfigBuilder#registerTypeWithArgument} instead. + * @see AbstractConfigBuilder#registerTypeHierarchyWithSuggestor */ - public ModConfigBuilder registerTypeWithSuggestor(Class type, TypeAdapter adapter, Pair>, CheckedBiFunction, String, T, CommandSyntaxException>> suggestor) { + public AbstractConfigBuilder registerTypeWithSuggestor(Class type, TypeAdapter adapter, Pair>, CheckedBiFunction, String, T, CommandSyntaxException>> suggestor) { this.builder.registerTypeAdapter(type, adapter); this.suggestors.put(type, suggestor); return this; @@ -89,9 +83,9 @@ public ModConfigBuilder registerTypeWithSuggestor(Class type, TypeAdapter * @param suggestor a pair of a custom suggestions provider and parser * @param the type * @return the current builder instance - * @implNote On clients, consider using {@link ModConfigBuilder#registerTypeHierarchyWithArgument} instead. + * @implNote On clients, consider using {@link AbstractConfigBuilder#registerTypeHierarchyWithArgument} instead. */ - public ModConfigBuilder registerTypeHierarchyWithSuggestor(Class type, TypeAdapter adapter, Pair>, CheckedBiFunction, String, T, CommandSyntaxException>> suggestor) { + public AbstractConfigBuilder registerTypeHierarchyWithSuggestor(Class type, TypeAdapter adapter, Pair>, CheckedBiFunction, String, T, CommandSyntaxException>> suggestor) { this.builder.registerTypeHierarchyAdapter(type, adapter); this.suggestors.put(type, suggestor); return this; @@ -101,12 +95,5 @@ public ModConfigBuilder registerTypeHierarchyWithSuggestor(Class type, Ty * Finalise the registration process. * @throws IllegalArgumentException when a configuration already exists for this mod */ - public void build() { - ModConfigImpl modConfig = new ModConfigImpl(this.modId, this.configsClass, this.builder.create(), this.arguments, this.suggestors); - if (BetterConfigImpl.getModConfigs().putIfAbsent(this.modId, modConfig) == null) { - BetterConfigInternals.init(modConfig); - return; - } - throw new IllegalArgumentException(this.modId); - } + public abstract void build(); } diff --git a/src/main/java/dev/xpple/betterconfig/api/Config.java b/common/src/main/java/dev/xpple/betterconfig/api/Config.java similarity index 100% rename from src/main/java/dev/xpple/betterconfig/api/Config.java rename to common/src/main/java/dev/xpple/betterconfig/api/Config.java diff --git a/src/main/java/dev/xpple/betterconfig/command/ConfigCommandHelper.java b/common/src/main/java/dev/xpple/betterconfig/command/ConfigCommandHelper.java similarity index 60% rename from src/main/java/dev/xpple/betterconfig/command/ConfigCommandHelper.java rename to common/src/main/java/dev/xpple/betterconfig/command/ConfigCommandHelper.java index e48e3ba..aa1d777 100644 --- a/src/main/java/dev/xpple/betterconfig/command/ConfigCommandHelper.java +++ b/common/src/main/java/dev/xpple/betterconfig/command/ConfigCommandHelper.java @@ -1,111 +1,108 @@ package dev.xpple.betterconfig.command; +import dev.xpple.betterconfig.api.Config; +import dev.xpple.betterconfig.impl.AbstractConfigImpl; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; import com.mojang.brigadier.suggestion.SuggestionProvider; -import dev.xpple.betterconfig.api.Config; -import dev.xpple.betterconfig.command.suggestion.EnumSuggestionProvider; -import dev.xpple.betterconfig.impl.BetterConfigImpl; -import dev.xpple.betterconfig.impl.ModConfigImpl; import dev.xpple.betterconfig.util.CheckedFunction; -import net.minecraft.command.CommandSource; -import net.minecraft.text.Text; import java.lang.reflect.Type; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.function.Predicate; import static com.mojang.brigadier.arguments.StringArgumentType.*; -public abstract class ConfigCommandHelper { +public abstract class ConfigCommandHelper { - private static final DynamicCommandExceptionType INVALID_ENUM_EXCEPTION = new DynamicCommandExceptionType(value -> Text.translatable("argument.enum.invalid", value)); + protected abstract > SuggestionProvider enumSuggestionProvider(Class type); + protected abstract DynamicCommandExceptionType invalidEnumException(); - protected LiteralArgumentBuilder create(String rootLiteral) { + protected final LiteralArgumentBuilder create(String rootLiteral, Collection> abstractConfigs) { LiteralArgumentBuilder root = LiteralArgumentBuilder.literal(rootLiteral); - for (ModConfigImpl modConfig : BetterConfigImpl.getModConfigs().values()) { + for (AbstractConfigImpl abstractConfig : abstractConfigs) { Map> literals = new HashMap<>(); - for (String config : modConfig.getConfigs().keySet()) { - @SuppressWarnings("unchecked") - Predicate condition = (Predicate) modConfig.getConditions().get(config); + for (String config : abstractConfig.getConfigs().keySet()) { + Predicate condition = abstractConfig.getConditions().get(config); LiteralArgumentBuilder configLiteral = LiteralArgumentBuilder.literal(config).requires(condition); literals.put(config, configLiteral); - configLiteral.then(LiteralArgumentBuilder.literal("get").executes(ctx -> get(ctx.getSource(), modConfig, config))); - configLiteral.then(LiteralArgumentBuilder.literal("reset").executes(ctx -> reset(ctx.getSource(), modConfig, config))); + configLiteral.then(LiteralArgumentBuilder.literal("get").executes(ctx -> get(ctx.getSource(), abstractConfig, config))); + configLiteral.then(LiteralArgumentBuilder.literal("reset").executes(ctx -> reset(ctx.getSource(), abstractConfig, config))); } - modConfig.getSetters().keySet().forEach(config -> { - Config annotation = modConfig.getAnnotations().get(config); + abstractConfig.getSetters().keySet().forEach(config -> { + Config annotation = abstractConfig.getAnnotations().get(config); Config.Setter setter = annotation.setter(); - Class type = setter.type() == Config.EMPTY.class ? modConfig.getType(config) : setter.type(); - var argumentPair = modConfig.getArgument(type); - var suggestorPair = modConfig.getSuggestor(type); + Class type = setter.type() == Config.EMPTY.class ? abstractConfig.getType(config) : setter.type(); + var argumentPair = abstractConfig.getArgument(type); + var suggestorPair = abstractConfig.getSuggestor(type); if (type.isEnum()) { //noinspection rawtypes, unchecked - RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", string()).suggests(new EnumSuggestionProvider<>((Class) type)); + RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", string()).suggests(this.enumSuggestionProvider((Class) type)); subCommand.executes(ctx -> { String value = getString(ctx, "value"); - return set(ctx.getSource(), modConfig, config, Arrays.stream(type.getEnumConstants()).filter(c -> c.toString().equals(value)).findAny().orElseThrow(() -> INVALID_ENUM_EXCEPTION.create(value))); + return set(ctx.getSource(), abstractConfig, config, Arrays.stream(type.getEnumConstants()).filter(c -> c.toString().equals(value)).findAny().orElseThrow(() -> this.invalidEnumException().create(value))); }); literals.get(config).then(LiteralArgumentBuilder.literal("set").then(subCommand)); } else if (argumentPair != null) { RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", argumentPair.getLeft().get()); - subCommand.executes(ctx -> set(ctx.getSource(), modConfig, config, argumentPair.getRight().apply(ctx, "value"))); + subCommand.executes(ctx -> set(ctx.getSource(), abstractConfig, config, argumentPair.getRight().apply(ctx, "value"))); literals.get(config).then(LiteralArgumentBuilder.literal("set").then(subCommand)); } else if (suggestorPair != null) { RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", greedyString()); //noinspection unchecked - subCommand.suggests((SuggestionProvider) suggestorPair.getLeft().get()).executes(ctx -> set(ctx.getSource(), modConfig, config, suggestorPair.getRight().apply(ctx, "value"))); + subCommand.suggests((SuggestionProvider) suggestorPair.getLeft().get()).executes(ctx -> set(ctx.getSource(), abstractConfig, config, suggestorPair.getRight().apply(ctx, "value"))); literals.get(config).then(LiteralArgumentBuilder.literal("set").then(subCommand)); } }); - modConfig.getAdders().keySet().forEach(config -> { - Config annotation = modConfig.getAnnotations().get(config); + abstractConfig.getAdders().keySet().forEach(config -> { + Config annotation = abstractConfig.getAnnotations().get(config); Config.Adder adder = annotation.adder(); - Class type = adder.type() == Config.EMPTY.class ? (Class) modConfig.getParameterTypes(config)[0] : adder.type(); - var argumentPair = modConfig.getArgument(type); - var suggestorPair = modConfig.getSuggestor(type); + Class type = adder.type() == Config.EMPTY.class ? (Class) abstractConfig.getParameterTypes(config)[0] : adder.type(); + var argumentPair = abstractConfig.getArgument(type); + var suggestorPair = abstractConfig.getSuggestor(type); if (type.isEnum()) { //noinspection rawtypes, unchecked - RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", string()).suggests(new EnumSuggestionProvider<>((Class) type)); + RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", string()).suggests(this.enumSuggestionProvider((Class) type)); subCommand.executes(ctx -> { String value = getString(ctx, "value"); - return add(ctx.getSource(), modConfig, config, Arrays.stream(type.getEnumConstants()).filter(c -> c.toString().equals(value)).findAny().orElseThrow(() -> INVALID_ENUM_EXCEPTION.create(value))); + return add(ctx.getSource(), abstractConfig, config, Arrays.stream(type.getEnumConstants()).filter(c -> c.toString().equals(value)).findAny().orElseThrow(() -> this.invalidEnumException().create(value))); }); literals.get(config).then(LiteralArgumentBuilder.literal("add").then(subCommand)); } else if (argumentPair != null) { RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", argumentPair.getLeft().get()); - subCommand.executes(ctx -> add(ctx.getSource(), modConfig, config, argumentPair.getRight().apply(ctx, "value"))); + subCommand.executes(ctx -> add(ctx.getSource(), abstractConfig, config, argumentPair.getRight().apply(ctx, "value"))); literals.get(config).then(LiteralArgumentBuilder.literal("add").then(subCommand)); } else if (suggestorPair != null) { RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", greedyString()); //noinspection unchecked - subCommand.suggests((SuggestionProvider) suggestorPair.getLeft().get()).executes(ctx -> add(ctx.getSource(), modConfig, config, suggestorPair.getRight().apply(ctx, "value"))); + subCommand.suggests((SuggestionProvider) suggestorPair.getLeft().get()).executes(ctx -> add(ctx.getSource(), abstractConfig, config, suggestorPair.getRight().apply(ctx, "value"))); literals.get(config).then(LiteralArgumentBuilder.literal("add").then(subCommand)); } }); - modConfig.getPutters().keySet().forEach(config -> { - Config annotation = modConfig.getAnnotations().get(config); + abstractConfig.getPutters().keySet().forEach(config -> { + Config annotation = abstractConfig.getAnnotations().get(config); Config.Putter putter = annotation.putter(); - Type[] types = modConfig.getParameterTypes(config); + Type[] types = abstractConfig.getParameterTypes(config); Class keyType = putter.keyType() == Config.EMPTY.class ? (Class) types[0] : putter.keyType(); RequiredArgumentBuilder subCommand; CheckedFunction, ?, CommandSyntaxException> getKey; - var argumentKeyPair = modConfig.getArgument(keyType); - var suggestorKeyPair = modConfig.getSuggestor(keyType); + var argumentKeyPair = abstractConfig.getArgument(keyType); + var suggestorKeyPair = abstractConfig.getSuggestor(keyType); if (keyType.isEnum()) { //noinspection rawtypes, unchecked - subCommand = RequiredArgumentBuilder.argument("key", string()).suggests(new EnumSuggestionProvider<>((Class) keyType)); + subCommand = RequiredArgumentBuilder.argument("key", string()).suggests(this.enumSuggestionProvider((Class) keyType)); getKey = ctx -> { String value = getString(ctx, "key"); - return Arrays.stream(keyType.getEnumConstants()).filter(c -> c.toString().equals(value)).findAny().orElseThrow(() -> INVALID_ENUM_EXCEPTION.create(value)); + return Arrays.stream(keyType.getEnumConstants()).filter(c -> c.toString().equals(value)).findAny().orElseThrow(() -> this.invalidEnumException().create(value)); }; } else if (argumentKeyPair != null) { subCommand = RequiredArgumentBuilder.argument("key", argumentKeyPair.getLeft().get()); @@ -119,66 +116,66 @@ protected LiteralArgumentBuilder create(String rootLiteral) { return; } Class valueType = putter.valueType() == Config.EMPTY.class ? (Class) types[1] : putter.valueType(); - var argumentValuePair = modConfig.getArgument(valueType); - var suggestorValuePair = modConfig.getSuggestor(valueType); + var argumentValuePair = abstractConfig.getArgument(valueType); + var suggestorValuePair = abstractConfig.getSuggestor(valueType); if (valueType.isEnum()) { //noinspection rawtypes, unchecked - RequiredArgumentBuilder subSubCommand = RequiredArgumentBuilder.argument("value", string()).suggests(new EnumSuggestionProvider<>((Class) valueType)); + RequiredArgumentBuilder subSubCommand = RequiredArgumentBuilder.argument("value", string()).suggests(this.enumSuggestionProvider((Class) valueType)); subCommand.executes(ctx -> { String value = getString(ctx, "value"); - return put(ctx.getSource(), modConfig, config, getKey.apply(ctx), Arrays.stream(valueType.getEnumConstants()).filter(c -> c.toString().equals(value)).findAny().orElseThrow(() -> INVALID_ENUM_EXCEPTION.create(value))); + return put(ctx.getSource(), abstractConfig, config, getKey.apply(ctx), Arrays.stream(valueType.getEnumConstants()).filter(c -> c.toString().equals(value)).findAny().orElseThrow(() -> this.invalidEnumException().create(value))); }); literals.get(config).then(LiteralArgumentBuilder.literal("put").then(subCommand.then(subSubCommand))); } else if (argumentValuePair != null) { RequiredArgumentBuilder subSubCommand = RequiredArgumentBuilder.argument("value", argumentValuePair.getLeft().get()); - subSubCommand.executes(ctx -> put(ctx.getSource(), modConfig, config, getKey.apply(ctx), argumentValuePair.getRight().apply(ctx, "value"))); + subSubCommand.executes(ctx -> put(ctx.getSource(), abstractConfig, config, getKey.apply(ctx), argumentValuePair.getRight().apply(ctx, "value"))); literals.get(config).then(LiteralArgumentBuilder.literal("put").then(subCommand.then(subSubCommand))); } else if (suggestorValuePair != null) { RequiredArgumentBuilder subSubCommand = RequiredArgumentBuilder.argument("value", greedyString()); //noinspection unchecked - subSubCommand.suggests((SuggestionProvider) suggestorValuePair.getLeft().get()).executes(ctx -> put(ctx.getSource(), modConfig, config, getKey.apply(ctx), suggestorValuePair.getRight().apply(ctx, "value"))); + subSubCommand.suggests((SuggestionProvider) suggestorValuePair.getLeft().get()).executes(ctx -> put(ctx.getSource(), abstractConfig, config, getKey.apply(ctx), suggestorValuePair.getRight().apply(ctx, "value"))); literals.get(config).then(LiteralArgumentBuilder.literal("put").then(subCommand.then(subSubCommand))); } }); - modConfig.getRemovers().keySet().forEach(config -> { - Config annotation = modConfig.getAnnotations().get(config); + abstractConfig.getRemovers().keySet().forEach(config -> { + Config annotation = abstractConfig.getAnnotations().get(config); Config.Remover remover = annotation.remover(); - Class type = remover.type() == Config.EMPTY.class ? (Class) modConfig.getParameterTypes(config)[0] : remover.type(); - var argumentPair = modConfig.getArgument(type); - var suggestorPair = modConfig.getSuggestor(type); + Class type = remover.type() == Config.EMPTY.class ? (Class) abstractConfig.getParameterTypes(config)[0] : remover.type(); + var argumentPair = abstractConfig.getArgument(type); + var suggestorPair = abstractConfig.getSuggestor(type); if (type.isEnum()) { //noinspection rawtypes, unchecked - RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", string()).suggests(new EnumSuggestionProvider<>((Class) type)); + RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", string()).suggests(this.enumSuggestionProvider((Class) type)); subCommand.executes(ctx -> { String value = getString(ctx, "value"); - return remove(ctx.getSource(), modConfig, config, Arrays.stream(type.getEnumConstants()).filter(c -> c.toString().equals(value)).findAny().orElseThrow(() -> INVALID_ENUM_EXCEPTION.create(value))); + return remove(ctx.getSource(), abstractConfig, config, Arrays.stream(type.getEnumConstants()).filter(c -> c.toString().equals(value)).findAny().orElseThrow(() -> this.invalidEnumException().create(value))); }); literals.get(config).then(LiteralArgumentBuilder.literal("remove").then(subCommand)); } else if (argumentPair != null) { RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", argumentPair.getLeft().get()); - subCommand.executes(ctx -> remove(ctx.getSource(), modConfig, config, argumentPair.getRight().apply(ctx, "value"))); + subCommand.executes(ctx -> remove(ctx.getSource(), abstractConfig, config, argumentPair.getRight().apply(ctx, "value"))); literals.get(config).then(LiteralArgumentBuilder.literal("remove").then(subCommand)); } else if (suggestorPair != null) { RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", greedyString()); //noinspection unchecked - subCommand.suggests((SuggestionProvider) suggestorPair.getLeft().get()).executes(ctx -> remove(ctx.getSource(), modConfig, config, suggestorPair.getRight().apply(ctx, "value"))); + subCommand.suggests((SuggestionProvider) suggestorPair.getLeft().get()).executes(ctx -> remove(ctx.getSource(), abstractConfig, config, suggestorPair.getRight().apply(ctx, "value"))); literals.get(config).then(LiteralArgumentBuilder.literal("remove").then(subCommand)); } }); - literals.values().forEach(literal -> root.then(LiteralArgumentBuilder.literal(modConfig.getModId()).then(literal))); + literals.values().forEach(literal -> root.then(LiteralArgumentBuilder.literal(abstractConfig.getIdentifier()).then(literal))); } return root; } - protected abstract int get(S source, ModConfigImpl modConfig, String config); + protected abstract int get(S source, AbstractConfigImpl abstractConfig, String config); - protected abstract int reset(S source, ModConfigImpl modConfig, String config); + protected abstract int reset(S source, AbstractConfigImpl abstractConfig, String config); - protected abstract int set(S source, ModConfigImpl modConfig, String config, Object value) throws CommandSyntaxException; + protected abstract int set(S source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException; - protected abstract int add(S source, ModConfigImpl modConfig, String config, Object value) throws CommandSyntaxException; + protected abstract int add(S source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException; - protected abstract int put(S source, ModConfigImpl modConfig, String config, Object key, Object value) throws CommandSyntaxException; + protected abstract int put(S source, AbstractConfigImpl abstractConfig, String config, Object key, Object value) throws CommandSyntaxException; - protected abstract int remove(S source, ModConfigImpl modConfig, String config, Object value) throws CommandSyntaxException; + protected abstract int remove(S source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException; } diff --git a/common/src/main/java/dev/xpple/betterconfig/command/package-info.java b/common/src/main/java/dev/xpple/betterconfig/command/package-info.java new file mode 100644 index 0000000..0d98523 --- /dev/null +++ b/common/src/main/java/dev/xpple/betterconfig/command/package-info.java @@ -0,0 +1,4 @@ +@ApiStatus.Internal +package dev.xpple.betterconfig.command; + +import org.jetbrains.annotations.ApiStatus; diff --git a/common/src/main/java/dev/xpple/betterconfig/command/suggestion/AbstractEnumSuggestionProvider.java b/common/src/main/java/dev/xpple/betterconfig/command/suggestion/AbstractEnumSuggestionProvider.java new file mode 100644 index 0000000..bb87a07 --- /dev/null +++ b/common/src/main/java/dev/xpple/betterconfig/command/suggestion/AbstractEnumSuggestionProvider.java @@ -0,0 +1,12 @@ +package dev.xpple.betterconfig.command.suggestion; + +import com.mojang.brigadier.suggestion.SuggestionProvider; + +public abstract class AbstractEnumSuggestionProvider> implements SuggestionProvider { + + final Class enumClass; + + public AbstractEnumSuggestionProvider(Class enumClass) { + this.enumClass = enumClass; + } +} diff --git a/common/src/main/java/dev/xpple/betterconfig/command/suggestion/package-info.java b/common/src/main/java/dev/xpple/betterconfig/command/suggestion/package-info.java new file mode 100644 index 0000000..91f7912 --- /dev/null +++ b/common/src/main/java/dev/xpple/betterconfig/command/suggestion/package-info.java @@ -0,0 +1,4 @@ +@ApiStatus.Internal +package dev.xpple.betterconfig.command.suggestion; + +import org.jetbrains.annotations.ApiStatus; diff --git a/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java b/common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java similarity index 62% rename from src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java rename to common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java index 886ae38..364f1cb 100644 --- a/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java +++ b/common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java @@ -7,13 +7,12 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.suggestion.SuggestionProvider; +import dev.xpple.betterconfig.api.AbstractConfig; import dev.xpple.betterconfig.api.Config; -import dev.xpple.betterconfig.api.ModConfig; import dev.xpple.betterconfig.util.CheckedBiConsumer; import dev.xpple.betterconfig.util.CheckedBiFunction; import dev.xpple.betterconfig.util.CheckedConsumer; -import net.minecraft.command.CommandSource; -import net.minecraft.util.Pair; +import org.apache.commons.lang3.tuple.Pair; import java.io.BufferedWriter; import java.io.IOException; @@ -21,32 +20,29 @@ import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.nio.file.Files; -import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.function.Predicate; import java.util.function.Supplier; -import static dev.xpple.betterconfig.BetterConfig.LOGGER; -import static dev.xpple.betterconfig.BetterConfig.MOD_PATH; - -public class ModConfigImpl implements ModConfig { - - private static final Map, Pair> defaultArguments = ImmutableMap., Pair>builder() - .put(boolean.class, new Pair<>((Supplier>) BoolArgumentType::bool, (CheckedBiFunction, String, Boolean, CommandSyntaxException>) BoolArgumentType::getBool)) - .put(Boolean.class, new Pair<>((Supplier>) BoolArgumentType::bool, (CheckedBiFunction, String, Boolean, CommandSyntaxException>) BoolArgumentType::getBool)) - .put(double.class, new Pair<>((Supplier>) DoubleArgumentType::doubleArg, (CheckedBiFunction, String, Double, CommandSyntaxException>) DoubleArgumentType::getDouble)) - .put(Double.class, new Pair<>((Supplier>) DoubleArgumentType::doubleArg, (CheckedBiFunction, String, Double, CommandSyntaxException>) DoubleArgumentType::getDouble)) - .put(float.class, new Pair<>((Supplier>) FloatArgumentType::floatArg, (CheckedBiFunction, String, Float, CommandSyntaxException>) FloatArgumentType::getFloat)) - .put(Float.class, new Pair<>((Supplier>) FloatArgumentType::floatArg, (CheckedBiFunction, String, Float, CommandSyntaxException>) FloatArgumentType::getFloat)) - .put(int.class, new Pair<>((Supplier>) IntegerArgumentType::integer, (CheckedBiFunction, String, Integer, CommandSyntaxException>) IntegerArgumentType::getInteger)) - .put(Integer.class, new Pair<>((Supplier>) IntegerArgumentType::integer, (CheckedBiFunction, String, Integer, CommandSyntaxException>) IntegerArgumentType::getInteger)) - .put(long.class, new Pair<>((Supplier>) LongArgumentType::longArg, (CheckedBiFunction, String, Long, CommandSyntaxException>) LongArgumentType::getLong)) - .put(Long.class, new Pair<>((Supplier>) LongArgumentType::longArg, (CheckedBiFunction, String, Long, CommandSyntaxException>) LongArgumentType::getLong)) - .put(String.class, new Pair<>((Supplier>) StringArgumentType::string, (CheckedBiFunction, String, String, CommandSyntaxException>) StringArgumentType::getString)) +import static dev.xpple.betterconfig.BetterConfigCommon.LOGGER; + +public abstract class AbstractConfigImpl implements AbstractConfig { + + Map, Pair> defaultArguments = ImmutableMap., Pair>builder() + .put(boolean.class, Pair.of((Supplier>) BoolArgumentType::bool, (CheckedBiFunction, String, Boolean, CommandSyntaxException>) BoolArgumentType::getBool)) + .put(Boolean.class, Pair.of((Supplier>) BoolArgumentType::bool, (CheckedBiFunction, String, Boolean, CommandSyntaxException>) BoolArgumentType::getBool)) + .put(double.class, Pair.of((Supplier>) DoubleArgumentType::doubleArg, (CheckedBiFunction, String, Double, CommandSyntaxException>) DoubleArgumentType::getDouble)) + .put(Double.class, Pair.of((Supplier>) DoubleArgumentType::doubleArg, (CheckedBiFunction, String, Double, CommandSyntaxException>) DoubleArgumentType::getDouble)) + .put(float.class, Pair.of((Supplier>) FloatArgumentType::floatArg, (CheckedBiFunction, String, Float, CommandSyntaxException>) FloatArgumentType::getFloat)) + .put(Float.class, Pair.of((Supplier>) FloatArgumentType::floatArg, (CheckedBiFunction, String, Float, CommandSyntaxException>) FloatArgumentType::getFloat)) + .put(int.class, Pair.of((Supplier>) IntegerArgumentType::integer, (CheckedBiFunction, String, Integer, CommandSyntaxException>) IntegerArgumentType::getInteger)) + .put(Integer.class, Pair.of((Supplier>) IntegerArgumentType::integer, (CheckedBiFunction, String, Integer, CommandSyntaxException>) IntegerArgumentType::getInteger)) + .put(long.class, Pair.of((Supplier>) LongArgumentType::longArg, (CheckedBiFunction, String, Long, CommandSyntaxException>) LongArgumentType::getLong)) + .put(Long.class, Pair.of((Supplier>) LongArgumentType::longArg, (CheckedBiFunction, String, Long, CommandSyntaxException>) LongArgumentType::getLong)) + .put(String.class, Pair.of((Supplier>) StringArgumentType::string, (CheckedBiFunction, String, String, CommandSyntaxException>) StringArgumentType::getString)) .build(); - private final String modId; private final Class configsClass; private final Gson gson; @@ -54,8 +50,7 @@ public class ModConfigImpl implements ModConfig { private final Map, Pair> arguments; private final Map, Pair> suggestors; - public ModConfigImpl(String modId, Class configsClass, Gson gson, Map, Pair> arguments, Map, Pair> suggestors) { - this.modId = modId; + protected AbstractConfigImpl(Class configsClass, Gson gson, Map, Pair> arguments, Map, Pair> suggestors) { this.configsClass = configsClass; this.gson = gson.newBuilder().setPrettyPrinting().create(); this.inlineGson = gson; @@ -63,10 +58,7 @@ public ModConfigImpl(String modId, Class configsClass, Gson gson, Map getConfigsClass() { @@ -78,18 +70,13 @@ public Gson getGson() { } @SuppressWarnings("unchecked") - public Pair>, CheckedBiFunction, String, T, CommandSyntaxException>> getArgument(Class type) { - return (Pair>, CheckedBiFunction, String, T, CommandSyntaxException>>) this.arguments.getOrDefault(type, defaultArguments.get(type)); + public Pair>, CheckedBiFunction, String, T, CommandSyntaxException>> getArgument(Class type) { + return (Pair>, CheckedBiFunction, String, T, CommandSyntaxException>>) this.arguments.getOrDefault(type, defaultArguments.get(type)); } @SuppressWarnings("unchecked") - public Pair>, CheckedBiFunction, String, T, CommandSyntaxException>> getSuggestor(Class type) { - return (Pair>, CheckedBiFunction, String, T, CommandSyntaxException>>) this.suggestors.get(type); - } - - @Override - public Path getConfigsPath() { - return MOD_PATH.resolve(this.modId).resolve("config.json"); + public Pair>, CheckedBiFunction, String, T, CommandSyntaxException>> getSuggestor(Class type) { + return (Pair>, CheckedBiFunction, String, T, CommandSyntaxException>>) this.suggestors.get(type); } @Override @@ -238,7 +225,7 @@ public Map> getRemovers( return this.removers; } - public Map> getConditions() { + public Map> getConditions() { return this.conditions; } @@ -252,6 +239,6 @@ public Map getAnnotations() { private final Map> adders = new HashMap<>(); private final Map> putters = new HashMap<>(); private final Map> removers = new HashMap<>(); - private final Map> conditions = new HashMap<>(); + private final Map> conditions = new HashMap<>(); private final Map annotations = new HashMap<>(); } diff --git a/src/main/java/dev/xpple/betterconfig/impl/BetterConfigInternals.java b/common/src/main/java/dev/xpple/betterconfig/impl/BetterConfigInternals.java similarity index 76% rename from src/main/java/dev/xpple/betterconfig/impl/BetterConfigInternals.java rename to common/src/main/java/dev/xpple/betterconfig/impl/BetterConfigInternals.java index 79190aa..165d381 100644 --- a/src/main/java/dev/xpple/betterconfig/impl/BetterConfigInternals.java +++ b/common/src/main/java/dev/xpple/betterconfig/impl/BetterConfigInternals.java @@ -4,7 +4,6 @@ import com.google.gson.JsonParser; import com.mojang.brigadier.exceptions.CommandSyntaxException; import dev.xpple.betterconfig.api.Config; -import net.minecraft.command.CommandSource; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -14,20 +13,20 @@ import java.util.Collection; import java.util.Map; -import static dev.xpple.betterconfig.BetterConfig.LOGGER; +import static dev.xpple.betterconfig.BetterConfigCommon.LOGGER; public class BetterConfigInternals { - public static void init(ModConfigImpl modConfig) { + public static void init(AbstractConfigImpl abstractConfig) { JsonObject root; - try (BufferedReader reader = Files.newBufferedReader(modConfig.getConfigsPath())) { + try (BufferedReader reader = Files.newBufferedReader(abstractConfig.getConfigsPath())) { root = JsonParser.parseReader(reader).getAsJsonObject(); } catch (IOException e) { root = new JsonObject(); LOGGER.warn("Could not read config file, default values will be used."); } - for (Field field : modConfig.getConfigsClass().getDeclaredFields()) { + for (Field field : abstractConfig.getConfigsClass().getDeclaredFields()) { Config annotation = field.getAnnotation(Config.class); if (annotation == null) { continue; @@ -36,24 +35,24 @@ public static void init(ModConfigImpl modConfig) { field.setAccessible(true); String fieldName = field.getName(); - modConfig.getConfigs().put(fieldName, field); + abstractConfig.getConfigs().put(fieldName, field); try { - modConfig.getDefaults().put(fieldName, field.get(null)); + abstractConfig.getDefaults().put(fieldName, field.get(null)); } catch (ReflectiveOperationException e) { throw new AssertionError(e); } - modConfig.getAnnotations().put(fieldName, annotation); + abstractConfig.getAnnotations().put(fieldName, annotation); if (!annotation.temporary()) { try { if (root.has(fieldName)) { - Object value = modConfig.getGson().fromJson(root.get(fieldName), field.getGenericType()); + Object value = abstractConfig.getGson().fromJson(root.get(fieldName), field.getGenericType()); if (Modifier.isFinal(field.getModifiers())) { throw new AssertionError("Config field '" + fieldName + "' should not be final"); } field.set(null, value); } else { - root.add(fieldName, modConfig.getGson().toJsonTree(field.get(null))); + root.add(fieldName, abstractConfig.getGson().toJsonTree(field.get(null))); } } catch (Exception e) { throw new AssertionError(e); @@ -61,16 +60,22 @@ public static void init(ModConfigImpl modConfig) { } if (annotation.condition().isEmpty()) { - modConfig.getConditions().put(fieldName, source -> true); + abstractConfig.getConditions().put(fieldName, source -> true); } else { Method predicateMethod; boolean hasParameter = false; try { - predicateMethod = modConfig.getConfigsClass().getDeclaredMethod(annotation.condition()); + predicateMethod = abstractConfig.getConfigsClass().getDeclaredMethod(annotation.condition()); } catch (ReflectiveOperationException e) { hasParameter = true; try { - predicateMethod = modConfig.getConfigsClass().getDeclaredMethod(annotation.condition(), CommandSource.class); + Class clazz; + try { + clazz = Class.forName("net.minecraft.command.CommandSource"); + } catch (ReflectiveOperationException e1) { + clazz = Class.forName("io.papermc.paper.command.brigadier.CommandSourceStack"); + } + predicateMethod = abstractConfig.getConfigsClass().getDeclaredMethod(annotation.condition(), clazz); } catch (ReflectiveOperationException e1) { throw new AssertionError(e1); } @@ -86,7 +91,7 @@ public static void init(ModConfigImpl modConfig) { Method predicateMethod_f = predicateMethod; if (hasParameter) { - modConfig.getConditions().put(fieldName, source -> { + abstractConfig.getConditions().put(fieldName, source -> { try { return (Boolean) predicateMethod_f.invoke(null, source); } catch (ReflectiveOperationException e) { @@ -94,7 +99,7 @@ public static void init(ModConfigImpl modConfig) { } }); } else { - modConfig.getConditions().put(fieldName, source -> { + abstractConfig.getConditions().put(fieldName, source -> { try { return (Boolean) predicateMethod_f.invoke(null); } catch (ReflectiveOperationException e) { @@ -109,25 +114,25 @@ public static void init(ModConfigImpl modConfig) { } Class type = field.getType(); if (Collection.class.isAssignableFrom(type)) { - initCollection(modConfig, field, annotation); + initCollection(abstractConfig, field, annotation); } else if (Map.class.isAssignableFrom(type)) { - initMap(modConfig, field, annotation); + initMap(abstractConfig, field, annotation); } else { - initObject(modConfig, field, annotation); + initObject(abstractConfig, field, annotation); } } //noinspection ResultOfMethodCallIgnored - modConfig.getConfigsPath().getParent().toFile().mkdirs(); - try (BufferedWriter writer = Files.newBufferedWriter(modConfig.getConfigsPath())) { - writer.write(modConfig.getGson().toJson(root)); + abstractConfig.getConfigsPath().getParent().toFile().mkdirs(); + try (BufferedWriter writer = Files.newBufferedWriter(abstractConfig.getConfigsPath())) { + writer.write(abstractConfig.getGson().toJson(root)); } catch (IOException e) { LOGGER.error("Could not save config file."); e.printStackTrace(); } } - private static void initCollection(ModConfigImpl modConfig, Field field, Config annotation) { + private static void initCollection(AbstractConfigImpl abstractConfig, Field field, Config annotation) { String fieldName = field.getName(); Type[] types = ((ParameterizedType) field.getGenericType()).getActualTypeArguments(); Config.Adder adder = annotation.adder(); @@ -141,7 +146,7 @@ private static void initCollection(ModConfigImpl modConfig, Field field, Config } catch (ReflectiveOperationException e) { throw new AssertionError(e); } - modConfig.getAdders().put(fieldName, value -> { + abstractConfig.getAdders().put(fieldName, value -> { try { add.invoke(field.get(null), value); } catch (ReflectiveOperationException e) { @@ -152,12 +157,12 @@ private static void initCollection(ModConfigImpl modConfig, Field field, Config Class type = adder.type() == Config.EMPTY.class ? (Class) types[0] : adder.type(); Method adderMethod; try { - adderMethod = modConfig.getConfigsClass().getDeclaredMethod(adderMethodName, type); + adderMethod = abstractConfig.getConfigsClass().getDeclaredMethod(adderMethodName, type); } catch (ReflectiveOperationException e) { throw new AssertionError(e); } adderMethod.setAccessible(true); - modConfig.getAdders().put(fieldName, value -> { + abstractConfig.getAdders().put(fieldName, value -> { try { adderMethod.invoke(null, value); } catch (ReflectiveOperationException e) { @@ -179,7 +184,7 @@ private static void initCollection(ModConfigImpl modConfig, Field field, Config } catch (ReflectiveOperationException e) { throw new AssertionError(e); } - modConfig.getRemovers().put(fieldName, value -> { + abstractConfig.getRemovers().put(fieldName, value -> { try { remove.invoke(field.get(null), value); } catch (ReflectiveOperationException e) { @@ -190,12 +195,12 @@ private static void initCollection(ModConfigImpl modConfig, Field field, Config Class type = remover.type() == Config.EMPTY.class ? (Class) types[0] : remover.type(); Method removerMethod; try { - removerMethod = modConfig.getConfigsClass().getDeclaredMethod(removerMethodName, type); + removerMethod = abstractConfig.getConfigsClass().getDeclaredMethod(removerMethodName, type); } catch (ReflectiveOperationException e) { throw new AssertionError(e); } removerMethod.setAccessible(true); - modConfig.getRemovers().put(fieldName, value -> { + abstractConfig.getRemovers().put(fieldName, value -> { try { removerMethod.invoke(null, value); } catch (ReflectiveOperationException e) { @@ -208,7 +213,7 @@ private static void initCollection(ModConfigImpl modConfig, Field field, Config } } - private static void initMap(ModConfigImpl modConfig, Field field, Config annotation) { + private static void initMap(AbstractConfigImpl abstractConfig, Field field, Config annotation) { String fieldName = field.getName(); Type[] types = ((ParameterizedType) field.getGenericType()).getActualTypeArguments(); Config.Adder adder = annotation.adder(); @@ -219,12 +224,12 @@ private static void initMap(ModConfigImpl modConfig, Field field, Config annotat Class type = adder.type() == Config.EMPTY.class ? (Class) types[0] : adder.type(); Method adderMethod; try { - adderMethod = modConfig.getConfigsClass().getDeclaredMethod(adderMethodName, type); + adderMethod = abstractConfig.getConfigsClass().getDeclaredMethod(adderMethodName, type); } catch (ReflectiveOperationException e) { throw new AssertionError(e); } adderMethod.setAccessible(true); - modConfig.getAdders().put(fieldName, key -> { + abstractConfig.getAdders().put(fieldName, key -> { try { adderMethod.invoke(null, key); } catch (ReflectiveOperationException e) { @@ -246,7 +251,7 @@ private static void initMap(ModConfigImpl modConfig, Field field, Config annotat } catch (ReflectiveOperationException e) { throw new AssertionError(e); } - modConfig.getPutters().put(fieldName, (key, value) -> { + abstractConfig.getPutters().put(fieldName, (key, value) -> { try { put.invoke(field.get(null), key, value); } catch (ReflectiveOperationException e) { @@ -258,12 +263,12 @@ private static void initMap(ModConfigImpl modConfig, Field field, Config annotat Class valueType = putter.valueType() == Config.EMPTY.class ? (Class) types[1] : putter.valueType(); Method putterMethod; try { - putterMethod = modConfig.getConfigsClass().getDeclaredMethod(putterMethodName, keyType, valueType); + putterMethod = abstractConfig.getConfigsClass().getDeclaredMethod(putterMethodName, keyType, valueType); } catch (ReflectiveOperationException e) { throw new AssertionError(e); } putterMethod.setAccessible(true); - modConfig.getPutters().put(fieldName, (key, value) -> { + abstractConfig.getPutters().put(fieldName, (key, value) -> { try { putterMethod.invoke(null, key, value); } catch (ReflectiveOperationException e) { @@ -285,7 +290,7 @@ private static void initMap(ModConfigImpl modConfig, Field field, Config annotat } catch (ReflectiveOperationException e) { throw new AssertionError(e); } - modConfig.getRemovers().put(fieldName, key -> { + abstractConfig.getRemovers().put(fieldName, key -> { try { remove.invoke(field.get(null), key); } catch (ReflectiveOperationException e) { @@ -296,12 +301,12 @@ private static void initMap(ModConfigImpl modConfig, Field field, Config annotat Class type = remover.type() == Config.EMPTY.class ? (Class) types[0] : remover.type(); Method removerMethod; try { - removerMethod = modConfig.getConfigsClass().getDeclaredMethod(removerMethodName, type); + removerMethod = abstractConfig.getConfigsClass().getDeclaredMethod(removerMethodName, type); } catch (ReflectiveOperationException e) { throw new AssertionError(e); } removerMethod.setAccessible(true); - modConfig.getRemovers().put(fieldName, key -> { + abstractConfig.getRemovers().put(fieldName, key -> { try { removerMethod.invoke(null, key); } catch (ReflectiveOperationException e) { @@ -314,14 +319,14 @@ private static void initMap(ModConfigImpl modConfig, Field field, Config annotat } } - private static void initObject(ModConfigImpl modConfig, Field field, Config annotation) { + private static void initObject(AbstractConfigImpl abstractConfig, Field field, Config annotation) { String fieldName = field.getName(); Config.Setter setter = annotation.setter(); String setterMethodName = setter.value(); //noinspection StatementWithEmptyBody if (setterMethodName.equals("none")) { } else if (setterMethodName.isEmpty()) { - modConfig.getSetters().put(fieldName, value -> { + abstractConfig.getSetters().put(fieldName, value -> { try { field.set(null, value); } catch (ReflectiveOperationException e) { @@ -332,12 +337,12 @@ private static void initObject(ModConfigImpl modConfig, Field field, Config anno Class type = setter.type() == Config.EMPTY.class ? field.getType() : setter.type(); Method setterMethod; try { - setterMethod = modConfig.getConfigsClass().getDeclaredMethod(setterMethodName, type); + setterMethod = abstractConfig.getConfigsClass().getDeclaredMethod(setterMethodName, type); } catch (ReflectiveOperationException e) { throw new AssertionError(e); } setterMethod.setAccessible(true); - modConfig.getSetters().put(fieldName, value -> { + abstractConfig.getSetters().put(fieldName, value -> { try { setterMethod.invoke(null, value); } catch (ReflectiveOperationException e) { diff --git a/src/main/java/dev/xpple/betterconfig/impl/package-info.java b/common/src/main/java/dev/xpple/betterconfig/impl/package-info.java similarity index 100% rename from src/main/java/dev/xpple/betterconfig/impl/package-info.java rename to common/src/main/java/dev/xpple/betterconfig/impl/package-info.java diff --git a/src/main/java/dev/xpple/betterconfig/util/CheckedBiConsumer.java b/common/src/main/java/dev/xpple/betterconfig/util/CheckedBiConsumer.java similarity index 100% rename from src/main/java/dev/xpple/betterconfig/util/CheckedBiConsumer.java rename to common/src/main/java/dev/xpple/betterconfig/util/CheckedBiConsumer.java diff --git a/src/main/java/dev/xpple/betterconfig/util/CheckedBiFunction.java b/common/src/main/java/dev/xpple/betterconfig/util/CheckedBiFunction.java similarity index 100% rename from src/main/java/dev/xpple/betterconfig/util/CheckedBiFunction.java rename to common/src/main/java/dev/xpple/betterconfig/util/CheckedBiFunction.java diff --git a/src/main/java/dev/xpple/betterconfig/util/CheckedConsumer.java b/common/src/main/java/dev/xpple/betterconfig/util/CheckedConsumer.java similarity index 100% rename from src/main/java/dev/xpple/betterconfig/util/CheckedConsumer.java rename to common/src/main/java/dev/xpple/betterconfig/util/CheckedConsumer.java diff --git a/src/main/java/dev/xpple/betterconfig/util/CheckedFunction.java b/common/src/main/java/dev/xpple/betterconfig/util/CheckedFunction.java similarity index 100% rename from src/main/java/dev/xpple/betterconfig/util/CheckedFunction.java rename to common/src/main/java/dev/xpple/betterconfig/util/CheckedFunction.java diff --git a/fabric/build.gradle b/fabric/build.gradle new file mode 100644 index 0000000..cd7bdc9 --- /dev/null +++ b/fabric/build.gradle @@ -0,0 +1,146 @@ +plugins { + id 'fabric-loom' version '1.2-SNAPSHOT' + id 'maven-publish' +} + +sourceCompatibility = JavaVersion.VERSION_17 +targetCompatibility = JavaVersion.VERSION_17 + +archivesBaseName = project.archives_base_name +version = "${project.base_version}-fabric" +group = project.maven_group + +loom { + splitEnvironmentSourceSets() +} + +sourceSets { + testmod { + compileClasspath += main.compileClasspath + runtimeClasspath += main.runtimeClasspath + + compileClasspath += client.compileClasspath + runtimeClasspath += client.runtimeClasspath + } +} + +loom { + mods { + betterconfig { + sourceSet sourceSets.main + sourceSet sourceSets.client + } + testmod { + sourceSet sourceSets.testmod + } + } + + runs { + testmodClient { + client() + name = "Test Mod Client" + source sourceSets.testmod + } + testmodServer { + server() + name = "Test Mod Server" + source sourceSets.testmod + } + } +} + +repositories { + // Add repositories to retrieve artifacts from in here. + // You should only use this when depending on other mods because + // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. + // See https://docs.gradle.org/current/userguide/declaring_repositories.html + // for more information about repositories. +} + +configurations { + includeInJar +} + +dependencies { + includeInJar project(':common') + + // To change the versions see the gradle.properties file + minecraft "com.mojang:minecraft:${project.minecraft_version}" + mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + modImplementation "net.fabricmc:fabric-loader:${project.fabric_loader_version}" + + // Fabric API. This is technically optional, but you probably want it anyway. + modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}" + + // Uncomment the following line to enable the deprecated Fabric API modules. + // These are included in the Fabric API production distribution and allow you to update your mod to the latest modules at a later more convenient time. + + // modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}" + + configurations.implementation.extendsFrom(configurations.includeInJar) +} + +processResources { + def props = [base_version: project.version, fabric_loader_version: project.fabric_loader_version] + inputs.properties props + filesMatching("fabric.mod.json") { + expand props + } +} + +tasks.withType(JavaCompile).configureEach { + it.options.release = 17 +} + +java { + // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task + // if it is present. + // If you remove this line, sources will not be generated. + withSourcesJar() +} + +jar { + from("LICENSE") { + rename {"${it}_${project.archivesBaseName}"} + } + dependsOn ':common:remapJar' + from { + configurations.includeInJar.collect { + it.isDirectory() ? it : zipTree(it) + } + } +} + +// configure the maven publication +publishing { + publications { + mavenJava(MavenPublication) { + artifactId project.archivesBaseName + from components.java + } + } + + // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. + repositories { + // Add repositories to publish to here. + // Notice: This block does NOT have the same function as the block in the top level. + // The repositories here will be used for publishing your artifact, not for + // retrieving dependencies. + maven { + name = "xpple" + url = "sftp://xpple.dev:22/maven.xpple.dev/maven2" + credentials { + username = System.getenv("MAVEN_USER") + password = System.getenv("MAVEN_PASS") + } + } + maven { + name = "GitHubPackages" + url = "https://maven.pkg.github.com/xpple/BetterConfig" + credentials { + username = System.getenv("GITHUB_ACTOR") + password = System.getenv("GITHUB_TOKEN") + } + } + } +} diff --git a/src/client/java/dev/xpple/betterconfig/BetterConfigClient.java b/fabric/src/client/java/dev/xpple/betterconfig/BetterConfigClient.java similarity index 100% rename from src/client/java/dev/xpple/betterconfig/BetterConfigClient.java rename to fabric/src/client/java/dev/xpple/betterconfig/BetterConfigClient.java 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 new file mode 100644 index 0000000..0749bc1 --- /dev/null +++ b/fabric/src/client/java/dev/xpple/betterconfig/command/client/ConfigCommandClient.java @@ -0,0 +1,72 @@ +package dev.xpple.betterconfig.command.client; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.SuggestionProvider; +import dev.xpple.betterconfig.command.ConfigCommandHelper; +import dev.xpple.betterconfig.command.suggestion.EnumSuggestionProvider; +import dev.xpple.betterconfig.impl.AbstractConfigImpl; +import dev.xpple.betterconfig.impl.BetterConfigImpl; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.text.Text; + +public class ConfigCommandClient extends ConfigCommandHelper { + + @Override + protected > SuggestionProvider enumSuggestionProvider(Class type) { + return new EnumSuggestionProvider<>(type); + } + + @Override + protected DynamicCommandExceptionType invalidEnumException() { + return new DynamicCommandExceptionType(value -> Text.translatable("argument.enum.invalid", value)); + } + + @SuppressWarnings("unchecked") + public void register(CommandDispatcher dispatcher) { + dispatcher.register(this.create("cconfig", BetterConfigImpl.getModConfigs().values().stream().map(modConfig -> (AbstractConfigImpl) modConfig).toList())); + } + + @Override + protected int get(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config) { + source.sendFeedback(Text.translatable("betterconfig.commands.config.get", config, abstractConfig.asString(config))); + return Command.SINGLE_SUCCESS; + } + + @Override + protected int reset(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config) { + abstractConfig.reset(config); + source.sendFeedback(Text.translatable("betterconfig.commands.config.reset", config, abstractConfig.asString(config))); + return Command.SINGLE_SUCCESS; + } + + @Override + protected int set(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { + abstractConfig.set(config, value); + source.sendFeedback(Text.translatable("betterconfig.commands.config.set", config, abstractConfig.asString(config))); + return Command.SINGLE_SUCCESS; + } + + @Override + protected int add(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { + abstractConfig.add(config, value); + source.sendFeedback(Text.translatable("betterconfig.commands.config.add", abstractConfig.asString(value), config)); + return Command.SINGLE_SUCCESS; + } + + @Override + protected int put(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config, Object key, Object value) throws CommandSyntaxException { + abstractConfig.put(config, key, value); + source.sendFeedback(Text.translatable("betterconfig.commands.config.put", key, abstractConfig.asString(value), config)); + return Command.SINGLE_SUCCESS; + } + + @Override + protected int remove(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { + abstractConfig.remove(config, value); + source.sendFeedback(Text.translatable("betterconfig.commands.config.remove", abstractConfig.asString(value), config)); + return Command.SINGLE_SUCCESS; + } +} diff --git a/src/client/resources/betterconfig.mixins.client.json b/fabric/src/client/resources/betterconfig.mixins.client.json similarity index 100% rename from src/client/resources/betterconfig.mixins.client.json rename to fabric/src/client/resources/betterconfig.mixins.client.json diff --git a/src/main/java/dev/xpple/betterconfig/BetterConfig.java b/fabric/src/main/java/dev/xpple/betterconfig/BetterConfig.java similarity index 83% rename from src/main/java/dev/xpple/betterconfig/BetterConfig.java rename to fabric/src/main/java/dev/xpple/betterconfig/BetterConfig.java index fec6070..ad7be12 100644 --- a/src/main/java/dev/xpple/betterconfig/BetterConfig.java +++ b/fabric/src/main/java/dev/xpple/betterconfig/BetterConfig.java @@ -8,18 +8,13 @@ import net.minecraft.command.CommandRegistryAccess; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import java.nio.file.Path; public class BetterConfig implements DedicatedServerModInitializer { - public static final String MOD_ID = "betterconfig"; public static final Path MOD_PATH = FabricLoader.getInstance().getConfigDir(); - public static final Logger LOGGER = LogManager.getLogger(MOD_ID); - @Override public void onInitializeServer() { CommandRegistrationCallback.EVENT.register(BetterConfig::registerCommands); diff --git a/src/main/java/dev/xpple/betterconfig/api/BetterConfigAPI.java b/fabric/src/main/java/dev/xpple/betterconfig/api/BetterConfigAPI.java similarity index 100% rename from src/main/java/dev/xpple/betterconfig/api/BetterConfigAPI.java rename to fabric/src/main/java/dev/xpple/betterconfig/api/BetterConfigAPI.java diff --git a/fabric/src/main/java/dev/xpple/betterconfig/api/ModConfig.java b/fabric/src/main/java/dev/xpple/betterconfig/api/ModConfig.java new file mode 100644 index 0000000..9cb1821 --- /dev/null +++ b/fabric/src/main/java/dev/xpple/betterconfig/api/ModConfig.java @@ -0,0 +1,9 @@ +package dev.xpple.betterconfig.api; + +public interface ModConfig extends AbstractConfig { + /** + * Get the identifier of the mod of this configuration. + * @return the mod's identifier + */ + String getModId(); +} diff --git a/fabric/src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java b/fabric/src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java new file mode 100644 index 0000000..bb12e80 --- /dev/null +++ b/fabric/src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java @@ -0,0 +1,26 @@ +package dev.xpple.betterconfig.api; + +import dev.xpple.betterconfig.impl.BetterConfigInternals; +import dev.xpple.betterconfig.impl.BetterConfigImpl; +import dev.xpple.betterconfig.impl.ModConfigImpl; +import net.minecraft.command.CommandSource; + +public class ModConfigBuilder extends AbstractConfigBuilder { + + private final String modId; + + public ModConfigBuilder(String modId, Class configsClass) { + super(configsClass); + this.modId = modId; + } + + @Override + public void build() { + ModConfigImpl modConfig = new ModConfigImpl<>(this.modId, this.configsClass, this.builder.create(), this.arguments, this.suggestors); + if (BetterConfigImpl.getModConfigs().putIfAbsent(this.modId, modConfig) == null) { + BetterConfigInternals.init(modConfig); + return; + } + throw new IllegalArgumentException(this.modId); + } +} diff --git a/fabric/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java b/fabric/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java new file mode 100644 index 0000000..c073893 --- /dev/null +++ b/fabric/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java @@ -0,0 +1,71 @@ +package dev.xpple.betterconfig.command; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.SuggestionProvider; +import dev.xpple.betterconfig.command.suggestion.EnumSuggestionProvider; +import dev.xpple.betterconfig.impl.AbstractConfigImpl; +import dev.xpple.betterconfig.impl.BetterConfigImpl; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.Text; + +public class ConfigCommand extends ConfigCommandHelper { + + @Override + protected > SuggestionProvider enumSuggestionProvider(Class type) { + return new EnumSuggestionProvider<>(type); + } + + @Override + protected DynamicCommandExceptionType invalidEnumException() { + return new DynamicCommandExceptionType(value -> Text.translatable("argument.enum.invalid", value)); + } + + @SuppressWarnings("unchecked") + public void register(CommandDispatcher dispatcher) { + dispatcher.register(this.create("config", BetterConfigImpl.getModConfigs().values().stream().map(modConfig -> (AbstractConfigImpl) modConfig).toList()).requires(source -> source.hasPermissionLevel(4))); + } + + @Override + protected int get(ServerCommandSource source, AbstractConfigImpl abstractConfig, String config) { + source.sendFeedback(() -> Text.translatableWithFallback("betterconfig.commands.config.get", "%s is currently set to %s.", config, abstractConfig.asString(config)), true); + return Command.SINGLE_SUCCESS; + } + + @Override + protected int reset(ServerCommandSource source, AbstractConfigImpl abstractConfig, String config) { + abstractConfig.reset(config); + source.sendFeedback(() -> Text.translatableWithFallback("betterconfig.commands.config.reset", "%s has been reset to %s.", config, abstractConfig.asString(config)), true); + return Command.SINGLE_SUCCESS; + } + + @Override + protected int set(ServerCommandSource source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { + abstractConfig.set(config, value); + source.sendFeedback(() -> Text.translatableWithFallback("betterconfig.commands.config.set", "%s has been set to %s.", config, abstractConfig.asString(config)), true); + return Command.SINGLE_SUCCESS; + } + + @Override + protected int add(ServerCommandSource source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { + abstractConfig.add(config, value); + source.sendFeedback(() -> Text.translatableWithFallback("betterconfig.commands.config.add", "%s has been added to %s.", abstractConfig.asString(value), config), true); + return Command.SINGLE_SUCCESS; + } + + @Override + protected int put(ServerCommandSource source, AbstractConfigImpl abstractConfig, String config, Object key, Object value) throws CommandSyntaxException { + abstractConfig.put(config, key, value); + source.sendFeedback(() -> Text.translatableWithFallback("betterconfig.commands.config.put", "The mapping %s=%s has been added to %s.", key, abstractConfig.asString(value), config), true); + return Command.SINGLE_SUCCESS; + } + + @Override + protected int remove(ServerCommandSource source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { + abstractConfig.remove(config, value); + source.sendFeedback(() -> Text.translatableWithFallback("betterconfig.commands.config.remove", "%s has been removed from %s.", abstractConfig.asString(value), config), true); + return Command.SINGLE_SUCCESS; + } +} diff --git a/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java b/fabric/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java similarity index 66% rename from src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java rename to fabric/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java index fcd87d3..85182d6 100644 --- a/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java +++ b/fabric/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java @@ -1,7 +1,6 @@ package dev.xpple.betterconfig.command.suggestion; import com.mojang.brigadier.context.CommandContext; -import com.mojang.brigadier.suggestion.SuggestionProvider; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; import net.minecraft.command.CommandSource; @@ -9,16 +8,14 @@ import java.util.Arrays; import java.util.concurrent.CompletableFuture; -public class EnumSuggestionProvider> implements SuggestionProvider { - - private final Class enumClass; +public class EnumSuggestionProvider> extends AbstractEnumSuggestionProvider { public EnumSuggestionProvider(Class enumClass) { - this.enumClass = enumClass; + super(enumClass); } @Override - public CompletableFuture getSuggestions(CommandContext context, SuggestionsBuilder builder) { + public CompletableFuture getSuggestions(CommandContext context, SuggestionsBuilder builder) { return CommandSource.suggestMatching(Arrays.stream(this.enumClass.getEnumConstants()).map(Enum::name), builder); } } diff --git a/src/main/java/dev/xpple/betterconfig/impl/BetterConfigImpl.java b/fabric/src/main/java/dev/xpple/betterconfig/impl/BetterConfigImpl.java similarity index 80% rename from src/main/java/dev/xpple/betterconfig/impl/BetterConfigImpl.java rename to fabric/src/main/java/dev/xpple/betterconfig/impl/BetterConfigImpl.java index 9e83d6f..a9b1e0b 100644 --- a/src/main/java/dev/xpple/betterconfig/impl/BetterConfigImpl.java +++ b/fabric/src/main/java/dev/xpple/betterconfig/impl/BetterConfigImpl.java @@ -8,7 +8,7 @@ public class BetterConfigImpl implements BetterConfigAPI { - private static final Map modConfigs = new HashMap<>(); + private static final Map> modConfigs = new HashMap<>(); @Override public ModConfig getModConfig(String modId) { @@ -19,7 +19,7 @@ public ModConfig getModConfig(String modId) { return modConfig; } - public static Map getModConfigs() { + public static Map> getModConfigs() { return modConfigs; } diff --git a/fabric/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java b/fabric/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java new file mode 100644 index 0000000..496e76f --- /dev/null +++ b/fabric/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java @@ -0,0 +1,36 @@ +package dev.xpple.betterconfig.impl; + +import com.google.gson.Gson; +import dev.xpple.betterconfig.api.ModConfig; +import net.minecraft.command.CommandSource; +import org.apache.commons.lang3.tuple.Pair; + +import java.nio.file.Path; +import java.util.Map; + +import static dev.xpple.betterconfig.BetterConfig.MOD_PATH; + +public class ModConfigImpl extends AbstractConfigImpl implements ModConfig { + + private final String modId; + + public ModConfigImpl(String modId, Class configsClass, Gson gson, Map, Pair> arguments, Map, Pair> suggestors) { + super(configsClass, gson, arguments, suggestors); + this.modId = modId; + } + + @Override + public String getModId() { + return this.modId; + } + + @Override + public Path getConfigsPath() { + return MOD_PATH.resolve(this.modId).resolve("config.json"); + } + + @Override + public String getIdentifier() { + return this.getModId(); + } +} diff --git a/src/main/resources/assets/betterconfig/icon.png b/fabric/src/main/resources/assets/betterconfig/icon.png similarity index 100% rename from src/main/resources/assets/betterconfig/icon.png rename to fabric/src/main/resources/assets/betterconfig/icon.png diff --git a/src/main/resources/assets/betterconfig/lang/en_us.json b/fabric/src/main/resources/assets/betterconfig/lang/en_us.json similarity index 100% rename from src/main/resources/assets/betterconfig/lang/en_us.json rename to fabric/src/main/resources/assets/betterconfig/lang/en_us.json diff --git a/src/main/resources/assets/betterconfig/lang/fr_fr.json b/fabric/src/main/resources/assets/betterconfig/lang/fr_fr.json similarity index 100% rename from src/main/resources/assets/betterconfig/lang/fr_fr.json rename to fabric/src/main/resources/assets/betterconfig/lang/fr_fr.json diff --git a/src/main/resources/betterconfig.mixins.json b/fabric/src/main/resources/betterconfig.mixins.json similarity index 100% rename from src/main/resources/betterconfig.mixins.json rename to fabric/src/main/resources/betterconfig.mixins.json diff --git a/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json similarity index 91% rename from src/main/resources/fabric.mod.json rename to fabric/src/main/resources/fabric.mod.json index 725c7e5..277289e 100644 --- a/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -1,7 +1,7 @@ { "schemaVersion": 1, "id": "betterconfig", - "version": "${version}", + "version": "${base_version}", "name": "BetterConfig", "description": "A very powerful and easy to use command based configuration library for servers and clients.", "authors": [ @@ -30,7 +30,7 @@ } ], "depends": { - "fabricloader": ">=0.14.17", + "fabricloader": ">=${fabric_loader_version}", "minecraft": "1.20.x", "java": ">=17", "fabric-api": "*" diff --git a/src/testmod/java/dev/xpple/betterconfig/BlockAdapter.java b/fabric/src/testmod/java/dev/xpple/betterconfig/BlockAdapter.java similarity index 100% rename from src/testmod/java/dev/xpple/betterconfig/BlockAdapter.java rename to fabric/src/testmod/java/dev/xpple/betterconfig/BlockAdapter.java diff --git a/src/testmod/java/dev/xpple/betterconfig/BlockArgumentType.java b/fabric/src/testmod/java/dev/xpple/betterconfig/BlockArgumentType.java similarity index 100% rename from src/testmod/java/dev/xpple/betterconfig/BlockArgumentType.java rename to fabric/src/testmod/java/dev/xpple/betterconfig/BlockArgumentType.java diff --git a/src/testmod/java/dev/xpple/betterconfig/BlockSuggestionProvider.java b/fabric/src/testmod/java/dev/xpple/betterconfig/BlockSuggestionProvider.java similarity index 100% rename from src/testmod/java/dev/xpple/betterconfig/BlockSuggestionProvider.java rename to fabric/src/testmod/java/dev/xpple/betterconfig/BlockSuggestionProvider.java diff --git a/src/testmod/java/dev/xpple/betterconfig/Configs.java b/fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java similarity index 100% rename from src/testmod/java/dev/xpple/betterconfig/Configs.java rename to fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java diff --git a/src/testmod/java/dev/xpple/betterconfig/TestEnum.java b/fabric/src/testmod/java/dev/xpple/betterconfig/TestEnum.java similarity index 100% rename from src/testmod/java/dev/xpple/betterconfig/TestEnum.java rename to fabric/src/testmod/java/dev/xpple/betterconfig/TestEnum.java diff --git a/src/testmod/java/dev/xpple/betterconfig/TestMod.java b/fabric/src/testmod/java/dev/xpple/betterconfig/TestMod.java similarity index 84% rename from src/testmod/java/dev/xpple/betterconfig/TestMod.java rename to fabric/src/testmod/java/dev/xpple/betterconfig/TestMod.java index cca5c4c..a970149 100644 --- a/src/testmod/java/dev/xpple/betterconfig/TestMod.java +++ b/fabric/src/testmod/java/dev/xpple/betterconfig/TestMod.java @@ -3,12 +3,10 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import dev.xpple.betterconfig.api.ModConfigBuilder; import net.fabricmc.api.DedicatedServerModInitializer; -import net.fabricmc.fabric.api.command.v2.ArgumentTypeRegistry; import net.minecraft.block.Block; -import net.minecraft.command.argument.serialize.ConstantArgumentSerializer; import net.minecraft.registry.Registries; import net.minecraft.util.Identifier; -import net.minecraft.util.Pair; +import org.apache.commons.lang3.tuple.Pair; public class TestMod implements DedicatedServerModInitializer { @Override @@ -16,7 +14,7 @@ public void onInitializeServer() { //ArgumentTypeRegistry.registerArgumentType(new Identifier("testmod", "block"), BlockArgumentType.class, ConstantArgumentSerializer.of(BlockArgumentType::block)); new ModConfigBuilder("testmod", Configs.class) - .registerTypeHierarchyWithSuggestor(Block.class, new BlockAdapter(), new Pair<>(BlockSuggestionProvider::new, (ctx, name) -> { + .registerTypeHierarchyWithSuggestor(Block.class, new BlockAdapter(), Pair.of(BlockSuggestionProvider::new, (ctx, name) -> { String blockString = ctx.getArgument(name, String.class); Identifier blockId = Identifier.tryParse(blockString); if (blockId == null) { diff --git a/src/testmod/java/dev/xpple/betterconfig/TestModClient.java b/fabric/src/testmod/java/dev/xpple/betterconfig/TestModClient.java similarity index 77% rename from src/testmod/java/dev/xpple/betterconfig/TestModClient.java rename to fabric/src/testmod/java/dev/xpple/betterconfig/TestModClient.java index 641783a..fb3ca17 100644 --- a/src/testmod/java/dev/xpple/betterconfig/TestModClient.java +++ b/fabric/src/testmod/java/dev/xpple/betterconfig/TestModClient.java @@ -3,13 +3,13 @@ import dev.xpple.betterconfig.api.ModConfigBuilder; import net.fabricmc.api.ClientModInitializer; import net.minecraft.block.Block; -import net.minecraft.util.Pair; +import org.apache.commons.lang3.tuple.Pair; public class TestModClient implements ClientModInitializer { @Override public void onInitializeClient() { new ModConfigBuilder("testmodclient", Configs.class) - .registerTypeHierarchyWithArgument(Block.class, new BlockAdapter(), new Pair<>(BlockArgumentType::block, BlockArgumentType::getBlock)) + .registerTypeHierarchyWithArgument(Block.class, new BlockAdapter(), Pair.of(BlockArgumentType::block, BlockArgumentType::getBlock)) .build(); } } diff --git a/src/testmod/resources/fabric.mod.json b/fabric/src/testmod/resources/fabric.mod.json similarity index 100% rename from src/testmod/resources/fabric.mod.json rename to fabric/src/testmod/resources/fabric.mod.json diff --git a/gradle.properties b/gradle.properties index d684603..288d4e9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,16 +2,19 @@ org.gradle.jvmargs=-Xmx1G org.gradle.parallel=true -# Fabric Properties +# BetterConfig Properties +base_version=1.1.5-multi-platform +maven_group=dev.xpple +archives_base_name=betterconfig + +# Fabric Loader Properties # check these on https://fabricmc.net/develop minecraft_version=1.20.1 yarn_mappings=1.20.1+build.9 -loader_version=0.14.21 +fabric_loader_version=0.14.21 -# Mod Properties -mod_version=1.1.5 -maven_group=dev.xpple -archives_base_name=betterconfig +# Fabric Properties +fabric_api_version=0.85.0+1.20.1 -# Dependencies -fabric_version=0.85.0+1.20.1 +# Paper Properties +paper_api_version=1.20 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 943f0cbfa754578e88a3dae77fce6e3dea56edbf..033e24c4cdf41af1ab109bc7f253b2b887023340 100644 GIT binary patch delta 26632 zcmY(q1CS;`vo1WgZQIt4ZQHi(cgN;Cw(Xf6+dH;BJ2rNVyWctI|L;8!9bH*ji0 zd@?Ja3f~7$xB-V$mIH^t0D>Z5CgGujVk9xSfc{qv83F_Z#L3l)864#Q_E^XK??xa5 zC?P0DGa0BO+&@JUywiWFrT?eV2m$wBqYpwf*uMe-xdGyzK5!4Wc?R7d^q;u>Pc+Ar z{3kY7V@W{$)7%l9|GV$(<2L^#j0XRw|4DlPpRsNfn*YW&PteqXVPk-Rz`*=_BoPq) za(Fp7Xb=!@R1gpWpa~`+5Sa)XICDq~8Pe?7UxJd_5yu2|~_=yWmbXC`e-Tr8O8x(zdt)iZ1s^ zXT*Y`b0c!6_()7xz{Ccba97RRV&N!!I5C2BK;eg`9)HI2t$mzHOaHDIwTAG^XxEY? zCrY`)|43^CP#-dVtYXuqdPYscy5glEPdB5Mm@dpK<<(bb5$-V$X%ONoA z);JlOSAQV_3EtsVxK5N$n19fOg@s=D9(fdNrfWMS zp)S56N;Ut9i8Uq%aXXm~$tFrm9;U0*XFTw-<1%~IZu5mF-R~cjnc$3ofsRd`ZQUV` zEzh9hzwF|*JgOr>nd|%Me_=!UY9VqRk(wV%!aYx)wm0G_RH{rh_2r&yS_gJPS^ps6 zL1_G?TEycFsK1{xQrij|EDFuB&m?>jww2~K2-3SKAMCO(D~z+o4bV_qhMgiCeYtjY z;NjV}j}No#5_ls@*GJU`7z&wXH$%I7g&dnJsp|G!8s0cl@a8Pxma;J)(YP^sDYtP$ zmlh%T?aKocW%6m~k(xvY+0pV+Z*%(7g+6oWXSUCeEPm%5@weR1jSj&PX}S_Bih+af z*p*(k2WAfh)#eQ@PMsAPGX@R}J%BwlEpMA_ZWuDT?D&cd#Az1;3P2g*(uy?-Cjnu> zsqG>IRKpN>OjnA0uq!uF7b5Cf5St1z8(N=wsj96{ci3%aJt+Hgk(PW*}s9Lwj2?@-Gj^Oq3*V1vWdrv<}12wvu^u=R+ddk zpzaLAOnW*i3CTEh)?vFDxqc%#!&5+Zzs`NeIT2sY>x+t#v9&=-a8^>X(v~<6Drkcw5mA%yj4)) zCq{P+I^2$#@mKuw1K5F9axjn}M(ss-FapfBu~YRHbrix8&^~yfTHufsmPgIe22yJy z$sI0yC_iCfeD>(b+F95Pxps8kdaTRU0~x*ADZI_$DDbUX*p)HLGU6*;TgKNVHAEOABhJuhs|n3O@0%O&Pe6x}H$#by&{i3j7M_uF~J z&BlnU_QMShV4v#=-=3_O*|phe{|T$FVT6(k$4InFXeDzoapWH7HPga~xy1W=tHu_! zV+Y~Lm*0vBqkQMdUAk*jb+Mo~&PrsS4IyK68(JeasonlOXrO57(c zP&{?Mn}bfVn8FvU^s^ilPfVx91YzI$5U0d?5r=FZQk+5P=Kr+Mj6*=7n5Yw1I}0KbV(#5_Ka ziWd_M4YN|2H!2Mk9H{wPIF*8V4vbwdXFbs$;-OpIbSrmU?5r^X)1X`vjXut$h%4Qp zwS_^9G)o+Ix&Lrrz`Q9i$PrHWp8X;6%Spfu5KOcczWKWiu?4Bn{Ekf5%fxK&%5&DQ zAnj7-u>G6_tKkS13>upCf}!di_b5Mi%FC3C*vS8oKmTzeLbJB2m3^lyrT5 zzb^jt6b5Wf?)Wg(l)DR+lnRA1#Y^q}WXyJ`L!|XCODptz)}d`J^q*x59g=sk-c(3l zKw{JW?O4T~7uKjhq)_?TI#1ml)~1-$qA`PPgq6$wt^C~l{5DUJ-Fnb#OS|G8f8C9Z zHQreAA$H%x@{*!*Y?HrM`Rlpw8mVcmP~e@OZkpA;133c8j7c6(g2n;y8i`;Cso6*s=H(OpiZBlODaJ)9jg%|7T8yQ`}}ktIq!b{hIZ{f2RBAWdQqa@%~4;wI%<5V4Zk| zOuh>o1SARy1cV)UXG;K3HgUIBcQx^}aCI}W7qhl7v$JqzGP5^vb4yj%)56!l_zH)x zgb`y_YlNhe^bL~V#Pt=CD{RS7tu3SF5-yc6h;Yuz@nl1v&H2gydXP^7=ua1{K&F*T zf4fd_?UpGhT z4@VoNP&o!lb+N+({LH^)8j*l8G7%g97bBC_x~4E%IZCQd!%WHCb399J6&cqaHkr;H zeX;}emJQMjsXu;QtZ%| z^CLN#tY+%ui;=9KrP0gxEL<)+HGkLYFH(mYnIZh{Fz#8{!&<*LFB~SiiNBPzp=Qz+ zeG{RIiL7{GkO-;}+P-HCKD7?nyF9J!I9ne*$BcD7jzAnhtTQ4`ISS7RyOBgy&IG4& zn7#w=W(Kbsz7HpCL=uHzd89jT(R+53!xf6kNUaweqI)oyQpaY=yCSWR{=ql9nA?LX zZz7sU4n!wy*~BW7L2CqQHo0_bQj$%Nx=1HiB%$eH<07Qi3Zo?onoILGEIiPXzT6^#Zx5V(nn;%Z+;&NUY zHp5pEzV01dE!hc3U6cE+4%^w=Wuo|XzbL(u!N#&$Jf#HZ1ijTYH)yaOZ^2&+t$(!axLY^xAP(+l|4j$Hl2~{zX>ImyTEH zkZ4Yt$!FWt`)k2u(~CCpHZdA*o+;f2%S%DEO(B8j4m5!Ftq}0Z;@&*ZC&HcYDJHj_ z&JtKAM!Zw*L4q1jE?2$HMS=}%K|Vm3@g#EUmv=|M27P;SIp;3n%5i`5dUPt;S^$MI z9Q*(*env5`*%+o!I2d+Q%(Ih&9gzz2-^V6zjA>R!70tv9F1i zMait<$|4nqI&tr}&p5+NJ+b=#EPiKM6e7#@b%_*|Q~_ll-(ypp^YTK_qD`}V%s(?_ z+Z-|fsr$ntn@@OFG-3)l!aT4qrTjQ)tUk zT%F^?)}4~FR@~WE%HA*ZUnc4Qcj+Z@(y9f(KtQ1X1s#I_6L(kvUu`h}TCOI}&K9oX zHg4{&Hl`l#HcpNjuJ&S1j{mHJ`~PPSa@F*d&_yu5%COT`j>wcTQE4Gt7{|$aaqQ$_ zY(-V8Y)Zq&&e+lhEIiqB(H^z-;VF_|Y!95+M%nd3izp}@n@*-W0#4Yh0zcl~5c}!! z%#%iHLPW7(r*r^pH^u|^&^je|bIC;^$sue*{ce>dJ_CsiX;}!Bf1RaRV%1C0eq9I3 zoqBa+CR*0uz42SSGS>Q+$!8j@n|Ny?dTiR+^`gVn+nMjlScGcw-|pBENr?8P5Efg+ z*cWar4ER9W;eRQrAW^kaK8oD^2~RqY38Y}zT;*lNiNq@s;(RyiqG zEG{<@g@>EGxH51yxbYS{>=6r}_o93LVx9qIYKXuKe<$YlabK~0S}tTJi&=4Lkai`H zZ#ly`uD5Yp4`!EN>6#c1m`@>;DX^0b3m;2FQ2S*6lk{j?SmhC7%$SUc&ArFg{z<93 zog5>j{bdH=vD*oYu&^_5xx=YOQ2Ks$#gSx|d@B1z?Vt6i4nU1lnz$W$_|5VsT1y|l zR-=qjerOl-oueko^sK6SJhzL3Y=07Y0Wir)nbQ@>oYlkl?-fQy`dT5H$LHJ{jKHRl zl21`&h+HK34Fo~o(Xu0=kcKC0Vo^N&kZ?v64sZdnCOO^qw^k*I6oxz!rha!2zo$#h zN_x#cFwU;na-kLX2+VG+&my~%S?_U1K-fcp)Wf_*@Gfco$gt?+BNkZB@NKkiP{4LE z0GOA|511!(pNJCLWL5J%sgtwz>-W%&YJTJosQqM1vv`KBj;PB|Az$q0Du3-WyD4Bpgwi;RQqx&gD`Z zOcdK-YHKXV&EvY~;bHZe7$nbBsGrTT_Q3P!kM;|*%`pLDg`iZc4eMw9f)(3*81D$5 zDu}w#jSB9?JK=RN*F@IE$Omyt>VUE)k}n1cP+TFW-;rJrNNiE^a9TQ}?u2ErfKc4qyn*0% z^_-GvOW*LsoFW@bphfph4h!+=Z;P%$2H84;?yB6h_BTnUshi|NyF(@Kt)18ux{K7m z=AVZ>qkC@YYMY$Yv>h@7%~qSxgMxgkToAB73V9Al=_Smm3`Jji>8flZ)h&X2V%AP) z%&`TIx&_r!vTwqhIWWi9_42TR0vHJ4ozpLBA69-+@qbY>CFI*hMLd|eM;VIKTc`in zCFxb41-(h7TOY94*+&rWl9ZdSnEfp!zA8E4nt(57r1IV^e53hzjKEf&zQf5;KtY$oTBA&i~qmB>x3(H04yX32mB*6KHsH2aXrLEDSMy4*OB0}` zrS+UCLjijSW|y0}?w8-w_j%R){9EYz^9!e+_Je}_XGtuuoyLSKQVxx2GGnM4ff$RT zn~{`~JXQi%%Nd|C%GphxMu{s@Vxd2V*vJ6wq9(nANJhS&7Rrj7tDSU5wBt19;7_tY zM54ZLt-+wv_=mz7H-O9+#}4ftVWQi_nZB~Rb=o0(#b$ag2N%kSqjhReDT{Z;nWYr> zL$S39sXTrDxE{b(@g&MGO_#xy-erJ;aI-K$ zLW6xF-j;VO%M@nqAk~DWGr6#hB^FFG@%tkVB0%&b{kX-gai=AM5L_3&7HHy%L z?K;DNk_P@a8+U{MD%ckFt;UAOf6--8G1E34$Z~nb(hh8IOsP_dnuZj;ipD`&9rlzU zYnfwqwE}EUu|6*0X!|Ri=uq#Ujo)hvxaf`0`Q*kqmP=WV_lC4j>=>xWV6yvovQNgu zTjI5bdeBX0S^iPA{XJgiHmOj@ywR^mjvn1>rT9vqzwT5}Yq-QP=%A~I!RC-w!+J#~l^iqn{=lUX1yIzJ|~&(+ns%AqzhfcPAU#N43h8V(L1IQg4*N znqijUD5jgS!BEp7BknZONE7;S%;N+upxwnq>6muAk@LdOCgwniVJ(o9^2r0hrl6s4?#JX;h&cFLW7BK$%k&?9Sa;c z#B|h3#o`DhhfJnh;OIOq)=$5_svTtN36_CcyQNaumzcGL&Qthu4;b8d)egh2m2a-o zS`2FM3~GZu;QPzLUdJ84ohCxV3a3}=8bIU4lWtzCz8a&Wa&P0gdzGZ`1XGd}qSNXs zW8H%A>3AB$e#P6i4)zKV?v~3dSpiB-=@EB-!`-)DzO2x4i7Qi+?ALh%-*b+tub=5G zp3Sz>;(XM6EaC%`6Ax?Z;av{88tQz1ZL5?jx5IVZfUssaI|2tn*RfS~s?)+p17KV4 z3QMfZay7P%E7#q$xxMpz8`oAOR=`DL1h0(3V3+!g2pb^C!un=SSX2)ofGYq_zG>XI zAO~+)_G=k4oK?R10GA{hM*vrnMOL#V^RHMDpa5f6WHPm}Z@vfKi0aStcaZQXw$e?3 z2mV5S7mTI!QrcZyDrx$>B3x-~Jivh<I`kSxDYdxwKdWp z=^R-hFS0u&=^fTsMz%TZ;jlEk58VN#??Y0)jQrdziI7k9K8GRYwuAdV0>F?w*|2`@ z@N9=$GW0Us8HC+C zMzzS<(Us&KHOCG98{*Oi6sr~TWc$sCWI{M);c9;&}2Xzj|x_AQoMP7utAETgCl*{zKO!!nvUop9%{ z&2HPboc#$IXsd0)G0*7f49=c+8Emm?eg{wGk*wz)1!QGPBwnv zBY3G=p?Fh|&trxIjAv?5R$GgXZoB?Ydt5VSUvOOw$2hLHXvxo_edA|~0EVhq5vJ}V zEVrMOVy28S2(sK-b*f!l+XJ!c_rD`0D`hnCT9cjL{^~joxmR@$&LzP5Vo^k2?}9s)m2)ukbB9zj zGz?uIs9@FAptW<4I!}_0uCicHz`ZA@F|bbZQeM-XI*=Mqi>A^pxIBLAIkGXOb}f4a zEDDz3{wVTpFHPU#d;P;Wz~+i$B?^LfIwAm`%VSjlzYR50Jl2mXk5Ubbn2)b5`nw;7 z3HNc!zrbW2&>v7^t&N$+OjAoeXUW6tkt7LTYzK-XBv6&|y z3Z~5xUFXP;B%;F*N2bljO07MK%`r)I9D;~s#u%0uoBNB6tsv$m{D?R$()3)EFdF#Q zruYsw9rZ}0?Q4%6^!UP*($W;OCwImvY(}mA6B5;&PFEX7rK~U{3>Ntj_=Pjr(Cvth zmi{{xAdEDZ<=Y(ej4t{JX$hs5_xbbbky-gGJdfxS;aa5hZrx4XnjHoC6V5>+<6Bf- z-pt%T%o!#)l}zWa7`Y~@xHbmtN<0zP7>t~0j)!TMhm5Dqf}FL2CwqHriaB?PN)yx{ zTlqZv@?UV2s22qezP)%UM%*+fX1>10*2s*kfbE?ORp7asKAGh}$s73_#7Rjfa<285 zq+ucF&t-SjQifjP&DggeWOm!MPZRx3_g(Sr#KmQ`YTg} zz4iTXe+(;LBRCH@?k56xcS4s!`FgTx9#g|sYla7IJ1+F2LBBL1&(59^TBx=c^ z(_}wP@cQ<+&7OpRh<#>i?zKo%y+p}=YSEFt3D>H_dORJ7x1#fMxO!T7_GRY2T6*5B z{@d0^*kh1|iZ|hq9nt|0@Ybq4De^|Xp+5r$CqC#7VvW6MHzom8fvD)m?j>h2dmX}2 zx$DOjpbV76Cm=lTWd%Xh(K``ev=<(thcf}TtEe6jz$I4cPbTtc*4f(jqhuv~J7m0u z8VywNsP`cM83{RrkjnV+M>Mhay)+6jrFqvs?pM{EXN-}Y*_vn)s~Atow+yA+SVMFW z8`*!i-m}p;0R{lRUJJP0zc??5V@ZYsSj$xu^1X}mzk85quD_Zdt$zCt{gqYlOS@pn zku8mR9_A)HkrrwbisT=ro4A>2l_hIv3{#t#e$P8ffyE$AyveGYMnSxd(U7?tI}R`j zmpu=nXUUnW2DXg0`3Sa_+OwAUisIQs{6 zA>4V2g%7QB8H&6TC?g^Tabni~c7c-#zx=*{4mazfZgD_xH%}%_QC%9V%s&3J%Be$H z95x+I_Dcbv#L2BON%|X$0+afcjwf8K*^Rv|4Og+RYPXCg>U^YwjFD4Hfq%1uafQ-q{UlRuO*o0i9v})pp(qI!P%y&S!wq}M5hUqbdl>`$A0qt=wOII`YFDlkAZ&hcqf_nn#s_R@635een?hu_2ei=i3VS z{y8Q>fW(QDK@pO8K+oO+*(wAG*^CTVqeT3n#;HvbM}n_TimiQohn4b-qTv{O$pM%C zb$|+2kG!b$_6`2Of87Oel6k&=DOnB%-~fOTuq;HKIpvqxZ4WLE1u6xJpp!}`7mSJ) z3`+sZ4$D!nAa$P{D{r}=qiw&u5$)M*S{kF<)|$q&U`mgULcbxQ*R>wd7NeJ5zj9qY z{Vep{v!2YlaPuD67btwab+qNz`ptW?1FQ6LF%S`Djr-k`LD#V~WTAg8QZJe%YtxMf zn7vQTw(>g_$x|ED@YjVUJn2|?;mFexh04D!gqTg=2}a`^h36C$v$UMd478a^IcA8P zeNx6`P989|NrMS-bFWJ?kn^aUZ(k9E@0c0-yG0TcN3=0|;(JQ(pEo+`9+(<|b@$rj z8ZwO{T~5Ipg#2wJt-s(bLw zWlmFxh{!uuwBZ^*!{@wSXx|jG>lhQW^9DxbVLHyjwORQzbEHczUKF12?ClF)r(4F% z=n1q$uVN;BRFcr`Yd!po$lG_|b9%ll_0PO)*SBO^^^TaSpI=X5B*eSHsD&;C;3khI zTWV*a+DMkd+WLphbcv59&X^HxjG5$;^Cet-=w`-6Lz@!eowU!uB7cT>U35zw_OSg@ zI-&On%$3|-e)&t(8(qKhipP71h-XxNhwl*xoLN2VHafZR=oPX5Yq|f1mAhN@u<0Jy zHN$=Wft2gC@cPrfTj$Wr)*l`Sn8!uZn{Q3TjnQE(V_(r3vLwSW!d^#5l9(!-o*$Q9 ziXQ0zZEmz$T*)KU+wcR=&Gr>u@d)eKv`5I? zPZ|~G$3sZqU{7t87;J3Ejdx-dgOxi8k&jvVRd2MpyWCb>-s5ypwiEXQ@W$7*$^G~F z>h${Z{2ZaB&EZ@J+xTEcw8)JvLss{FwchDw8})Q+CBD+ulx}mY>+E3XN!VCQ5Bd)c z#xrY&SW*%y>dRxDw0nsQg)LH8&8UEioBvicmuIC!WQoa^S-g%s(POLjyfzD(Wfe|- znRh_1o8gQiPX}2m@+WHz;3o?a#zoquq|9(g;i#hg z8KhN8SnW%mw7Zs(^Hem&fpUNc3qfof%P-B@g7->-K6iLvH6xpO)a5|KG7x9eM&f-c zmsC!l0GC5dZ^~MEbf$z}5HGY0-jWT=-0^)^c7?VmmkS5>Cfo%au*eXg=#j?C4nHkd z?o$B65`R5p)%D3sooXfALcFQ9kqt0y-!~;~LxS#BWh>?0;hQ?z=ccUo+tS z@Q8coVMF4GbUi5Oku`d=@Uo597g71Xgdu35Y#>k^@|7#igBh>ZP1gIl2T=a0){-3Q zGYwc!q=UKs{C1)NP@echTsS*JR65#1s^GRY=tfSMX?j--u|@dSu2R+DfK@JlawY4V z0i4QnlbtbIr)F#1hYt@wdkiX=O+w+2AVSw=rQBE+);cN!ZVEWBYcQ#bM9gQlid7Iz zj~kYW5fyaK2a`e7;)?xsl94zAnb}0&gv}uW#vAEuPcfnZi)1y(;S7|0mPm+EM=CSn z1?DW5YXuDH7@QOywpKij5<_J$X^}efzsS?n#FJb-slp>lg)!}&M&|d2wd*NOQ-;Z1 z*q1EAqz;O8sCC3DX?H;U%Fp%nC`cJHj*n^b%;wnH<$}idnCP$7a|nj2;M7w!&DF>R z^CH1v(|E%HN5RHCW3>BIMWb!D{@J5#b{~RqH_|`A19f>Y!PP!nNvy~km`V+c`IX1P%itNTla1%k3?d& zaZ7a7zF0#DW~WPF{|Xn|Td}T(1!I)RDO$cX;drhC94*1^i61kqVK{IX7ZxZ_|1O$n zjU&@fk~r055jkn8Av_OXE5+KY{DGQI;}jB=h}-tIn8rijm+!i)nFe1?pDq|L=Hd~= zwUcv*(VJd4>0d@ zk~g^oNaRj0yJ1{(LWcBfoJ5bLC<;j%W}tJA?i8^`?99HNe_;x_Irc-~lPBgrHT0Fv ziXgPPI^>&Lqlr%mlR^v>0tg=>kGr?(BL2N_j(8Yj`vo15Xmmkdz zpqieQI4&=Jj^&sw3eue=<+r54Zg}?{5&PhBl-wucP5Y8z-cKzcvA=!zfG-1l>a9LK zxj*S&-Xugt5(Wfhe^yPrxJ||i1xrQmA`J1f+M!^R0LqeKfa*3+X25S#OvEqJVJ(h! zc2W++uW8arbr#sMV2});uF8seF$)E_`{8pCv#HK zMxz6moeM|Z_-PgLJ$RW?6TYno%AS*?mN9X)uWczAGmLlXdnUqcwV_UV`8d)zI>HM0 zd!XI?*2Yn7cWd=y_5bR|9Y)(3m?TW&(47lOW zf6E_#x?J;3tDOQKUOebN{iQjET&Jhb%gpp_YD`yR2i-jBWPZ>;gnK4j;lW9oWjdiX z86EUa>Ceb%tW2b^PZhS%PWCfUALXQtFuv2;^US|W{})a zVwqmhC1@KTTM51QLMtLP+cxyw>`;`Czi$<8s%FXodEwC7P?Zun-9%VImF};^$7(9iuyoKp^&Xv6ofcZpfWq^Jp6&S&L}t)bB{4R`AAI@Qy(<-)m8z z0MJ+T4KnIYTWl2H;ddrxjcn4AyY(k|JxjN)T1XOdtim~1|G8R$Sn^_kdj3^i5_?W+ zuDbE}S@9$5U%g3JN~r2Q7}Ww_GTA~?_xvI2P>$qXH%&{{ti!B=qRJXgRmfV^nwd84 z5*-adnU2Q4i?61H`mMux!sLx-r9TC}k?g=xP~3GCiAMutVMPp>uu3$L$wcXvn(V@P=1$63hP5G$ zt%6*ua{oRMz{*&tH1{bxIQ=N|h9T&2UI2hjaf+`(ha;$>sJQ%vZ0rDL=kUijsvD1R z@$`j)kuqHpd4oI-flhfl0JxUYrEJZ-x4YY53BDJ4KPuL0a;ob+(Fa0PtzHai`-qd8Ul0b)$uD9>Kn{?sWup{j zo-P-xDr1!O&)!#+`hbO;2!5r^_(TX;feo5up$;ah6Ogo`I;*)3PV1z|{e)q(b$!*} z8IjRdRl5))$qP~8l<(k>Y2X&Wr-X%@!vU5J3c|u0Wl42h=@xQ!oyh z)ZgbN%mh;y>>0!>CTq&iO#maTJ%DzW=Tz?YlGxtaSGi=r&w zcpy1#CP%7S66piQ>Ey-N1$@4U$v_!}7W5=;m|bL(8yZh!^38Y>NXSK;w1E8L*&!NO zT~Irrx(^?oxSvChkZ)w|fD7Rx^hZjZd2pvdTtOyvsBnD4BA2+{!CJgpT^S<{NvlpY zA){hyLV{0t=wY9?BRhtxlFENmlv`aX8|F-QMtI5koOkZ z(>2b_OUd8<4dH(6mE$gMz;}q+ptDt^pDq^=zy7{#Ir{-8U0QiM0W#?6?=2Lya=hIF z%R0=8eeIPMO<6<>+3vU=49^(#G_-~)=k)hyGUo)^hWgIf2A;886gG#o>b}96h~8aP z74PO6zjF>gkE4^TRR8MeYVc+Ijz%Nzh(M+Bza#HRJ}l+@D#ExtUNNn!`orVksn(;! zoTHXgB8Q}~6JM&c1K6Q}^p{9Tx~7*^HTpDb=@FFqjHsxWK@X>Oc7XI3AJXzM%7s?n zfI!T#r<(;7P(i;g=iQFyYB;MfBrJsV_z;u9NbLQk1T5NBVbJhStinjabhT2 z1rOCCeXK9D?1Zv;K$PZKB~#sv1oI;_?jSA%2$1-IUzKr(01g;m-aS+9@l}Ex!A_A# zg0>Khi6Fl9&ffPPG0^50rFmw_QG0$?_s2XENxRao&N*yJw>`YNL)Vx5@ZsE^#wNvu z4c>t-kv@3inpy1U71=Gk0W(v9n0R*fWTk*Td<+5kCDC;X{U}Bkq+a|;{wP~GhD|z@ z5Y&iWi8^qX0w|F(1d3AlB9YBEqw4fCKBB+TVv0g}K4H1Af5rwP!KdD_VTwCq@+qnQ zrqE8cRj-`qipyI$#f{5bKIIJs(rLMvVh_5Y6|$gX(pNQCQ;~M3r6aZF%baF3OV6O$ zwLpS?d{9)0N(h3TAWP55i~deOOu|g){Lt-}xz`$)0jTnvE6ufn>hrX+XUW~U;RZ5| z%_4ntTLw>&8zd9;g#1drS1))^n)N)U_((807UY9Rd5v__;(^x{lI&A`{7a{|Ub(Aa zZ@Xqd(r4p*KWD-ta<3h)6WK5h&ZWlT7N>-nie2UrPJ6MQl z9!J45>|K}HSI}iPw$&-H2^grL;Ou(*l3TDLx&Xw50a6VQ9!(E_JAMQ(%}6RmIl8C!zxKeq+uho1RzRhZzDPhno`8KIRuEN#q{|f;G6x%DJhemZyD@@EUwY6o zuwY~K74IH~Lh)sP{mg@BcRNdXr1o~k;A%aollcA3{t4M*NRic7M2*wI>TrRdYEbHX zRSxKz-z6>9Zcl@w8t7FXzyWl?B3;RZiS1`TiEU55S3H-&}$`vh@%N zqU>D0&01nF_jz=O7OC)=q*LD5Rdymjg}L>-O5zB=#D92BstN?*|3snvDY^e(2f_`Bm!p0iRStwYWB*aRQ*UZLIGcml(b@E?el3-YF6fFq2(k;`CRm zBU>%SR2llLGy%%R)hi{$EWLz3u3ZJVh1LBG4qFcbEzC#90oeircQjHl7Jlde2lsU_ zE*Lb3kgP@~C~hN=F#@}^e&cQN!~3+_ORz$fm@RbYPtcoSZgQ+>fY01wET;O5y%0K3) z{v~enBJk?pxsm39tfBvKQNwc2{-1QEa~~rc=RcN5Iy?vn*?*CDzAB*s6s-Tl9MwEi z!_Y$c7VtDNCcqpZ_eP^M(FuY~5I;yFksbyqnk3E2n3@qxPcpG&XQ$7~c<;R_srlp9 z`zMB1yFxqF|4!|zL_Jydd1~+R-Q2!x>D%VRBO5djJ}$K)0v zgcS3grN&r1EVvmCAgQrrl9A-r{lh4RqTWm%*NSDpIC%gP6Fft8J|qT#X?b6Vf2?bg zE^iEes)$`qHY}(G?zb+Ka~LukT$#pYP-QZ*7UmR91I85GlF?!<)+DR@MNuXp3nOiV z$!S%ff>MTJ@Le(3MFzElZ(!dU90!w0UFO7VnOQ>DN>d^u;B)xpRRnEg*go9Mh?SjJ z%Ste)m2_;Hf~_vE)!cMuxmo9oifZUreM;&dyAPX1yEC*k9U1GnC;#oHjGGLb>@QeQ z?p8cAANkY<%2ndEu~yh1>wI8YiUR?g18;J+f{d5Ek_#GsI8QlxryZLii6k!-sKZ>V zOlGNH9)aWvyV48dT zX&~CxSK+_T?fUU`uP!!}+R6NGV-EAE-d&n{vpV6JF#Ix6J1Y%PKLHu6Q-&d)w>p~0 zL%0}65BAu!35s9q8GDw+pi>I|)r+1C@iamQh>K;D__M*cSd1!z>$Qa+)P?=K^DHdT zkwVB%Ezj)8pSS9LF$HIvr9?`sE@o8Ua{92EKbCXrA$Z-9YqK|N-Bl*uQsxO{QnSv& zVmNxXVG)U0wz9BLFcCqF-Lh+`m9LhgXgYIcumB$HF0f z&!X^t7k^>JU(T8>GPo9ZMk$q2is#m2Izz(2hjtfCPa3SMVP06AgkYtqg?T|YPi zNb*Keppu4h_4`>=aYUd_PM2jDHrc~(SmTLVgYsFTjH1j?(}OQZP$@eId4h{Yh;Fd% zafXn2BsnoCwl#PJ6d$J}KVsnF3^5=D0A@o%IHia_U<>58<^jwWpOq{ZA^{zW%Xj=l zy#|fmy5q_$oi*XcPW=G1fPsw!wSjezFyBZ|MDfj-+xmzKCE-uv|D6SDG%sKD{YTry z1`?HX0sawylyOG$n?3013HLrmnNw)ZNC=5dBTZu|B!Pw4>~go)H3X7{EzMU;-{bg9 z97)z3cMI^}G>3kQ@c3p>X%;uUPJVg2@7)6BpAXMt%pmaET!|7o;h6+sI=I)9?ut?p z@efe0+H;NL#vI_iXVKVSdB!-E*SF7GuKpJtfWv4hcaxYOjz3T?$Pj#hnivO|OwU=G zjBo_?GS!dfm?5tV@Z{H>cAJAc8kN++oaqsTFu0m>)XR$+Le{#Cuoq(edW@*ru%&AX z#e5rCeKHb~)$!DZzn<~Pyod1XT#q)lY9IQOd|Xv_e{j@BIBb@Mnv}YC4~bM+5&y_T z2MCyCTn0VbR4G~(J4DbSsSY>~cEaQ^O4+lO$SpeI-v5f+?7HYq<*;yGmT~D-HOXMi z#bwf|Oh`pC76H?Q0(m5g6Pqi7s6|5H3k*gwnM`GhLDo=x*bHJcpP#wQ0>YrDJFgGJ z%w)18ahn*g4SQ_OH4d|QND5Ka?NuQl18_$9W(>JKLkU@9zln=mE8<~&^Iab|N|h6l ztThuot*2BJuZ2&5O_bIg;IaARjt%$Rr}?Sp{3A8pLs{*@ZtR9(G0`UDRPU%0HOMB< zIHaDyWJIb^#EAutc-7a!`zg?t`%BOTqj(lbI?!VgGeOsyFw`eSQfgD&Q5QsI06VOe zEmgL{d_tbT>M?HIyR`H%R(p9 z_f$Y=bJG3>BxwqB3n?^lF*J${2zhM;ZHwe?ieg})I9F7LNXla8+U-kQyXSyc-Cwr7-yJv8l2D;v=LuWSI|efXliv)_@w0vJrPPtuNv-p8 zl-;^nP&RlyOTQKP>RkXRefK5l`u>_kovX5o4AXozGfxZfTL(v)jt>im-G*6+eEEl^ zV2z+?X0UFz8fk6z)EE5oc21tO&JX1Od! zA8q zzz>1$Nx2vwX|7)J6FC9@Oq7nTAuaF9ne#rje8a=%lSSqi@CE&&{p!+pJY*w!H=)!0 zi~CpK9Y$hqX}98tXYVs3f8Y$aU!}s!3pYU8*D0I&lz)F;{>t8TCzvaAQ7Y(| zoB(aUd}4kOLKG-{65$azJe1(;-4{!Ay8!ZUSDo40hYg@|GWLh}vQ&g<{Qk{)(5qvgBmD?k!^GHa7ZnyqwL&Rqxbg zEcQA2OCBJ>hz;clVJjNsY@{GXhK2CF%o=AG3De_j>PEt0?fU{P?>n~f29L#P5Z?Ag zg<^AVd|(Ov?}+jrB#F1TDV)WYH0hf9GG?q(*i6nJWJpXnfOZ4nQ@q+7%UghDLcCaLuME3j(&pZ-&Db$L@co|$ zwN%()WoAquyw4NHJQ>;}?t$wrfB1SSZl<3;rsZeCr4xR06jI`FZ9+kJPOXiCK#lMx zT?<>gkzl1bbuDI|A`jLqx?S6Yf^PYBnOTyUa6uiymSOTzu9*s$TCIB9mXO-ak{uwEN7E7q5GVrj!jQ5#v!@@9m@ zy(Z_k<>hwNvfajN29Y{h=5b<6xs)a?E2i6^itiC~L6I%h(?t5hdMt~>9}XE!Hub z!gy^jLphNkV&StbmAYAvNV+irWjH$X!%u+1EV`F&IVzWJ%UsuX{SJ;mo+D)KW(#t>yrwS%@V24k5f`EzbU>it(+k`-&vg6bC@96%!+= zohHC$U7KqMsF1iWvKICrLR zSe)X%c%itvyKB+n4#lBp@rB|pi_7BfuEn89aSFw)xI>WwrSG=)dCq;#^LwBDkezEX zGnq{CCCTKU)40JEfccp)Q)*c@7p;$J0XcC8hHXi`tOAWgAlOOM>s_yMu}k>!2E$0P%Z12ik;O^y>6PH4A*E5b(tdOaRB>QoH+g09V9|K#b)H6wMAXL?>5`NxTKt+ zKery7p(pOC2jFVCrkT;>apJ%AFpo^XR}UE9gl0eidRS;#C)KN8n(;{^N{MW;ZRr%3 z^oU`d-xcOv9zVtPonO%xxHs1%=GR{w_Yqvmw=Fo^WF|mZ^r2d{`4tM_H(S_Bq~@xn zV%R}p*(aRbrD4P9xON?Tu=%o)W7Ayj#8Uk+gJJA$#INOSs^bvNQKZH#D4J5|yOqCy zc-XMYc1bc{h76B72%zaik~d#2hZK=H(pX8;OEFEOqF2i^@is;3N7krtHjOUhNnP7& znu$7Q=BuRrY{@O2PIEl;F23}BhC~2$sJ4+)k>LlP#l7fwD%e9!q?BJPo%g)q<@<2<8k zCU}}OPPIxr&ROdD%_(W6H5(q?ssOv*`WX^E`5VN`e%0CSpvGkVJ}3N}r^I!`%BO`( z8&BId?$t=$RJTcSQ)I6-vxiP)u9MgBhy~j~=)tQr$ir3_VexCA*bIey9>-76wJZ71 z-jBk1WCGf-CoD7h+Xi!$6f*mYQ$;XO z6$*ohJLd3}%vA(^PZ>0I6e;G_J>15`svlO^=x~7z9hz@XTI}cat*{a<7b`!weh#eB zCekl{V`cM2Uu9NBo4qQ22q2{adIl~7TrxxT+xs-(kJf8UzhbnMS;T2~T5a*@J#}_G zB2m!~l8&db@-)dXdfG;#J4S|0Spm#U;u!nl^p;&uxifmGqNlX9BkNuYVwILzWqLnt zt1TX(ITm|%& zas%A+OmekfsgA~2W=Iuux=BZ$BC>6UhArgdb4>{KX&`@bch${?FWxHv_l%5wG^){{ zV_(Ul%?gYeVpBpr^suYyS zYj92B;j7dXRy|+pCrq9Yd)WK@%UIE}W7G2N=X2$Fb3q}$wlxH=@i2>*ZLgR$P__GB zM3%vibEsCxG`Ic8%^03u>E&YY8Gjs&9dU2eChal#pd!RIN<{Gl6yuv5X(iySy4u%9 z(?y4^FwEUr$5=XELAnTIQC<|^qId0B635r`iqOB^GlYl)Kvg@G73X}6>^tVWk!tGi z;*;v{M)#4teZyY8)LrL2JYWFEyH+z0-jx+2pCjEklu z_3f|LrAW)WnaEMlLA1)STM%EPd(hKbm(5)vy$c<^;fL^5jnE_oyJf>&&|ni2UN61hbsGOz<6$)I1Wi( zgvgmVf;Q}1g}#;94apEu!-^{Wp2y+N38%m$1fr=)7vS)II5}!WOGx}Ab(*);-VwOo)Z0n))B|6rql`f)U zgQqf>g!yj^RUqasSSX>>jz&Yf8Rld{Dyh3|RG+~whIkfu%wE>HH6j1#^Rj4o3TK5A z={1ApUdBR}>o1#>O65~!9CtY`<}@?>P8VZcA?6=idX5HX*A{oK7ROBhl?kzLV)!rtV$g`pfYG7eaY$^>*xn86S6~HJeG1P zL=7T;X#rGjXfaH8I+Fjnp2eY7O4>!!fGfa7nJ?Hbx0jvm>y<<&6>_KCP5b~?j{!3! zy{bX!7KRt6sKGv3vNPVVb33sEFTK4W|JeaG18$n8Wh^bi0rb{{rF>U0YfD@{g_XpD zzh`J0b{s@82t*&{=CrgDxa*Z!aQw&?8^f^}$&-OP+R-dbFli`+9jB71LNl)*E%@Vr zydy3BY#>ecZs!pU+_1WT#`71v`3Yo9%3|vx9NkUx5tYX*-yisn3>iv)q(7DOg)up& zBNVvIHV~DZyc+m+#Oz8q>qcE9CJVWW`b1ybbp_(MO4SjO{ed)(kt-*ZvTBoN0X=t= zFAWOE=LXvy;#Cx~nHH@UD3}y|ikQ#37(7yGn}z=Gil4K`=E;?9$azOy%|@AV>W}xx z|L_7XzTr{cvCpxgo9~!DylltNl(24}+I4&LCPrAHkW`huA(l zy@!aaN71B_Xdh`hEj-b{f6^>d_t=%$tuyV=G+@^FD!J`0>1cElzJV^JLVP@@4J%8$k8JLcwU_IZFJ-)hlP)PGY zcaS{5-FVGDaYXtOG;?B>8GNeBkQtq3#z>a08K2yCPWtf*#*0kO{?H*4BT`!EG$EQE z#>OKtt%GA(Dd4D3-iD@!#|KQjw_>IPLx3+EKm#kt(Z(K5=`K+(~D3eY_`>?Kr z^v16@U_|)Zx>CDQ@{Yf=d^VJTytmC(HQV$1l<~w16jp2;Db$Qq9fD?}oW8IF)T_>I zqy`;2!)9b4`Xw4SJO##^a&c_pegJi~3~;lR>*Y-%r4Xdh+z9q8c&A4RF@=|}LOv`; zRWYOlmIva>iYja8X{|9VR0H!7nw@fe(+L)iu5`c6-7Wf5@l7S_)79mqaUbAdRSL>0 z4V8>D_YX7)yA9hO;D4`@kG%?zCkO-lyFkAfy|%x& z6U=u)Y6gzhbV1Y$C&N)BW_u#K9=OVWTx%*6A1qc2V%9JQCW|M=B2=r4l{em;VT&_+ zWpu*@8zGkZ#u=+8Zbst4KS8Z@*A}CZ?M-=s*@`TuiZ4|CmKd9pq#rAUTjxof2LKDX%`l$_Ei`D2-pt_U7qi zqgTn2@RpVq;}`KdF7Z8_z&5`Y?B58!HHPnd-28kuM{EgsYnfHV-iXZ^P}NWEC6Cgm z8X5Q$5%>r_+2wx*`owBYO*vi;gKy*7F6;$=ZnMxVu^oD>1lE4lD_0V(raHC7Zz-)- z@Xq`e*4Sb>*7}CoP5`7j2F<0RFI;*Vz4($+XC#xc$=W$_jTv`RJ>QN3l8aCxieyX? zA}0(VBc{BPzyUXsak#pWlGGX3#;1k-6E&6B`ok#CiFU`Jh^oior3Nb5d34mjXG**&uX zXg_@%Df1YOp7MaFf^MrtmC1Ctq_kB)+H&nsZJR0voA0B7n`ThOv$F3rx~KH&Ow)Ot zF9nM2CsXYWyPUt%ES0&7rDws&+H05TmP1lAc?;QJ()XhyD2pGlN?$<$r4U#?$P0vI z354iGku*5OW{?*o(i-mKBf)lVa7;V8KqG~~wz>4p%WvVBdFO)SdRo5Z>?X)JKQUa^ zVJqei?!F_Hl~PFT#={h3@qW0?WoNAGiF`(*iKZ}?1LgNf*5e+aK9Kw*>#CKxeLz|e ztlL+7p!-Qt7QsP~B#PS4iZAe7JlBIQv`*;*E~$~QkpQVO^tP%tnl`k{lRHzLTJA;j z9kQ(4$@YCWc&RQBA!^E_K_m`#o*0Nicc>T)%S6t z2kVBiBK#{Amd16jD0A5YYZ!^m8Xoaf+mMdwbgqVrCx()0SIJEfC^6vX8B0=jNn-iX@! zla`3`n}7_8)4xYrX&|SzDH-0)Ipj7Denj>*p(xoj=B)60c-f&=$g-G$0}%zyv?L}9gp^5$Iw`SxXOVe)h~2HJX66sXcHMVn^@N}wqcKH#3W*1{ z(sj{;w~PUVp;%=Gz#!Yaxu5)@LS!=7y?OK?R4kYmgzsb2l;?SrFZI)=c$6bQHVrdo zBMR;MenLLgYMwJ&MmWXL`!d%*sXxWVy;MqQWd0*&YK}uWjVk^lt73PRBZW%q2qb8+ zU!Q*#f508O{ohl41iZ3-8;eKYGpEv5L6&CYufU!!g$Cz)o2@ z=#wT2;j}qxkv{7ONHjJY?W`w6n()%HBgx;LBrY;xK-miOa+5kJi%!ld9CUyK;AJ7Yx0;;^ebG$MOH?uW>8k!v>+3;4Y8&raPL}@ z$PAmM_m0yz(Y5hMx&YkhILdx{Wl|!XL+Z71x`uA8QhArEwp`V`P#o#GTH<5?FHUP>H%QP5*i_>p-u$PE^hH4RNB#k6$?2)#g0J$Q6~Oz}@)T89%(W`O=x+>xASZ zoX|Q$s5GSO{z`32FzDKtgY~)KC?mXaUE9l8X0fc4%Rlqm97Ft69*W^>QDYGLAn!K& zthDt7vE6o~4NGld^{V8@Rm6DRcqu&+^zHU&zUkss49vs4%8M@YDH3msqd;{?}M+Y_OjYnyhoX;}`-- zHJahCOUisSwLa$A84-AS7yIjNA{=~cpiC*N-)9V*#wlEg6LBh^;=c=cQ|3~7>$dV} z>sK=7c*B1gB|ysGo6?J$Y5Yq4xaU(l{{CXuFQotEm6)9Y!E?U2;H)#WM#>(y-{~YZ zXTZklzOmo1WnKevzwyj^$1oA_{(HJ4ZX%Oz1w|^;Ljj+^114P%gJP2%HRr^!KHae= zv>@69rJ{}n=dmC}7Hq;H19tN@dh-Lh4$yFIn1hno6&Se!XiW}c$gKUgkS?SI&S)jZ zTwMGbecRW5ow2p1Jw5!~p@UKGl||cTXBsesH@ zY|m-WiD#v2otKRM3Dg`LoN2F18{D#8f2*#kvZnpM1$7Q>JN6P`Vg~4bFQ7e9RYnt& zfiHRn0@qS!m1Y)twYRCyRfR= zr#pW-&S>a>JUA5y1@_cKT%V*JV6E-o?_%C zj~Gw9Tu`k^1`!((?$$sYN~sl9-`4I&DL#H0U%YrfXXrE#GplMtA6D@(8f7?p7)flK z5R>Xz3P4S=3JP&?;NJ;x6QQzt@tskGei^+Jwrp5vdgqB+X6#HoLwB@dDg2>9!mWpf z_>4cN2=G2HzAtc7a$4xKP+UNi&Zpt}T8D}KXr)J?;^OL`UnXv75CrpIn8D9}IBe6$ zH`8bHJScpJCoh=>ShJihI>ooSUTD{AZfXFu=E(&aw}Gm~0fKn)iB#9Qe1zU?Y-4+U z^#KR{l+Uo+_n495xY~o-xF0|4gM(fpbPHV^_EJahV zGhiH=oQtoOho3{nGf6e?ffb1~iY(#E&Im~KN>HDV2@RaSD7#F@lHQZhdN~5e5%D=# zSat%8m0$_O$qH|~BLP8`(BhCM!Q_n1%)m;}f&pErA>(XG?1fOq4^m>2TVnJ4z)CoS zv6Mu{*_C($!(74BB2e;)xlv|GCNPi!F=wMqxG*&&Cp?jne@c{H za(S`BsCy-}N+uBU`@=@`2X{$LJYr!zgsSfVUteEg{yPJqHaS)H5al-*FaZn<{qK|B zqzfdlGNdN zGPepiv&7ckr?liSh5T0Dz=8U!n#Ej+-Q1(%`B!KP7`4ikKi2?fXH3}hJ;%BKr$^8y z-;KL<(T8urn6NekQPN$CgE_EW`jW85)Z5KCPyDnXiC&}6-Z>GANEe9M&dKlaoRidI z_>^=5EvVM1%wERfgZI{+yqQ38*Zsa;TPt3kwIQuLWL0;QFzZ7*of-ZVQ|q|BzTSQm zpmmB~6mqfNZOp3^DOkVsPme#Y6JbQhc0S#6VfQMKi%oXqZZ5&WW^cPB31|unv2253 zg-6ansz?_MaffIxD7L47*w!=-{iPW{>q6B1!WRAB^i$twhq&=i)f*>Vcngm;vdQ05 zb>sD>A!waONLz>`o_?&C*Vz|$e*Gx^{Yw%4}^$6IlR? z`Zt!#T1k84G>Pg6&_pB$=g5|JEZ5LAmU<&r&{h(unY+%o_;tq(+{`)#tj>424y1y5 zXu6r7blNM5nnsqE)=KL;apu{Xg)by-krlU1O>&-1gUg6lh4_@kXd=bLB_$;YTFcnh z$}BVUIlG$k#f|zx&G4Z{cJ_8YxN}A7+(mTZ&DgLWryU%#+~)L`A9mN8VU|nFJ zgHIwNYUgZu=98V$$@B$P>>BlwKm|U-L>i|!M%g;_v1n|jOI&GqLuWN+u+82NyzR>` zNvu2bVhFcMESD<}^lnw2yX1#kFNlob8ZU1xlS+6?-i|Aa2k&Uw5D0TCPlmjymajz} z@}L5D05vexfxH^^6XqW1u5jQ>N5AlD|1_UjVS80sJPx4ILF%RO_Yt)v(Bk>lBWD;E z;UyeUY;cE@bz9Do@gjXTp`Sxj!j@RY9Z7J;lBe#f_h z3=W`JD~D6c<%>7qc$;#1$4EPadm1HB3Uyr&XyU_0U0$-_bej`tgu3Vr+U{2CJsI^n z^UmEpoKcEDvDK?fQM9u4>aDTrv=Hp3H3e3Ru#IFpNsF}CrS`}yT&fzp;z^?Fi2sB) z*IC%s*=ht>cdYKO1SeJFoV7;f)2ejtHS#T=SiCK)jH}vSNSbd0E1H*NUd7?zFG_sr zMtq_*n#c^~nIiQEJ&Sa(=YW<{zw8~=J??tza4x=ZnS-nf8?olMcksSffH<{iDI|9n z$rot<)F0!eD_#p>sqZ6;R7p-O;wts5_Agy2W){)eu8e*6^-GgY{Cf#7yFW0$wj~#~ zKdmRbfo@gNRqq)$*#vVHksjC#VWVHTz=Xo@eteicM^YRDVI8hG>F@h?PZbG-&sQ$_ ze&ide<(@i7IsDO)iCbpV46ZR_&5y9QO_{i&(gIRDyh_lB;pXAJ#z`SG>%Ln%|4;~n zQ<3y-AAP_|;q^#>p-j&+!Swk$LYX9qC(eyw0cu^`fe~v*)H4;U55o*!+X2>0r_p!U zf)%6hj0Hl5AouhGRl>Ch%8e3k%&SnlSofh>UBw<<-}-RwJDe|3RGF~ab65{0>eGZ6 z1gd>}=%5X}s1iz5-FH)^wbi=eq7P%YRNoDzhrXsEkOtX|68D3VSA%Kh=+9m#c5~@Y z>k!33!h}PU8XcIk?F*+H)D@}gGTDjMgLzmD&{c`pKy~h+#KZ?879{v*1qhcW=H;xCk3=yd#btz|4y|K-H)bj%A{)4-wch#m5AfLHZkM z)h(`5m%Er))*Bs-NA`?lBK3JAD;@V-v)cPL3~jI9EOqHe>sVj+^VSBSqJwoEuZbOv z=kOMkLE8d!YHPMur^G_`H`&c!G(rs`zF1O;Jqoy*^ozi?@h>@qC87m;Hg(O2GhQvvOJ-h!UJ22=Qb4{ z8ek#jnoXBWR2N}ERjXi=0l-isLa0vJKV`w?0{XGEmmOhT;AO-k14OII8hp4;=1VB{u*+=^DNYYIN~X%H3iJA};<>N$aw{F}g^-5M(C1c2 z;QZ*09h2{nWj>YtsiGino=p@(iw0vnCB8gD>=*8ZgbfD~OYf$60e|701E4KO*kM!W z6-cemd-GKU(XOzK%-7eP6t)z3ARk!)plwN_1?tzw0LOsXQ@0_qciRLBA!k+2t_zRe z{?FSIi{>Ct7gRpMc11PufHNfYmK(<`|H|V^KXBWbCBf)=nAzAR@)$jltf77F78 zkzsBZe9Fusaog-S+32|a4)rXB2NG>KR&Foz5l6QaT|H5@7B+d4C_GM|uBzC^8@rj` zH+*Vb8DU!gVb|5ajL-T4CG<5V{dQSTdXv-C8Hf*`ytbnLVHKliZvVmW8|cSpn#8m; zAtUPo+GC~Io#;Rv{fGC$=xR!^06YNPf6%6F*Ixd9)B*@DTBC=q?S2DLZ?BR5Md7Ve z|3#^+GeIfubscCqv#$1s3j_;oi2PL_w?PM`S~iTKCH|%jv<%q%O|NafftHm7K(NY| zAe6c!1%mUpgrU^>)^Dl6mq4)Twj7iy+qQ+4I6H2*|6NG_{gMSZeMc8sd$~gmSmFe4 z(Nlv3zCrzl;&f937J0yZ{0!joZ@;}BhB8+9p$q{qXy^CS8BDv>fD<9`jF2F>=i6^a zB9w6`@<&B{4-x%8w;uk41R9ZgaUl4`9x7l*{4asuHuI%`(5n*v`4t7tfrIvhpxlpp z)Bt+fKfbWblK*9#T>*&pUr}=fXf@UUY9e5t8h~I3J~E((uCSp40c~~D0ti0dM+M+m zLfKSc;K6UWaOMMQ0IxMz{Xi1>kqrGnwFRHs2!Sy+fA`||IAI-Pz^;KQ4xx{U{Q17H zga4~>ESOUXbbGMz;Y-^82J>I|;s4_#^uH)b_O~dh%>Rid{+FNsCmQkp7%K|WaE4kU zA^87;5`%wj;Qzy)f1t?1u>FsTKmHuMfMxXhUH)4S8jiaQwS6e?T{!&E$yLV=1)Bu8^KkTft-&48<%IN>}htbwkw0g(>8I7~)Kh-B=WZ<52#DDbUzgtcJyC=_Ieyb#1Q2s;uKda%t g7Q_E?zh>z_(nw(Q3jz#&7=D;+To{(L52Ty)(*OVf delta 24877 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 17a8ddc..9f4197d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -2,5 +2,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 65dcd68..fcb6fca 100644 --- a/gradlew +++ b/gradlew @@ -85,9 +85,6 @@ done APP_BASE_NAME=${0##*/} APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,10 +130,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. @@ -144,7 +144,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +152,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -197,6 +197,10 @@ if "$cygwin" || "$msys" ; then done fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Collect all arguments for the java command; # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # shell script including quotes and variable substitutions, so put them in diff --git a/paper/build.gradle b/paper/build.gradle new file mode 100644 index 0000000..c5cbf08 --- /dev/null +++ b/paper/build.gradle @@ -0,0 +1,94 @@ +plugins { + id 'java' + id 'maven-publish' +} + +archivesBaseName = project.archives_base_name +group = project.maven_group +version = "${project.base_version}-paper" + +repositories { + mavenLocal() + mavenCentral() + maven { + name = "papermc-repo" + url = "https://repo.papermc.io/repository/maven-public/" + } + maven { + name = "sonatype" + url = "https://oss.sonatype.org/content/groups/public/" + } +} + +configurations { + includeInJar +} + +dependencies { + configurations.implementation.extendsFrom(configurations.includeInJar) + includeInJar project(':common') + + compileOnly "io.papermc.paper:paper-api:1.20.1-R0.1-SNAPSHOT" +} + +processResources { + def props = [base_version: project.version, paper_api_version: project.paper_api_version] + inputs.properties props + filteringCharset 'UTF-8' + filesMatching('plugin.yml') { + expand props + } +} + +def targetJavaVersion = 17 +java { + def javaVersion = JavaVersion.toVersion(targetJavaVersion) + sourceCompatibility = javaVersion + targetCompatibility = javaVersion + if (JavaVersion.current() < javaVersion) { + toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion) + } +} + +tasks.withType(JavaCompile).configureEach { + if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) { + options.release = targetJavaVersion + } +} + +jar { + dependsOn ':common:remapJar' + from { + configurations.includeInJar.collect { + it.isDirectory() ? it : zipTree(it) + } + } +} + +publishing { + publications { + mavenJava(MavenPublication) { + artifactId project.archivesBaseName + from components.java + } + } + + repositories { + maven { + name = "xpple" + url = "sftp://xpple.dev:22/maven.xpple.dev/maven2" + credentials { + username = System.getenv("MAVEN_USER") + password = System.getenv("MAVEN_PASS") + } + } + maven { + name = "GitHubPackages" + url = "https://maven.pkg.github.com/xpple/BetterConfig" + credentials { + username = System.getenv("GITHUB_ACTOR") + password = System.getenv("GITHUB_TOKEN") + } + } + } +} diff --git a/paper/src/main/java/dev/xpple/betterconfig/BetterConfig.java b/paper/src/main/java/dev/xpple/betterconfig/BetterConfig.java new file mode 100644 index 0000000..ed78846 --- /dev/null +++ b/paper/src/main/java/dev/xpple/betterconfig/BetterConfig.java @@ -0,0 +1,25 @@ +package dev.xpple.betterconfig; + +import dev.xpple.betterconfig.command.ConfigCommand; +import io.papermc.paper.event.server.ServerResourcesReloadedEvent; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.plugin.java.JavaPlugin; + +import java.nio.file.Path; + +public final class BetterConfig extends JavaPlugin { + + public static final Path PLUGIN_PATH = Bukkit.getPluginsFolder().toPath(); + + @Override + public void onEnable() { + this.getServer().getPluginManager().registerEvents(new Listener() { + @EventHandler + public void reload(ServerResourcesReloadedEvent event) { + event.getCommands().register(BetterConfig.this, new ConfigCommand().register()); + } + }, this); + } +} diff --git a/paper/src/main/java/dev/xpple/betterconfig/api/BetterConfigAPI.java b/paper/src/main/java/dev/xpple/betterconfig/api/BetterConfigAPI.java new file mode 100644 index 0000000..35f130c --- /dev/null +++ b/paper/src/main/java/dev/xpple/betterconfig/api/BetterConfigAPI.java @@ -0,0 +1,17 @@ +package dev.xpple.betterconfig.api; + +import dev.xpple.betterconfig.impl.BetterConfigImpl; + +public interface BetterConfigAPI { + + static BetterConfigAPI getInstance() { + return BetterConfigImpl.INSTANCE; + } + + /** + * Get the configurations for the specified plugin. + * @param pluginName the plugin's name + * @return the configurations for the specified plugin + */ + PluginConfig getPluginConfig(String pluginName); +} diff --git a/paper/src/main/java/dev/xpple/betterconfig/api/PluginConfig.java b/paper/src/main/java/dev/xpple/betterconfig/api/PluginConfig.java new file mode 100644 index 0000000..7c0bd36 --- /dev/null +++ b/paper/src/main/java/dev/xpple/betterconfig/api/PluginConfig.java @@ -0,0 +1,9 @@ +package dev.xpple.betterconfig.api; + +public interface PluginConfig extends AbstractConfig { + /** + * Get the name of the plugin of this configuration. + * @return the plugin's name + */ + String getPluginName(); +} diff --git a/paper/src/main/java/dev/xpple/betterconfig/api/PluginConfigBuilder.java b/paper/src/main/java/dev/xpple/betterconfig/api/PluginConfigBuilder.java new file mode 100644 index 0000000..cff8af4 --- /dev/null +++ b/paper/src/main/java/dev/xpple/betterconfig/api/PluginConfigBuilder.java @@ -0,0 +1,26 @@ +package dev.xpple.betterconfig.api; + +import dev.xpple.betterconfig.impl.BetterConfigImpl; +import dev.xpple.betterconfig.impl.BetterConfigInternals; +import dev.xpple.betterconfig.impl.PluginConfigImpl; +import io.papermc.paper.command.brigadier.CommandSourceStack; + +public class PluginConfigBuilder extends AbstractConfigBuilder { + + private final String pluginName; + + public PluginConfigBuilder(String pluginName, Class configsClass) { + super(configsClass); + this.pluginName = pluginName; + } + + @Override + public void build() { + PluginConfigImpl pluginConfig = new PluginConfigImpl(this.pluginName, this.configsClass, this.builder.create(), this.arguments, this.suggestors); + if (BetterConfigImpl.getPluginConfigs().putIfAbsent(this.pluginName, pluginConfig) == null) { + BetterConfigInternals.init(pluginConfig); + return; + } + throw new IllegalArgumentException(this.pluginName); + } +} diff --git a/paper/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java b/paper/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java new file mode 100644 index 0000000..8e92a2c --- /dev/null +++ b/paper/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java @@ -0,0 +1,78 @@ +package dev.xpple.betterconfig.command; + +import dev.xpple.betterconfig.command.suggestion.EnumSuggestionProvider; +import dev.xpple.betterconfig.impl.AbstractConfigImpl; +import dev.xpple.betterconfig.impl.BetterConfigImpl; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.SuggestionProvider; +import com.mojang.brigadier.tree.LiteralCommandNode; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.MessageComponentSerializer; +import net.kyori.adventure.text.Component; +import org.bukkit.Server; + +public class ConfigCommand extends ConfigCommandHelper { + + @Override + protected > SuggestionProvider enumSuggestionProvider(Class type) { + return new EnumSuggestionProvider<>(type); + } + + @Override + protected DynamicCommandExceptionType invalidEnumException() { + return new DynamicCommandExceptionType(value -> MessageComponentSerializer.message().serialize(Component.translatable("argument.enum.invalid", Component.text(String.valueOf(value))))); + } + + public LiteralCommandNode register() { + return this.create("config", BetterConfigImpl.getPluginConfigs().values()).build(); + } + + @Override + protected int get(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config) { + Component component = Component.translatable("betterconfig.commands.config.get", "%s is currently set to %s.", Component.text(config), Component.text(abstractConfig.asString(config))); + source.getExecutor().getServer().broadcast(component, Server.BROADCAST_CHANNEL_ADMINISTRATIVE); + return Command.SINGLE_SUCCESS; + } + + @Override + protected int reset(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config) { + abstractConfig.reset(config); + Component component = Component.translatable("betterconfig.commands.config.reset", "%s has been reset to %s.", Component.text(config), Component.text(abstractConfig.asString(config))); + source.getExecutor().getServer().broadcast(component, Server.BROADCAST_CHANNEL_ADMINISTRATIVE); + return Command.SINGLE_SUCCESS; + } + + @Override + protected int set(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { + abstractConfig.set(config, value); + Component component = Component.translatable("betterconfig.commands.config.set", "%s has been set to %s.", Component.text(config), Component.text(abstractConfig.asString(config))); + source.getExecutor().getServer().broadcast(component, Server.BROADCAST_CHANNEL_ADMINISTRATIVE); + return Command.SINGLE_SUCCESS; + } + + @Override + protected int add(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { + abstractConfig.add(config, value); + Component component = Component.translatable("betterconfig.commands.config.add", "%s has been added to %s.", Component.text(abstractConfig.asString(value)), Component.text(config)); + source.getExecutor().getServer().broadcast(component, Server.BROADCAST_CHANNEL_ADMINISTRATIVE); + return Command.SINGLE_SUCCESS; + } + + @Override + protected int put(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config, Object key, Object value) throws CommandSyntaxException { + abstractConfig.put(config, key, value); + Component component = Component.translatable("betterconfig.commands.config.put", "The mapping %s=%s has been added to %s.", Component.text(abstractConfig.asString(key)), Component.text(abstractConfig.asString(value)), Component.text(config)); + source.getExecutor().getServer().broadcast(component, Server.BROADCAST_CHANNEL_ADMINISTRATIVE); + return Command.SINGLE_SUCCESS; + } + + @Override + protected int remove(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { + abstractConfig.remove(config, value); + Component component = Component.translatable("betterconfig.commands.config.remove", "%s has been removed from %s.", Component.text(abstractConfig.asString(value)), Component.text(config)); + source.getExecutor().getServer().broadcast(component, Server.BROADCAST_CHANNEL_ADMINISTRATIVE); + return Command.SINGLE_SUCCESS; + } +} diff --git a/paper/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java b/paper/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java new file mode 100644 index 0000000..138ad2f --- /dev/null +++ b/paper/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java @@ -0,0 +1,39 @@ +package dev.xpple.betterconfig.command.suggestion; + +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import java.util.Arrays; +import java.util.Locale; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; + +public class EnumSuggestionProvider> extends AbstractEnumSuggestionProvider { + + public EnumSuggestionProvider(Class enumClass) { + super(enumClass); + } + + @Override + public CompletableFuture getSuggestions(CommandContext context, SuggestionsBuilder builder) { + return suggestMatching(Arrays.stream(this.enumClass.getEnumConstants()).map(Enum::name), builder); + } + + private static CompletableFuture suggestMatching(Stream candidates, SuggestionsBuilder builder) { + String string = builder.getRemaining().toLowerCase(Locale.ROOT); + Stream suggestions = candidates.filter(candidate -> shouldSuggest(string, candidate.toLowerCase(Locale.ROOT))); + suggestions.forEach(builder::suggest); + return builder.buildFuture(); + } + + private static boolean shouldSuggest(String remaining, String candidate) { + for (int i = 0; !candidate.startsWith(remaining, i); ++i) { + i = candidate.indexOf(95, i); + if (i < 0) { + return false; + } + } + return true; + } +} diff --git a/paper/src/main/java/dev/xpple/betterconfig/impl/BetterConfigImpl.java b/paper/src/main/java/dev/xpple/betterconfig/impl/BetterConfigImpl.java new file mode 100644 index 0000000..c04c7de --- /dev/null +++ b/paper/src/main/java/dev/xpple/betterconfig/impl/BetterConfigImpl.java @@ -0,0 +1,27 @@ +package dev.xpple.betterconfig.impl; + +import dev.xpple.betterconfig.api.BetterConfigAPI; +import dev.xpple.betterconfig.api.PluginConfig; + +import java.util.HashMap; +import java.util.Map; + +public class BetterConfigImpl implements BetterConfigAPI { + + private static final Map pluginConfigs = new HashMap<>(); + + @Override + public PluginConfig getPluginConfig(String pluginName) { + PluginConfig pluginConfig = pluginConfigs.get(pluginName); + if (pluginConfig == null) { + throw new IllegalArgumentException(pluginName); + } + return pluginConfig; + } + + public static Map getPluginConfigs() { + return pluginConfigs; + } + + public static final BetterConfigImpl INSTANCE = new BetterConfigImpl(); +} diff --git a/paper/src/main/java/dev/xpple/betterconfig/impl/PluginConfigImpl.java b/paper/src/main/java/dev/xpple/betterconfig/impl/PluginConfigImpl.java new file mode 100644 index 0000000..6897692 --- /dev/null +++ b/paper/src/main/java/dev/xpple/betterconfig/impl/PluginConfigImpl.java @@ -0,0 +1,36 @@ +package dev.xpple.betterconfig.impl; + +import com.google.gson.Gson; +import dev.xpple.betterconfig.api.PluginConfig; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import org.apache.commons.lang3.tuple.Pair; + +import java.nio.file.Path; +import java.util.Map; + +import static dev.xpple.betterconfig.BetterConfig.PLUGIN_PATH; + +public class PluginConfigImpl extends AbstractConfigImpl implements PluginConfig { + + private final String pluginName; + + public PluginConfigImpl(String pluginName, Class configsClass, Gson gson, Map, Pair> arguments, Map, Pair> suggestors) { + super(configsClass, gson, arguments, suggestors); + this.pluginName = pluginName; + } + + @Override + public String getPluginName() { + return this.pluginName; + } + + @Override + public Path getConfigsPath() { + return PLUGIN_PATH.resolve(this.pluginName).resolve("config.json"); + } + + @Override + public String getIdentifier() { + return this.getPluginName(); + } +} diff --git a/paper/src/main/resources/plugin.yml b/paper/src/main/resources/plugin.yml new file mode 100644 index 0000000..6e0344b --- /dev/null +++ b/paper/src/main/resources/plugin.yml @@ -0,0 +1,23 @@ +name: BetterConfig +version: '${base_version}' +description: A very powerful and easy to use command based configuration library for servers and clients. +author: xpple +website: https://xpple.dev/ +main: dev.xpple.betterconfig.BetterConfigPaper +api-version: '${paper_api_version}' +load: STARTUP +commands: + config: + description: The command used to change plugin configurations + usage: /config [] [] + permission: betterconfig.config + permission-message: Unknown command or insufficient permissions +permissions: + betterconfig.config: + description: Allows the use of the config command + default: op + betterconfig.*: + description: Wildcard permission + default: op + children: + - betterconfig.config diff --git a/settings.gradle b/settings.gradle index 56266b4..367ca31 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,4 +7,9 @@ pluginManagement { mavenCentral() gradlePluginPortal() } -} \ No newline at end of file +} + +include 'common' +include 'fabric' +include 'paper' +project(':paper').name = 'betterconfig' // silly hack needed for Paper diff --git a/src/client/java/dev/xpple/betterconfig/command/client/ConfigCommandClient.java b/src/client/java/dev/xpple/betterconfig/command/client/ConfigCommandClient.java deleted file mode 100644 index c6c9bea..0000000 --- a/src/client/java/dev/xpple/betterconfig/command/client/ConfigCommandClient.java +++ /dev/null @@ -1,56 +0,0 @@ -package dev.xpple.betterconfig.command.client; - -import com.mojang.brigadier.Command; -import com.mojang.brigadier.CommandDispatcher; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import dev.xpple.betterconfig.command.ConfigCommandHelper; -import dev.xpple.betterconfig.impl.ModConfigImpl; -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; -import net.minecraft.text.Text; - -public class ConfigCommandClient extends ConfigCommandHelper { - public void register(CommandDispatcher dispatcher) { - dispatcher.register(this.create("cconfig")); - } - - @Override - protected int get(FabricClientCommandSource source, ModConfigImpl modConfig, String config) { - source.sendFeedback(Text.translatable("betterconfig.commands.config.get", config, modConfig.asString(config))); - return Command.SINGLE_SUCCESS; - } - - @Override - protected int reset(FabricClientCommandSource source, ModConfigImpl modConfig, String config) { - modConfig.reset(config); - source.sendFeedback(Text.translatable("betterconfig.commands.config.reset", config, modConfig.asString(config))); - return Command.SINGLE_SUCCESS; - } - - @Override - protected int set(FabricClientCommandSource source, ModConfigImpl modConfig, String config, Object value) throws CommandSyntaxException { - modConfig.set(config, value); - source.sendFeedback(Text.translatable("betterconfig.commands.config.set", config, modConfig.asString(config))); - return Command.SINGLE_SUCCESS; - } - - @Override - protected int add(FabricClientCommandSource source, ModConfigImpl modConfig, String config, Object value) throws CommandSyntaxException { - modConfig.add(config, value); - source.sendFeedback(Text.translatable("betterconfig.commands.config.add", modConfig.asString(value), config)); - return Command.SINGLE_SUCCESS; - } - - @Override - protected int put(FabricClientCommandSource source, ModConfigImpl modConfig, String config, Object key, Object value) throws CommandSyntaxException { - modConfig.put(config, key, value); - source.sendFeedback(Text.translatable("betterconfig.commands.config.put", key, modConfig.asString(value), config)); - return Command.SINGLE_SUCCESS; - } - - @Override - protected int remove(FabricClientCommandSource source, ModConfigImpl modConfig, String config, Object value) throws CommandSyntaxException { - modConfig.remove(config, value); - source.sendFeedback(Text.translatable("betterconfig.commands.config.remove", modConfig.asString(value), config)); - return Command.SINGLE_SUCCESS; - } -} diff --git a/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java b/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java deleted file mode 100644 index a73b12a..0000000 --- a/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java +++ /dev/null @@ -1,55 +0,0 @@ -package dev.xpple.betterconfig.command; - -import com.mojang.brigadier.Command; -import com.mojang.brigadier.CommandDispatcher; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import dev.xpple.betterconfig.impl.ModConfigImpl; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.text.Text; - -public class ConfigCommand extends ConfigCommandHelper { - public void register(CommandDispatcher dispatcher) { - dispatcher.register(this.create("config").requires(source -> source.hasPermissionLevel(4))); - } - - @Override - protected int get(ServerCommandSource source, ModConfigImpl modConfig, String config) { - source.sendFeedback(() -> Text.translatableWithFallback("betterconfig.commands.config.get", "%s is currently set to %s.", config, modConfig.asString(config)), true); - return Command.SINGLE_SUCCESS; - } - - @Override - protected int reset(ServerCommandSource source, ModConfigImpl modConfig, String config) { - modConfig.reset(config); - source.sendFeedback(() -> Text.translatableWithFallback("betterconfig.commands.config.reset", "%s has been reset to %s.", config, modConfig.asString(config)), true); - return Command.SINGLE_SUCCESS; - } - - @Override - protected int set(ServerCommandSource source, ModConfigImpl modConfig, String config, Object value) throws CommandSyntaxException { - modConfig.set(config, value); - source.sendFeedback(() -> Text.translatableWithFallback("betterconfig.commands.config.set", "%s has been set to %s.", config, modConfig.asString(config)), true); - return Command.SINGLE_SUCCESS; - } - - @Override - protected int add(ServerCommandSource source, ModConfigImpl modConfig, String config, Object value) throws CommandSyntaxException { - modConfig.add(config, value); - source.sendFeedback(() -> Text.translatableWithFallback("betterconfig.commands.config.add", "%s has been added to %s.", modConfig.asString(value), config), true); - return Command.SINGLE_SUCCESS; - } - - @Override - protected int put(ServerCommandSource source, ModConfigImpl modConfig, String config, Object key, Object value) throws CommandSyntaxException { - modConfig.put(config, key, value); - source.sendFeedback(() -> Text.translatableWithFallback("betterconfig.commands.config.put", "The mapping %s=%s has been added to %s.", key, modConfig.asString(value), config), true); - return Command.SINGLE_SUCCESS; - } - - @Override - protected int remove(ServerCommandSource source, ModConfigImpl modConfig, String config, Object value) throws CommandSyntaxException { - modConfig.remove(config, value); - source.sendFeedback(() -> Text.translatableWithFallback("betterconfig.commands.config.remove", "%s has been removed from %s.", modConfig.asString(value), config), true); - return Command.SINGLE_SUCCESS; - } -} From 31c57790aa3082d38a8b74a5539fdb1eed488889 Mon Sep 17 00:00:00 2001 From: xpple Date: Wed, 19 Jul 2023 23:17:39 +0200 Subject: [PATCH 02/28] Thank you @DJtheRedstoner --- fabric/build.gradle | 3 +-- paper/build.gradle | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/fabric/build.gradle b/fabric/build.gradle index cd7bdc9..0e4305b 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -62,6 +62,7 @@ configurations { } dependencies { + configurations.compileOnly.extendsFrom(configurations.includeInJar) includeInJar project(':common') // To change the versions see the gradle.properties file @@ -76,8 +77,6 @@ dependencies { // These are included in the Fabric API production distribution and allow you to update your mod to the latest modules at a later more convenient time. // modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}" - - configurations.implementation.extendsFrom(configurations.includeInJar) } processResources { diff --git a/paper/build.gradle b/paper/build.gradle index c5cbf08..bff4f3c 100644 --- a/paper/build.gradle +++ b/paper/build.gradle @@ -25,7 +25,7 @@ configurations { } dependencies { - configurations.implementation.extendsFrom(configurations.includeInJar) + configurations.compileOnly.extendsFrom(configurations.includeInJar) includeInJar project(':common') compileOnly "io.papermc.paper:paper-api:1.20.1-R0.1-SNAPSHOT" From 458e17fbc2239bb902a018fa20526e9807a131fc Mon Sep 17 00:00:00 2001 From: xpple Date: Thu, 20 Jul 2023 19:13:06 +0200 Subject: [PATCH 03/28] Fix entrypoint for Paper --- .../java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java | 2 +- paper/src/main/resources/plugin.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java b/common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java index 3443406..9ceb14e 100644 --- a/common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java +++ b/common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java @@ -29,7 +29,7 @@ public abstract class AbstractConfigImpl implements AbstractConfig { - Map, Pair> defaultArguments = ImmutableMap., Pair>builder() + private final Map, Pair> defaultArguments = ImmutableMap., Pair>builder() .put(boolean.class, Pair.of((Supplier>) BoolArgumentType::bool, (CheckedBiFunction, String, Boolean, CommandSyntaxException>) BoolArgumentType::getBool)) .put(Boolean.class, Pair.of((Supplier>) BoolArgumentType::bool, (CheckedBiFunction, String, Boolean, CommandSyntaxException>) BoolArgumentType::getBool)) .put(double.class, Pair.of((Supplier>) DoubleArgumentType::doubleArg, (CheckedBiFunction, String, Double, CommandSyntaxException>) DoubleArgumentType::getDouble)) diff --git a/paper/src/main/resources/plugin.yml b/paper/src/main/resources/plugin.yml index 6e0344b..5113835 100644 --- a/paper/src/main/resources/plugin.yml +++ b/paper/src/main/resources/plugin.yml @@ -3,7 +3,7 @@ version: '${base_version}' description: A very powerful and easy to use command based configuration library for servers and clients. author: xpple website: https://xpple.dev/ -main: dev.xpple.betterconfig.BetterConfigPaper +main: dev.xpple.betterconfig.BetterConfig api-version: '${paper_api_version}' load: STARTUP commands: From ee371c394c3fdbf4fc529a95ffe1a2752ce7b272 Mon Sep 17 00:00:00 2001 From: xpple Date: Sat, 22 Jul 2023 18:03:39 +0200 Subject: [PATCH 04/28] Fix command registration + feedback --- .../dev/xpple/betterconfig/BetterConfig.java | 6 ++--- .../betterconfig/command/ConfigCommand.java | 26 +++++++++---------- paper/src/main/resources/plugin.yml | 6 ----- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/paper/src/main/java/dev/xpple/betterconfig/BetterConfig.java b/paper/src/main/java/dev/xpple/betterconfig/BetterConfig.java index ed78846..a940387 100644 --- a/paper/src/main/java/dev/xpple/betterconfig/BetterConfig.java +++ b/paper/src/main/java/dev/xpple/betterconfig/BetterConfig.java @@ -1,7 +1,7 @@ package dev.xpple.betterconfig; import dev.xpple.betterconfig.command.ConfigCommand; -import io.papermc.paper.event.server.ServerResourcesReloadedEvent; +import io.papermc.paper.event.server.ServerResourcesLoadEvent; import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -17,8 +17,8 @@ public final class BetterConfig extends JavaPlugin { public void onEnable() { this.getServer().getPluginManager().registerEvents(new Listener() { @EventHandler - public void reload(ServerResourcesReloadedEvent event) { - event.getCommands().register(BetterConfig.this, new ConfigCommand().register()); + public void load(ServerResourcesLoadEvent event) { + event.getCommands().register(BetterConfig.this, new ConfigCommand().build()); } }, this); } 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 51f6e49..4edf290 100644 --- a/paper/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java +++ b/paper/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java @@ -1,13 +1,13 @@ package dev.xpple.betterconfig.command; -import dev.xpple.betterconfig.command.suggestion.EnumSuggestionProvider; -import dev.xpple.betterconfig.impl.AbstractConfigImpl; -import dev.xpple.betterconfig.impl.BetterConfigImpl; import com.mojang.brigadier.Command; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; import com.mojang.brigadier.suggestion.SuggestionProvider; import com.mojang.brigadier.tree.LiteralCommandNode; +import dev.xpple.betterconfig.command.suggestion.EnumSuggestionProvider; +import dev.xpple.betterconfig.impl.AbstractConfigImpl; +import dev.xpple.betterconfig.impl.BetterConfigImpl; import io.papermc.paper.command.brigadier.CommandSourceStack; import io.papermc.paper.command.brigadier.MessageComponentSerializer; import net.kyori.adventure.text.Component; @@ -25,21 +25,21 @@ protected DynamicCommandExceptionType invalidEnumException() { return new DynamicCommandExceptionType(value -> MessageComponentSerializer.message().serialize(Component.translatable("argument.enum.invalid", Component.text(String.valueOf(value))))); } - public LiteralCommandNode register() { - return this.create("config", BetterConfigImpl.getPluginConfigs().values()).build(); + public LiteralCommandNode build() { + return this.create("config", BetterConfigImpl.getPluginConfigs().values()).requires(source -> source.getSender().hasPermission("betterconfig.config")).build(); } @Override protected int comment(CommandSourceStack source, String config, String comment) { - source.getExecutor().sendMessage(Component.translatable("betterconfig.commands.config.comment", "Comment for %s:", Component.text(config))); - source.getExecutor().sendMessage(Component.text(comment)); + source.getSender().sendMessage(Component.translatable("betterconfig.commands.config.comment", "Comment for %s:", Component.text(config))); + source.getSender().sendMessage(Component.text(comment)); return Command.SINGLE_SUCCESS; } @Override protected int get(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config) { Component component = Component.translatable("betterconfig.commands.config.get", "%s is currently set to %s.", Component.text(config), Component.text(abstractConfig.asString(config))); - source.getExecutor().sendMessage(component); + source.getSender().sendMessage(component); return Command.SINGLE_SUCCESS; } @@ -47,7 +47,7 @@ protected int get(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config) { abstractConfig.reset(config); Component component = Component.translatable("betterconfig.commands.config.reset", "%s has been reset to %s.", Component.text(config), Component.text(abstractConfig.asString(config))); - source.getExecutor().getServer().broadcast(component, Server.BROADCAST_CHANNEL_ADMINISTRATIVE); + source.getSender().getServer().broadcast(component, Server.BROADCAST_CHANNEL_ADMINISTRATIVE); return Command.SINGLE_SUCCESS; } @@ -55,7 +55,7 @@ protected int reset(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { abstractConfig.set(config, value); Component component = Component.translatable("betterconfig.commands.config.set", "%s has been set to %s.", Component.text(config), Component.text(abstractConfig.asString(config))); - source.getExecutor().getServer().broadcast(component, Server.BROADCAST_CHANNEL_ADMINISTRATIVE); + source.getSender().getServer().broadcast(component, Server.BROADCAST_CHANNEL_ADMINISTRATIVE); return Command.SINGLE_SUCCESS; } @@ -63,7 +63,7 @@ protected int set(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { abstractConfig.add(config, value); Component component = Component.translatable("betterconfig.commands.config.add", "%s has been added to %s.", Component.text(abstractConfig.asString(value)), Component.text(config)); - source.getExecutor().getServer().broadcast(component, Server.BROADCAST_CHANNEL_ADMINISTRATIVE); + source.getSender().getServer().broadcast(component, Server.BROADCAST_CHANNEL_ADMINISTRATIVE); return Command.SINGLE_SUCCESS; } @@ -71,7 +71,7 @@ protected int add(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config, Object key, Object value) throws CommandSyntaxException { abstractConfig.put(config, key, value); Component component = Component.translatable("betterconfig.commands.config.put", "The mapping %s=%s has been added to %s.", Component.text(abstractConfig.asString(key)), Component.text(abstractConfig.asString(value)), Component.text(config)); - source.getExecutor().getServer().broadcast(component, Server.BROADCAST_CHANNEL_ADMINISTRATIVE); + source.getSender().getServer().broadcast(component, Server.BROADCAST_CHANNEL_ADMINISTRATIVE); return Command.SINGLE_SUCCESS; } @@ -79,7 +79,7 @@ protected int put(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { abstractConfig.remove(config, value); Component component = Component.translatable("betterconfig.commands.config.remove", "%s has been removed from %s.", Component.text(abstractConfig.asString(value)), Component.text(config)); - source.getExecutor().getServer().broadcast(component, Server.BROADCAST_CHANNEL_ADMINISTRATIVE); + source.getSender().getServer().broadcast(component, Server.BROADCAST_CHANNEL_ADMINISTRATIVE); return Command.SINGLE_SUCCESS; } } diff --git a/paper/src/main/resources/plugin.yml b/paper/src/main/resources/plugin.yml index 5113835..187d0d2 100644 --- a/paper/src/main/resources/plugin.yml +++ b/paper/src/main/resources/plugin.yml @@ -6,12 +6,6 @@ website: https://xpple.dev/ main: dev.xpple.betterconfig.BetterConfig api-version: '${paper_api_version}' load: STARTUP -commands: - config: - description: The command used to change plugin configurations - usage: /config [] [] - permission: betterconfig.config - permission-message: Unknown command or insufficient permissions permissions: betterconfig.config: description: Allows the use of the config command From c0da376d0a76478ad637e28f77275d935d91b611 Mon Sep 17 00:00:00 2001 From: xpple Date: Sun, 23 Jul 2023 16:26:36 +0200 Subject: [PATCH 05/28] Add test plugin --- paper/build.gradle | 51 +++++++++++++ .../suggestion/EnumSuggestionProvider.java | 21 +----- .../suggestion/SuggestionProviderHelper.java | 56 ++++++++++++++ .../java/dev/xpple/betterconfig/Configs.java | 73 +++++++++++++++++++ .../xpple/betterconfig/MaterialAdapter.java | 22 ++++++ .../MaterialSuggestionProvider.java | 23 ++++++ .../java/dev/xpple/betterconfig/TestEnum.java | 7 ++ .../dev/xpple/betterconfig/TestPlugin.java | 32 ++++++++ paper/src/testplugin/resources/plugin.yml | 6 ++ 9 files changed, 271 insertions(+), 20 deletions(-) create mode 100644 paper/src/main/java/dev/xpple/betterconfig/command/suggestion/SuggestionProviderHelper.java create mode 100644 paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java create mode 100644 paper/src/testplugin/java/dev/xpple/betterconfig/MaterialAdapter.java create mode 100644 paper/src/testplugin/java/dev/xpple/betterconfig/MaterialSuggestionProvider.java create mode 100644 paper/src/testplugin/java/dev/xpple/betterconfig/TestEnum.java create mode 100644 paper/src/testplugin/java/dev/xpple/betterconfig/TestPlugin.java create mode 100644 paper/src/testplugin/resources/plugin.yml diff --git a/paper/build.gradle b/paper/build.gradle index bff4f3c..d0837fe 100644 --- a/paper/build.gradle +++ b/paper/build.gradle @@ -7,6 +7,15 @@ archivesBaseName = project.archives_base_name group = project.maven_group version = "${project.base_version}-paper" +sourceSets { + testplugin { + compileClasspath += main.compileClasspath + runtimeClasspath += main.runtimeClasspath + compileClasspath += main.output + runtimeClasspath += main.output + } +} + repositories { mavenLocal() mavenCentral() @@ -56,6 +65,48 @@ tasks.withType(JavaCompile).configureEach { } } +tasks.register('buildTestplugin', Jar) { + it.group = 'paper' + + it.archiveBaseName = 'testplugin' + it.archiveVersion = '1.0.0' + from sourceSets.testplugin.output +} + +tasks.register('copyJarsToServer') { + it.group = 'paper' + + doLast { + copy { + from jar + into "${projectDir}/run/plugins" + } + + copy { + from buildTestplugin + into "${projectDir}/run/plugins" + } + } +} + +copyJarsToServer.dependsOn(build, buildTestplugin) + +tasks.register('runTestpluginServer') { + it.group = 'paper' + + doLast { + javaexec { + workingDir = "${projectDir}/run" + main = '-jar' + args = ["${projectDir}/run/server.jar", '--nogui'] + jvmArgs = ['-Dcom.mojang.eula.agree=true'] + standardInput = System.in + } + } +} + +runTestpluginServer.dependsOn(copyJarsToServer) + jar { dependsOn ':common:remapJar' from { diff --git a/paper/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java b/paper/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java index 138ad2f..5d43f47 100644 --- a/paper/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java +++ b/paper/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java @@ -5,9 +5,7 @@ import com.mojang.brigadier.suggestion.SuggestionsBuilder; import java.util.Arrays; -import java.util.Locale; import java.util.concurrent.CompletableFuture; -import java.util.stream.Stream; public class EnumSuggestionProvider> extends AbstractEnumSuggestionProvider { @@ -17,23 +15,6 @@ public EnumSuggestionProvider(Class enumClass) { @Override public CompletableFuture getSuggestions(CommandContext context, SuggestionsBuilder builder) { - return suggestMatching(Arrays.stream(this.enumClass.getEnumConstants()).map(Enum::name), builder); - } - - private static CompletableFuture suggestMatching(Stream candidates, SuggestionsBuilder builder) { - String string = builder.getRemaining().toLowerCase(Locale.ROOT); - Stream suggestions = candidates.filter(candidate -> shouldSuggest(string, candidate.toLowerCase(Locale.ROOT))); - suggestions.forEach(builder::suggest); - return builder.buildFuture(); - } - - private static boolean shouldSuggest(String remaining, String candidate) { - for (int i = 0; !candidate.startsWith(remaining, i); ++i) { - i = candidate.indexOf(95, i); - if (i < 0) { - return false; - } - } - return true; + return SuggestionProviderHelper.suggestMatching(Arrays.stream(this.enumClass.getEnumConstants()).map(Enum::name), builder); } } diff --git a/paper/src/main/java/dev/xpple/betterconfig/command/suggestion/SuggestionProviderHelper.java b/paper/src/main/java/dev/xpple/betterconfig/command/suggestion/SuggestionProviderHelper.java new file mode 100644 index 0000000..13f3ed3 --- /dev/null +++ b/paper/src/main/java/dev/xpple/betterconfig/command/suggestion/SuggestionProviderHelper.java @@ -0,0 +1,56 @@ +package dev.xpple.betterconfig.command.suggestion; + +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import org.bukkit.NamespacedKey; + +import java.util.Locale; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Stream; + +public class SuggestionProviderHelper { + public static CompletableFuture suggestMatching(Stream candidates, SuggestionsBuilder builder) { + String string = builder.getRemaining().toLowerCase(Locale.ROOT); + Stream suggestions = candidates.filter(candidate -> shouldSuggest(string, candidate.toLowerCase(Locale.ROOT))); + suggestions.forEach(builder::suggest); + return builder.buildFuture(); + } + + public static CompletableFuture suggestNamespacedKeys(Stream candidates, SuggestionsBuilder builder) { + return suggestNamespacedKeys(candidates::iterator, builder); + } + + public static CompletableFuture suggestNamespacedKeys(Iterable candidates, SuggestionsBuilder builder) { + String string = builder.getRemaining().toLowerCase(Locale.ROOT); + forEachMatching(candidates, string, key -> key, key -> builder.suggest(key.toString())); + return builder.buildFuture(); + } + + private static void forEachMatching(Iterable candidates, String remaining, Function namespacedKeyFunction, Consumer action) { + boolean hasNamespace = remaining.indexOf(':') > -1; + + for (T candidate : candidates) { + NamespacedKey namespacedKey = namespacedKeyFunction.apply(candidate); + if (hasNamespace) { + String string = namespacedKey.toString(); + if (shouldSuggest(remaining, string)) { + action.accept(candidate); + } + } else if (shouldSuggest(remaining, namespacedKey.getNamespace()) || namespacedKey.getNamespace().equals("minecraft") && shouldSuggest(remaining, namespacedKey.getKey())) { + action.accept(candidate); + } + } + } + + private static boolean shouldSuggest(String remaining, String candidate) { + for (int i = 0; !candidate.startsWith(remaining, i); ++i) { + i = candidate.indexOf('_', i); + if (i < 0) { + return false; + } + } + return true; + } +} diff --git a/paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java b/paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java new file mode 100644 index 0000000..7ad7996 --- /dev/null +++ b/paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java @@ -0,0 +1,73 @@ +package dev.xpple.betterconfig; + +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import dev.xpple.betterconfig.api.Config; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import org.bukkit.Material; + +import java.util.*; + +@SuppressWarnings({"FieldMayBeFinal", "unused", "MismatchedQueryAndUpdateOfCollection"}) +public class Configs { + @Config + public static Material exampleMaterial = Material.STONE; + + @Config + public static Collection exampleMaterialList = new ArrayList<>(List.of(Material.PISTON, Material.STICKY_PISTON)); + + @Config + public static Map exampleStringMaterialMap = new HashMap<>(Map.of("sand", Material.SAND, "red_sand", Material.RED_SAND)); + + @Config + public static Map exampleMaterialStringMap = new HashMap<>(Map.of(Material.NETHERRACK, "nether", Material.END_STONE, "end")); + + @Config(adder = @Config.Adder("customAdder")) + public static Collection exampleCustomAdder = new ArrayList<>(List.of("1", "2")); + public static void customAdder(String string) throws CommandSyntaxException { + try { + Integer.parseInt(string); + } catch (NumberFormatException e) { + throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherParseException().create(string); + } + exampleCustomAdder.add(string); + } + + @Config(putter = @Config.Putter("none"), adder = @Config.Adder("customMapAdder")) + public static Map exampleMapAdder = new HashMap<>(Map.of("a", "A", "b", "B")); + public static void customMapAdder(String string) { + exampleMapAdder.put(string.toLowerCase(Locale.ROOT), string.toUpperCase(Locale.ROOT)); + } + + @Config(adder = @Config.Adder(value = "customTypeAdder", type = int.class)) + public static Collection exampleCustomType = new ArrayList<>(List.of("%", "@")); + public static void customTypeAdder(int codepoint) { + exampleCustomType.add(Character.toString(codepoint)); + } + + @Config + public static TestEnum exampleEnum = TestEnum.ONE; + + @Config(readOnly = true) + public static double exampleReadOnly = Math.PI; + + @Config(temporary = true) + public static double exampleTemporary = Math.random(); + + @Config + private static boolean examplePrivate = false; + + @Config(condition = "isXpple") + public static boolean exampleCondition = true; + public static boolean isXpple(CommandSourceStack source) { + return source.getSender().getName().equals("xpple"); + } + + @Config(setter = @Config.Setter("privateSetter")) + public static String examplePrivateSetter = "nice"; + private static void privateSetter(String string) { + examplePrivateSetter = string + '!'; + } + + @Config(comment = "This is a mysterious object") + public static Object exampleComment = null; +} diff --git a/paper/src/testplugin/java/dev/xpple/betterconfig/MaterialAdapter.java b/paper/src/testplugin/java/dev/xpple/betterconfig/MaterialAdapter.java new file mode 100644 index 0000000..8d9bf67 --- /dev/null +++ b/paper/src/testplugin/java/dev/xpple/betterconfig/MaterialAdapter.java @@ -0,0 +1,22 @@ +package dev.xpple.betterconfig; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; + +import java.io.IOException; + +class MaterialAdapter extends TypeAdapter { + @Override + public void write(JsonWriter writer, Material value) throws IOException { + writer.value(value.getKey().toString()); + } + + @Override + public Material read(JsonReader reader) throws IOException { + return Registry.MATERIAL.get(NamespacedKey.fromString(reader.nextString())); + } +} diff --git a/paper/src/testplugin/java/dev/xpple/betterconfig/MaterialSuggestionProvider.java b/paper/src/testplugin/java/dev/xpple/betterconfig/MaterialSuggestionProvider.java new file mode 100644 index 0000000..d822f47 --- /dev/null +++ b/paper/src/testplugin/java/dev/xpple/betterconfig/MaterialSuggestionProvider.java @@ -0,0 +1,23 @@ +package dev.xpple.betterconfig; + +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.SuggestionProvider; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import dev.xpple.betterconfig.command.suggestion.SuggestionProviderHelper; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; + +import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +class MaterialSuggestionProvider implements SuggestionProvider { + @Override + public CompletableFuture getSuggestions(CommandContext context, SuggestionsBuilder builder) { + Stream keyStream = StreamSupport.stream(Registry.MATERIAL.spliterator(), false).map(Material::getKey); + return SuggestionProviderHelper.suggestNamespacedKeys(keyStream, builder); + } +} diff --git a/paper/src/testplugin/java/dev/xpple/betterconfig/TestEnum.java b/paper/src/testplugin/java/dev/xpple/betterconfig/TestEnum.java new file mode 100644 index 0000000..fe145f6 --- /dev/null +++ b/paper/src/testplugin/java/dev/xpple/betterconfig/TestEnum.java @@ -0,0 +1,7 @@ +package dev.xpple.betterconfig; + +enum TestEnum { + ONE, + TWO, + THREE; +} diff --git a/paper/src/testplugin/java/dev/xpple/betterconfig/TestPlugin.java b/paper/src/testplugin/java/dev/xpple/betterconfig/TestPlugin.java new file mode 100644 index 0000000..6e19367 --- /dev/null +++ b/paper/src/testplugin/java/dev/xpple/betterconfig/TestPlugin.java @@ -0,0 +1,32 @@ +package dev.xpple.betterconfig; + +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import dev.xpple.betterconfig.api.PluginConfigBuilder; +import org.apache.commons.lang3.tuple.Pair; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.plugin.java.JavaPlugin; + +public class TestPlugin extends JavaPlugin { + + private static final String PLUGIN_NAME = "TestPlugin"; + + @Override + public void onEnable() { + new PluginConfigBuilder(PLUGIN_NAME, Configs.class) + .registerTypeHierarchyWithSuggestor(Material.class, new MaterialAdapter(), Pair.of(MaterialSuggestionProvider::new, (ctx, name) -> { + String materialString = ctx.getArgument(name, String.class); + NamespacedKey blockId = NamespacedKey.fromString(materialString); + if (blockId == null) { + throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().create(); + } + Material material = Registry.MATERIAL.get(blockId); + if (material == null) { + throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().create(); + } + return material; + })) + .build(); + } +} diff --git a/paper/src/testplugin/resources/plugin.yml b/paper/src/testplugin/resources/plugin.yml new file mode 100644 index 0000000..d773774 --- /dev/null +++ b/paper/src/testplugin/resources/plugin.yml @@ -0,0 +1,6 @@ +name: TestPlugin +version: '1.0.0' +main: dev.xpple.betterconfig.TestPlugin +api-version: '1.20' +load: STARTUP +authors: [xpple] From 5d5bd4f20aa0fab4770ea38df39252dc38c87a87 Mon Sep 17 00:00:00 2001 From: xpple Date: Sun, 23 Jul 2023 16:51:35 +0200 Subject: [PATCH 06/28] Update README --- README.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 27c30eb..8a05a6b 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,16 @@ public class Configs { public static String exampleString = "default"; } ``` -Finally, in your mod's `onInitialize(Client)` method, register the `Configs` class. Replace `` with your mod's -id. +For Fabric users, register the `Configs` class in your mod's `onInitialize(Client)` method. Replace `` with your +mod's id. ```java new ModConfigBuilder(, Configs.class).build(); ``` +For Paper users, register the `Configs` class in your plugin's `onEnable` method. Replace `` with your +plugin's name. +```java +new PluginConfigBuilder(, Configs.class).build(); +``` That's it! Now you can access `exampleString` through `Configs.exampleString`. You can edit `exampleString` by executing the following command. ``` @@ -25,7 +30,7 @@ the following command. ## That's not all! This mod also supports the use of `Collection`s and `Map`s as variable types. These configurations will have the options -`add`, `put` and `remove` available. Moreover, you can define your own (de)serialisers to create configurations with +`add`, `put` and `remove` available. Moreover, you can define your own (de)serialisers to create configurations with arbitrary types. To do this, all you have to do is register the (de)serialiser when you build your config. For instance, to create a variable with type `Block` you can do ```java @@ -33,8 +38,9 @@ new ModConfigBuilder(, Configs.class) .registerTypeHierarchyWithArgument(Block.class, new BlockAdapter(), new Pair<>(BlockArgumentType::block, BlockArgumentType::getBlock)) .build(); ``` -where `BlockAdapter` extends `TypeAdapter` and `BlockArgumentType` implements `ArgumentType`. See -[these tests](fabric/src/testmod/java/dev/xpple/betterconfig) for a complete picture. +where `BlockAdapter` extends `TypeAdapter` and `BlockArgumentType` implements `ArgumentType`. See +[these tests](fabric/src/testmod/java/dev/xpple/betterconfig) for a complete picture. An identical setup for Paper can +be found [here](paper/src/testplugin/java/dev/xpple/betterconfig). Furthermore, you can completely change the behaviour of updating your config values by creating your own methods. Simply add one or more of `setter`, `adder`, `putter` or `remover` as attribute to your `@Config` annotation. A great use for @@ -48,7 +54,7 @@ public static void customMapAdder(String string) { ``` The value of `"none"` for the putter indicates that no putter will be available. This way, you can use this `Map` in your code like usual, and add values to it using `/(c)config exampleMapAdder add `. For more details, see -[the JavaDocs for `@Config`](fabric/src/main/java/dev/xpple/betterconfig/api/Config.java). +[the JavaDocs for `@Config`](common/src/main/java/dev/xpple/betterconfig/api/Config.java). The parameters of the update method can also be customised. ```java From 72d4f0ee4bf6b6e58cff2a252b31f601f5740f84 Mon Sep 17 00:00:00 2001 From: xpple Date: Sun, 23 Jul 2023 20:26:48 +0200 Subject: [PATCH 07/28] Fix run configurations for Fabric --- fabric/build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fabric/build.gradle b/fabric/build.gradle index 0e4305b..655ee17 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -47,6 +47,10 @@ loom { source sourceSets.testmod } } + + runConfigs.configureEach { + ideConfigGenerated = true + } } repositories { @@ -63,6 +67,7 @@ configurations { dependencies { configurations.compileOnly.extendsFrom(configurations.includeInJar) + configurations.localRuntime.extendsFrom(configurations.includeInJar) includeInJar project(':common') // To change the versions see the gradle.properties file From 699f3d9827c1ed6da3beb2a098dbd53c0976e290 Mon Sep 17 00:00:00 2001 From: xpple Date: Sun, 23 Jul 2023 20:50:17 +0200 Subject: [PATCH 08/28] Update README --- README.md | 54 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 8a05a6b..986835a 100644 --- a/README.md +++ b/README.md @@ -12,27 +12,30 @@ public class Configs { public static String exampleString = "default"; } ``` -For Fabric users, register the `Configs` class in your mod's `onInitialize(Client)` method. Replace `` with your +Finally, register your `Configs` class. +- For Fabric users, register the `Configs` class in your mod's `onInitialize(Client)` method. Replace `` with your mod's id. -```java -new ModConfigBuilder(, Configs.class).build(); -``` -For Paper users, register the `Configs` class in your plugin's `onEnable` method. Replace `` with your + ```java + new ModConfigBuilder(, Configs.class).build(); + ``` +- For Paper users, register the `Configs` class in your plugin's `onEnable` method. Replace `` with your +plugin's name. + ```java + new PluginConfigBuilder(, Configs.class).build(); + ``` +That's it! Now you can access `exampleString` through `Configs.exampleString`. You can edit `exampleString` by using the +config command. +- On Fabric there are different commands for the client and server. For both, replace `` with your mod's id. + - On the client, execute `/cconfig exampleString set `. + - On servers, execute `/config exampleString set `. +- On Paper servers, execute `/config exampleString set `. Replace `` with your plugin's name. -```java -new PluginConfigBuilder(, Configs.class).build(); -``` -That's it! Now you can access `exampleString` through `Configs.exampleString`. You can edit `exampleString` by executing -the following command. -``` -/(c)config exampleString set -``` ## That's not all! -This mod also supports the use of `Collection`s and `Map`s as variable types. These configurations will have the options -`add`, `put` and `remove` available. Moreover, you can define your own (de)serialisers to create configurations with -arbitrary types. To do this, all you have to do is register the (de)serialiser when you build your config. For instance, -to create a variable with type `Block` you can do +This mod also natively supports the use of `Collection`s and `Map`s as variable types. These configurations will have +the options `add`, `put` and `remove` available. Moreover, you can define your own (de)serialisers to create +configurations with arbitrary types. To do this, all you have to do is register the (de)serialiser when you build your +config. For instance, to create configurations with type `Block` you can do ```java new ModConfigBuilder(, Configs.class) .registerTypeHierarchyWithArgument(Block.class, new BlockAdapter(), new Pair<>(BlockArgumentType::block, BlockArgumentType::getBlock)) @@ -44,7 +47,7 @@ be found [here](paper/src/testplugin/java/dev/xpple/betterconfig). Furthermore, you can completely change the behaviour of updating your config values by creating your own methods. Simply add one or more of `setter`, `adder`, `putter` or `remover` as attribute to your `@Config` annotation. A great use for -this would be adding key-pair entries to a `Map` based on a single value. Consider the following configuration. +this would be adding key-value entries to a `Map` based on a single value. Consider the following configuration. ```java @Config(putter = @Config.Putter("none"), adder = @Config.Adder("customMapAdder")) public static Map exampleMapAdder = new HashMap<>(Map.of("a", "A", "b", "B")); @@ -66,12 +69,16 @@ public static void customTypeAdder(int codepoint) { ``` For putters, there are separate key and value type attributes. +And many more things! For some illustrative examples, see the `Configs` class for both +[Fabric](fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java) and +[Paper](paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java). + ## Installation -Replace `${version}` with the artifact version. +Replace `${version}` with the artifact version. Append `-fabric` for Fabric and `-paper` for Paper. You may choose between my own maven repository and GitHub's package repository. ### My own -```gradle +```groovy repositories { maven { url 'https://maven.xpple.dev/maven2' @@ -79,7 +86,7 @@ repositories { } ``` ### GitHub packages -```gradle +```groovy repositories { maven { url 'https://maven.pkg.github.com/xpple/BetterConfig' @@ -91,8 +98,11 @@ repositories { } ``` Import it: -```gradle +```groovy dependencies { + // Fabric include modImplementation('dev.xpple:betterconfig:${version}') + // Paper (also include the JAR in the plugins folder) + compileOnly 'dev.xpple:betterconfig:${version}' } ``` From 2f391e9d6347d53062acc894314a9b79ae8e77ce Mon Sep 17 00:00:00 2001 From: xpple Date: Sat, 19 Aug 2023 20:18:10 +0200 Subject: [PATCH 09/28] Add platform service + fix bug in production --- .../xpple/betterconfig/impl/BetterConfigInternals.java | 9 ++------- .../java/dev/xpple/betterconfig/impl/Platform.java | 9 +++++++++ .../dev/xpple/betterconfig/impl/FabricPlatform.java | 10 ++++++++++ .../services/dev.xpple.betterconfig.impl.Platform | 1 + .../dev/xpple/betterconfig/impl/PaperPlatform.java | 10 ++++++++++ .../services/dev.xpple.betterconfig.impl.Platform | 1 + 6 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 common/src/main/java/dev/xpple/betterconfig/impl/Platform.java create mode 100644 fabric/src/main/java/dev/xpple/betterconfig/impl/FabricPlatform.java create mode 100644 fabric/src/main/resources/META-INF/services/dev.xpple.betterconfig.impl.Platform create mode 100644 paper/src/main/java/dev/xpple/betterconfig/impl/PaperPlatform.java create mode 100644 paper/src/main/resources/META-INF/services/dev.xpple.betterconfig.impl.Platform 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 cc342c3..7fa85a6 100644 --- a/common/src/main/java/dev/xpple/betterconfig/impl/BetterConfigInternals.java +++ b/common/src/main/java/dev/xpple/betterconfig/impl/BetterConfigInternals.java @@ -82,13 +82,8 @@ public static void init(AbstractConfigImpl abstractConfig) { } catch (ReflectiveOperationException e) { hasParameter = true; try { - Class clazz; - try { - clazz = Class.forName("net.minecraft.command.CommandSource"); - } catch (ReflectiveOperationException e1) { - clazz = Class.forName("io.papermc.paper.command.brigadier.CommandSourceStack"); - } - predicateMethod = abstractConfig.getConfigsClass().getDeclaredMethod(annotation.condition(), clazz); + Class commandSourceClass = Platform.current.getCommandSourceClass(); + predicateMethod = abstractConfig.getConfigsClass().getDeclaredMethod(annotation.condition(), commandSourceClass); } catch (ReflectiveOperationException e1) { throw new AssertionError(e1); } diff --git a/common/src/main/java/dev/xpple/betterconfig/impl/Platform.java b/common/src/main/java/dev/xpple/betterconfig/impl/Platform.java new file mode 100644 index 0000000..34c9afa --- /dev/null +++ b/common/src/main/java/dev/xpple/betterconfig/impl/Platform.java @@ -0,0 +1,9 @@ +package dev.xpple.betterconfig.impl; + +import java.util.ServiceLoader; + +public interface Platform { + Class getCommandSourceClass(); + + Platform current = ServiceLoader.load(Platform.class, Platform.class.getClassLoader()).iterator().next(); +} diff --git a/fabric/src/main/java/dev/xpple/betterconfig/impl/FabricPlatform.java b/fabric/src/main/java/dev/xpple/betterconfig/impl/FabricPlatform.java new file mode 100644 index 0000000..a6940c2 --- /dev/null +++ b/fabric/src/main/java/dev/xpple/betterconfig/impl/FabricPlatform.java @@ -0,0 +1,10 @@ +package dev.xpple.betterconfig.impl; + +import net.minecraft.command.CommandSource; + +public class FabricPlatform implements Platform { + @Override + public Class getCommandSourceClass() { + return CommandSource.class; + } +} diff --git a/fabric/src/main/resources/META-INF/services/dev.xpple.betterconfig.impl.Platform b/fabric/src/main/resources/META-INF/services/dev.xpple.betterconfig.impl.Platform new file mode 100644 index 0000000..260c578 --- /dev/null +++ b/fabric/src/main/resources/META-INF/services/dev.xpple.betterconfig.impl.Platform @@ -0,0 +1 @@ +dev.xpple.betterconfig.impl.FabricPlatform diff --git a/paper/src/main/java/dev/xpple/betterconfig/impl/PaperPlatform.java b/paper/src/main/java/dev/xpple/betterconfig/impl/PaperPlatform.java new file mode 100644 index 0000000..be3948c --- /dev/null +++ b/paper/src/main/java/dev/xpple/betterconfig/impl/PaperPlatform.java @@ -0,0 +1,10 @@ +package dev.xpple.betterconfig.impl; + +import io.papermc.paper.command.brigadier.CommandSourceStack; + +public class PaperPlatform implements Platform { + @Override + public Class getCommandSourceClass() { + return CommandSourceStack.class; + } +} diff --git a/paper/src/main/resources/META-INF/services/dev.xpple.betterconfig.impl.Platform b/paper/src/main/resources/META-INF/services/dev.xpple.betterconfig.impl.Platform new file mode 100644 index 0000000..b688434 --- /dev/null +++ b/paper/src/main/resources/META-INF/services/dev.xpple.betterconfig.impl.Platform @@ -0,0 +1 @@ +dev.xpple.betterconfig.impl.PaperPlatform From 97c99dd588c627e29267ac0fc26e26eef11fdeee Mon Sep 17 00:00:00 2001 From: xpple Date: Fri, 25 Aug 2023 16:38:59 +0200 Subject: [PATCH 10/28] Rename config field --- paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java b/paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java index bbdfd2e..64573d0 100644 --- a/paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java +++ b/paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java @@ -73,5 +73,5 @@ private static void privateSetter(String string) { public static Object exampleComment = null; @Config - public static BlockState exampleNativeArgument = Material.COMPOSTER.createBlockData().createBlockState(); + public static BlockState exampleNativeArgumentType = Material.COMPOSTER.createBlockData().createBlockState(); } From 8aa1571a34b46b6bd0d3be3b57028c545643d330 Mon Sep 17 00:00:00 2001 From: xpple Date: Wed, 21 Feb 2024 13:06:51 +0100 Subject: [PATCH 11/28] Update to 1.20.4 --- common/build.gradle | 2 +- fabric/build.gradle | 4 ++-- gradle.properties | 8 ++++---- paper/build.gradle | 4 ++-- .../java/dev/xpple/betterconfig/BetterConfig.java | 11 ++--------- .../java/dev/xpple/betterconfig/TestPlugin.java | 4 ++-- 6 files changed, 13 insertions(+), 20 deletions(-) diff --git a/common/build.gradle b/common/build.gradle index abf0822..54dd572 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'fabric-loom' version '1.2-SNAPSHOT' + id 'fabric-loom' version '1.5-SNAPSHOT' } sourceCompatibility = JavaVersion.VERSION_17 diff --git a/fabric/build.gradle b/fabric/build.gradle index 655ee17..0e978b4 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'fabric-loom' version '1.2-SNAPSHOT' + id 'fabric-loom' version '1.5-SNAPSHOT' id 'maven-publish' } @@ -132,7 +132,7 @@ publishing { // retrieving dependencies. maven { name = "xpple" - url = "sftp://xpple.dev:22/maven.xpple.dev/maven2" + url = "sftp://xpple.dev:22/maven.xpple.dev/httpdocs/maven2" credentials { username = System.getenv("MAVEN_USER") password = System.getenv("MAVEN_PASS") diff --git a/gradle.properties b/gradle.properties index 21e76fc..881d2d6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,12 +9,12 @@ archives_base_name=betterconfig # Fabric Loader Properties # check these on https://fabricmc.net/develop -minecraft_version=1.20.2 -yarn_mappings=1.20.2+build.4 -fabric_loader_version=0.14.22 +minecraft_version=1.20.4 +yarn_mappings=1.20.4+build.3 +fabric_loader_version=0.15.7 # Fabric Properties -fabric_api_version=0.89.3+1.20.2 +fabric_api_version=0.96.3+1.20.4 # Paper Properties paper_api_version=1.20 diff --git a/paper/build.gradle b/paper/build.gradle index d0837fe..3d963bb 100644 --- a/paper/build.gradle +++ b/paper/build.gradle @@ -37,7 +37,7 @@ dependencies { configurations.compileOnly.extendsFrom(configurations.includeInJar) includeInJar project(':common') - compileOnly "io.papermc.paper:paper-api:1.20.1-R0.1-SNAPSHOT" + compileOnly "io.papermc.paper:paper-api:1.20.4-R0.1-SNAPSHOT" } processResources { @@ -127,7 +127,7 @@ publishing { repositories { maven { name = "xpple" - url = "sftp://xpple.dev:22/maven.xpple.dev/maven2" + url = "sftp://xpple.dev:22/maven.xpple.dev/httpdocs/maven2" credentials { username = System.getenv("MAVEN_USER") password = System.getenv("MAVEN_PASS") diff --git a/paper/src/main/java/dev/xpple/betterconfig/BetterConfig.java b/paper/src/main/java/dev/xpple/betterconfig/BetterConfig.java index adc4697..cc8a230 100644 --- a/paper/src/main/java/dev/xpple/betterconfig/BetterConfig.java +++ b/paper/src/main/java/dev/xpple/betterconfig/BetterConfig.java @@ -1,10 +1,8 @@ package dev.xpple.betterconfig; import dev.xpple.betterconfig.command.ConfigCommand; -import io.papermc.paper.event.server.ServerResourcesLoadEvent; +import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents; import org.bukkit.Bukkit; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; import org.bukkit.plugin.java.JavaPlugin; import java.nio.file.Path; @@ -15,11 +13,6 @@ public final class BetterConfig extends JavaPlugin { @Override public void onEnable() { - this.getServer().getPluginManager().registerEvents(new Listener() { - @EventHandler - public void load(ServerResourcesLoadEvent event) { - event.getCommands().register(BetterConfig.this, ConfigCommand.build()); - } - }, this); + this.getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, event -> event.registrar().register(ConfigCommand.build())); } } diff --git a/paper/src/testplugin/java/dev/xpple/betterconfig/TestPlugin.java b/paper/src/testplugin/java/dev/xpple/betterconfig/TestPlugin.java index c71befd..632ed2a 100644 --- a/paper/src/testplugin/java/dev/xpple/betterconfig/TestPlugin.java +++ b/paper/src/testplugin/java/dev/xpple/betterconfig/TestPlugin.java @@ -2,7 +2,7 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import dev.xpple.betterconfig.api.PluginConfigBuilder; -import io.papermc.paper.command.brigadier.argument.VanillaArgumentTypes; +import io.papermc.paper.command.brigadier.argument.ArgumentTypes; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.Registry; @@ -28,7 +28,7 @@ public void onEnable() { } return material; }) - .registerTypeHierarchy(BlockState.class, new BlockStateAdapter(), VanillaArgumentTypes::blockState) + .registerTypeHierarchy(BlockState.class, new BlockStateAdapter(), ArgumentTypes::blockState) .build(); } } From 80a89795a9ad9db6520b3ef6b5b7657eb209b36a Mon Sep 17 00:00:00 2001 From: xpple Date: Fri, 23 Feb 2024 23:24:53 +0100 Subject: [PATCH 12/28] Port to mojmap + add custom argument type example --- common/build.gradle | 15 +++--- .../api/AbstractConfigBuilder.java | 24 ++++----- .../command/AbstractConfigCommand.java | 28 +++++----- .../betterconfig/impl/AbstractConfigImpl.java | 46 ++++++++-------- .../impl/BetterConfigInternals.java | 15 +++--- fabric/build.gradle | 19 ++++--- .../betterconfig/BetterConfigClient.java | 6 +-- .../command/client/ConfigCommandClient.java | 40 +++++++------- .../dev/xpple/betterconfig/BetterConfig.java | 10 ++-- .../betterconfig/api/ModConfigBuilder.java | 6 +-- .../betterconfig/command/ConfigCommand.java | 46 ++++++++-------- .../suggestion/EnumSuggestionProvider.java | 4 +- .../betterconfig/impl/FabricPlatform.java | 4 +- .../betterconfig/impl/ModConfigImpl.java | 13 +++-- .../dev/xpple/betterconfig/BlockAdapter.java | 10 ++-- .../xpple/betterconfig/BlockArgumentType.java | 18 +++---- .../xpple/betterconfig/BlockStateAdapter.java | 14 ++--- .../betterconfig/BlockSuggestionProvider.java | 12 ++--- .../java/dev/xpple/betterconfig/Configs.java | 26 +++++---- .../java/dev/xpple/betterconfig/TestMod.java | 24 ++++----- .../dev/xpple/betterconfig/TestModClient.java | 8 +-- gradle.properties | 2 +- paper/build.gradle | 4 +- .../betterconfig/impl/PluginConfigImpl.java | 5 +- .../java/dev/xpple/betterconfig/Configs.java | 11 +++- .../xpple/betterconfig/StructureAdapter.java | 22 ++++++++ .../betterconfig/StructureArgumentType.java | 53 +++++++++++++++++++ .../dev/xpple/betterconfig/TestPlugin.java | 2 + settings.gradle | 1 - 29 files changed, 294 insertions(+), 194 deletions(-) create mode 100644 paper/src/testplugin/java/dev/xpple/betterconfig/StructureAdapter.java create mode 100644 paper/src/testplugin/java/dev/xpple/betterconfig/StructureArgumentType.java diff --git a/common/build.gradle b/common/build.gradle index 54dd572..222019f 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -10,17 +10,20 @@ version = project.base_version group = project.maven_group repositories { - // Add repositories to retrieve artifacts from in here. - // You should only use this when depending on other mods because - // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. - // See https://docs.gradle.org/current/userguide/declaring_repositories.html - // for more information about repositories. + maven { + url = 'https://maven.parchmentmc.org' + } } dependencies { // To change the versions see the gradle.properties file minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + mappings loom.layered { + officialMojangMappings { + nameSyntheticMembers = true + } + parchment "org.parchmentmc.data:${project.parchment_mappings}" + } } tasks.withType(JavaCompile).configureEach { diff --git a/common/src/main/java/dev/xpple/betterconfig/api/AbstractConfigBuilder.java b/common/src/main/java/dev/xpple/betterconfig/api/AbstractConfigBuilder.java index b70a197..7d14248 100644 --- a/common/src/main/java/dev/xpple/betterconfig/api/AbstractConfigBuilder.java +++ b/common/src/main/java/dev/xpple/betterconfig/api/AbstractConfigBuilder.java @@ -14,12 +14,12 @@ import java.util.function.Function; import java.util.function.Supplier; -public abstract class AbstractConfigBuilder { +public abstract class AbstractConfigBuilder { final Class configsClass; final GsonBuilder builder = new GsonBuilder().serializeNulls().enableComplexMapKeySerialization(); - final Map, Function>> arguments = new HashMap<>(); + final Map, Function>> arguments = new HashMap<>(); final Map, Pair, CheckedBiFunction, String, ?, CommandSyntaxException>>> suggestors = new HashMap<>(); public AbstractConfigBuilder(Class configsClass) { @@ -38,15 +38,15 @@ public AbstractConfigBuilder(Class configsClass) { * as well. * @see AbstractConfigBuilder#registerTypeHierarchy(Class, TypeAdapter, Supplier) */ - public AbstractConfigBuilder registerType(Class type, TypeAdapter adapter, Supplier> argumentTypeSupplier) { - return this.registerType(type, adapter, registryAccess -> argumentTypeSupplier.get()); + public AbstractConfigBuilder registerType(Class type, TypeAdapter adapter, Supplier> argumentTypeSupplier) { + return this.registerType(type, adapter, buildContext -> argumentTypeSupplier.get()); } /** * Register a new type adapter and argument type for the specified type. * @param type the type's class * @param adapter the type adapter - * @param argumentTypeFunction a function for the argument type needing registry access + * @param argumentTypeFunction a function for the argument type needing build context * @param the type * @return the current builder instance * @implNote On servers, consider using {@link AbstractConfigBuilder#registerType(Class, TypeAdapter, SuggestionProvider, CheckedBiFunction)} @@ -54,7 +54,7 @@ public AbstractConfigBuilder registerType(Class type, TypeAdapter AbstractConfigBuilder registerType(Class type, TypeAdapter adapter, Function> argumentTypeFunction) { + public AbstractConfigBuilder registerType(Class type, TypeAdapter adapter, Function> argumentTypeFunction) { this.builder.registerTypeAdapter(type, adapter); this.arguments.put(type, argumentTypeFunction); return this; @@ -72,15 +72,15 @@ public AbstractConfigBuilder registerType(Class type, TypeAdapter AbstractConfigBuilder registerTypeHierarchy(Class type, TypeAdapter adapter, Supplier> argumentTypeSupplier) { - return this.registerTypeHierarchy(type, adapter, registryAccess -> argumentTypeSupplier.get()); + public AbstractConfigBuilder registerTypeHierarchy(Class type, TypeAdapter adapter, Supplier> argumentTypeSupplier) { + return this.registerTypeHierarchy(type, adapter, buildContext -> argumentTypeSupplier.get()); } /** * Register a new type adapter and argument type for the specified type and all subclasses. * @param type the type's class * @param adapter the type adapter - * @param argumentTypeFunction a function for the argument type needing registry access + * @param argumentTypeFunction a function for the argument type needing build context * @param the type * @return the current builder instance * @implNote On servers, consider using {@link AbstractConfigBuilder#registerTypeHierarchy(Class, TypeAdapter, SuggestionProvider, CheckedBiFunction)} @@ -88,7 +88,7 @@ public AbstractConfigBuilder registerTypeHierarchy(Class type, Type * as well. * @see AbstractConfigBuilder#registerType(Class, TypeAdapter, Function) */ - public AbstractConfigBuilder registerTypeHierarchy(Class type, TypeAdapter adapter, Function> argumentTypeFunction) { + public AbstractConfigBuilder registerTypeHierarchy(Class type, TypeAdapter adapter, Function> argumentTypeFunction) { this.builder.registerTypeHierarchyAdapter(type, adapter); this.arguments.put(type, argumentTypeFunction); return this; @@ -105,7 +105,7 @@ public AbstractConfigBuilder registerTypeHierarchy(Class type, Type * @implNote On clients, consider using {@link AbstractConfigBuilder#registerType(Class, TypeAdapter, Supplier)} instead. * @see AbstractConfigBuilder#registerTypeHierarchy(Class, TypeAdapter, SuggestionProvider, CheckedBiFunction) */ - public AbstractConfigBuilder registerType(Class type, TypeAdapter adapter, SuggestionProvider suggestionProvider, CheckedBiFunction, String, T, CommandSyntaxException> argumentParser) { + public AbstractConfigBuilder registerType(Class type, TypeAdapter adapter, SuggestionProvider suggestionProvider, CheckedBiFunction, String, T, CommandSyntaxException> argumentParser) { this.builder.registerTypeAdapter(type, adapter); this.suggestors.put(type, new Pair<>(suggestionProvider, argumentParser)); return this; @@ -122,7 +122,7 @@ public AbstractConfigBuilder registerType(Class type, TypeAdapter AbstractConfigBuilder registerTypeHierarchy(Class type, TypeAdapter adapter, SuggestionProvider suggestionProvider, CheckedBiFunction, String, T, CommandSyntaxException> argumentParser) { + public AbstractConfigBuilder registerTypeHierarchy(Class type, TypeAdapter adapter, SuggestionProvider suggestionProvider, CheckedBiFunction, String, T, CommandSyntaxException> argumentParser) { this.builder.registerTypeHierarchyAdapter(type, adapter); this.suggestors.put(type, new Pair<>(suggestionProvider, argumentParser)); return this; 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 58aeefc..76da693 100644 --- a/common/src/main/java/dev/xpple/betterconfig/command/AbstractConfigCommand.java +++ b/common/src/main/java/dev/xpple/betterconfig/command/AbstractConfigCommand.java @@ -19,7 +19,7 @@ import static com.mojang.brigadier.arguments.StringArgumentType.*; -public abstract class AbstractConfigCommand { +public abstract class AbstractConfigCommand { protected abstract > SuggestionProvider enumSuggestionProvider(Class type); protected abstract DynamicCommandExceptionType invalidEnumException(); @@ -30,9 +30,9 @@ protected AbstractConfigCommand(String rootLiteral) { this.rootLiteral = rootLiteral; } - protected final LiteralArgumentBuilder create(Collection> abstractConfigs, R registryAccess) { + protected final LiteralArgumentBuilder create(Collection> abstractConfigs, C buildContext) { LiteralArgumentBuilder root = LiteralArgumentBuilder.literal(this.rootLiteral); - for (AbstractConfigImpl abstractConfig : abstractConfigs) { + for (AbstractConfigImpl abstractConfig : abstractConfigs) { Map> literals = new HashMap<>(); for (String config : abstractConfig.getConfigs().keySet()) { Predicate condition = abstractConfig.getConditions().get(config); @@ -51,7 +51,7 @@ protected final LiteralArgumentBuilder create(Collection subCommand = RequiredArgumentBuilder.argument("value", argumentFunction.apply(registryAccess)); + RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", argumentFunction.apply(buildContext)); subCommand.executes(ctx -> set(ctx.getSource(), abstractConfig, config, ctx.getArgument("value", type))); literals.get(config).then(LiteralArgumentBuilder.literal("set").then(subCommand)); } else if (suggestorPair != null) { @@ -76,7 +76,7 @@ protected final LiteralArgumentBuilder create(Collection subCommand = RequiredArgumentBuilder.argument("value", argumentFunction.apply(registryAccess)); + RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", argumentFunction.apply(buildContext)); subCommand.executes(ctx -> add(ctx.getSource(), abstractConfig, config, ctx.getArgument("value", type))); literals.get(config).then(LiteralArgumentBuilder.literal("add").then(subCommand)); } else if (suggestorPair != null) { @@ -104,7 +104,7 @@ protected final LiteralArgumentBuilder create(Collection ctx.getArgument("key", keyType); } else if (keySuggestorPair != null) { subCommand = RequiredArgumentBuilder.argument("key", string()); @@ -125,7 +125,7 @@ protected final LiteralArgumentBuilder create(Collection subSubCommand = RequiredArgumentBuilder.argument("value", valueArgumentFunction.apply(registryAccess)); + RequiredArgumentBuilder subSubCommand = RequiredArgumentBuilder.argument("value", valueArgumentFunction.apply(buildContext)); subSubCommand.executes(ctx -> put(ctx.getSource(), abstractConfig, config, getKey.apply(ctx), ctx.getArgument("value", valueType))); literals.get(config).then(LiteralArgumentBuilder.literal("put").then(subCommand.then(subSubCommand))); } else if (valueSuggestorPair != null) { @@ -150,7 +150,7 @@ protected final LiteralArgumentBuilder create(Collection subCommand = RequiredArgumentBuilder.argument("value", argumentFunction.apply(registryAccess)); + RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", argumentFunction.apply(buildContext)); subCommand.executes(ctx -> remove(ctx.getSource(), abstractConfig, config, ctx.getArgument("value", type))); literals.get(config).then(LiteralArgumentBuilder.literal("remove").then(subCommand)); } else if (suggestorPair != null) { @@ -175,15 +175,15 @@ protected final LiteralArgumentBuilder create(Collection abstractConfig, String config); + protected abstract int get(S source, AbstractConfigImpl abstractConfig, String config); - protected abstract int reset(S source, AbstractConfigImpl abstractConfig, String config); + protected abstract int reset(S source, AbstractConfigImpl abstractConfig, String config); - protected abstract int set(S source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException; + protected abstract int set(S source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException; - protected abstract int add(S source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException; + protected abstract int add(S source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException; - protected abstract int put(S source, AbstractConfigImpl abstractConfig, String config, Object key, Object value) throws CommandSyntaxException; + protected abstract int put(S source, AbstractConfigImpl abstractConfig, String config, Object key, Object value) throws CommandSyntaxException; - protected abstract int remove(S source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException; + protected abstract int remove(S source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException; } diff --git a/common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java b/common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java index a2c4c2c..f5347d8 100644 --- a/common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java +++ b/common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java @@ -3,10 +3,17 @@ import com.google.common.collect.ImmutableMap; import com.google.gson.Gson; import com.google.gson.JsonObject; -import com.mojang.brigadier.arguments.*; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.arguments.BoolArgumentType; +import com.mojang.brigadier.arguments.DoubleArgumentType; +import com.mojang.brigadier.arguments.FloatArgumentType; +import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.arguments.LongArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.suggestion.SuggestionProvider; +import dev.xpple.betterconfig.BetterConfigCommon; import dev.xpple.betterconfig.api.AbstractConfig; import dev.xpple.betterconfig.api.Config; import dev.xpple.betterconfig.util.CheckedBiConsumer; @@ -25,32 +32,30 @@ import java.util.function.Function; import java.util.function.Predicate; -import static dev.xpple.betterconfig.BetterConfigCommon.LOGGER; - -public abstract class AbstractConfigImpl implements AbstractConfig { +public abstract class AbstractConfigImpl implements AbstractConfig { private static final Map, Function>> defaultArguments = ImmutableMap., Function>>builder() - .put(boolean.class, registryAccess -> BoolArgumentType.bool()) - .put(Boolean.class, registryAccess -> BoolArgumentType.bool()) - .put(double.class, registryAccess -> DoubleArgumentType.doubleArg()) - .put(Double.class, registryAccess -> DoubleArgumentType.doubleArg()) - .put(float.class, registryAccess -> FloatArgumentType.floatArg()) - .put(Float.class, registryAccess -> FloatArgumentType.floatArg()) - .put(int.class, registryAccess -> IntegerArgumentType.integer()) - .put(Integer.class, registryAccess -> IntegerArgumentType.integer()) - .put(long.class, registryAccess -> LongArgumentType.longArg()) - .put(Long.class, registryAccess -> LongArgumentType.longArg()) - .put(String.class, registryAccess -> StringArgumentType.string()) + .put(boolean.class, buildContext -> BoolArgumentType.bool()) + .put(Boolean.class, buildContext -> BoolArgumentType.bool()) + .put(double.class, buildContext -> DoubleArgumentType.doubleArg()) + .put(Double.class, buildContext -> DoubleArgumentType.doubleArg()) + .put(float.class, buildContext -> FloatArgumentType.floatArg()) + .put(Float.class, buildContext -> FloatArgumentType.floatArg()) + .put(int.class, buildContext -> IntegerArgumentType.integer()) + .put(Integer.class, buildContext -> IntegerArgumentType.integer()) + .put(long.class, buildContext -> LongArgumentType.longArg()) + .put(Long.class, buildContext -> LongArgumentType.longArg()) + .put(String.class, buildContext -> StringArgumentType.string()) .build(); private final Class configsClass; private final Gson gson; private final Gson inlineGson; - private final Map, Function>> arguments; + private final Map, Function>> arguments; private final Map, Pair, CheckedBiFunction, String, ?, CommandSyntaxException>>> suggestors; - protected AbstractConfigImpl(Class configsClass, Gson gson, Map, Function>> arguments, Map, Pair, CheckedBiFunction, String, ?, CommandSyntaxException>>> suggestors) { + protected AbstractConfigImpl(Class configsClass, Gson gson, Map, Function>> arguments, Map, Pair, CheckedBiFunction, String, ?, CommandSyntaxException>>> suggestors) { this.configsClass = configsClass; this.gson = gson.newBuilder().setPrettyPrinting().create(); this.inlineGson = gson; @@ -70,8 +75,8 @@ public Gson getGson() { } @SuppressWarnings("unchecked") - public Function> getArgument(Class type) { - return this.arguments.getOrDefault(type, (Function>) defaultArguments.get(type)); + public Function> getArgument(Class type) { + return this.arguments.getOrDefault(type, (Function>) defaultArguments.get(type)); } public Pair, CheckedBiFunction, String, ?, CommandSyntaxException>> getSuggestor(Class type) { @@ -193,8 +198,7 @@ public boolean save() { }); writer.write(this.gson.toJson(root)); } catch (IOException e) { - LOGGER.error("Could not save config file."); - e.printStackTrace(); + BetterConfigCommon.LOGGER.error("Could not save config file.", e); return false; } return true; 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 0cb0bd0..12ce356 100644 --- a/common/src/main/java/dev/xpple/betterconfig/impl/BetterConfigInternals.java +++ b/common/src/main/java/dev/xpple/betterconfig/impl/BetterConfigInternals.java @@ -3,20 +3,23 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.mojang.brigadier.exceptions.CommandSyntaxException; +import dev.xpple.betterconfig.BetterConfigCommon; import dev.xpple.betterconfig.api.Config; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; -import java.lang.reflect.*; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.util.Collection; import java.util.Map; import java.util.Objects; -import static dev.xpple.betterconfig.BetterConfigCommon.LOGGER; - public class BetterConfigInternals { public static void init(AbstractConfigImpl abstractConfig) { @@ -25,8 +28,7 @@ public static void init(AbstractConfigImpl abstractConfig) { root = JsonParser.parseReader(reader).getAsJsonObject(); } catch (IOException ignored) { } catch (Exception e) { - LOGGER.warn("Could not read config file, default values will be used."); - LOGGER.warn("The old config file will be renamed."); + BetterConfigCommon.LOGGER.warn("Could not read config file, default values will be used.\nThe old config file will be renamed.", e); try { Files.move(abstractConfig.getConfigsPath(), abstractConfig.getConfigsPath().resolveSibling("config_old.json"), StandardCopyOption.REPLACE_EXISTING); } catch (IOException ignored) { @@ -135,8 +137,7 @@ public static void init(AbstractConfigImpl abstractConfig) { try (BufferedWriter writer = Files.newBufferedWriter(abstractConfig.getConfigsPath())) { writer.write(abstractConfig.getGson().toJson(root)); } catch (IOException e) { - LOGGER.error("Could not save config file."); - e.printStackTrace(); + BetterConfigCommon.LOGGER.error("Could not save config file.", e); } } diff --git a/fabric/build.gradle b/fabric/build.gradle index 0e978b4..2d93994 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -6,8 +6,8 @@ plugins { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 -archivesBaseName = project.archives_base_name -version = "${project.base_version}-fabric" +archivesBaseName = "${project.archives_base_name}-fabric" +version = project.base_version group = project.maven_group loom { @@ -54,11 +54,9 @@ loom { } repositories { - // Add repositories to retrieve artifacts from in here. - // You should only use this when depending on other mods because - // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. - // See https://docs.gradle.org/current/userguide/declaring_repositories.html - // for more information about repositories. + maven { + url = 'https://maven.parchmentmc.org' + } } configurations { @@ -72,7 +70,12 @@ dependencies { // To change the versions see the gradle.properties file minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + mappings loom.layered { + officialMojangMappings { + nameSyntheticMembers = true + } + parchment "org.parchmentmc.data:${project.parchment_mappings}" + } modImplementation "net.fabricmc:fabric-loader:${project.fabric_loader_version}" // Fabric API. This is technically optional, but you probably want it anyway. diff --git a/fabric/src/client/java/dev/xpple/betterconfig/BetterConfigClient.java b/fabric/src/client/java/dev/xpple/betterconfig/BetterConfigClient.java index 286172b..349a5b2 100644 --- a/fabric/src/client/java/dev/xpple/betterconfig/BetterConfigClient.java +++ b/fabric/src/client/java/dev/xpple/betterconfig/BetterConfigClient.java @@ -5,7 +5,7 @@ import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; -import net.minecraft.command.CommandRegistryAccess; +import net.minecraft.commands.CommandBuildContext; public class BetterConfigClient implements ClientModInitializer { @@ -14,7 +14,7 @@ public void onInitializeClient() { ClientCommandRegistrationCallback.EVENT.register(BetterConfigClient::registerCommands); } - private static void registerCommands(CommandDispatcher dispatcher, CommandRegistryAccess registryAccess) { - ConfigCommandClient.register(dispatcher, registryAccess); + private static void registerCommands(CommandDispatcher dispatcher, CommandBuildContext buildContext) { + ConfigCommandClient.register(dispatcher, buildContext); } } 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 9bc14d0..3a78d8b 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 @@ -10,10 +10,10 @@ import dev.xpple.betterconfig.impl.AbstractConfigImpl; import dev.xpple.betterconfig.impl.BetterConfigImpl; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; -import net.minecraft.command.CommandRegistryAccess; -import net.minecraft.text.Text; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.network.chat.Component; -public class ConfigCommandClient extends AbstractConfigCommand { +public class ConfigCommandClient extends AbstractConfigCommand { @Override protected > SuggestionProvider enumSuggestionProvider(Class type) { @@ -22,7 +22,7 @@ protected > SuggestionProvider enum @Override protected DynamicCommandExceptionType invalidEnumException() { - return new DynamicCommandExceptionType(value -> Text.translatable("argument.enum.invalid", value)); + return new DynamicCommandExceptionType(value -> Component.translatable("argument.enum.invalid", value)); } private ConfigCommandClient() { @@ -30,55 +30,55 @@ private ConfigCommandClient() { } @SuppressWarnings("unchecked") - public static void register(CommandDispatcher dispatcher, CommandRegistryAccess registryAccess) { - dispatcher.register(new ConfigCommandClient().create(BetterConfigImpl.getModConfigs().values().stream().map(modConfig -> (AbstractConfigImpl) modConfig).toList(), registryAccess)); + public static void register(CommandDispatcher dispatcher, CommandBuildContext buildContext) { + dispatcher.register(new ConfigCommandClient().create(BetterConfigImpl.getModConfigs().values().stream().map(modConfig -> (AbstractConfigImpl) modConfig).toList(), buildContext)); } @Override protected int comment(FabricClientCommandSource source, String config, String comment) { - source.sendFeedback(Text.translatable("betterconfig.commands.config.comment", config)); - source.sendFeedback(Text.of(comment)); + source.sendFeedback(Component.translatable("betterconfig.commands.config.comment", config)); + source.sendFeedback(Component.literal(comment)); return Command.SINGLE_SUCCESS; } @Override - protected int get(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config) { - source.sendFeedback(Text.translatable("betterconfig.commands.config.get", config, abstractConfig.asString(config))); + protected int get(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config) { + source.sendFeedback(Component.translatable("betterconfig.commands.config.get", config, abstractConfig.asString(config))); return Command.SINGLE_SUCCESS; } @Override - protected int reset(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config) { + protected int reset(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config) { abstractConfig.reset(config); - source.sendFeedback(Text.translatable("betterconfig.commands.config.reset", config, abstractConfig.asString(config))); + source.sendFeedback(Component.translatable("betterconfig.commands.config.reset", config, abstractConfig.asString(config))); return Command.SINGLE_SUCCESS; } @Override - protected int set(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { + protected int set(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { abstractConfig.set(config, value); - source.sendFeedback(Text.translatable("betterconfig.commands.config.set", config, abstractConfig.asString(config))); + source.sendFeedback(Component.translatable("betterconfig.commands.config.set", config, abstractConfig.asString(config))); return Command.SINGLE_SUCCESS; } @Override - protected int add(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { + protected int add(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { abstractConfig.add(config, value); - source.sendFeedback(Text.translatable("betterconfig.commands.config.add", abstractConfig.asString(value), config)); + source.sendFeedback(Component.translatable("betterconfig.commands.config.add", abstractConfig.asString(value), config)); return Command.SINGLE_SUCCESS; } @Override - protected int put(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config, Object key, Object value) throws CommandSyntaxException { + protected int put(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config, Object key, Object value) throws CommandSyntaxException { abstractConfig.put(config, key, value); - source.sendFeedback(Text.translatable("betterconfig.commands.config.put", abstractConfig.asString(key), abstractConfig.asString(value), config)); + source.sendFeedback(Component.translatable("betterconfig.commands.config.put", abstractConfig.asString(key), abstractConfig.asString(value), config)); return Command.SINGLE_SUCCESS; } @Override - protected int remove(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { + protected int remove(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { abstractConfig.remove(config, value); - source.sendFeedback(Text.translatable("betterconfig.commands.config.remove", abstractConfig.asString(value), config)); + source.sendFeedback(Component.translatable("betterconfig.commands.config.remove", abstractConfig.asString(value), config)); return Command.SINGLE_SUCCESS; } } diff --git a/fabric/src/main/java/dev/xpple/betterconfig/BetterConfig.java b/fabric/src/main/java/dev/xpple/betterconfig/BetterConfig.java index 64c2868..db9675e 100644 --- a/fabric/src/main/java/dev/xpple/betterconfig/BetterConfig.java +++ b/fabric/src/main/java/dev/xpple/betterconfig/BetterConfig.java @@ -5,9 +5,9 @@ import net.fabricmc.api.DedicatedServerModInitializer; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.command.CommandRegistryAccess; -import net.minecraft.server.command.CommandManager; -import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; import java.nio.file.Path; @@ -20,7 +20,7 @@ public void onInitializeServer() { CommandRegistrationCallback.EVENT.register(BetterConfig::registerCommands); } - private static void registerCommands(CommandDispatcher dispatcher, CommandRegistryAccess registryAccess, CommandManager.RegistrationEnvironment environment) { - ConfigCommand.register(dispatcher, registryAccess); + private static void registerCommands(CommandDispatcher dispatcher, CommandBuildContext buildContext, Commands.CommandSelection selection) { + ConfigCommand.register(dispatcher, buildContext); } } diff --git a/fabric/src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java b/fabric/src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java index a7a1c04..be15d00 100644 --- a/fabric/src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java +++ b/fabric/src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java @@ -3,10 +3,10 @@ import dev.xpple.betterconfig.impl.BetterConfigImpl; import dev.xpple.betterconfig.impl.BetterConfigInternals; import dev.xpple.betterconfig.impl.ModConfigImpl; -import net.minecraft.command.CommandRegistryAccess; -import net.minecraft.command.CommandSource; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.SharedSuggestionProvider; -public class ModConfigBuilder extends AbstractConfigBuilder { +public class ModConfigBuilder extends AbstractConfigBuilder { private final String modId; 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 b1622c6..614e078 100644 --- a/fabric/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java +++ b/fabric/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java @@ -8,20 +8,20 @@ import dev.xpple.betterconfig.command.suggestion.EnumSuggestionProvider; import dev.xpple.betterconfig.impl.AbstractConfigImpl; import dev.xpple.betterconfig.impl.BetterConfigImpl; -import net.minecraft.command.CommandRegistryAccess; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.text.Text; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.network.chat.Component; -public class ConfigCommand extends AbstractConfigCommand { +public class ConfigCommand extends AbstractConfigCommand { @Override - protected > SuggestionProvider enumSuggestionProvider(Class type) { + protected > SuggestionProvider enumSuggestionProvider(Class type) { return new EnumSuggestionProvider<>(type); } @Override protected DynamicCommandExceptionType invalidEnumException() { - return new DynamicCommandExceptionType(value -> Text.translatable("argument.enum.invalid", value)); + return new DynamicCommandExceptionType(value -> Component.translatable("argument.enum.invalid", value)); } private ConfigCommand() { @@ -29,55 +29,55 @@ private ConfigCommand() { } @SuppressWarnings("unchecked") - public static void register(CommandDispatcher dispatcher, CommandRegistryAccess registryAccess) { - dispatcher.register(new ConfigCommand().create(BetterConfigImpl.getModConfigs().values().stream().map(modConfig -> (AbstractConfigImpl) modConfig).toList(), registryAccess).requires(source -> source.hasPermissionLevel(4))); + public static void register(CommandDispatcher dispatcher, CommandBuildContext buildContext) { + dispatcher.register(new ConfigCommand().create(BetterConfigImpl.getModConfigs().values().stream().map(modConfig -> (AbstractConfigImpl) modConfig).toList(), buildContext).requires(source -> source.hasPermission(4))); } @Override - protected int comment(ServerCommandSource source, String config, String comment) { - source.sendFeedback(() -> Text.translatableWithFallback("betterconfig.commands.config.comment", "Comment for %s:", config), false); - source.sendFeedback(() -> Text.of(comment), false); + protected int comment(CommandSourceStack source, String config, String comment) { + source.sendSuccess(() -> Component.translatableWithFallback("betterconfig.commands.config.comment", "Comment for %s:", config), false); + source.sendSuccess(() -> Component.literal(comment), false); return Command.SINGLE_SUCCESS; } @Override - protected int get(ServerCommandSource source, AbstractConfigImpl abstractConfig, String config) { - source.sendFeedback(() -> Text.translatableWithFallback("betterconfig.commands.config.get", "%s is currently set to %s.", config, abstractConfig.asString(config)), false); + protected int get(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config) { + source.sendSuccess(() -> Component.translatableWithFallback("betterconfig.commands.config.get", "%s is currently set to %s.", config, abstractConfig.asString(config)), false); return Command.SINGLE_SUCCESS; } @Override - protected int reset(ServerCommandSource source, AbstractConfigImpl abstractConfig, String config) { + protected int reset(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config) { abstractConfig.reset(config); - source.sendFeedback(() -> Text.translatableWithFallback("betterconfig.commands.config.reset", "%s has been reset to %s.", config, abstractConfig.asString(config)), true); + source.sendSuccess(() -> Component.translatableWithFallback("betterconfig.commands.config.reset", "%s has been reset to %s.", config, abstractConfig.asString(config)), true); return Command.SINGLE_SUCCESS; } @Override - protected int set(ServerCommandSource source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { + protected int set(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { abstractConfig.set(config, value); - source.sendFeedback(() -> Text.translatableWithFallback("betterconfig.commands.config.set", "%s has been set to %s.", config, abstractConfig.asString(config)), true); + source.sendSuccess(() -> Component.translatableWithFallback("betterconfig.commands.config.set", "%s has been set to %s.", config, abstractConfig.asString(config)), true); return Command.SINGLE_SUCCESS; } @Override - protected int add(ServerCommandSource source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { + protected int add(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { abstractConfig.add(config, value); - source.sendFeedback(() -> Text.translatableWithFallback("betterconfig.commands.config.add", "%s has been added to %s.", abstractConfig.asString(value), config), true); + source.sendSuccess(() -> Component.translatableWithFallback("betterconfig.commands.config.add", "%s has been added to %s.", abstractConfig.asString(value), config), true); return Command.SINGLE_SUCCESS; } @Override - protected int put(ServerCommandSource source, AbstractConfigImpl abstractConfig, String config, Object key, Object value) throws CommandSyntaxException { + protected int put(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config, Object key, Object value) throws CommandSyntaxException { abstractConfig.put(config, key, value); - source.sendFeedback(() -> Text.translatableWithFallback("betterconfig.commands.config.put", "The mapping %s=%s has been added to %s.", abstractConfig.asString(key), abstractConfig.asString(value), config), true); + source.sendSuccess(() -> Component.translatableWithFallback("betterconfig.commands.config.put", "The mapping %s=%s has been added to %s.", abstractConfig.asString(key), abstractConfig.asString(value), config), true); return Command.SINGLE_SUCCESS; } @Override - protected int remove(ServerCommandSource source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { + protected int remove(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { abstractConfig.remove(config, value); - source.sendFeedback(() -> Text.translatableWithFallback("betterconfig.commands.config.remove", "%s has been removed from %s.", abstractConfig.asString(value), config), true); + source.sendSuccess(() -> Component.translatableWithFallback("betterconfig.commands.config.remove", "%s has been removed from %s.", abstractConfig.asString(value), config), true); return Command.SINGLE_SUCCESS; } } diff --git a/fabric/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java b/fabric/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java index 85182d6..f56287e 100644 --- a/fabric/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java +++ b/fabric/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java @@ -3,7 +3,7 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; -import net.minecraft.command.CommandSource; +import net.minecraft.commands.SharedSuggestionProvider; import java.util.Arrays; import java.util.concurrent.CompletableFuture; @@ -16,6 +16,6 @@ public EnumSuggestionProvider(Class enumClass) { @Override public CompletableFuture getSuggestions(CommandContext context, SuggestionsBuilder builder) { - return CommandSource.suggestMatching(Arrays.stream(this.enumClass.getEnumConstants()).map(Enum::name), builder); + return SharedSuggestionProvider.suggest(Arrays.stream(this.enumClass.getEnumConstants()).map(Enum::name), builder); } } diff --git a/fabric/src/main/java/dev/xpple/betterconfig/impl/FabricPlatform.java b/fabric/src/main/java/dev/xpple/betterconfig/impl/FabricPlatform.java index a6940c2..b510556 100644 --- a/fabric/src/main/java/dev/xpple/betterconfig/impl/FabricPlatform.java +++ b/fabric/src/main/java/dev/xpple/betterconfig/impl/FabricPlatform.java @@ -1,10 +1,10 @@ package dev.xpple.betterconfig.impl; -import net.minecraft.command.CommandSource; +import net.minecraft.commands.SharedSuggestionProvider; public class FabricPlatform implements Platform { @Override public Class getCommandSourceClass() { - return CommandSource.class; + return SharedSuggestionProvider.class; } } diff --git a/fabric/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java b/fabric/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java index 2cc2d7e..00b78fe 100644 --- a/fabric/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java +++ b/fabric/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java @@ -5,23 +5,22 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.suggestion.SuggestionProvider; +import dev.xpple.betterconfig.BetterConfig; import dev.xpple.betterconfig.api.ModConfig; import dev.xpple.betterconfig.util.CheckedBiFunction; import dev.xpple.betterconfig.util.Pair; -import net.minecraft.command.CommandRegistryAccess; -import net.minecraft.command.CommandSource; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.SharedSuggestionProvider; import java.nio.file.Path; import java.util.Map; import java.util.function.Function; -import static dev.xpple.betterconfig.BetterConfig.MOD_PATH; - -public class ModConfigImpl extends AbstractConfigImpl implements ModConfig { +public class ModConfigImpl extends AbstractConfigImpl implements ModConfig { private final String modId; - public ModConfigImpl(String modId, Class configsClass, Gson gson, Map, Function>> arguments, Map, Pair, CheckedBiFunction, String, ?, CommandSyntaxException>>> suggestors) { + public ModConfigImpl(String modId, Class configsClass, Gson gson, Map, Function>> arguments, Map, Pair, CheckedBiFunction, String, ?, CommandSyntaxException>>> suggestors) { super(configsClass, gson, arguments, suggestors); this.modId = modId; } @@ -33,7 +32,7 @@ public String getModId() { @Override public Path getConfigsPath() { - return MOD_PATH.resolve(this.modId).resolve("config.json"); + return BetterConfig.MOD_PATH.resolve(this.modId).resolve("config.json"); } @Override diff --git a/fabric/src/testmod/java/dev/xpple/betterconfig/BlockAdapter.java b/fabric/src/testmod/java/dev/xpple/betterconfig/BlockAdapter.java index 79d8324..f559bea 100644 --- a/fabric/src/testmod/java/dev/xpple/betterconfig/BlockAdapter.java +++ b/fabric/src/testmod/java/dev/xpple/betterconfig/BlockAdapter.java @@ -3,20 +3,20 @@ import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; -import net.minecraft.block.Block; -import net.minecraft.registry.Registries; -import net.minecraft.util.Identifier; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; import java.io.IOException; class BlockAdapter extends TypeAdapter { @Override public void write(JsonWriter writer, Block block) throws IOException { - writer.value(Registries.BLOCK.getId(block).toString()); + writer.value(BuiltInRegistries.BLOCK.getKey(block).toString()); } @Override public Block read(JsonReader reader) throws IOException { - return Registries.BLOCK.get(new Identifier(reader.nextString())); + return BuiltInRegistries.BLOCK.get(new ResourceLocation(reader.nextString())); } } diff --git a/fabric/src/testmod/java/dev/xpple/betterconfig/BlockArgumentType.java b/fabric/src/testmod/java/dev/xpple/betterconfig/BlockArgumentType.java index dd3e73a..219e0f1 100644 --- a/fabric/src/testmod/java/dev/xpple/betterconfig/BlockArgumentType.java +++ b/fabric/src/testmod/java/dev/xpple/betterconfig/BlockArgumentType.java @@ -6,10 +6,10 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; -import net.minecraft.block.Block; -import net.minecraft.command.CommandSource; -import net.minecraft.registry.Registries; -import net.minecraft.util.Identifier; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; import java.util.Arrays; import java.util.Collection; @@ -26,24 +26,24 @@ public static BlockArgumentType block() { return new BlockArgumentType(); } - public static Block getBlock(CommandContext context, String name) { + public static Block getBlock(CommandContext context, String name) { return context.getArgument(name, Block.class); } @Override public Block parse(StringReader reader) throws CommandSyntaxException { int cursor = reader.getCursor(); - Identifier identifier = Identifier.fromCommandInput(reader); - if (!Registries.BLOCK.containsId(identifier)) { + ResourceLocation key = ResourceLocation.read(reader); + if (!BuiltInRegistries.BLOCK.containsKey(key)) { reader.setCursor(cursor); throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().create(); } - return Registries.BLOCK.get(identifier); + return BuiltInRegistries.BLOCK.get(key); } @Override public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { - return CommandSource.suggestIdentifiers(Registries.BLOCK.getIds(), builder); + return SharedSuggestionProvider.suggestResource(BuiltInRegistries.BLOCK.keySet(), builder); } @Override diff --git a/fabric/src/testmod/java/dev/xpple/betterconfig/BlockStateAdapter.java b/fabric/src/testmod/java/dev/xpple/betterconfig/BlockStateAdapter.java index d10e453..0e5b938 100644 --- a/fabric/src/testmod/java/dev/xpple/betterconfig/BlockStateAdapter.java +++ b/fabric/src/testmod/java/dev/xpple/betterconfig/BlockStateAdapter.java @@ -7,17 +7,17 @@ import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import com.mojang.serialization.JsonOps; -import net.minecraft.block.BlockState; -import net.minecraft.command.argument.BlockStateArgument; +import net.minecraft.commands.arguments.blocks.BlockInput; +import net.minecraft.world.level.block.state.BlockState; import java.io.IOException; import java.util.Collections; import java.util.Optional; -class BlockStateAdapter extends TypeAdapter { +class BlockStateAdapter extends TypeAdapter { @Override - public void write(JsonWriter writer, BlockStateArgument blockState) throws IOException { - Optional jsonElement = BlockState.CODEC.encodeStart(JsonOps.INSTANCE, blockState.getBlockState()).result(); + public void write(JsonWriter writer, BlockInput blockState) throws IOException { + Optional jsonElement = BlockState.CODEC.encodeStart(JsonOps.INSTANCE, blockState.getState()).result(); if (jsonElement.isEmpty()) { throw new IOException(); } @@ -25,11 +25,11 @@ public void write(JsonWriter writer, BlockStateArgument blockState) throws IOExc } @Override - public BlockStateArgument read(JsonReader reader) throws IOException { + public BlockInput read(JsonReader reader) throws IOException { Optional blockState = BlockState.CODEC.parse(JsonOps.INSTANCE, JsonParser.parseReader(reader)).result(); if (blockState.isEmpty()) { throw new IOException(); } - return new BlockStateArgument(blockState.get(), Collections.emptySet(), null); + return new BlockInput(blockState.get(), Collections.emptySet(), null); } } diff --git a/fabric/src/testmod/java/dev/xpple/betterconfig/BlockSuggestionProvider.java b/fabric/src/testmod/java/dev/xpple/betterconfig/BlockSuggestionProvider.java index 7e608c1..9c922ed 100644 --- a/fabric/src/testmod/java/dev/xpple/betterconfig/BlockSuggestionProvider.java +++ b/fabric/src/testmod/java/dev/xpple/betterconfig/BlockSuggestionProvider.java @@ -4,15 +4,15 @@ import com.mojang.brigadier.suggestion.SuggestionProvider; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; -import net.minecraft.command.CommandSource; -import net.minecraft.registry.Registries; -import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.core.registries.BuiltInRegistries; import java.util.concurrent.CompletableFuture; -class BlockSuggestionProvider implements SuggestionProvider { +class BlockSuggestionProvider implements SuggestionProvider { @Override - public CompletableFuture getSuggestions(CommandContext context, SuggestionsBuilder builder) { - return CommandSource.suggestIdentifiers(Registries.BLOCK.getIds(), builder); + public CompletableFuture getSuggestions(CommandContext context, SuggestionsBuilder builder) { + return SharedSuggestionProvider.suggestResource(BuiltInRegistries.BLOCK.keySet(), builder); } } diff --git a/fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java b/fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java index f2f20a0..068b3da 100644 --- a/fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java +++ b/fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java @@ -2,13 +2,19 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import dev.xpple.betterconfig.api.Config; -import net.minecraft.block.Block; -import net.minecraft.block.Blocks; -import net.minecraft.command.CommandSource; -import net.minecraft.command.argument.BlockStateArgument; -import net.minecraft.server.command.ServerCommandSource; - -import java.util.*; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.commands.arguments.blocks.BlockInput; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; @SuppressWarnings({"FieldMayBeFinal", "unused", "MismatchedQueryAndUpdateOfCollection"}) public class Configs { @@ -61,8 +67,8 @@ public static void customTypeAdder(int codepoint) { @Config(condition = "isServer") public static boolean exampleServerOnlyConfig = true; - public static boolean isServer(CommandSource source) { - return source instanceof ServerCommandSource; + public static boolean isServer(SharedSuggestionProvider source) { + return source instanceof CommandSourceStack; } @Config(setter = @Config.Setter("privateSetter")) @@ -75,5 +81,5 @@ private static void privateSetter(String string) { public static Object exampleComment = null; @Config - public static BlockStateArgument exampleRegistryAccess = new BlockStateArgument(Blocks.COMPOSTER.getDefaultState(), Collections.emptySet(), null); + public static BlockInput exampleRegistryAccess = new BlockInput(Blocks.COMPOSTER.defaultBlockState(), Collections.emptySet(), null); } diff --git a/fabric/src/testmod/java/dev/xpple/betterconfig/TestMod.java b/fabric/src/testmod/java/dev/xpple/betterconfig/TestMod.java index 531d1dc..3f9b972 100644 --- a/fabric/src/testmod/java/dev/xpple/betterconfig/TestMod.java +++ b/fabric/src/testmod/java/dev/xpple/betterconfig/TestMod.java @@ -4,31 +4,31 @@ import dev.xpple.betterconfig.api.ModConfigBuilder; import net.fabricmc.api.DedicatedServerModInitializer; import net.fabricmc.fabric.api.command.v2.ArgumentTypeRegistry; -import net.minecraft.block.Block; -import net.minecraft.command.argument.BlockStateArgument; -import net.minecraft.command.argument.BlockStateArgumentType; -import net.minecraft.command.argument.serialize.ConstantArgumentSerializer; -import net.minecraft.registry.Registries; -import net.minecraft.util.Identifier; +import net.minecraft.commands.arguments.blocks.BlockInput; +import net.minecraft.commands.arguments.blocks.BlockStateArgument; +import net.minecraft.commands.synchronization.SingletonArgumentInfo; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; public class TestMod implements DedicatedServerModInitializer { @Override public void onInitializeServer() { - //ArgumentTypeRegistry.registerArgumentType(new Identifier("testmod", "block"), BlockArgumentType.class, ConstantArgumentSerializer.of(BlockArgumentType::block)); + //ArgumentTypeRegistry.registerArgumentType(new ResourceLocation("testmod", "block"), BlockArgumentType.class, SingletonArgumentInfo.contextFree(BlockArgumentType::block)); new ModConfigBuilder("testmod", Configs.class) .registerTypeHierarchy(Block.class, new BlockAdapter(), new BlockSuggestionProvider(), (ctx, name) -> { String blockString = ctx.getArgument(name, String.class); - Identifier blockId = Identifier.tryParse(blockString); - if (blockId == null) { + ResourceLocation blockKey = ResourceLocation.tryParse(blockString); + if (blockKey == null) { throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().create(); } - if (Registries.BLOCK.containsId(blockId)) { - return Registries.BLOCK.get(blockId); + if (BuiltInRegistries.BLOCK.containsKey(blockKey)) { + return BuiltInRegistries.BLOCK.get(blockKey); } throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().create(); }) - .registerTypeHierarchy(BlockStateArgument.class, new BlockStateAdapter(), BlockStateArgumentType::blockState) + .registerTypeHierarchy(BlockInput.class, new BlockStateAdapter(), BlockStateArgument::block) .build(); } } diff --git a/fabric/src/testmod/java/dev/xpple/betterconfig/TestModClient.java b/fabric/src/testmod/java/dev/xpple/betterconfig/TestModClient.java index 0faf195..f36a4f4 100644 --- a/fabric/src/testmod/java/dev/xpple/betterconfig/TestModClient.java +++ b/fabric/src/testmod/java/dev/xpple/betterconfig/TestModClient.java @@ -2,16 +2,16 @@ import dev.xpple.betterconfig.api.ModConfigBuilder; import net.fabricmc.api.ClientModInitializer; -import net.minecraft.block.Block; -import net.minecraft.command.argument.BlockStateArgument; -import net.minecraft.command.argument.BlockStateArgumentType; +import net.minecraft.commands.arguments.blocks.BlockInput; +import net.minecraft.commands.arguments.blocks.BlockStateArgument; +import net.minecraft.world.level.block.Block; public class TestModClient implements ClientModInitializer { @Override public void onInitializeClient() { new ModConfigBuilder("testmodclient", Configs.class) .registerTypeHierarchy(Block.class, new BlockAdapter(), BlockArgumentType::block) - .registerTypeHierarchy(BlockStateArgument.class, new BlockStateAdapter(), BlockStateArgumentType::blockState) + .registerTypeHierarchy(BlockInput.class, new BlockStateAdapter(), BlockStateArgument::block) .build(); } } diff --git a/gradle.properties b/gradle.properties index 881d2d6..cc83699 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,7 @@ archives_base_name=betterconfig # Fabric Loader Properties # check these on https://fabricmc.net/develop minecraft_version=1.20.4 -yarn_mappings=1.20.4+build.3 +parchment_mappings=parchment-1.20.3:2023.12.31@zip fabric_loader_version=0.15.7 # Fabric Properties diff --git a/paper/build.gradle b/paper/build.gradle index 3d963bb..a715a52 100644 --- a/paper/build.gradle +++ b/paper/build.gradle @@ -3,9 +3,9 @@ plugins { id 'maven-publish' } -archivesBaseName = project.archives_base_name +archivesBaseName = "${project.archives_base_name}-paper" group = project.maven_group -version = "${project.base_version}-paper" +version = project.base_version sourceSets { testplugin { diff --git a/paper/src/main/java/dev/xpple/betterconfig/impl/PluginConfigImpl.java b/paper/src/main/java/dev/xpple/betterconfig/impl/PluginConfigImpl.java index 8651197..1e3759b 100644 --- a/paper/src/main/java/dev/xpple/betterconfig/impl/PluginConfigImpl.java +++ b/paper/src/main/java/dev/xpple/betterconfig/impl/PluginConfigImpl.java @@ -5,6 +5,7 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.suggestion.SuggestionProvider; +import dev.xpple.betterconfig.BetterConfig; import dev.xpple.betterconfig.api.PluginConfig; import dev.xpple.betterconfig.util.CheckedBiFunction; import dev.xpple.betterconfig.util.Pair; @@ -14,8 +15,6 @@ import java.util.Map; import java.util.function.Function; -import static dev.xpple.betterconfig.BetterConfig.PLUGIN_PATH; - public class PluginConfigImpl extends AbstractConfigImpl implements PluginConfig { private final String pluginName; @@ -32,7 +31,7 @@ public String getPluginName() { @Override public Path getConfigsPath() { - return PLUGIN_PATH.resolve(this.pluginName).resolve("config.json"); + return BetterConfig.PLUGIN_PATH.resolve(this.pluginName).resolve("config.json"); } @Override diff --git a/paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java b/paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java index 64573d0..b860580 100644 --- a/paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java +++ b/paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java @@ -5,8 +5,14 @@ import io.papermc.paper.command.brigadier.CommandSourceStack; import org.bukkit.Material; import org.bukkit.block.BlockState; +import org.bukkit.generator.structure.Structure; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; @SuppressWarnings({"FieldMayBeFinal", "unused", "MismatchedQueryAndUpdateOfCollection"}) public class Configs { @@ -74,4 +80,7 @@ private static void privateSetter(String string) { @Config public static BlockState exampleNativeArgumentType = Material.COMPOSTER.createBlockData().createBlockState(); + + @Config + public static Structure exampleCustomArgumentType = Structure.MANSION; } diff --git a/paper/src/testplugin/java/dev/xpple/betterconfig/StructureAdapter.java b/paper/src/testplugin/java/dev/xpple/betterconfig/StructureAdapter.java new file mode 100644 index 0000000..e620df7 --- /dev/null +++ b/paper/src/testplugin/java/dev/xpple/betterconfig/StructureAdapter.java @@ -0,0 +1,22 @@ +package dev.xpple.betterconfig; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.generator.structure.Structure; + +import java.io.IOException; + +class StructureAdapter extends TypeAdapter { + @Override + public void write(JsonWriter writer, Structure value) throws IOException { + writer.value(value.getKey().toString()); + } + + @Override + public Structure read(JsonReader reader) throws IOException { + return Registry.STRUCTURE.get(NamespacedKey.fromString(reader.nextString())); + } +} diff --git a/paper/src/testplugin/java/dev/xpple/betterconfig/StructureArgumentType.java b/paper/src/testplugin/java/dev/xpple/betterconfig/StructureArgumentType.java new file mode 100644 index 0000000..704b08a --- /dev/null +++ b/paper/src/testplugin/java/dev/xpple/betterconfig/StructureArgumentType.java @@ -0,0 +1,53 @@ +package dev.xpple.betterconfig; + +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import dev.xpple.betterconfig.command.suggestion.SuggestionProviderHelper; +import io.papermc.paper.command.brigadier.MessageComponentSerializer; +import io.papermc.paper.command.brigadier.argument.ArgumentTypes; +import io.papermc.paper.command.brigadier.argument.CustomArgumentType; +import net.kyori.adventure.text.Component; +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.generator.structure.Structure; +import org.jetbrains.annotations.NotNull; + +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +class StructureArgumentType extends CustomArgumentType.Converted { + + private static final SimpleCommandExceptionType ERROR_INVALID = new SimpleCommandExceptionType(MessageComponentSerializer.message().serialize(Component.translatable("argument.id.invalid"))); + + private static final Set STRUCTURES = StreamSupport.stream(Registry.STRUCTURE.spliterator(), false) + .map(Keyed::getKey) + .collect(Collectors.toUnmodifiableSet()); + + private StructureArgumentType() { + super(ArgumentTypes.namespacedKey()); + } + + public static StructureArgumentType structure() { + return new StructureArgumentType(); + } + + @Override + public @NotNull Structure convert(@NotNull NamespacedKey key) throws CommandSyntaxException { + Structure structure = Registry.STRUCTURE.get(key); + if (structure == null) { + throw ERROR_INVALID.create(); + } + return structure; + } + + @Override + public @NotNull CompletableFuture listSuggestions(@NotNull CommandContext context, @NotNull SuggestionsBuilder builder) { + return SuggestionProviderHelper.suggestNamespacedKeys(STRUCTURES, builder); + } +} diff --git a/paper/src/testplugin/java/dev/xpple/betterconfig/TestPlugin.java b/paper/src/testplugin/java/dev/xpple/betterconfig/TestPlugin.java index 632ed2a..b81e3b1 100644 --- a/paper/src/testplugin/java/dev/xpple/betterconfig/TestPlugin.java +++ b/paper/src/testplugin/java/dev/xpple/betterconfig/TestPlugin.java @@ -7,6 +7,7 @@ import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.BlockState; +import org.bukkit.generator.structure.Structure; import org.bukkit.plugin.java.JavaPlugin; public class TestPlugin extends JavaPlugin { @@ -29,6 +30,7 @@ public void onEnable() { return material; }) .registerTypeHierarchy(BlockState.class, new BlockStateAdapter(), ArgumentTypes::blockState) + .registerTypeHierarchy(Structure.class, new StructureAdapter(), StructureArgumentType::structure) .build(); } } diff --git a/settings.gradle b/settings.gradle index 367ca31..2f7d774 100644 --- a/settings.gradle +++ b/settings.gradle @@ -12,4 +12,3 @@ pluginManagement { include 'common' include 'fabric' include 'paper' -project(':paper').name = 'betterconfig' // silly hack needed for Paper From bc9139f999dc989a24157a76d075409e2c290fb6 Mon Sep 17 00:00:00 2001 From: xpple Date: Sat, 24 Feb 2024 01:06:37 +0100 Subject: [PATCH 13/28] Add wrapped argument types for Fabric servers --- .../betterconfig/mixin/MixinCommands.java | 26 +++++++ .../RequiredArgumentBuilderAccessor.java | 18 +++++ .../betterconfig/mixin/package-info.java | 4 ++ .../util/WrappedArgumentType.java | 67 +++++++++++++++++++ .../main/resources/betterconfig.mixins.json | 4 +- .../java/dev/xpple/betterconfig/Configs.java | 5 ++ .../xpple/betterconfig/StructureAdapter.java | 22 ++++++ .../betterconfig/StructureArgumentType.java | 42 ++++++++++++ .../java/dev/xpple/betterconfig/TestMod.java | 2 + .../betterconfig/StructureArgumentType.java | 6 +- 10 files changed, 192 insertions(+), 4 deletions(-) create mode 100644 fabric/src/main/java/dev/xpple/betterconfig/mixin/MixinCommands.java create mode 100644 fabric/src/main/java/dev/xpple/betterconfig/mixin/RequiredArgumentBuilderAccessor.java create mode 100644 fabric/src/main/java/dev/xpple/betterconfig/mixin/package-info.java create mode 100644 fabric/src/main/java/dev/xpple/betterconfig/util/WrappedArgumentType.java create mode 100644 fabric/src/testmod/java/dev/xpple/betterconfig/StructureAdapter.java create mode 100644 fabric/src/testmod/java/dev/xpple/betterconfig/StructureArgumentType.java diff --git a/fabric/src/main/java/dev/xpple/betterconfig/mixin/MixinCommands.java b/fabric/src/main/java/dev/xpple/betterconfig/mixin/MixinCommands.java new file mode 100644 index 0000000..724a438 --- /dev/null +++ b/fabric/src/main/java/dev/xpple/betterconfig/mixin/MixinCommands.java @@ -0,0 +1,26 @@ +package dev.xpple.betterconfig.mixin; + +import com.llamalad7.mixinextras.sugar.Local; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import com.mojang.brigadier.tree.CommandNode; +import dev.xpple.betterconfig.util.WrappedArgumentType; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.commands.SharedSuggestionProvider; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Map; + +@Mixin(Commands.class) +public abstract class MixinCommands { + @Inject(method = "fillUsableCommands", at = @At(value = "INVOKE", target = "Lcom/mojang/brigadier/builder/RequiredArgumentBuilder;getSuggestionsProvider()Lcom/mojang/brigadier/suggestion/SuggestionProvider;", ordinal = 0), remap = false) + private void replace(CommandNode rootCommandSource, CommandNode rootSuggestion, CommandSourceStack source, Map, CommandNode> commandNodeToSuggestionNode, CallbackInfo ci, @Local RequiredArgumentBuilder requiredArgumentBuilder) { + if (requiredArgumentBuilder.getType() instanceof WrappedArgumentType wrappedArgumentType) { + ((RequiredArgumentBuilderAccessor) requiredArgumentBuilder).setSuggestionsProvider(wrappedArgumentType::listSuggestions); + ((RequiredArgumentBuilderAccessor) requiredArgumentBuilder).setType(wrappedArgumentType.getNativeType()); + } + } +} diff --git a/fabric/src/main/java/dev/xpple/betterconfig/mixin/RequiredArgumentBuilderAccessor.java b/fabric/src/main/java/dev/xpple/betterconfig/mixin/RequiredArgumentBuilderAccessor.java new file mode 100644 index 0000000..a6368b1 --- /dev/null +++ b/fabric/src/main/java/dev/xpple/betterconfig/mixin/RequiredArgumentBuilderAccessor.java @@ -0,0 +1,18 @@ +package dev.xpple.betterconfig.mixin; + +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import com.mojang.brigadier.suggestion.SuggestionProvider; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(value = RequiredArgumentBuilder.class, remap = false) +public interface RequiredArgumentBuilderAccessor { + @Mutable + @Accessor + void setType(ArgumentType type); + + @Accessor + void setSuggestionsProvider(SuggestionProvider suggestionsProvider); +} diff --git a/fabric/src/main/java/dev/xpple/betterconfig/mixin/package-info.java b/fabric/src/main/java/dev/xpple/betterconfig/mixin/package-info.java new file mode 100644 index 0000000..96b320a --- /dev/null +++ b/fabric/src/main/java/dev/xpple/betterconfig/mixin/package-info.java @@ -0,0 +1,4 @@ +@ApiStatus.Internal +package dev.xpple.betterconfig.mixin; + +import org.jetbrains.annotations.ApiStatus; diff --git a/fabric/src/main/java/dev/xpple/betterconfig/util/WrappedArgumentType.java b/fabric/src/main/java/dev/xpple/betterconfig/util/WrappedArgumentType.java new file mode 100644 index 0000000..38a8a89 --- /dev/null +++ b/fabric/src/main/java/dev/xpple/betterconfig/util/WrappedArgumentType.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024 Owen1212055 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package dev.xpple.betterconfig.util; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; + +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +public abstract class WrappedArgumentType implements ArgumentType { + private final ArgumentType nativeType; + + protected WrappedArgumentType(ArgumentType nativeType) { + this.nativeType = nativeType; + } + + public abstract T parse(StringReader reader) throws CommandSyntaxException; + + public final ArgumentType getNativeType() { + return this.nativeType; + } + + public Collection getExamples() { + return this.nativeType.getExamples(); + } + + public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { + return this.nativeType.listSuggestions(context, builder); + } + + public abstract static class Converted extends WrappedArgumentType { + protected Converted(ArgumentType nativeType) { + super(nativeType); + } + + public final T parse(StringReader reader) throws CommandSyntaxException { + return this.convert(this.getNativeType().parse(reader)); + } + + public abstract T convert(N nativeType) throws CommandSyntaxException; + } +} diff --git a/fabric/src/main/resources/betterconfig.mixins.json b/fabric/src/main/resources/betterconfig.mixins.json index f30c545..9fa2ea6 100644 --- a/fabric/src/main/resources/betterconfig.mixins.json +++ b/fabric/src/main/resources/betterconfig.mixins.json @@ -2,7 +2,9 @@ "required": true, "package": "dev.xpple.betterconfig.mixin", "compatibilityLevel": "JAVA_17", - "mixins": [ + "server": [ + "MixinCommands", + "RequiredArgumentBuilderAccessor" ], "injectors": { "defaultRequire": 1 diff --git a/fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java b/fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java index 068b3da..3ba7e7b 100644 --- a/fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java +++ b/fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java @@ -7,6 +7,8 @@ import net.minecraft.commands.arguments.blocks.BlockInput; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.levelgen.structure.StructureType; +import net.minecraft.world.level.levelgen.structure.structures.WoodlandMansionStructure; import java.util.ArrayList; import java.util.Collection; @@ -82,4 +84,7 @@ private static void privateSetter(String string) { @Config public static BlockInput exampleRegistryAccess = new BlockInput(Blocks.COMPOSTER.defaultBlockState(), Collections.emptySet(), null); + + @Config + public static StructureType exampleConvertedArgumentType = StructureType.WOODLAND_MANSION; } diff --git a/fabric/src/testmod/java/dev/xpple/betterconfig/StructureAdapter.java b/fabric/src/testmod/java/dev/xpple/betterconfig/StructureAdapter.java new file mode 100644 index 0000000..152c4df --- /dev/null +++ b/fabric/src/testmod/java/dev/xpple/betterconfig/StructureAdapter.java @@ -0,0 +1,22 @@ +package dev.xpple.betterconfig; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.levelgen.structure.StructureType; + +import java.io.IOException; + +class StructureAdapter extends TypeAdapter> { + @Override + public void write(JsonWriter writer, StructureType structure) throws IOException { + writer.value(BuiltInRegistries.STRUCTURE_TYPE.getKey(structure).toString()); + } + + @Override + public StructureType read(JsonReader reader) throws IOException { + return BuiltInRegistries.STRUCTURE_TYPE.get(new ResourceLocation(reader.nextString())); + } +} diff --git a/fabric/src/testmod/java/dev/xpple/betterconfig/StructureArgumentType.java b/fabric/src/testmod/java/dev/xpple/betterconfig/StructureArgumentType.java new file mode 100644 index 0000000..d5c6e4b --- /dev/null +++ b/fabric/src/testmod/java/dev/xpple/betterconfig/StructureArgumentType.java @@ -0,0 +1,42 @@ +package dev.xpple.betterconfig; + +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import dev.xpple.betterconfig.util.WrappedArgumentType; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.commands.arguments.ResourceLocationArgument; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.levelgen.structure.StructureType; + +import java.util.concurrent.CompletableFuture; + +public class StructureArgumentType extends WrappedArgumentType.Converted, ResourceLocation> { + + private static final DynamicCommandExceptionType INVALID_STRUCTURE_ID_EXCEPTION = new DynamicCommandExceptionType(id -> Component.translatable("structure_block.invalid_structure_name", id)); + + private StructureArgumentType() { + super(ResourceLocationArgument.id()); + } + + public static StructureArgumentType structure() { + return new StructureArgumentType(); + } + + @Override + public StructureType convert(ResourceLocation key) throws CommandSyntaxException { + if (!BuiltInRegistries.STRUCTURE_TYPE.containsKey(key)) { + throw INVALID_STRUCTURE_ID_EXCEPTION.create(Component.translationArg(key)); + } + return BuiltInRegistries.STRUCTURE_TYPE.get(key); + } + + @Override + public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { + return SharedSuggestionProvider.suggestResource(BuiltInRegistries.STRUCTURE_TYPE.keySet(), builder); + } +} diff --git a/fabric/src/testmod/java/dev/xpple/betterconfig/TestMod.java b/fabric/src/testmod/java/dev/xpple/betterconfig/TestMod.java index 3f9b972..81e7f17 100644 --- a/fabric/src/testmod/java/dev/xpple/betterconfig/TestMod.java +++ b/fabric/src/testmod/java/dev/xpple/betterconfig/TestMod.java @@ -10,6 +10,7 @@ import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.levelgen.structure.StructureType; public class TestMod implements DedicatedServerModInitializer { @Override @@ -29,6 +30,7 @@ public void onInitializeServer() { throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().create(); }) .registerTypeHierarchy(BlockInput.class, new BlockStateAdapter(), BlockStateArgument::block) + .registerTypeHierarchy((Class>) (Class) StructureType.class, new StructureAdapter(), StructureArgumentType::structure) .build(); } } diff --git a/paper/src/testplugin/java/dev/xpple/betterconfig/StructureArgumentType.java b/paper/src/testplugin/java/dev/xpple/betterconfig/StructureArgumentType.java index 704b08a..b7836b0 100644 --- a/paper/src/testplugin/java/dev/xpple/betterconfig/StructureArgumentType.java +++ b/paper/src/testplugin/java/dev/xpple/betterconfig/StructureArgumentType.java @@ -2,7 +2,7 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; import dev.xpple.betterconfig.command.suggestion.SuggestionProviderHelper; @@ -23,7 +23,7 @@ class StructureArgumentType extends CustomArgumentType.Converted { - private static final SimpleCommandExceptionType ERROR_INVALID = new SimpleCommandExceptionType(MessageComponentSerializer.message().serialize(Component.translatable("argument.id.invalid"))); + private static final DynamicCommandExceptionType INVALID_STRUCTURE_ID_EXCEPTION = new DynamicCommandExceptionType(id -> MessageComponentSerializer.message().serialize(Component.translatable("structure_block.invalid_structure_name", id.toString()))); private static final Set STRUCTURES = StreamSupport.stream(Registry.STRUCTURE.spliterator(), false) .map(Keyed::getKey) @@ -41,7 +41,7 @@ public static StructureArgumentType structure() { public @NotNull Structure convert(@NotNull NamespacedKey key) throws CommandSyntaxException { Structure structure = Registry.STRUCTURE.get(key); if (structure == null) { - throw ERROR_INVALID.create(); + throw INVALID_STRUCTURE_ID_EXCEPTION.create(key); } return structure; } From e3377dd54f62c532b8e8bc2c8556e9ee16d1e778 Mon Sep 17 00:00:00 2001 From: xpple Date: Wed, 28 Feb 2024 17:43:06 +0100 Subject: [PATCH 14/28] Remove suggestors in favour of wrapped argument types --- .../api/AbstractConfigBuilder.java | 68 +++++-------------- .../command/AbstractConfigCommand.java | 30 -------- .../betterconfig/impl/AbstractConfigImpl.java | 12 +--- .../betterconfig/api/ModConfigBuilder.java | 2 +- .../betterconfig/impl/ModConfigImpl.java | 9 +-- .../util/WrappedArgumentType.java | 12 +++- .../betterconfig/BlockSuggestionProvider.java | 18 ----- .../BlockWrappedArgumentType.java | 47 +++++++++++++ .../java/dev/xpple/betterconfig/Configs.java | 3 +- .../java/dev/xpple/betterconfig/TestMod.java | 14 +--- .../dev/xpple/betterconfig/TestModClient.java | 2 + .../betterconfig/api/PluginConfigBuilder.java | 2 +- .../betterconfig/impl/PluginConfigImpl.java | 9 +-- .../BlockMaterialArgumentType.java | 43 ++++++++++++ .../dev/xpple/betterconfig/TestPlugin.java | 16 +---- 15 files changed, 128 insertions(+), 159 deletions(-) delete mode 100644 fabric/src/testmod/java/dev/xpple/betterconfig/BlockSuggestionProvider.java create mode 100644 fabric/src/testmod/java/dev/xpple/betterconfig/BlockWrappedArgumentType.java create mode 100644 paper/src/testplugin/java/dev/xpple/betterconfig/BlockMaterialArgumentType.java diff --git a/common/src/main/java/dev/xpple/betterconfig/api/AbstractConfigBuilder.java b/common/src/main/java/dev/xpple/betterconfig/api/AbstractConfigBuilder.java index 7d14248..e2e357c 100644 --- a/common/src/main/java/dev/xpple/betterconfig/api/AbstractConfigBuilder.java +++ b/common/src/main/java/dev/xpple/betterconfig/api/AbstractConfigBuilder.java @@ -3,11 +3,6 @@ import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; import com.mojang.brigadier.arguments.ArgumentType; -import com.mojang.brigadier.context.CommandContext; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.suggestion.SuggestionProvider; -import dev.xpple.betterconfig.util.CheckedBiFunction; -import dev.xpple.betterconfig.util.Pair; import java.util.HashMap; import java.util.Map; @@ -20,7 +15,6 @@ public abstract class AbstractConfigBuilder { final GsonBuilder builder = new GsonBuilder().serializeNulls().enableComplexMapKeySerialization(); final Map, Function>> arguments = new HashMap<>(); - final Map, Pair, CheckedBiFunction, String, ?, CommandSyntaxException>>> suggestors = new HashMap<>(); public AbstractConfigBuilder(Class configsClass) { this.configsClass = configsClass; @@ -33,9 +27,10 @@ public AbstractConfigBuilder(Class configsClass) { * @param argumentTypeSupplier a supplier for the argument type * @param the type * @return the current builder instance - * @implNote On servers, consider using {@link AbstractConfigBuilder#registerType(Class, TypeAdapter, SuggestionProvider, CheckedBiFunction)} - * instead. To use this method on servers, operators need to register the brigadier argument type - * as well. + * @implNote On servers, this requires that the argument type is known to the client. This holds + * true for all argument types that natively exist in the game. Any custom argument types must be + * converted, however. For this, use {@link dev.xpple.betterconfig.util.WrappedArgumentType} on + * Fabric or {@link io.papermc.paper.command.brigadier.argument.CustomArgumentType} on Paper. * @see AbstractConfigBuilder#registerTypeHierarchy(Class, TypeAdapter, Supplier) */ public AbstractConfigBuilder registerType(Class type, TypeAdapter adapter, Supplier> argumentTypeSupplier) { @@ -49,9 +44,10 @@ public AbstractConfigBuilder registerType(Class type, TypeAdapter the type * @return the current builder instance - * @implNote On servers, consider using {@link AbstractConfigBuilder#registerType(Class, TypeAdapter, SuggestionProvider, CheckedBiFunction)} - * instead. To use this method on servers, operators need to register the brigadier argument type - * as well. + * @implNote On servers, this requires that the argument type is known to the client. This holds + * true for all argument types that natively exist in the game. Any custom argument types must be + * converted, however. For this, use {@link dev.xpple.betterconfig.util.WrappedArgumentType} on + * Fabric or {@link io.papermc.paper.command.brigadier.argument.CustomArgumentType} on Paper. * @see AbstractConfigBuilder#registerTypeHierarchy(Class, TypeAdapter, Function) */ public AbstractConfigBuilder registerType(Class type, TypeAdapter adapter, Function> argumentTypeFunction) { @@ -67,9 +63,10 @@ public AbstractConfigBuilder registerType(Class type, TypeAdapter the type * @return the current builder instance - * @implNote On servers, consider using {@link AbstractConfigBuilder#registerTypeHierarchy(Class, TypeAdapter, SuggestionProvider, CheckedBiFunction)} - * instead. To use this method on servers, operators need to register the brigadier argument type - * as well. + * @implNote On servers, this requires that the argument type is known to the client. This holds + * true for all argument types that natively exist in the game. Any custom argument types must be + * converted, however. For this, use {@link dev.xpple.betterconfig.util.WrappedArgumentType} on + * Fabric or {@link io.papermc.paper.command.brigadier.argument.CustomArgumentType} on Paper. * @see AbstractConfigBuilder#registerType(Class, TypeAdapter, Supplier) */ public AbstractConfigBuilder registerTypeHierarchy(Class type, TypeAdapter adapter, Supplier> argumentTypeSupplier) { @@ -83,9 +80,10 @@ public AbstractConfigBuilder registerTypeHierarchy(Class type, Type * @param argumentTypeFunction a function for the argument type needing build context * @param the type * @return the current builder instance - * @implNote On servers, consider using {@link AbstractConfigBuilder#registerTypeHierarchy(Class, TypeAdapter, SuggestionProvider, CheckedBiFunction)} - * instead. To use this method on servers, operators need to register the brigadier argument type - * as well. + * @implNote On servers, this requires that the argument type is known to the client. This holds + * true for all argument types that natively exist in the game. Any custom argument types must be + * converted, however. For this, use {@link dev.xpple.betterconfig.util.WrappedArgumentType} on + * Fabric or {@link io.papermc.paper.command.brigadier.argument.CustomArgumentType} on Paper. * @see AbstractConfigBuilder#registerType(Class, TypeAdapter, Function) */ public AbstractConfigBuilder registerTypeHierarchy(Class type, TypeAdapter adapter, Function> argumentTypeFunction) { @@ -94,40 +92,6 @@ public AbstractConfigBuilder registerTypeHierarchy(Class type, Type return this; } - /** - * Register a new type adapter and suggestor for the specified type. - * @param type the type's class - * @param adapter the type adapter - * @param suggestionProvider a suggestion provider for the type - * @param argumentParser a parser for the argument - * @param the type - * @return the current builder instance - * @implNote On clients, consider using {@link AbstractConfigBuilder#registerType(Class, TypeAdapter, Supplier)} instead. - * @see AbstractConfigBuilder#registerTypeHierarchy(Class, TypeAdapter, SuggestionProvider, CheckedBiFunction) - */ - public AbstractConfigBuilder registerType(Class type, TypeAdapter adapter, SuggestionProvider suggestionProvider, CheckedBiFunction, String, T, CommandSyntaxException> argumentParser) { - this.builder.registerTypeAdapter(type, adapter); - this.suggestors.put(type, new Pair<>(suggestionProvider, argumentParser)); - return this; - } - - /** - * Register a new type adapter and suggestor for the specified type and all subclasses. - * @param type the type's class - * @param adapter the type adapter - * @param suggestionProvider a suggestion provider for the type - * @param argumentParser a parser for the argument - * @param the type - * @return the current builder instance - * @implNote On clients, consider using {@link AbstractConfigBuilder#registerTypeHierarchy(Class, TypeAdapter, Supplier)} instead. - * @see AbstractConfigBuilder#registerType(Class, TypeAdapter, SuggestionProvider, CheckedBiFunction) - */ - public AbstractConfigBuilder registerTypeHierarchy(Class type, TypeAdapter adapter, SuggestionProvider suggestionProvider, CheckedBiFunction, String, T, CommandSyntaxException> argumentParser) { - this.builder.registerTypeHierarchyAdapter(type, adapter); - this.suggestors.put(type, new Pair<>(suggestionProvider, argumentParser)); - return this; - } - /** * Finalise the registration process. * @throws IllegalArgumentException when a configuration already exists for this mod 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 76da693..ccea116 100644 --- a/common/src/main/java/dev/xpple/betterconfig/command/AbstractConfigCommand.java +++ b/common/src/main/java/dev/xpple/betterconfig/command/AbstractConfigCommand.java @@ -49,16 +49,10 @@ protected final LiteralArgumentBuilder create(Collection type = setter.type() == Config.EMPTY.class ? abstractConfig.getType(config) : setter.type(); var argumentFunction = abstractConfig.getArgument(type); - var suggestorPair = abstractConfig.getSuggestor(type); if (argumentFunction != null) { RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", argumentFunction.apply(buildContext)); subCommand.executes(ctx -> set(ctx.getSource(), abstractConfig, config, ctx.getArgument("value", type))); literals.get(config).then(LiteralArgumentBuilder.literal("set").then(subCommand)); - } else if (suggestorPair != null) { - RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", greedyString()); - //noinspection unchecked - subCommand.suggests((SuggestionProvider) suggestorPair.left()).executes(ctx -> set(ctx.getSource(), abstractConfig, config, suggestorPair.right().apply(ctx, "value"))); - literals.get(config).then(LiteralArgumentBuilder.literal("set").then(subCommand)); } else if (type.isEnum()) { //noinspection rawtypes, unchecked RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", string()).suggests(this.enumSuggestionProvider((Class) type)); @@ -74,16 +68,10 @@ protected final LiteralArgumentBuilder create(Collection type = adder.type() == Config.EMPTY.class ? (Class) abstractConfig.getParameterTypes(config)[0] : adder.type(); var argumentFunction = abstractConfig.getArgument(type); - var suggestorPair = abstractConfig.getSuggestor(type); if (argumentFunction != null) { RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", argumentFunction.apply(buildContext)); subCommand.executes(ctx -> add(ctx.getSource(), abstractConfig, config, ctx.getArgument("value", type))); literals.get(config).then(LiteralArgumentBuilder.literal("add").then(subCommand)); - } else if (suggestorPair != null) { - RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", greedyString()); - //noinspection unchecked - subCommand.suggests((SuggestionProvider) suggestorPair.left()).executes(ctx -> add(ctx.getSource(), abstractConfig, config, suggestorPair.right().apply(ctx, "value"))); - literals.get(config).then(LiteralArgumentBuilder.literal("add").then(subCommand)); } else if (type.isEnum()) { //noinspection rawtypes, unchecked RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", string()).suggests(this.enumSuggestionProvider((Class) type)); @@ -102,15 +90,9 @@ protected final LiteralArgumentBuilder create(Collection subCommand; CheckedFunction, ?, CommandSyntaxException> getKey; var keyArgumentFunction = abstractConfig.getArgument(keyType); - var keySuggestorPair = abstractConfig.getSuggestor(keyType); if (keyArgumentFunction != null) { subCommand = RequiredArgumentBuilder.argument("key", keyArgumentFunction.apply(buildContext)); getKey = ctx -> ctx.getArgument("key", keyType); - } else if (keySuggestorPair != null) { - subCommand = RequiredArgumentBuilder.argument("key", string()); - //noinspection unchecked - subCommand.suggests((SuggestionProvider) keySuggestorPair.left()); - getKey = ctx -> keySuggestorPair.right().apply(ctx, "key"); } else if (keyType.isEnum()) { //noinspection rawtypes, unchecked subCommand = RequiredArgumentBuilder.argument("key", string()).suggests(this.enumSuggestionProvider((Class) keyType)); @@ -123,16 +105,10 @@ protected final LiteralArgumentBuilder create(Collection valueType = putter.valueType() == Config.EMPTY.class ? (Class) types[1] : putter.valueType(); var valueArgumentFunction = abstractConfig.getArgument(valueType); - var valueSuggestorPair = abstractConfig.getSuggestor(valueType); if (valueArgumentFunction != null) { RequiredArgumentBuilder subSubCommand = RequiredArgumentBuilder.argument("value", valueArgumentFunction.apply(buildContext)); subSubCommand.executes(ctx -> put(ctx.getSource(), abstractConfig, config, getKey.apply(ctx), ctx.getArgument("value", valueType))); literals.get(config).then(LiteralArgumentBuilder.literal("put").then(subCommand.then(subSubCommand))); - } else if (valueSuggestorPair != null) { - RequiredArgumentBuilder subSubCommand = RequiredArgumentBuilder.argument("value", greedyString()); - //noinspection unchecked - subSubCommand.suggests((SuggestionProvider) valueSuggestorPair.left()).executes(ctx -> put(ctx.getSource(), abstractConfig, config, getKey.apply(ctx), valueSuggestorPair.right().apply(ctx, "value"))); - literals.get(config).then(LiteralArgumentBuilder.literal("put").then(subCommand.then(subSubCommand))); } else if (valueType.isEnum()) { //noinspection rawtypes, unchecked RequiredArgumentBuilder subSubCommand = RequiredArgumentBuilder.argument("value", string()).suggests(this.enumSuggestionProvider((Class) valueType)); @@ -148,16 +124,10 @@ protected final LiteralArgumentBuilder create(Collection type = remover.type() == Config.EMPTY.class ? (Class) abstractConfig.getParameterTypes(config)[0] : remover.type(); var argumentFunction = abstractConfig.getArgument(type); - var suggestorPair = abstractConfig.getSuggestor(type); if (argumentFunction != null) { RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", argumentFunction.apply(buildContext)); subCommand.executes(ctx -> remove(ctx.getSource(), abstractConfig, config, ctx.getArgument("value", type))); literals.get(config).then(LiteralArgumentBuilder.literal("remove").then(subCommand)); - } else if (suggestorPair != null) { - RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", greedyString()); - //noinspection unchecked - subCommand.suggests((SuggestionProvider) suggestorPair.left()).executes(ctx -> remove(ctx.getSource(), abstractConfig, config, suggestorPair.right().apply(ctx, "value"))); - literals.get(config).then(LiteralArgumentBuilder.literal("remove").then(subCommand)); } else if (type.isEnum()) { //noinspection rawtypes, unchecked RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", string()).suggests(this.enumSuggestionProvider((Class) type)); diff --git a/common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java b/common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java index f5347d8..acdf097 100644 --- a/common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java +++ b/common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java @@ -10,16 +10,12 @@ import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.arguments.LongArgumentType; import com.mojang.brigadier.arguments.StringArgumentType; -import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.suggestion.SuggestionProvider; import dev.xpple.betterconfig.BetterConfigCommon; import dev.xpple.betterconfig.api.AbstractConfig; import dev.xpple.betterconfig.api.Config; import dev.xpple.betterconfig.util.CheckedBiConsumer; -import dev.xpple.betterconfig.util.CheckedBiFunction; import dev.xpple.betterconfig.util.CheckedConsumer; -import dev.xpple.betterconfig.util.Pair; import java.io.BufferedWriter; import java.io.IOException; @@ -53,14 +49,12 @@ public abstract class AbstractConfigImpl implements AbstractConfig { private final Gson gson; private final Gson inlineGson; private final Map, Function>> arguments; - private final Map, Pair, CheckedBiFunction, String, ?, CommandSyntaxException>>> suggestors; - protected AbstractConfigImpl(Class configsClass, Gson gson, Map, Function>> arguments, Map, Pair, CheckedBiFunction, String, ?, CommandSyntaxException>>> suggestors) { + protected AbstractConfigImpl(Class configsClass, Gson gson, Map, Function>> arguments) { this.configsClass = configsClass; this.gson = gson.newBuilder().setPrettyPrinting().create(); this.inlineGson = gson; this.arguments = arguments; - this.suggestors = suggestors; } public abstract String getIdentifier(); @@ -79,10 +73,6 @@ public Gson getGson() { return this.arguments.getOrDefault(type, (Function>) defaultArguments.get(type)); } - public Pair, CheckedBiFunction, String, ?, CommandSyntaxException>> getSuggestor(Class type) { - return this.suggestors.get(type); - } - @Override public Object get(String config) { Field field = this.configs.get(config); diff --git a/fabric/src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java b/fabric/src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java index be15d00..062943e 100644 --- a/fabric/src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java +++ b/fabric/src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java @@ -17,7 +17,7 @@ public ModConfigBuilder(String modId, Class configsClass) { @Override public void build() { - ModConfigImpl modConfig = new ModConfigImpl<>(this.modId, this.configsClass, this.builder.create(), this.arguments, this.suggestors); + ModConfigImpl modConfig = new ModConfigImpl<>(this.modId, this.configsClass, this.builder.create(), this.arguments); if (BetterConfigImpl.getModConfigs().putIfAbsent(this.modId, modConfig) == null) { BetterConfigInternals.init(modConfig); return; diff --git a/fabric/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java b/fabric/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java index 00b78fe..cc2593c 100644 --- a/fabric/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java +++ b/fabric/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java @@ -2,13 +2,8 @@ import com.google.gson.Gson; import com.mojang.brigadier.arguments.ArgumentType; -import com.mojang.brigadier.context.CommandContext; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.suggestion.SuggestionProvider; import dev.xpple.betterconfig.BetterConfig; import dev.xpple.betterconfig.api.ModConfig; -import dev.xpple.betterconfig.util.CheckedBiFunction; -import dev.xpple.betterconfig.util.Pair; import net.minecraft.commands.CommandBuildContext; import net.minecraft.commands.SharedSuggestionProvider; @@ -20,8 +15,8 @@ public class ModConfigImpl extends AbstractC private final String modId; - public ModConfigImpl(String modId, Class configsClass, Gson gson, Map, Function>> arguments, Map, Pair, CheckedBiFunction, String, ?, CommandSyntaxException>>> suggestors) { - super(configsClass, gson, arguments, suggestors); + public ModConfigImpl(String modId, Class configsClass, Gson gson, Map, Function>> arguments) { + super(configsClass, gson, arguments); this.modId = modId; } diff --git a/fabric/src/main/java/dev/xpple/betterconfig/util/WrappedArgumentType.java b/fabric/src/main/java/dev/xpple/betterconfig/util/WrappedArgumentType.java index 38a8a89..3bc1c36 100644 --- a/fabric/src/main/java/dev/xpple/betterconfig/util/WrappedArgumentType.java +++ b/fabric/src/main/java/dev/xpple/betterconfig/util/WrappedArgumentType.java @@ -35,20 +35,27 @@ public abstract class WrappedArgumentType implements ArgumentType { private final ArgumentType nativeType; + /** + * @param nativeType the native argument type, the client needs + * to understand this! + */ protected WrappedArgumentType(ArgumentType nativeType) { this.nativeType = nativeType; } - public abstract T parse(StringReader reader) throws CommandSyntaxException; - public final ArgumentType getNativeType() { return this.nativeType; } + @Override + public abstract T parse(StringReader reader) throws CommandSyntaxException; + + @Override public Collection getExamples() { return this.nativeType.getExamples(); } + @Override public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { return this.nativeType.listSuggestions(context, builder); } @@ -58,6 +65,7 @@ protected Converted(ArgumentType nativeType) { super(nativeType); } + @Override public final T parse(StringReader reader) throws CommandSyntaxException { return this.convert(this.getNativeType().parse(reader)); } diff --git a/fabric/src/testmod/java/dev/xpple/betterconfig/BlockSuggestionProvider.java b/fabric/src/testmod/java/dev/xpple/betterconfig/BlockSuggestionProvider.java deleted file mode 100644 index 9c922ed..0000000 --- a/fabric/src/testmod/java/dev/xpple/betterconfig/BlockSuggestionProvider.java +++ /dev/null @@ -1,18 +0,0 @@ -package dev.xpple.betterconfig; - -import com.mojang.brigadier.context.CommandContext; -import com.mojang.brigadier.suggestion.SuggestionProvider; -import com.mojang.brigadier.suggestion.Suggestions; -import com.mojang.brigadier.suggestion.SuggestionsBuilder; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.SharedSuggestionProvider; -import net.minecraft.core.registries.BuiltInRegistries; - -import java.util.concurrent.CompletableFuture; - -class BlockSuggestionProvider implements SuggestionProvider { - @Override - public CompletableFuture getSuggestions(CommandContext context, SuggestionsBuilder builder) { - return SharedSuggestionProvider.suggestResource(BuiltInRegistries.BLOCK.keySet(), builder); - } -} diff --git a/fabric/src/testmod/java/dev/xpple/betterconfig/BlockWrappedArgumentType.java b/fabric/src/testmod/java/dev/xpple/betterconfig/BlockWrappedArgumentType.java new file mode 100644 index 0000000..6f09fd4 --- /dev/null +++ b/fabric/src/testmod/java/dev/xpple/betterconfig/BlockWrappedArgumentType.java @@ -0,0 +1,47 @@ +package dev.xpple.betterconfig; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import dev.xpple.betterconfig.util.WrappedArgumentType; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.commands.arguments.blocks.BlockPredicateArgument; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; + +import java.util.concurrent.CompletableFuture; + +public class BlockWrappedArgumentType extends WrappedArgumentType { + + private static final DynamicCommandExceptionType INVALID_BLOCK_ID_EXCEPTION = new DynamicCommandExceptionType(id -> Component.translatable("argument.block.id.invalid", id)); + + private BlockWrappedArgumentType(CommandBuildContext buildContext) { + super(BlockPredicateArgument.blockPredicate(buildContext)); + } + + public static BlockWrappedArgumentType block(CommandBuildContext buildContext) { + return new BlockWrappedArgumentType(buildContext); + } + + @Override + public Block parse(StringReader reader) throws CommandSyntaxException { + int cursor = reader.getCursor(); + ResourceLocation key = ResourceLocation.read(reader); + if (!BuiltInRegistries.BLOCK.containsKey(key)) { + reader.setCursor(cursor); + throw INVALID_BLOCK_ID_EXCEPTION.create(Component.translationArg(key)); + } + return BuiltInRegistries.BLOCK.get(key); + } + + @Override + public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { + return SharedSuggestionProvider.suggestResource(BuiltInRegistries.BLOCK.keySet(), builder); + } +} diff --git a/fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java b/fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java index 3ba7e7b..6f8e7e1 100644 --- a/fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java +++ b/fabric/src/testmod/java/dev/xpple/betterconfig/Configs.java @@ -8,7 +8,6 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.levelgen.structure.StructureType; -import net.minecraft.world.level.levelgen.structure.structures.WoodlandMansionStructure; import java.util.ArrayList; import java.util.Collection; @@ -86,5 +85,5 @@ private static void privateSetter(String string) { public static BlockInput exampleRegistryAccess = new BlockInput(Blocks.COMPOSTER.defaultBlockState(), Collections.emptySet(), null); @Config - public static StructureType exampleConvertedArgumentType = StructureType.WOODLAND_MANSION; + public static StructureType exampleConvertedArgumentType = StructureType.WOODLAND_MANSION; } diff --git a/fabric/src/testmod/java/dev/xpple/betterconfig/TestMod.java b/fabric/src/testmod/java/dev/xpple/betterconfig/TestMod.java index 81e7f17..cac75f0 100644 --- a/fabric/src/testmod/java/dev/xpple/betterconfig/TestMod.java +++ b/fabric/src/testmod/java/dev/xpple/betterconfig/TestMod.java @@ -1,13 +1,11 @@ package dev.xpple.betterconfig; -import com.mojang.brigadier.exceptions.CommandSyntaxException; import dev.xpple.betterconfig.api.ModConfigBuilder; import net.fabricmc.api.DedicatedServerModInitializer; import net.fabricmc.fabric.api.command.v2.ArgumentTypeRegistry; import net.minecraft.commands.arguments.blocks.BlockInput; import net.minecraft.commands.arguments.blocks.BlockStateArgument; import net.minecraft.commands.synchronization.SingletonArgumentInfo; -import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.levelgen.structure.StructureType; @@ -18,17 +16,7 @@ public void onInitializeServer() { //ArgumentTypeRegistry.registerArgumentType(new ResourceLocation("testmod", "block"), BlockArgumentType.class, SingletonArgumentInfo.contextFree(BlockArgumentType::block)); new ModConfigBuilder("testmod", Configs.class) - .registerTypeHierarchy(Block.class, new BlockAdapter(), new BlockSuggestionProvider(), (ctx, name) -> { - String blockString = ctx.getArgument(name, String.class); - ResourceLocation blockKey = ResourceLocation.tryParse(blockString); - if (blockKey == null) { - throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().create(); - } - if (BuiltInRegistries.BLOCK.containsKey(blockKey)) { - return BuiltInRegistries.BLOCK.get(blockKey); - } - throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().create(); - }) + .registerTypeHierarchy(Block.class, new BlockAdapter(), BlockWrappedArgumentType::block) .registerTypeHierarchy(BlockInput.class, new BlockStateAdapter(), BlockStateArgument::block) .registerTypeHierarchy((Class>) (Class) StructureType.class, new StructureAdapter(), StructureArgumentType::structure) .build(); diff --git a/fabric/src/testmod/java/dev/xpple/betterconfig/TestModClient.java b/fabric/src/testmod/java/dev/xpple/betterconfig/TestModClient.java index f36a4f4..e196556 100644 --- a/fabric/src/testmod/java/dev/xpple/betterconfig/TestModClient.java +++ b/fabric/src/testmod/java/dev/xpple/betterconfig/TestModClient.java @@ -5,6 +5,7 @@ import net.minecraft.commands.arguments.blocks.BlockInput; import net.minecraft.commands.arguments.blocks.BlockStateArgument; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.levelgen.structure.StructureType; public class TestModClient implements ClientModInitializer { @Override @@ -12,6 +13,7 @@ public void onInitializeClient() { new ModConfigBuilder("testmodclient", Configs.class) .registerTypeHierarchy(Block.class, new BlockAdapter(), BlockArgumentType::block) .registerTypeHierarchy(BlockInput.class, new BlockStateAdapter(), BlockStateArgument::block) + .registerTypeHierarchy((Class>) (Class) StructureType.class, new StructureAdapter(), StructureArgumentType::structure) .build(); } } diff --git a/paper/src/main/java/dev/xpple/betterconfig/api/PluginConfigBuilder.java b/paper/src/main/java/dev/xpple/betterconfig/api/PluginConfigBuilder.java index 2ef9b9c..162ee96 100644 --- a/paper/src/main/java/dev/xpple/betterconfig/api/PluginConfigBuilder.java +++ b/paper/src/main/java/dev/xpple/betterconfig/api/PluginConfigBuilder.java @@ -16,7 +16,7 @@ public PluginConfigBuilder(String pluginName, Class configsClass) { @Override public void build() { - PluginConfigImpl pluginConfig = new PluginConfigImpl(this.pluginName, this.configsClass, this.builder.create(), this.arguments, this.suggestors); + PluginConfigImpl pluginConfig = new PluginConfigImpl(this.pluginName, this.configsClass, this.builder.create(), this.arguments); if (BetterConfigImpl.getPluginConfigs().putIfAbsent(this.pluginName, pluginConfig) == null) { BetterConfigInternals.init(pluginConfig); return; diff --git a/paper/src/main/java/dev/xpple/betterconfig/impl/PluginConfigImpl.java b/paper/src/main/java/dev/xpple/betterconfig/impl/PluginConfigImpl.java index 1e3759b..f0fe9ec 100644 --- a/paper/src/main/java/dev/xpple/betterconfig/impl/PluginConfigImpl.java +++ b/paper/src/main/java/dev/xpple/betterconfig/impl/PluginConfigImpl.java @@ -2,13 +2,8 @@ import com.google.gson.Gson; import com.mojang.brigadier.arguments.ArgumentType; -import com.mojang.brigadier.context.CommandContext; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.suggestion.SuggestionProvider; import dev.xpple.betterconfig.BetterConfig; import dev.xpple.betterconfig.api.PluginConfig; -import dev.xpple.betterconfig.util.CheckedBiFunction; -import dev.xpple.betterconfig.util.Pair; import io.papermc.paper.command.brigadier.CommandSourceStack; import java.nio.file.Path; @@ -19,8 +14,8 @@ public class PluginConfigImpl extends AbstractConfigImpl configsClass, Gson gson, Map, Function>> arguments, Map, Pair, CheckedBiFunction, String, ?, CommandSyntaxException>>> suggestors) { - super(configsClass, gson, arguments, suggestors); + public PluginConfigImpl(String pluginName, Class configsClass, Gson gson, Map, Function>> arguments) { + super(configsClass, gson, arguments); this.pluginName = pluginName; } diff --git a/paper/src/testplugin/java/dev/xpple/betterconfig/BlockMaterialArgumentType.java b/paper/src/testplugin/java/dev/xpple/betterconfig/BlockMaterialArgumentType.java new file mode 100644 index 0000000..da44258 --- /dev/null +++ b/paper/src/testplugin/java/dev/xpple/betterconfig/BlockMaterialArgumentType.java @@ -0,0 +1,43 @@ +package dev.xpple.betterconfig; + +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import dev.xpple.betterconfig.command.suggestion.SuggestionProviderHelper; +import io.papermc.paper.command.brigadier.argument.ArgumentTypes; +import io.papermc.paper.command.brigadier.argument.CustomArgumentType; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.block.BlockState; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +public class BlockMaterialArgumentType extends CustomArgumentType.Converted { + + private static final Set BLOCKS = Arrays.stream(Material.values()) + .filter(Material::isBlock) + .map(Material::getKey) + .collect(Collectors.toUnmodifiableSet()); + + private BlockMaterialArgumentType() { + super(ArgumentTypes.blockState()); + } + + public static BlockMaterialArgumentType block() { + return new BlockMaterialArgumentType(); + } + + @Override + public @NotNull Material convert(@NotNull BlockState state) { + return state.getType(); + } + + @Override + public @NotNull CompletableFuture listSuggestions(@NotNull CommandContext context, @NotNull SuggestionsBuilder builder) { + return SuggestionProviderHelper.suggestNamespacedKeys(BLOCKS, builder); + } +} diff --git a/paper/src/testplugin/java/dev/xpple/betterconfig/TestPlugin.java b/paper/src/testplugin/java/dev/xpple/betterconfig/TestPlugin.java index b81e3b1..d66ee7f 100644 --- a/paper/src/testplugin/java/dev/xpple/betterconfig/TestPlugin.java +++ b/paper/src/testplugin/java/dev/xpple/betterconfig/TestPlugin.java @@ -1,11 +1,8 @@ package dev.xpple.betterconfig; -import com.mojang.brigadier.exceptions.CommandSyntaxException; import dev.xpple.betterconfig.api.PluginConfigBuilder; import io.papermc.paper.command.brigadier.argument.ArgumentTypes; import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.Registry; import org.bukkit.block.BlockState; import org.bukkit.generator.structure.Structure; import org.bukkit.plugin.java.JavaPlugin; @@ -17,18 +14,7 @@ public class TestPlugin extends JavaPlugin { @Override public void onEnable() { new PluginConfigBuilder(PLUGIN_NAME, Configs.class) - .registerType(Material.class, new MaterialAdapter(), new MaterialSuggestionProvider(), (ctx, name) -> { - String materialString = ctx.getArgument(name, String.class); - NamespacedKey blockId = NamespacedKey.fromString(materialString); - if (blockId == null) { - throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().create(); - } - Material material = Registry.MATERIAL.get(blockId); - if (material == null) { - throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().create(); - } - return material; - }) + .registerType(Material.class, new MaterialAdapter(), BlockMaterialArgumentType::block) .registerTypeHierarchy(BlockState.class, new BlockStateAdapter(), ArgumentTypes::blockState) .registerTypeHierarchy(Structure.class, new StructureAdapter(), StructureArgumentType::structure) .build(); From 2f5fb0a3f8edb3046c8b5fbd23a7d333e15d023a Mon Sep 17 00:00:00 2001 From: xpple Date: Mon, 22 Apr 2024 15:46:23 +0200 Subject: [PATCH 15/28] Clean up command building --- .../command/AbstractConfigCommand.java | 202 +++++++++--------- 1 file changed, 106 insertions(+), 96 deletions(-) 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 ccea116..5bea448 100644 --- a/common/src/main/java/dev/xpple/betterconfig/command/AbstractConfigCommand.java +++ b/common/src/main/java/dev/xpple/betterconfig/command/AbstractConfigCommand.java @@ -13,8 +13,6 @@ import java.lang.reflect.Type; import java.util.Arrays; import java.util.Collection; -import java.util.HashMap; -import java.util.Map; import java.util.function.Predicate; import static com.mojang.brigadier.arguments.StringArgumentType.*; @@ -33,112 +31,124 @@ protected AbstractConfigCommand(String rootLiteral) { protected final LiteralArgumentBuilder create(Collection> abstractConfigs, C buildContext) { LiteralArgumentBuilder root = LiteralArgumentBuilder.literal(this.rootLiteral); for (AbstractConfigImpl abstractConfig : abstractConfigs) { - Map> literals = new HashMap<>(); + LiteralArgumentBuilder identifierLiteral = LiteralArgumentBuilder.literal(abstractConfig.getIdentifier()); for (String config : abstractConfig.getConfigs().keySet()) { Predicate condition = abstractConfig.getConditions().get(config); LiteralArgumentBuilder configLiteral = LiteralArgumentBuilder.literal(config).requires(condition); - literals.put(config, configLiteral); configLiteral.then(LiteralArgumentBuilder.literal("get").executes(ctx -> get(ctx.getSource(), abstractConfig, config))); configLiteral.then(LiteralArgumentBuilder.literal("reset").executes(ctx -> reset(ctx.getSource(), abstractConfig, config))); - } - abstractConfig.getComments().forEach((config, comment) -> literals.get(config).then(LiteralArgumentBuilder.literal("comment").executes(ctx -> comment(ctx.getSource(), config, comment)))); - abstractConfig.getSetters().keySet().forEach(config -> { - Config annotation = abstractConfig.getAnnotations().get(config); - Config.Setter setter = annotation.setter(); - Class type = setter.type() == Config.EMPTY.class ? abstractConfig.getType(config) : setter.type(); - var argumentFunction = abstractConfig.getArgument(type); - if (argumentFunction != null) { - RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", argumentFunction.apply(buildContext)); - subCommand.executes(ctx -> set(ctx.getSource(), abstractConfig, config, ctx.getArgument("value", type))); - literals.get(config).then(LiteralArgumentBuilder.literal("set").then(subCommand)); - } else if (type.isEnum()) { - //noinspection rawtypes, unchecked - RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", string()).suggests(this.enumSuggestionProvider((Class) type)); - subCommand.executes(ctx -> { - String value = getString(ctx, "value"); - return set(ctx.getSource(), abstractConfig, config, Arrays.stream(type.getEnumConstants()).filter(c -> ((Enum) c).name().equals(value)).findAny().orElseThrow(() -> this.invalidEnumException().create(value))); - }); - literals.get(config).then(LiteralArgumentBuilder.literal("set").then(subCommand)); + String comment = abstractConfig.getComments().get(config); + if (comment != null) { + configLiteral.then(LiteralArgumentBuilder.literal("comment").executes(ctx -> comment(ctx.getSource(), config, comment))); } - }); - abstractConfig.getAdders().keySet().forEach(config -> { - Config annotation = abstractConfig.getAnnotations().get(config); - Config.Adder adder = annotation.adder(); - Class type = adder.type() == Config.EMPTY.class ? (Class) abstractConfig.getParameterTypes(config)[0] : adder.type(); - var argumentFunction = abstractConfig.getArgument(type); - if (argumentFunction != null) { - RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", argumentFunction.apply(buildContext)); - subCommand.executes(ctx -> add(ctx.getSource(), abstractConfig, config, ctx.getArgument("value", type))); - literals.get(config).then(LiteralArgumentBuilder.literal("add").then(subCommand)); - } else if (type.isEnum()) { - //noinspection rawtypes, unchecked - RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", string()).suggests(this.enumSuggestionProvider((Class) type)); - subCommand.executes(ctx -> { - String value = getString(ctx, "value"); - return add(ctx.getSource(), abstractConfig, config, Arrays.stream(type.getEnumConstants()).filter(c -> ((Enum) c).name().equals(value)).findAny().orElseThrow(() -> this.invalidEnumException().create(value))); - }); - literals.get(config).then(LiteralArgumentBuilder.literal("add").then(subCommand)); + + if (abstractConfig.getSetters().containsKey(config)) { + Config annotation = abstractConfig.getAnnotations().get(config); + Config.Setter setter = annotation.setter(); + Class type = setter.type() == Config.EMPTY.class ? abstractConfig.getType(config) : setter.type(); + var argumentFunction = abstractConfig.getArgument(type); + if (argumentFunction != null) { + RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", argumentFunction.apply(buildContext)); + subCommand.executes(ctx -> set(ctx.getSource(), abstractConfig, config, ctx.getArgument("value", type))); + configLiteral.then(LiteralArgumentBuilder.literal("set").then(subCommand)); + } else if (type.isEnum()) { + //noinspection rawtypes, unchecked + RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", string()).suggests(this.enumSuggestionProvider((Class) type)); + subCommand.executes(ctx -> { + String value = getString(ctx, "value"); + return set(ctx.getSource(), abstractConfig, config, Arrays.stream(type.getEnumConstants()).filter(c -> ((Enum) c).name().equals(value)).findAny().orElseThrow(() -> this.invalidEnumException().create(value))); + }); + configLiteral.then(LiteralArgumentBuilder.literal("set").then(subCommand)); + } } - }); - abstractConfig.getPutters().keySet().forEach(config -> { - Config annotation = abstractConfig.getAnnotations().get(config); - Config.Putter putter = annotation.putter(); - Type[] types = abstractConfig.getParameterTypes(config); - Class keyType = putter.keyType() == Config.EMPTY.class ? (Class) types[0] : putter.keyType(); - RequiredArgumentBuilder subCommand; - CheckedFunction, ?, CommandSyntaxException> getKey; - var keyArgumentFunction = abstractConfig.getArgument(keyType); - if (keyArgumentFunction != null) { - subCommand = RequiredArgumentBuilder.argument("key", keyArgumentFunction.apply(buildContext)); - getKey = ctx -> ctx.getArgument("key", keyType); - } else if (keyType.isEnum()) { - //noinspection rawtypes, unchecked - subCommand = RequiredArgumentBuilder.argument("key", string()).suggests(this.enumSuggestionProvider((Class) keyType)); - getKey = ctx -> { - String value = getString(ctx, "key"); - return Arrays.stream(keyType.getEnumConstants()).filter(c -> ((Enum) c).name().equals(value)).findAny().orElseThrow(() -> this.invalidEnumException().create(value)); - }; - } else { - return; + + if (abstractConfig.getAdders().containsKey(config)) { + Config annotation = abstractConfig.getAnnotations().get(config); + Config.Adder adder = annotation.adder(); + Class type = adder.type() == Config.EMPTY.class ? (Class) abstractConfig.getParameterTypes(config)[0] : adder.type(); + var argumentFunction = abstractConfig.getArgument(type); + if (argumentFunction != null) { + RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", argumentFunction.apply(buildContext)); + subCommand.executes(ctx -> add(ctx.getSource(), abstractConfig, config, ctx.getArgument("value", type))); + configLiteral.then(LiteralArgumentBuilder.literal("add").then(subCommand)); + } else if (type.isEnum()) { + // noinspection rawtypes, unchecked + RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", string()).suggests(this.enumSuggestionProvider((Class) type)); + subCommand.executes(ctx -> { + String value = getString(ctx, "value"); + return add(ctx.getSource(), abstractConfig, config, Arrays.stream(type.getEnumConstants()).filter(c -> ((Enum) c).name().equals(value)).findAny().orElseThrow(() -> this.invalidEnumException().create(value))); + }); + configLiteral.then(LiteralArgumentBuilder.literal("add").then(subCommand)); + } } - Class valueType = putter.valueType() == Config.EMPTY.class ? (Class) types[1] : putter.valueType(); - var valueArgumentFunction = abstractConfig.getArgument(valueType); - if (valueArgumentFunction != null) { - RequiredArgumentBuilder subSubCommand = RequiredArgumentBuilder.argument("value", valueArgumentFunction.apply(buildContext)); - subSubCommand.executes(ctx -> put(ctx.getSource(), abstractConfig, config, getKey.apply(ctx), ctx.getArgument("value", valueType))); - literals.get(config).then(LiteralArgumentBuilder.literal("put").then(subCommand.then(subSubCommand))); - } else if (valueType.isEnum()) { - //noinspection rawtypes, unchecked - RequiredArgumentBuilder subSubCommand = RequiredArgumentBuilder.argument("value", string()).suggests(this.enumSuggestionProvider((Class) valueType)); - subCommand.executes(ctx -> { - String value = getString(ctx, "value"); - return put(ctx.getSource(), abstractConfig, config, getKey.apply(ctx), Arrays.stream(valueType.getEnumConstants()).filter(c -> ((Enum) c).name().equals(value)).findAny().orElseThrow(() -> this.invalidEnumException().create(value))); - }); - literals.get(config).then(LiteralArgumentBuilder.literal("put").then(subCommand.then(subSubCommand))); + + if (abstractConfig.getPutters().containsKey(config)) { + Config annotation = abstractConfig.getAnnotations().get(config); + Config.Putter putter = annotation.putter(); + Type[] types = abstractConfig.getParameterTypes(config); + Class keyType = putter.keyType() == Config.EMPTY.class ? (Class) types[0] : putter.keyType(); + RequiredArgumentBuilder subCommand; + CheckedFunction, ?, CommandSyntaxException> getKey; + var keyArgumentFunction = abstractConfig.getArgument(keyType); + if (keyArgumentFunction != null) { + subCommand = RequiredArgumentBuilder.argument("key", keyArgumentFunction.apply(buildContext)); + getKey = ctx -> ctx.getArgument("key", keyType); + } else if (keyType.isEnum()) { + //noinspection rawtypes, unchecked + subCommand = RequiredArgumentBuilder.argument("key", string()).suggests(this.enumSuggestionProvider((Class) keyType)); + getKey = ctx -> { + String value = getString(ctx, "key"); + return Arrays.stream(keyType.getEnumConstants()).filter(c -> ((Enum) c).name().equals(value)).findAny().orElseThrow(() -> this.invalidEnumException().create(value)); + }; + } else { + subCommand = null; + getKey = null; + } + if (subCommand != null) { + Class valueType = putter.valueType() == Config.EMPTY.class ? (Class) types[1] : putter.valueType(); + var valueArgumentFunction = abstractConfig.getArgument(valueType); + if (valueArgumentFunction != null) { + RequiredArgumentBuilder subSubCommand = RequiredArgumentBuilder.argument("value", valueArgumentFunction.apply(buildContext)); + subSubCommand.executes(ctx -> put(ctx.getSource(), abstractConfig, config, getKey.apply(ctx), ctx.getArgument("value", valueType))); + configLiteral.then(LiteralArgumentBuilder.literal("put").then(subCommand.then(subSubCommand))); + } else if (valueType.isEnum()) { + //noinspection rawtypes, unchecked + RequiredArgumentBuilder subSubCommand = RequiredArgumentBuilder.argument("value", string()).suggests(this.enumSuggestionProvider((Class) valueType)); + subCommand.executes(ctx -> { + String value = getString(ctx, "value"); + return put(ctx.getSource(), abstractConfig, config, getKey.apply(ctx), Arrays.stream(valueType.getEnumConstants()).filter(c -> ((Enum) c).name().equals(value)).findAny().orElseThrow(() -> this.invalidEnumException().create(value))); + }); + configLiteral.then(LiteralArgumentBuilder.literal("put").then(subCommand.then(subSubCommand))); + } + } } - }); - abstractConfig.getRemovers().keySet().forEach(config -> { - Config annotation = abstractConfig.getAnnotations().get(config); - Config.Remover remover = annotation.remover(); - Class type = remover.type() == Config.EMPTY.class ? (Class) abstractConfig.getParameterTypes(config)[0] : remover.type(); - var argumentFunction = abstractConfig.getArgument(type); - if (argumentFunction != null) { - RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", argumentFunction.apply(buildContext)); - subCommand.executes(ctx -> remove(ctx.getSource(), abstractConfig, config, ctx.getArgument("value", type))); - literals.get(config).then(LiteralArgumentBuilder.literal("remove").then(subCommand)); - } else if (type.isEnum()) { - //noinspection rawtypes, unchecked - RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", string()).suggests(this.enumSuggestionProvider((Class) type)); - subCommand.executes(ctx -> { - String value = getString(ctx, "value"); - return remove(ctx.getSource(), abstractConfig, config, Arrays.stream(type.getEnumConstants()).filter(c -> ((Enum) c).name().equals(value)).findAny().orElseThrow(() -> this.invalidEnumException().create(value))); - }); - literals.get(config).then(LiteralArgumentBuilder.literal("remove").then(subCommand)); + + if (abstractConfig.getRemovers().containsKey(config)) { + Config annotation = abstractConfig.getAnnotations().get(config); + Config.Remover remover = annotation.remover(); + Class type = remover.type() == Config.EMPTY.class ? (Class) abstractConfig.getParameterTypes(config)[0] : remover.type(); + var argumentFunction = abstractConfig.getArgument(type); + if (argumentFunction != null) { + RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", argumentFunction.apply(buildContext)); + subCommand.executes(ctx -> remove(ctx.getSource(), abstractConfig, config, ctx.getArgument("value", type))); + configLiteral.then(LiteralArgumentBuilder.literal("remove").then(subCommand)); + } else if (type.isEnum()) { + //noinspection rawtypes, unchecked + RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", string()).suggests(this.enumSuggestionProvider((Class) type)); + subCommand.executes(ctx -> { + String value = getString(ctx, "value"); + return remove(ctx.getSource(), abstractConfig, config, Arrays.stream(type.getEnumConstants()).filter(c -> ((Enum) c).name().equals(value)).findAny().orElseThrow(() -> this.invalidEnumException().create(value))); + }); + configLiteral.then(LiteralArgumentBuilder.literal("remove").then(subCommand)); + } } - }); - literals.values().forEach(literal -> root.then(LiteralArgumentBuilder.literal(abstractConfig.getIdentifier()).then(literal))); + + identifierLiteral.then(configLiteral); + } + + root.then(identifierLiteral); } return root; } From c09ea1c7d7e276c25ffa8ac529748b6ad8c97c67 Mon Sep 17 00:00:00 2001 From: xpple Date: Mon, 22 Apr 2024 15:46:36 +0200 Subject: [PATCH 16/28] Delete Pair class --- common/src/main/java/dev/xpple/betterconfig/util/Pair.java | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 common/src/main/java/dev/xpple/betterconfig/util/Pair.java diff --git a/common/src/main/java/dev/xpple/betterconfig/util/Pair.java b/common/src/main/java/dev/xpple/betterconfig/util/Pair.java deleted file mode 100644 index d63c249..0000000 --- a/common/src/main/java/dev/xpple/betterconfig/util/Pair.java +++ /dev/null @@ -1,4 +0,0 @@ -package dev.xpple.betterconfig.util; - -public record Pair(L left, R right) { -} From 9ebaa8fe0fc3d15a3068cbada91c42f9d542c339 Mon Sep 17 00:00:00 2001 From: xpple Date: Mon, 22 Apr 2024 15:55:05 +0200 Subject: [PATCH 17/28] Delete leftover material suggestion provider class --- .../MaterialSuggestionProvider.java | 23 ------------------- 1 file changed, 23 deletions(-) delete mode 100644 paper/src/testplugin/java/dev/xpple/betterconfig/MaterialSuggestionProvider.java diff --git a/paper/src/testplugin/java/dev/xpple/betterconfig/MaterialSuggestionProvider.java b/paper/src/testplugin/java/dev/xpple/betterconfig/MaterialSuggestionProvider.java deleted file mode 100644 index d822f47..0000000 --- a/paper/src/testplugin/java/dev/xpple/betterconfig/MaterialSuggestionProvider.java +++ /dev/null @@ -1,23 +0,0 @@ -package dev.xpple.betterconfig; - -import com.mojang.brigadier.context.CommandContext; -import com.mojang.brigadier.suggestion.SuggestionProvider; -import com.mojang.brigadier.suggestion.Suggestions; -import com.mojang.brigadier.suggestion.SuggestionsBuilder; -import dev.xpple.betterconfig.command.suggestion.SuggestionProviderHelper; -import io.papermc.paper.command.brigadier.CommandSourceStack; -import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.Registry; - -import java.util.concurrent.CompletableFuture; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -class MaterialSuggestionProvider implements SuggestionProvider { - @Override - public CompletableFuture getSuggestions(CommandContext context, SuggestionsBuilder builder) { - Stream keyStream = StreamSupport.stream(Registry.MATERIAL.spliterator(), false).map(Material::getKey); - return SuggestionProviderHelper.suggestNamespacedKeys(keyStream, builder); - } -} From 230de00db3992e81bd04cebcfa6fd49fd6393d68 Mon Sep 17 00:00:00 2001 From: xpple Date: Wed, 15 May 2024 15:43:34 +0200 Subject: [PATCH 18/28] Update to Minecraft 1.20.6 --- common/build.gradle | 8 ++++---- fabric/build.gradle | 8 ++++---- fabric/src/main/resources/fabric.mod.json | 2 +- gradle.properties | 16 +++++++++------- gradle/wrapper/gradle-wrapper.properties | 2 +- paper/build.gradle | 7 +++---- paper/src/main/resources/plugin.yml | 2 +- .../betterconfig/BlockMaterialArgumentType.java | 8 +++++--- .../xpple/betterconfig/StructureAdapter.java | 7 ++++--- .../betterconfig/StructureArgumentType.java | 17 ++++++++++------- paper/src/testplugin/resources/plugin.yml | 2 +- 11 files changed, 43 insertions(+), 36 deletions(-) diff --git a/common/build.gradle b/common/build.gradle index 222019f..0044b6a 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -1,9 +1,9 @@ plugins { - id 'fabric-loom' version '1.5-SNAPSHOT' + id 'fabric-loom' version '1.6-SNAPSHOT' } -sourceCompatibility = JavaVersion.VERSION_17 -targetCompatibility = JavaVersion.VERSION_17 +sourceCompatibility = JavaVersion.VERSION_21 +targetCompatibility = JavaVersion.VERSION_21 archivesBaseName = project.archives_base_name version = project.base_version @@ -27,7 +27,7 @@ dependencies { } tasks.withType(JavaCompile).configureEach { - it.options.release = 17 + it.options.release = 21 } jar { diff --git a/fabric/build.gradle b/fabric/build.gradle index 2d93994..b3256a8 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -1,10 +1,10 @@ plugins { - id 'fabric-loom' version '1.5-SNAPSHOT' + id 'fabric-loom' version '1.6-SNAPSHOT' id 'maven-publish' } -sourceCompatibility = JavaVersion.VERSION_17 -targetCompatibility = JavaVersion.VERSION_17 +sourceCompatibility = JavaVersion.VERSION_21 +targetCompatibility = JavaVersion.VERSION_21 archivesBaseName = "${project.archives_base_name}-fabric" version = project.base_version @@ -96,7 +96,7 @@ processResources { } tasks.withType(JavaCompile).configureEach { - it.options.release = 17 + it.options.release = 21 } java { diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 277289e..46bb267 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -32,7 +32,7 @@ "depends": { "fabricloader": ">=${fabric_loader_version}", "minecraft": "1.20.x", - "java": ">=17", + "java": ">=21", "fabric-api": "*" }, "custom": { diff --git a/gradle.properties b/gradle.properties index cc83699..7b05d55 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,14 +7,16 @@ base_version=1.2.1-multi-platform maven_group=dev.xpple archives_base_name=betterconfig -# Fabric Loader Properties -# check these on https://fabricmc.net/develop -minecraft_version=1.20.4 -parchment_mappings=parchment-1.20.3:2023.12.31@zip -fabric_loader_version=0.15.7 +# Minecraft properties +minecraft_version=1.20.6 # Fabric Properties -fabric_api_version=0.96.3+1.20.4 +# check these on https://fabricmc.net/develop +# https://ldtteam.jfrog.io/ui/native/parchmentmc-public/org/parchmentmc/data/ +fabric_api_version=0.98.0+1.20.6 +parchment_mappings=parchment-1.20.6:2024.05.01@zip +fabric_loader_version=0.15.11 # Paper Properties -paper_api_version=1.20 +paper_api_version=1.20.6-R0.1-SNAPSHOT +plugin_yml_paper_api_version=1.20.6 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3fa8f86..b82aa23 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/paper/build.gradle b/paper/build.gradle index a715a52..2088094 100644 --- a/paper/build.gradle +++ b/paper/build.gradle @@ -17,7 +17,6 @@ sourceSets { } repositories { - mavenLocal() mavenCentral() maven { name = "papermc-repo" @@ -37,11 +36,11 @@ dependencies { configurations.compileOnly.extendsFrom(configurations.includeInJar) includeInJar project(':common') - compileOnly "io.papermc.paper:paper-api:1.20.4-R0.1-SNAPSHOT" + compileOnly "io.papermc.paper:paper-api:${paper_api_version}" } processResources { - def props = [base_version: project.version, paper_api_version: project.paper_api_version] + def props = [base_version: project.version, plugin_yml_paper_api_version: project.plugin_yml_paper_api_version] inputs.properties props filteringCharset 'UTF-8' filesMatching('plugin.yml') { @@ -49,7 +48,7 @@ processResources { } } -def targetJavaVersion = 17 +def targetJavaVersion = 21 java { def javaVersion = JavaVersion.toVersion(targetJavaVersion) sourceCompatibility = javaVersion diff --git a/paper/src/main/resources/plugin.yml b/paper/src/main/resources/plugin.yml index 187d0d2..3961b8f 100644 --- a/paper/src/main/resources/plugin.yml +++ b/paper/src/main/resources/plugin.yml @@ -4,7 +4,7 @@ description: A very powerful and easy to use command based configuration library author: xpple website: https://xpple.dev/ main: dev.xpple.betterconfig.BetterConfig -api-version: '${paper_api_version}' +api-version: '${plugin_yml_paper_api_version}' load: STARTUP permissions: betterconfig.config: diff --git a/paper/src/testplugin/java/dev/xpple/betterconfig/BlockMaterialArgumentType.java b/paper/src/testplugin/java/dev/xpple/betterconfig/BlockMaterialArgumentType.java index da44258..1934911 100644 --- a/paper/src/testplugin/java/dev/xpple/betterconfig/BlockMaterialArgumentType.java +++ b/paper/src/testplugin/java/dev/xpple/betterconfig/BlockMaterialArgumentType.java @@ -1,5 +1,6 @@ package dev.xpple.betterconfig; +import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; @@ -16,15 +17,16 @@ import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; -public class BlockMaterialArgumentType extends CustomArgumentType.Converted { +public class BlockMaterialArgumentType implements CustomArgumentType.Converted { private static final Set BLOCKS = Arrays.stream(Material.values()) .filter(Material::isBlock) .map(Material::getKey) .collect(Collectors.toUnmodifiableSet()); - private BlockMaterialArgumentType() { - super(ArgumentTypes.blockState()); + @Override + public @NotNull ArgumentType getNativeType() { + return ArgumentTypes.blockState(); } public static BlockMaterialArgumentType block() { diff --git a/paper/src/testplugin/java/dev/xpple/betterconfig/StructureAdapter.java b/paper/src/testplugin/java/dev/xpple/betterconfig/StructureAdapter.java index e620df7..023f46a 100644 --- a/paper/src/testplugin/java/dev/xpple/betterconfig/StructureAdapter.java +++ b/paper/src/testplugin/java/dev/xpple/betterconfig/StructureAdapter.java @@ -3,8 +3,9 @@ import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; +import io.papermc.paper.registry.RegistryAccess; +import io.papermc.paper.registry.RegistryKey; import org.bukkit.NamespacedKey; -import org.bukkit.Registry; import org.bukkit.generator.structure.Structure; import java.io.IOException; @@ -12,11 +13,11 @@ class StructureAdapter extends TypeAdapter { @Override public void write(JsonWriter writer, Structure value) throws IOException { - writer.value(value.getKey().toString()); + writer.value(RegistryAccess.registryAccess().getRegistry(RegistryKey.STRUCTURE).getKey(value).toString()); } @Override public Structure read(JsonReader reader) throws IOException { - return Registry.STRUCTURE.get(NamespacedKey.fromString(reader.nextString())); + return RegistryAccess.registryAccess().getRegistry(RegistryKey.STRUCTURE).get(NamespacedKey.fromString(reader.nextString())); } } diff --git a/paper/src/testplugin/java/dev/xpple/betterconfig/StructureArgumentType.java b/paper/src/testplugin/java/dev/xpple/betterconfig/StructureArgumentType.java index b7836b0..90cdbd4 100644 --- a/paper/src/testplugin/java/dev/xpple/betterconfig/StructureArgumentType.java +++ b/paper/src/testplugin/java/dev/xpple/betterconfig/StructureArgumentType.java @@ -1,5 +1,6 @@ package dev.xpple.betterconfig; +import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; @@ -9,10 +10,11 @@ import io.papermc.paper.command.brigadier.MessageComponentSerializer; import io.papermc.paper.command.brigadier.argument.ArgumentTypes; import io.papermc.paper.command.brigadier.argument.CustomArgumentType; +import io.papermc.paper.registry.RegistryAccess; +import io.papermc.paper.registry.RegistryKey; import net.kyori.adventure.text.Component; import org.bukkit.Keyed; import org.bukkit.NamespacedKey; -import org.bukkit.Registry; import org.bukkit.generator.structure.Structure; import org.jetbrains.annotations.NotNull; @@ -21,16 +23,17 @@ import java.util.stream.Collectors; import java.util.stream.StreamSupport; -class StructureArgumentType extends CustomArgumentType.Converted { +class StructureArgumentType implements CustomArgumentType.Converted { - private static final DynamicCommandExceptionType INVALID_STRUCTURE_ID_EXCEPTION = new DynamicCommandExceptionType(id -> MessageComponentSerializer.message().serialize(Component.translatable("structure_block.invalid_structure_name", id.toString()))); + private static final DynamicCommandExceptionType INVALID_STRUCTURE_ID_EXCEPTION = new DynamicCommandExceptionType(id -> MessageComponentSerializer.message().serialize(Component.translatable("structure_block.invalid_structure_name").arguments(Component.text(id.toString())))); - private static final Set STRUCTURES = StreamSupport.stream(Registry.STRUCTURE.spliterator(), false) + private static final Set STRUCTURES = StreamSupport.stream(RegistryAccess.registryAccess().getRegistry(RegistryKey.STRUCTURE).spliterator(), false) .map(Keyed::getKey) .collect(Collectors.toUnmodifiableSet()); - private StructureArgumentType() { - super(ArgumentTypes.namespacedKey()); + @Override + public @NotNull ArgumentType getNativeType() { + return ArgumentTypes.namespacedKey(); } public static StructureArgumentType structure() { @@ -39,7 +42,7 @@ public static StructureArgumentType structure() { @Override public @NotNull Structure convert(@NotNull NamespacedKey key) throws CommandSyntaxException { - Structure structure = Registry.STRUCTURE.get(key); + Structure structure = RegistryAccess.registryAccess().getRegistry(RegistryKey.STRUCTURE).get(key); if (structure == null) { throw INVALID_STRUCTURE_ID_EXCEPTION.create(key); } diff --git a/paper/src/testplugin/resources/plugin.yml b/paper/src/testplugin/resources/plugin.yml index d773774..ca4c530 100644 --- a/paper/src/testplugin/resources/plugin.yml +++ b/paper/src/testplugin/resources/plugin.yml @@ -1,6 +1,6 @@ name: TestPlugin version: '1.0.0' main: dev.xpple.betterconfig.TestPlugin -api-version: '1.20' +api-version: '1.20.6' load: STARTUP authors: [xpple] From 41a24e594f63b758226dd34d6bbcc307c1b9e208 Mon Sep 17 00:00:00 2001 From: xpple Date: Wed, 15 May 2024 15:49:21 +0200 Subject: [PATCH 19/28] Update workflows --- .github/workflows/build.yml | 12 ++++++------ .github/workflows/release.yml | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b003222..4a26c48 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,18 +17,18 @@ jobs: matrix: # Use these Java versions java: [ - 17, # Current Java LTS & minimum supported by Minecraft + 21, # Current Java LTS & minimum supported by Minecraft ] # and run on both Linux and Windows os: [ubuntu-22.04, windows-2022] runs-on: ${{ matrix.os }} steps: - name: checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: validate gradle wrapper - uses: gradle/wrapper-validation-action@v1 + uses: gradle/wrapper-validation-action@v3 - name: setup jdk ${{ matrix.java }} - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: ${{ matrix.java }} distribution: 'microsoft' @@ -39,8 +39,8 @@ jobs: - name: build run: ./gradlew build - name: capture build artifacts - if: ${{ runner.os == 'Linux' && matrix.java == '17' }} # Only upload artifacts built from latest java on one OS - uses: actions/upload-artifact@v3 + if: ${{ runner.os == 'Linux' && matrix.java == '21' }} # Only upload artifacts built from latest java on one OS + uses: actions/upload-artifact@v4 with: name: Artifacts path: build/libs/ diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ef98d75..e613cd4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,13 +9,13 @@ jobs: contents: read packages: write steps: - - uses: actions/checkout@v3 - - uses: actions/setup-java@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 with: - java-version: '17' + java-version: '21' distribution: 'adopt' - name: Validate Gradle wrapper - uses: gradle/wrapper-validation-action@v1 + uses: gradle/wrapper-validation-action@v3 - name: Publish package run: gradle publish env: From 4658514af3fb8cc90a805354bddaf2dd3f65a6c6 Mon Sep 17 00:00:00 2001 From: xpple Date: Wed, 15 May 2024 16:21:51 +0200 Subject: [PATCH 20/28] Use deep copied value when resetting config --- .../java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java | 2 +- .../java/dev/xpple/betterconfig/impl/BetterConfigInternals.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java b/common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java index acdf097..cd6ae39 100644 --- a/common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java +++ b/common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java @@ -103,7 +103,7 @@ public void reset(String config) { throw new IllegalArgumentException(); } try { - field.set(null, this.defaults.get(config)); + field.set(null, this.gson.fromJson(this.gson.toJsonTree(this.defaults.get(config)), field.getGenericType())); } catch (ReflectiveOperationException e) { throw new AssertionError(e); } 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 12ce356..a21a662 100644 --- a/common/src/main/java/dev/xpple/betterconfig/impl/BetterConfigInternals.java +++ b/common/src/main/java/dev/xpple/betterconfig/impl/BetterConfigInternals.java @@ -48,7 +48,7 @@ public static void init(AbstractConfigImpl abstractConfig) { String fieldName = field.getName(); abstractConfig.getConfigs().put(fieldName, field); try { - abstractConfig.getDefaults().put(fieldName, field.get(null)); + abstractConfig.getDefaults().put(fieldName, abstractConfig.getGson().fromJson(abstractConfig.getGson().toJsonTree(field.get(null)), field.getGenericType())); } catch (ReflectiveOperationException e) { throw new AssertionError(e); } From 86065ed07bff26c0d497a50cab9b5242008b35a0 Mon Sep 17 00:00:00 2001 From: xpple Date: Mon, 5 Aug 2024 23:08:44 +0200 Subject: [PATCH 21/28] What was I thinking??? --- README.md | 8 +- .../betterconfig/BetterConfigCommon.java | 4 +- .../betterconfig/api/BetterConfigAPI.java | 1 - .../{AbstractConfig.java => ModConfig.java} | 8 +- ...nfigBuilder.java => ModConfigBuilder.java} | 41 +++++--- .../command/AbstractConfigCommand.java | 98 +++++++++---------- .../AbstractEnumSuggestionProvider.java | 12 --- .../command/suggestion/package-info.java | 4 - .../betterconfig/impl/BetterConfigImpl.java | 4 +- .../impl/BetterConfigInternals.java | 82 ++++++++-------- ...ractConfigImpl.java => ModConfigImpl.java} | 19 +++- .../dev/xpple/betterconfig/impl/Platform.java | 10 ++ .../command/client/ConfigCommandClient.java | 51 ++++------ .../dev/xpple/betterconfig/api/ModConfig.java | 9 -- .../betterconfig/api/ModConfigBuilder.java | 27 ----- .../betterconfig/command/ConfigCommand.java | 51 ++++------ .../suggestion/EnumSuggestionProvider.java | 21 ---- .../betterconfig/impl/FabricPlatform.java | 22 +++++ .../betterconfig/impl/ModConfigImpl.java | 37 ------- .../java/dev/xpple/betterconfig/TestMod.java | 5 +- .../dev/xpple/betterconfig/TestModClient.java | 4 +- gradle.properties | 8 +- paper/build.gradle | 4 - .../betterconfig/api/BetterConfigAPI.java | 17 ---- .../xpple/betterconfig/api/PluginConfig.java | 9 -- .../betterconfig/api/PluginConfigBuilder.java | 26 ----- .../betterconfig/command/ConfigCommand.java | 53 ++++------ .../suggestion/EnumSuggestionProvider.java | 20 ---- .../betterconfig/impl/BetterConfigImpl.java | 27 ----- .../betterconfig/impl/PaperPlatform.java | 24 +++++ .../betterconfig/impl/PluginConfigImpl.java | 36 ------- .../dev/xpple/betterconfig/TestPlugin.java | 4 +- 32 files changed, 271 insertions(+), 475 deletions(-) rename {fabric => common}/src/main/java/dev/xpple/betterconfig/api/BetterConfigAPI.java (99%) rename common/src/main/java/dev/xpple/betterconfig/api/{AbstractConfig.java => ModConfig.java} (94%) rename common/src/main/java/dev/xpple/betterconfig/api/{AbstractConfigBuilder.java => ModConfigBuilder.java} (67%) delete mode 100644 common/src/main/java/dev/xpple/betterconfig/command/suggestion/AbstractEnumSuggestionProvider.java delete mode 100644 common/src/main/java/dev/xpple/betterconfig/command/suggestion/package-info.java rename {fabric => common}/src/main/java/dev/xpple/betterconfig/impl/BetterConfigImpl.java (79%) rename common/src/main/java/dev/xpple/betterconfig/impl/{AbstractConfigImpl.java => ModConfigImpl.java} (94%) delete mode 100644 fabric/src/main/java/dev/xpple/betterconfig/api/ModConfig.java delete mode 100644 fabric/src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java delete mode 100644 fabric/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java delete mode 100644 fabric/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java delete mode 100644 paper/src/main/java/dev/xpple/betterconfig/api/BetterConfigAPI.java delete mode 100644 paper/src/main/java/dev/xpple/betterconfig/api/PluginConfig.java delete mode 100644 paper/src/main/java/dev/xpple/betterconfig/api/PluginConfigBuilder.java delete mode 100644 paper/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java delete mode 100644 paper/src/main/java/dev/xpple/betterconfig/impl/BetterConfigImpl.java delete mode 100644 paper/src/main/java/dev/xpple/betterconfig/impl/PluginConfigImpl.java diff --git a/README.md b/README.md index f789ef8..99bc32f 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ mod's id. - For Paper users, register the `Configs` class in your plugin's `onEnable` method. Replace `` with your plugin's name. ```java - new PluginConfigBuilder(, Configs.class).build(); + new ModConfigBuilder(, Configs.class).build(); ``` That's it! Now you can access `exampleString` through `Configs.exampleString`. You can edit `exampleString` by using the config command. @@ -78,7 +78,7 @@ Replace `${version}` with the artifact version. Append `-fabric` for Fabric and You may choose between my own maven repository and GitHub's package repository. ### My own -```groovy +```gradle repositories { maven { url 'https://maven.xpple.dev/maven2' @@ -86,7 +86,7 @@ repositories { } ``` ### GitHub packages -```groovy +```gradle repositories { maven { url 'https://maven.pkg.github.com/xpple/BetterConfig' @@ -98,7 +98,7 @@ repositories { } ``` Import it: -```groovy +```gradle dependencies { // Fabric include modImplementation('dev.xpple:betterconfig-fabric:${betterconfig-version}') diff --git a/common/src/main/java/dev/xpple/betterconfig/BetterConfigCommon.java b/common/src/main/java/dev/xpple/betterconfig/BetterConfigCommon.java index 1a06657..607d5a9 100644 --- a/common/src/main/java/dev/xpple/betterconfig/BetterConfigCommon.java +++ b/common/src/main/java/dev/xpple/betterconfig/BetterConfigCommon.java @@ -6,6 +6,6 @@ @ApiStatus.Internal public class BetterConfigCommon { - public static final String BASE_ID = "betterconfig"; - public static final Logger LOGGER = LoggerFactory.getLogger(BASE_ID); + public static final String MOD_ID = "betterconfig"; + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); } diff --git a/fabric/src/main/java/dev/xpple/betterconfig/api/BetterConfigAPI.java b/common/src/main/java/dev/xpple/betterconfig/api/BetterConfigAPI.java similarity index 99% rename from fabric/src/main/java/dev/xpple/betterconfig/api/BetterConfigAPI.java rename to common/src/main/java/dev/xpple/betterconfig/api/BetterConfigAPI.java index decb3eb..f44b54f 100644 --- a/fabric/src/main/java/dev/xpple/betterconfig/api/BetterConfigAPI.java +++ b/common/src/main/java/dev/xpple/betterconfig/api/BetterConfigAPI.java @@ -3,7 +3,6 @@ import dev.xpple.betterconfig.impl.BetterConfigImpl; public interface BetterConfigAPI { - static BetterConfigAPI getInstance() { return BetterConfigImpl.INSTANCE; } diff --git a/common/src/main/java/dev/xpple/betterconfig/api/AbstractConfig.java b/common/src/main/java/dev/xpple/betterconfig/api/ModConfig.java similarity index 94% rename from common/src/main/java/dev/xpple/betterconfig/api/AbstractConfig.java rename to common/src/main/java/dev/xpple/betterconfig/api/ModConfig.java index 67a43a9..2dbe603 100644 --- a/common/src/main/java/dev/xpple/betterconfig/api/AbstractConfig.java +++ b/common/src/main/java/dev/xpple/betterconfig/api/ModConfig.java @@ -4,7 +4,13 @@ import java.nio.file.Path; -public interface AbstractConfig { +public interface ModConfig { + /** + * Get the identifier of the mod of this configuration. + * @return the mod's identifier + */ + String getModId(); + /** * Get the class where all the configurations for this mod are defined. * @return the class with all configurations diff --git a/common/src/main/java/dev/xpple/betterconfig/api/AbstractConfigBuilder.java b/common/src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java similarity index 67% rename from common/src/main/java/dev/xpple/betterconfig/api/AbstractConfigBuilder.java rename to common/src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java index e2e357c..6fa5bbb 100644 --- a/common/src/main/java/dev/xpple/betterconfig/api/AbstractConfigBuilder.java +++ b/common/src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java @@ -3,20 +3,26 @@ import com.google.gson.GsonBuilder; import com.google.gson.TypeAdapter; import com.mojang.brigadier.arguments.ArgumentType; +import dev.xpple.betterconfig.impl.BetterConfigImpl; +import dev.xpple.betterconfig.impl.BetterConfigInternals; +import dev.xpple.betterconfig.impl.ModConfigImpl; import java.util.HashMap; import java.util.Map; import java.util.function.Function; import java.util.function.Supplier; -public abstract class AbstractConfigBuilder { +public final class ModConfigBuilder { - final Class configsClass; + private final String modId; - final GsonBuilder builder = new GsonBuilder().serializeNulls().enableComplexMapKeySerialization(); - final Map, Function>> arguments = new HashMap<>(); + private final Class configsClass; - public AbstractConfigBuilder(Class configsClass) { + private final GsonBuilder builder = new GsonBuilder().serializeNulls().enableComplexMapKeySerialization(); + private final Map, Function>> arguments = new HashMap<>(); + + public ModConfigBuilder(String modId, Class configsClass) { + this.modId = modId; this.configsClass = configsClass; } @@ -31,9 +37,9 @@ public AbstractConfigBuilder(Class configsClass) { * true for all argument types that natively exist in the game. Any custom argument types must be * converted, however. For this, use {@link dev.xpple.betterconfig.util.WrappedArgumentType} on * Fabric or {@link io.papermc.paper.command.brigadier.argument.CustomArgumentType} on Paper. - * @see AbstractConfigBuilder#registerTypeHierarchy(Class, TypeAdapter, Supplier) + * @see ModConfigBuilder#registerTypeHierarchy(Class, TypeAdapter, Supplier) */ - public AbstractConfigBuilder registerType(Class type, TypeAdapter adapter, Supplier> argumentTypeSupplier) { + public ModConfigBuilder registerType(Class type, TypeAdapter adapter, Supplier> argumentTypeSupplier) { return this.registerType(type, adapter, buildContext -> argumentTypeSupplier.get()); } @@ -48,9 +54,9 @@ public AbstractConfigBuilder registerType(Class type, TypeAdapter AbstractConfigBuilder registerType(Class type, TypeAdapter adapter, Function> argumentTypeFunction) { + public ModConfigBuilder registerType(Class type, TypeAdapter adapter, Function> argumentTypeFunction) { this.builder.registerTypeAdapter(type, adapter); this.arguments.put(type, argumentTypeFunction); return this; @@ -67,9 +73,9 @@ public AbstractConfigBuilder registerType(Class type, TypeAdapter AbstractConfigBuilder registerTypeHierarchy(Class type, TypeAdapter adapter, Supplier> argumentTypeSupplier) { + public ModConfigBuilder registerTypeHierarchy(Class type, TypeAdapter adapter, Supplier> argumentTypeSupplier) { return this.registerTypeHierarchy(type, adapter, buildContext -> argumentTypeSupplier.get()); } @@ -84,9 +90,9 @@ public AbstractConfigBuilder registerTypeHierarchy(Class type, Type * true for all argument types that natively exist in the game. Any custom argument types must be * converted, however. For this, use {@link dev.xpple.betterconfig.util.WrappedArgumentType} on * Fabric or {@link io.papermc.paper.command.brigadier.argument.CustomArgumentType} on Paper. - * @see AbstractConfigBuilder#registerType(Class, TypeAdapter, Function) + * @see ModConfigBuilder#registerType(Class, TypeAdapter, Function) */ - public AbstractConfigBuilder registerTypeHierarchy(Class type, TypeAdapter adapter, Function> argumentTypeFunction) { + public ModConfigBuilder registerTypeHierarchy(Class type, TypeAdapter adapter, Function> argumentTypeFunction) { this.builder.registerTypeHierarchyAdapter(type, adapter); this.arguments.put(type, argumentTypeFunction); return this; @@ -96,5 +102,12 @@ public AbstractConfigBuilder registerTypeHierarchy(Class type, Type * Finalise the registration process. * @throws IllegalArgumentException when a configuration already exists for this mod */ - public abstract void build(); + public void build() { + ModConfigImpl modConfig = new ModConfigImpl<>(this.modId, this.configsClass, this.builder.create(), this.arguments); + if (BetterConfigImpl.getModConfigs().putIfAbsent(this.modId, modConfig) == null) { + BetterConfigInternals.init(modConfig); + return; + } + throw new IllegalArgumentException(this.modId); + } } 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 5bea448..8f5f65d 100644 --- a/common/src/main/java/dev/xpple/betterconfig/command/AbstractConfigCommand.java +++ b/common/src/main/java/dev/xpple/betterconfig/command/AbstractConfigCommand.java @@ -4,10 +4,9 @@ import com.mojang.brigadier.builder.RequiredArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; -import com.mojang.brigadier.suggestion.SuggestionProvider; import dev.xpple.betterconfig.api.Config; -import dev.xpple.betterconfig.impl.AbstractConfigImpl; +import dev.xpple.betterconfig.impl.ModConfigImpl; +import dev.xpple.betterconfig.impl.Platform; import dev.xpple.betterconfig.util.CheckedFunction; import java.lang.reflect.Type; @@ -19,88 +18,85 @@ public abstract class AbstractConfigCommand { - protected abstract > SuggestionProvider enumSuggestionProvider(Class type); - protected abstract DynamicCommandExceptionType invalidEnumException(); - private final String rootLiteral; protected AbstractConfigCommand(String rootLiteral) { this.rootLiteral = rootLiteral; } - protected final LiteralArgumentBuilder create(Collection> abstractConfigs, C buildContext) { + protected final LiteralArgumentBuilder create(Collection> modConfigs, C buildContext) { LiteralArgumentBuilder root = LiteralArgumentBuilder.literal(this.rootLiteral); - for (AbstractConfigImpl abstractConfig : abstractConfigs) { - LiteralArgumentBuilder identifierLiteral = LiteralArgumentBuilder.literal(abstractConfig.getIdentifier()); - for (String config : abstractConfig.getConfigs().keySet()) { - Predicate condition = abstractConfig.getConditions().get(config); + for (ModConfigImpl modConfig : modConfigs) { + LiteralArgumentBuilder identifierLiteral = LiteralArgumentBuilder.literal(modConfig.getModId()); + for (String config : modConfig.getConfigs().keySet()) { + Predicate condition = modConfig.getConditions().get(config); LiteralArgumentBuilder configLiteral = LiteralArgumentBuilder.literal(config).requires(condition); - configLiteral.then(LiteralArgumentBuilder.literal("get").executes(ctx -> get(ctx.getSource(), abstractConfig, config))); - configLiteral.then(LiteralArgumentBuilder.literal("reset").executes(ctx -> reset(ctx.getSource(), abstractConfig, config))); + configLiteral.then(LiteralArgumentBuilder.literal("get").executes(ctx -> get(ctx.getSource(), modConfig, config))); + configLiteral.then(LiteralArgumentBuilder.literal("reset").executes(ctx -> reset(ctx.getSource(), modConfig, config))); - String comment = abstractConfig.getComments().get(config); + String comment = modConfig.getComments().get(config); if (comment != null) { configLiteral.then(LiteralArgumentBuilder.literal("comment").executes(ctx -> comment(ctx.getSource(), config, comment))); } - if (abstractConfig.getSetters().containsKey(config)) { - Config annotation = abstractConfig.getAnnotations().get(config); + if (modConfig.getSetters().containsKey(config)) { + Config annotation = modConfig.getAnnotations().get(config); Config.Setter setter = annotation.setter(); - Class type = setter.type() == Config.EMPTY.class ? abstractConfig.getType(config) : setter.type(); - var argumentFunction = abstractConfig.getArgument(type); + Class type = setter.type() == Config.EMPTY.class ? modConfig.getType(config) : setter.type(); + var argumentFunction = modConfig.getArgument(type); if (argumentFunction != null) { RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", argumentFunction.apply(buildContext)); - subCommand.executes(ctx -> set(ctx.getSource(), abstractConfig, config, ctx.getArgument("value", type))); + subCommand.executes(ctx -> set(ctx.getSource(), modConfig, config, ctx.getArgument("value", type))); configLiteral.then(LiteralArgumentBuilder.literal("set").then(subCommand)); } else if (type.isEnum()) { //noinspection rawtypes, unchecked - RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", string()).suggests(this.enumSuggestionProvider((Class) type)); + RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", string()).suggests(Platform.current.enumSuggestionProvider((Class) type)); subCommand.executes(ctx -> { String value = getString(ctx, "value"); - return set(ctx.getSource(), abstractConfig, config, Arrays.stream(type.getEnumConstants()).filter(c -> ((Enum) c).name().equals(value)).findAny().orElseThrow(() -> this.invalidEnumException().create(value))); + return set(ctx.getSource(), modConfig, config, Arrays.stream(type.getEnumConstants()).filter(c -> ((Enum) c).name().equals(value)).findAny().orElseThrow(() -> Platform.current.invalidEnumException().create(value))); }); configLiteral.then(LiteralArgumentBuilder.literal("set").then(subCommand)); } } - if (abstractConfig.getAdders().containsKey(config)) { - Config annotation = abstractConfig.getAnnotations().get(config); + if (modConfig.getAdders().containsKey(config)) { + Config annotation = modConfig.getAnnotations().get(config); Config.Adder adder = annotation.adder(); - Class type = adder.type() == Config.EMPTY.class ? (Class) abstractConfig.getParameterTypes(config)[0] : adder.type(); - var argumentFunction = abstractConfig.getArgument(type); + Class type = adder.type() == Config.EMPTY.class ? (Class) modConfig.getParameterTypes(config)[0] : adder.type(); + var argumentFunction = modConfig.getArgument(type); if (argumentFunction != null) { RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", argumentFunction.apply(buildContext)); - subCommand.executes(ctx -> add(ctx.getSource(), abstractConfig, config, ctx.getArgument("value", type))); + subCommand.executes(ctx -> add(ctx.getSource(), modConfig, config, ctx.getArgument("value", type))); configLiteral.then(LiteralArgumentBuilder.literal("add").then(subCommand)); } else if (type.isEnum()) { // noinspection rawtypes, unchecked - RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", string()).suggests(this.enumSuggestionProvider((Class) type)); + RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", string()).suggests(Platform.current.enumSuggestionProvider((Class) type)); subCommand.executes(ctx -> { String value = getString(ctx, "value"); - return add(ctx.getSource(), abstractConfig, config, Arrays.stream(type.getEnumConstants()).filter(c -> ((Enum) c).name().equals(value)).findAny().orElseThrow(() -> this.invalidEnumException().create(value))); + return add(ctx.getSource(), modConfig, config, Arrays.stream(type.getEnumConstants()).filter(c -> ((Enum) c).name().equals(value)).findAny().orElseThrow(() -> Platform.current.invalidEnumException().create(value))); }); configLiteral.then(LiteralArgumentBuilder.literal("add").then(subCommand)); } } - if (abstractConfig.getPutters().containsKey(config)) { - Config annotation = abstractConfig.getAnnotations().get(config); + if (modConfig.getPutters().containsKey(config)) { + Config annotation = modConfig.getAnnotations().get(config); Config.Putter putter = annotation.putter(); - Type[] types = abstractConfig.getParameterTypes(config); + Type[] types = modConfig.getParameterTypes(config); Class keyType = putter.keyType() == Config.EMPTY.class ? (Class) types[0] : putter.keyType(); RequiredArgumentBuilder subCommand; CheckedFunction, ?, CommandSyntaxException> getKey; - var keyArgumentFunction = abstractConfig.getArgument(keyType); + var keyArgumentFunction = modConfig.getArgument(keyType); if (keyArgumentFunction != null) { subCommand = RequiredArgumentBuilder.argument("key", keyArgumentFunction.apply(buildContext)); getKey = ctx -> ctx.getArgument("key", keyType); } else if (keyType.isEnum()) { //noinspection rawtypes, unchecked - subCommand = RequiredArgumentBuilder.argument("key", string()).suggests(this.enumSuggestionProvider((Class) keyType)); + subCommand = RequiredArgumentBuilder.argument("key", string()).suggests(Platform.current.enumSuggestionProvider((Class) keyType)); getKey = ctx -> { String value = getString(ctx, "key"); - return Arrays.stream(keyType.getEnumConstants()).filter(c -> ((Enum) c).name().equals(value)).findAny().orElseThrow(() -> this.invalidEnumException().create(value)); + return Arrays.stream(keyType.getEnumConstants()).filter(c -> ((Enum) c).name().equals(value)).findAny().orElseThrow(() -> Platform.current.invalidEnumException().create(value)); }; } else { subCommand = null; @@ -108,38 +104,38 @@ protected final LiteralArgumentBuilder create(Collection valueType = putter.valueType() == Config.EMPTY.class ? (Class) types[1] : putter.valueType(); - var valueArgumentFunction = abstractConfig.getArgument(valueType); + var valueArgumentFunction = modConfig.getArgument(valueType); if (valueArgumentFunction != null) { RequiredArgumentBuilder subSubCommand = RequiredArgumentBuilder.argument("value", valueArgumentFunction.apply(buildContext)); - subSubCommand.executes(ctx -> put(ctx.getSource(), abstractConfig, config, getKey.apply(ctx), ctx.getArgument("value", valueType))); + subSubCommand.executes(ctx -> put(ctx.getSource(), modConfig, config, getKey.apply(ctx), ctx.getArgument("value", valueType))); configLiteral.then(LiteralArgumentBuilder.literal("put").then(subCommand.then(subSubCommand))); } else if (valueType.isEnum()) { //noinspection rawtypes, unchecked - RequiredArgumentBuilder subSubCommand = RequiredArgumentBuilder.argument("value", string()).suggests(this.enumSuggestionProvider((Class) valueType)); + RequiredArgumentBuilder subSubCommand = RequiredArgumentBuilder.argument("value", string()).suggests(Platform.current.enumSuggestionProvider((Class) valueType)); subCommand.executes(ctx -> { String value = getString(ctx, "value"); - return put(ctx.getSource(), abstractConfig, config, getKey.apply(ctx), Arrays.stream(valueType.getEnumConstants()).filter(c -> ((Enum) c).name().equals(value)).findAny().orElseThrow(() -> this.invalidEnumException().create(value))); + return put(ctx.getSource(), modConfig, config, getKey.apply(ctx), Arrays.stream(valueType.getEnumConstants()).filter(c -> ((Enum) c).name().equals(value)).findAny().orElseThrow(() -> Platform.current.invalidEnumException().create(value))); }); configLiteral.then(LiteralArgumentBuilder.literal("put").then(subCommand.then(subSubCommand))); } } } - if (abstractConfig.getRemovers().containsKey(config)) { - Config annotation = abstractConfig.getAnnotations().get(config); + if (modConfig.getRemovers().containsKey(config)) { + Config annotation = modConfig.getAnnotations().get(config); Config.Remover remover = annotation.remover(); - Class type = remover.type() == Config.EMPTY.class ? (Class) abstractConfig.getParameterTypes(config)[0] : remover.type(); - var argumentFunction = abstractConfig.getArgument(type); + Class type = remover.type() == Config.EMPTY.class ? (Class) modConfig.getParameterTypes(config)[0] : remover.type(); + var argumentFunction = modConfig.getArgument(type); if (argumentFunction != null) { RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", argumentFunction.apply(buildContext)); - subCommand.executes(ctx -> remove(ctx.getSource(), abstractConfig, config, ctx.getArgument("value", type))); + subCommand.executes(ctx -> remove(ctx.getSource(), modConfig, config, ctx.getArgument("value", type))); configLiteral.then(LiteralArgumentBuilder.literal("remove").then(subCommand)); } else if (type.isEnum()) { //noinspection rawtypes, unchecked - RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", string()).suggests(this.enumSuggestionProvider((Class) type)); + RequiredArgumentBuilder subCommand = RequiredArgumentBuilder.argument("value", string()).suggests(Platform.current.enumSuggestionProvider((Class) type)); subCommand.executes(ctx -> { String value = getString(ctx, "value"); - return remove(ctx.getSource(), abstractConfig, config, Arrays.stream(type.getEnumConstants()).filter(c -> ((Enum) c).name().equals(value)).findAny().orElseThrow(() -> this.invalidEnumException().create(value))); + return remove(ctx.getSource(), modConfig, config, Arrays.stream(type.getEnumConstants()).filter(c -> ((Enum) c).name().equals(value)).findAny().orElseThrow(() -> Platform.current.invalidEnumException().create(value))); }); configLiteral.then(LiteralArgumentBuilder.literal("remove").then(subCommand)); } @@ -155,15 +151,15 @@ protected final LiteralArgumentBuilder create(Collection abstractConfig, String config); + protected abstract int get(S source, ModConfigImpl modConfig, String config); - protected abstract int reset(S source, AbstractConfigImpl abstractConfig, String config); + protected abstract int reset(S source, ModConfigImpl modConfig, String config); - protected abstract int set(S source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException; + protected abstract int set(S source, ModConfigImpl modConfig, String config, Object value) throws CommandSyntaxException; - protected abstract int add(S source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException; + protected abstract int add(S source, ModConfigImpl modConfig, String config, Object value) throws CommandSyntaxException; - protected abstract int put(S source, AbstractConfigImpl abstractConfig, String config, Object key, Object value) throws CommandSyntaxException; + protected abstract int put(S source, ModConfigImpl modConfig, String config, Object key, Object value) throws CommandSyntaxException; - protected abstract int remove(S source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException; + protected abstract int remove(S source, ModConfigImpl modConfig, String config, Object value) throws CommandSyntaxException; } diff --git a/common/src/main/java/dev/xpple/betterconfig/command/suggestion/AbstractEnumSuggestionProvider.java b/common/src/main/java/dev/xpple/betterconfig/command/suggestion/AbstractEnumSuggestionProvider.java deleted file mode 100644 index bb87a07..0000000 --- a/common/src/main/java/dev/xpple/betterconfig/command/suggestion/AbstractEnumSuggestionProvider.java +++ /dev/null @@ -1,12 +0,0 @@ -package dev.xpple.betterconfig.command.suggestion; - -import com.mojang.brigadier.suggestion.SuggestionProvider; - -public abstract class AbstractEnumSuggestionProvider> implements SuggestionProvider { - - final Class enumClass; - - public AbstractEnumSuggestionProvider(Class enumClass) { - this.enumClass = enumClass; - } -} diff --git a/common/src/main/java/dev/xpple/betterconfig/command/suggestion/package-info.java b/common/src/main/java/dev/xpple/betterconfig/command/suggestion/package-info.java deleted file mode 100644 index 91f7912..0000000 --- a/common/src/main/java/dev/xpple/betterconfig/command/suggestion/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -@ApiStatus.Internal -package dev.xpple.betterconfig.command.suggestion; - -import org.jetbrains.annotations.ApiStatus; diff --git a/fabric/src/main/java/dev/xpple/betterconfig/impl/BetterConfigImpl.java b/common/src/main/java/dev/xpple/betterconfig/impl/BetterConfigImpl.java similarity index 79% rename from fabric/src/main/java/dev/xpple/betterconfig/impl/BetterConfigImpl.java rename to common/src/main/java/dev/xpple/betterconfig/impl/BetterConfigImpl.java index a9b1e0b..e5d7835 100644 --- a/fabric/src/main/java/dev/xpple/betterconfig/impl/BetterConfigImpl.java +++ b/common/src/main/java/dev/xpple/betterconfig/impl/BetterConfigImpl.java @@ -8,7 +8,7 @@ public class BetterConfigImpl implements BetterConfigAPI { - private static final Map> modConfigs = new HashMap<>(); + private static final Map> modConfigs = new HashMap<>(); @Override public ModConfig getModConfig(String modId) { @@ -19,7 +19,7 @@ public ModConfig getModConfig(String modId) { return modConfig; } - public static Map> getModConfigs() { + public static Map> getModConfigs() { return modConfigs; } 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 a21a662..73cdf3b 100644 --- a/common/src/main/java/dev/xpple/betterconfig/impl/BetterConfigInternals.java +++ b/common/src/main/java/dev/xpple/betterconfig/impl/BetterConfigInternals.java @@ -22,22 +22,22 @@ public class BetterConfigInternals { - public static void init(AbstractConfigImpl abstractConfig) { + public static void init(ModConfigImpl modConfig) { JsonObject root = null; - try (BufferedReader reader = Files.newBufferedReader(abstractConfig.getConfigsPath())) { + try (BufferedReader reader = Files.newBufferedReader(modConfig.getConfigsPath())) { root = JsonParser.parseReader(reader).getAsJsonObject(); } catch (IOException ignored) { } catch (Exception e) { BetterConfigCommon.LOGGER.warn("Could not read config file, default values will be used.\nThe old config file will be renamed.", e); try { - Files.move(abstractConfig.getConfigsPath(), abstractConfig.getConfigsPath().resolveSibling("config_old.json"), StandardCopyOption.REPLACE_EXISTING); + Files.move(modConfig.getConfigsPath(), modConfig.getConfigsPath().resolveSibling("config_old.json"), StandardCopyOption.REPLACE_EXISTING); } catch (IOException ignored) { } } finally { root = Objects.requireNonNullElse(root, new JsonObject()); } - for (Field field : abstractConfig.getConfigsClass().getDeclaredFields()) { + for (Field field : modConfig.getConfigsClass().getDeclaredFields()) { Config annotation = field.getAnnotation(Config.class); if (annotation == null) { continue; @@ -46,28 +46,28 @@ public static void init(AbstractConfigImpl abstractConfig) { field.setAccessible(true); String fieldName = field.getName(); - abstractConfig.getConfigs().put(fieldName, field); + modConfig.getConfigs().put(fieldName, field); try { - abstractConfig.getDefaults().put(fieldName, abstractConfig.getGson().fromJson(abstractConfig.getGson().toJsonTree(field.get(null)), field.getGenericType())); + modConfig.getDefaults().put(fieldName, modConfig.getGson().fromJson(modConfig.getGson().toJsonTree(field.get(null)), field.getGenericType())); } catch (ReflectiveOperationException e) { throw new AssertionError(e); } - abstractConfig.getAnnotations().put(fieldName, annotation); + modConfig.getAnnotations().put(fieldName, annotation); if (!annotation.comment().isEmpty()) { - abstractConfig.getComments().put(fieldName, annotation.comment()); + modConfig.getComments().put(fieldName, annotation.comment()); } if (!annotation.temporary()) { try { if (root.has(fieldName)) { - Object value = abstractConfig.getGson().fromJson(root.get(fieldName), field.getGenericType()); + Object value = modConfig.getGson().fromJson(root.get(fieldName), field.getGenericType()); if (Modifier.isFinal(field.getModifiers())) { throw new AssertionError("Config field '" + fieldName + "' should not be final"); } field.set(null, value); } else { - root.add(fieldName, abstractConfig.getGson().toJsonTree(field.get(null))); + root.add(fieldName, modConfig.getGson().toJsonTree(field.get(null))); } } catch (Exception e) { throw new AssertionError(e); @@ -75,17 +75,17 @@ public static void init(AbstractConfigImpl abstractConfig) { } if (annotation.condition().isEmpty()) { - abstractConfig.getConditions().put(fieldName, source -> true); + modConfig.getConditions().put(fieldName, source -> true); } else { Method predicateMethod; boolean hasParameter = false; try { - predicateMethod = abstractConfig.getConfigsClass().getDeclaredMethod(annotation.condition()); + predicateMethod = modConfig.getConfigsClass().getDeclaredMethod(annotation.condition()); } catch (ReflectiveOperationException e) { hasParameter = true; try { Class commandSourceClass = Platform.current.getCommandSourceClass(); - predicateMethod = abstractConfig.getConfigsClass().getDeclaredMethod(annotation.condition(), commandSourceClass); + predicateMethod = modConfig.getConfigsClass().getDeclaredMethod(annotation.condition(), commandSourceClass); } catch (ReflectiveOperationException e1) { throw new AssertionError(e1); } @@ -101,7 +101,7 @@ public static void init(AbstractConfigImpl abstractConfig) { Method predicateMethod_f = predicateMethod; if (hasParameter) { - abstractConfig.getConditions().put(fieldName, source -> { + modConfig.getConditions().put(fieldName, source -> { try { return (Boolean) predicateMethod_f.invoke(null, source); } catch (ReflectiveOperationException e) { @@ -109,7 +109,7 @@ public static void init(AbstractConfigImpl abstractConfig) { } }); } else { - abstractConfig.getConditions().put(fieldName, source -> { + modConfig.getConditions().put(fieldName, source -> { try { return (Boolean) predicateMethod_f.invoke(null); } catch (ReflectiveOperationException e) { @@ -124,24 +124,24 @@ public static void init(AbstractConfigImpl abstractConfig) { } Class type = field.getType(); if (Collection.class.isAssignableFrom(type)) { - initCollection(abstractConfig, field, annotation); + initCollection(modConfig, field, annotation); } else if (Map.class.isAssignableFrom(type)) { - initMap(abstractConfig, field, annotation); + initMap(modConfig, field, annotation); } else { - initObject(abstractConfig, field, annotation); + initObject(modConfig, field, annotation); } } //noinspection ResultOfMethodCallIgnored - abstractConfig.getConfigsPath().getParent().toFile().mkdirs(); - try (BufferedWriter writer = Files.newBufferedWriter(abstractConfig.getConfigsPath())) { - writer.write(abstractConfig.getGson().toJson(root)); + modConfig.getConfigsPath().getParent().toFile().mkdirs(); + try (BufferedWriter writer = Files.newBufferedWriter(modConfig.getConfigsPath())) { + writer.write(modConfig.getGson().toJson(root)); } catch (IOException e) { BetterConfigCommon.LOGGER.error("Could not save config file.", e); } } - private static void initCollection(AbstractConfigImpl abstractConfig, Field field, Config annotation) { + private static void initCollection(ModConfigImpl modConfig, Field field, Config annotation) { String fieldName = field.getName(); Type[] types = ((ParameterizedType) field.getGenericType()).getActualTypeArguments(); Config.Adder adder = annotation.adder(); @@ -155,7 +155,7 @@ private static void initCollection(AbstractConfigImpl abstractConfig, Fiel } catch (ReflectiveOperationException e) { throw new AssertionError(e); } - abstractConfig.getAdders().put(fieldName, value -> { + modConfig.getAdders().put(fieldName, value -> { try { add.invoke(field.get(null), value); } catch (ReflectiveOperationException e) { @@ -166,12 +166,12 @@ private static void initCollection(AbstractConfigImpl abstractConfig, Fiel Class type = adder.type() == Config.EMPTY.class ? (Class) types[0] : adder.type(); Method adderMethod; try { - adderMethod = abstractConfig.getConfigsClass().getDeclaredMethod(adderMethodName, type); + adderMethod = modConfig.getConfigsClass().getDeclaredMethod(adderMethodName, type); } catch (ReflectiveOperationException e) { throw new AssertionError(e); } adderMethod.setAccessible(true); - abstractConfig.getAdders().put(fieldName, value -> { + modConfig.getAdders().put(fieldName, value -> { try { adderMethod.invoke(null, value); } catch (ReflectiveOperationException e) { @@ -193,7 +193,7 @@ private static void initCollection(AbstractConfigImpl abstractConfig, Fiel } catch (ReflectiveOperationException e) { throw new AssertionError(e); } - abstractConfig.getRemovers().put(fieldName, value -> { + modConfig.getRemovers().put(fieldName, value -> { try { remove.invoke(field.get(null), value); } catch (ReflectiveOperationException e) { @@ -204,12 +204,12 @@ private static void initCollection(AbstractConfigImpl abstractConfig, Fiel Class type = remover.type() == Config.EMPTY.class ? (Class) types[0] : remover.type(); Method removerMethod; try { - removerMethod = abstractConfig.getConfigsClass().getDeclaredMethod(removerMethodName, type); + removerMethod = modConfig.getConfigsClass().getDeclaredMethod(removerMethodName, type); } catch (ReflectiveOperationException e) { throw new AssertionError(e); } removerMethod.setAccessible(true); - abstractConfig.getRemovers().put(fieldName, value -> { + modConfig.getRemovers().put(fieldName, value -> { try { removerMethod.invoke(null, value); } catch (ReflectiveOperationException e) { @@ -222,7 +222,7 @@ private static void initCollection(AbstractConfigImpl abstractConfig, Fiel } } - private static void initMap(AbstractConfigImpl abstractConfig, Field field, Config annotation) { + private static void initMap(ModConfigImpl modConfig, Field field, Config annotation) { String fieldName = field.getName(); Type[] types = ((ParameterizedType) field.getGenericType()).getActualTypeArguments(); Config.Adder adder = annotation.adder(); @@ -233,12 +233,12 @@ private static void initMap(AbstractConfigImpl abstractConfig, Field field Class type = adder.type() == Config.EMPTY.class ? (Class) types[0] : adder.type(); Method adderMethod; try { - adderMethod = abstractConfig.getConfigsClass().getDeclaredMethod(adderMethodName, type); + adderMethod = modConfig.getConfigsClass().getDeclaredMethod(adderMethodName, type); } catch (ReflectiveOperationException e) { throw new AssertionError(e); } adderMethod.setAccessible(true); - abstractConfig.getAdders().put(fieldName, key -> { + modConfig.getAdders().put(fieldName, key -> { try { adderMethod.invoke(null, key); } catch (ReflectiveOperationException e) { @@ -260,7 +260,7 @@ private static void initMap(AbstractConfigImpl abstractConfig, Field field } catch (ReflectiveOperationException e) { throw new AssertionError(e); } - abstractConfig.getPutters().put(fieldName, (key, value) -> { + modConfig.getPutters().put(fieldName, (key, value) -> { try { put.invoke(field.get(null), key, value); } catch (ReflectiveOperationException e) { @@ -272,12 +272,12 @@ private static void initMap(AbstractConfigImpl abstractConfig, Field field Class valueType = putter.valueType() == Config.EMPTY.class ? (Class) types[1] : putter.valueType(); Method putterMethod; try { - putterMethod = abstractConfig.getConfigsClass().getDeclaredMethod(putterMethodName, keyType, valueType); + putterMethod = modConfig.getConfigsClass().getDeclaredMethod(putterMethodName, keyType, valueType); } catch (ReflectiveOperationException e) { throw new AssertionError(e); } putterMethod.setAccessible(true); - abstractConfig.getPutters().put(fieldName, (key, value) -> { + modConfig.getPutters().put(fieldName, (key, value) -> { try { putterMethod.invoke(null, key, value); } catch (ReflectiveOperationException e) { @@ -299,7 +299,7 @@ private static void initMap(AbstractConfigImpl abstractConfig, Field field } catch (ReflectiveOperationException e) { throw new AssertionError(e); } - abstractConfig.getRemovers().put(fieldName, key -> { + modConfig.getRemovers().put(fieldName, key -> { try { remove.invoke(field.get(null), key); } catch (ReflectiveOperationException e) { @@ -310,12 +310,12 @@ private static void initMap(AbstractConfigImpl abstractConfig, Field field Class type = remover.type() == Config.EMPTY.class ? (Class) types[0] : remover.type(); Method removerMethod; try { - removerMethod = abstractConfig.getConfigsClass().getDeclaredMethod(removerMethodName, type); + removerMethod = modConfig.getConfigsClass().getDeclaredMethod(removerMethodName, type); } catch (ReflectiveOperationException e) { throw new AssertionError(e); } removerMethod.setAccessible(true); - abstractConfig.getRemovers().put(fieldName, key -> { + modConfig.getRemovers().put(fieldName, key -> { try { removerMethod.invoke(null, key); } catch (ReflectiveOperationException e) { @@ -328,14 +328,14 @@ private static void initMap(AbstractConfigImpl abstractConfig, Field field } } - private static void initObject(AbstractConfigImpl abstractConfig, Field field, Config annotation) { + private static void initObject(ModConfigImpl modConfig, Field field, Config annotation) { String fieldName = field.getName(); Config.Setter setter = annotation.setter(); String setterMethodName = setter.value(); //noinspection StatementWithEmptyBody if (setterMethodName.equals("none")) { } else if (setterMethodName.isEmpty()) { - abstractConfig.getSetters().put(fieldName, value -> { + modConfig.getSetters().put(fieldName, value -> { try { field.set(null, value); } catch (ReflectiveOperationException e) { @@ -346,12 +346,12 @@ private static void initObject(AbstractConfigImpl abstractConfig, Field fi Class type = setter.type() == Config.EMPTY.class ? field.getType() : setter.type(); Method setterMethod; try { - setterMethod = abstractConfig.getConfigsClass().getDeclaredMethod(setterMethodName, type); + setterMethod = modConfig.getConfigsClass().getDeclaredMethod(setterMethodName, type); } catch (ReflectiveOperationException e) { throw new AssertionError(e); } setterMethod.setAccessible(true); - abstractConfig.getSetters().put(fieldName, value -> { + modConfig.getSetters().put(fieldName, value -> { try { setterMethod.invoke(null, value); } catch (ReflectiveOperationException e) { diff --git a/common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java b/common/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java similarity index 94% rename from common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java rename to common/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java index cd6ae39..0010f66 100644 --- a/common/src/main/java/dev/xpple/betterconfig/impl/AbstractConfigImpl.java +++ b/common/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java @@ -12,7 +12,7 @@ import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.exceptions.CommandSyntaxException; import dev.xpple.betterconfig.BetterConfigCommon; -import dev.xpple.betterconfig.api.AbstractConfig; +import dev.xpple.betterconfig.api.ModConfig; import dev.xpple.betterconfig.api.Config; import dev.xpple.betterconfig.util.CheckedBiConsumer; import dev.xpple.betterconfig.util.CheckedConsumer; @@ -23,12 +23,13 @@ import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.nio.file.Files; +import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.function.Function; import java.util.function.Predicate; -public abstract class AbstractConfigImpl implements AbstractConfig { +public class ModConfigImpl implements ModConfig { private static final Map, Function>> defaultArguments = ImmutableMap., Function>>builder() .put(boolean.class, buildContext -> BoolArgumentType.bool()) @@ -44,20 +45,25 @@ public abstract class AbstractConfigImpl implements AbstractConfig { .put(String.class, buildContext -> StringArgumentType.string()) .build(); + private final String modId; private final Class configsClass; private final Gson gson; private final Gson inlineGson; private final Map, Function>> arguments; - protected AbstractConfigImpl(Class configsClass, Gson gson, Map, Function>> arguments) { + public ModConfigImpl(String modId, Class configsClass, Gson gson, Map, Function>> arguments) { + this.modId = modId; this.configsClass = configsClass; this.gson = gson.newBuilder().setPrettyPrinting().create(); this.inlineGson = gson; this.arguments = arguments; } - public abstract String getIdentifier(); + @Override + public String getModId() { + return this.modId; + } @Override public Class getConfigsClass() { @@ -73,6 +79,11 @@ public Gson getGson() { return this.arguments.getOrDefault(type, (Function>) defaultArguments.get(type)); } + @Override + public Path getConfigsPath() { + return Platform.current.getConfigsPath(this.modId); + } + @Override public Object get(String config) { Field field = this.configs.get(config); diff --git a/common/src/main/java/dev/xpple/betterconfig/impl/Platform.java b/common/src/main/java/dev/xpple/betterconfig/impl/Platform.java index 34c9afa..67ecb14 100644 --- a/common/src/main/java/dev/xpple/betterconfig/impl/Platform.java +++ b/common/src/main/java/dev/xpple/betterconfig/impl/Platform.java @@ -1,9 +1,19 @@ package dev.xpple.betterconfig.impl; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.SuggestionProvider; + +import java.nio.file.Path; import java.util.ServiceLoader; public interface Platform { + Path getConfigsPath(String modId); + Class getCommandSourceClass(); + DynamicCommandExceptionType invalidEnumException(); + + > SuggestionProvider enumSuggestionProvider(Class type); + Platform current = ServiceLoader.load(Platform.class, Platform.class.getClassLoader()).iterator().next(); } 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 3a78d8b..48653d2 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 @@ -3,35 +3,22 @@ import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; -import com.mojang.brigadier.suggestion.SuggestionProvider; import dev.xpple.betterconfig.command.AbstractConfigCommand; -import dev.xpple.betterconfig.command.suggestion.EnumSuggestionProvider; -import dev.xpple.betterconfig.impl.AbstractConfigImpl; import dev.xpple.betterconfig.impl.BetterConfigImpl; +import dev.xpple.betterconfig.impl.ModConfigImpl; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.minecraft.commands.CommandBuildContext; import net.minecraft.network.chat.Component; public class ConfigCommandClient extends AbstractConfigCommand { - @Override - protected > SuggestionProvider enumSuggestionProvider(Class type) { - return new EnumSuggestionProvider<>(type); - } - - @Override - protected DynamicCommandExceptionType invalidEnumException() { - return new DynamicCommandExceptionType(value -> Component.translatable("argument.enum.invalid", value)); - } - private ConfigCommandClient() { super("cconfig"); } @SuppressWarnings("unchecked") public static void register(CommandDispatcher dispatcher, CommandBuildContext buildContext) { - dispatcher.register(new ConfigCommandClient().create(BetterConfigImpl.getModConfigs().values().stream().map(modConfig -> (AbstractConfigImpl) modConfig).toList(), buildContext)); + dispatcher.register(new ConfigCommandClient().create(BetterConfigImpl.getModConfigs().values().stream().map(modConfig -> (ModConfigImpl) modConfig).toList(), buildContext)); } @Override @@ -42,43 +29,43 @@ protected int comment(FabricClientCommandSource source, String config, String co } @Override - protected int get(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config) { - source.sendFeedback(Component.translatable("betterconfig.commands.config.get", config, abstractConfig.asString(config))); + protected int get(FabricClientCommandSource source, ModConfigImpl modConfig, String config) { + source.sendFeedback(Component.translatable("betterconfig.commands.config.get", config, modConfig.asString(config))); return Command.SINGLE_SUCCESS; } @Override - protected int reset(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config) { - abstractConfig.reset(config); - source.sendFeedback(Component.translatable("betterconfig.commands.config.reset", config, abstractConfig.asString(config))); + protected int reset(FabricClientCommandSource source, ModConfigImpl modConfig, String config) { + modConfig.reset(config); + source.sendFeedback(Component.translatable("betterconfig.commands.config.reset", config, modConfig.asString(config))); return Command.SINGLE_SUCCESS; } @Override - protected int set(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { - abstractConfig.set(config, value); - source.sendFeedback(Component.translatable("betterconfig.commands.config.set", config, abstractConfig.asString(config))); + protected int set(FabricClientCommandSource source, ModConfigImpl modConfig, String config, Object value) throws CommandSyntaxException { + modConfig.set(config, value); + source.sendFeedback(Component.translatable("betterconfig.commands.config.set", config, modConfig.asString(config))); return Command.SINGLE_SUCCESS; } @Override - protected int add(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { - abstractConfig.add(config, value); - source.sendFeedback(Component.translatable("betterconfig.commands.config.add", abstractConfig.asString(value), config)); + protected int add(FabricClientCommandSource source, ModConfigImpl modConfig, String config, Object value) throws CommandSyntaxException { + modConfig.add(config, value); + source.sendFeedback(Component.translatable("betterconfig.commands.config.add", modConfig.asString(value), config)); return Command.SINGLE_SUCCESS; } @Override - protected int put(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config, Object key, Object value) throws CommandSyntaxException { - abstractConfig.put(config, key, value); - source.sendFeedback(Component.translatable("betterconfig.commands.config.put", abstractConfig.asString(key), abstractConfig.asString(value), config)); + protected int put(FabricClientCommandSource source, ModConfigImpl modConfig, String config, Object key, Object value) throws CommandSyntaxException { + modConfig.put(config, key, value); + source.sendFeedback(Component.translatable("betterconfig.commands.config.put", modConfig.asString(key), modConfig.asString(value), config)); return Command.SINGLE_SUCCESS; } @Override - protected int remove(FabricClientCommandSource source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { - abstractConfig.remove(config, value); - source.sendFeedback(Component.translatable("betterconfig.commands.config.remove", abstractConfig.asString(value), config)); + protected int remove(FabricClientCommandSource source, ModConfigImpl modConfig, String config, Object value) throws CommandSyntaxException { + modConfig.remove(config, value); + source.sendFeedback(Component.translatable("betterconfig.commands.config.remove", modConfig.asString(value), config)); return Command.SINGLE_SUCCESS; } } diff --git a/fabric/src/main/java/dev/xpple/betterconfig/api/ModConfig.java b/fabric/src/main/java/dev/xpple/betterconfig/api/ModConfig.java deleted file mode 100644 index 9cb1821..0000000 --- a/fabric/src/main/java/dev/xpple/betterconfig/api/ModConfig.java +++ /dev/null @@ -1,9 +0,0 @@ -package dev.xpple.betterconfig.api; - -public interface ModConfig extends AbstractConfig { - /** - * Get the identifier of the mod of this configuration. - * @return the mod's identifier - */ - String getModId(); -} diff --git a/fabric/src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java b/fabric/src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java deleted file mode 100644 index 062943e..0000000 --- a/fabric/src/main/java/dev/xpple/betterconfig/api/ModConfigBuilder.java +++ /dev/null @@ -1,27 +0,0 @@ -package dev.xpple.betterconfig.api; - -import dev.xpple.betterconfig.impl.BetterConfigImpl; -import dev.xpple.betterconfig.impl.BetterConfigInternals; -import dev.xpple.betterconfig.impl.ModConfigImpl; -import net.minecraft.commands.CommandBuildContext; -import net.minecraft.commands.SharedSuggestionProvider; - -public class ModConfigBuilder extends AbstractConfigBuilder { - - private final String modId; - - public ModConfigBuilder(String modId, Class configsClass) { - super(configsClass); - this.modId = modId; - } - - @Override - public void build() { - ModConfigImpl modConfig = new ModConfigImpl<>(this.modId, this.configsClass, this.builder.create(), this.arguments); - if (BetterConfigImpl.getModConfigs().putIfAbsent(this.modId, modConfig) == null) { - BetterConfigInternals.init(modConfig); - return; - } - throw new IllegalArgumentException(this.modId); - } -} 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 614e078..e7b0509 100644 --- a/fabric/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java +++ b/fabric/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java @@ -3,34 +3,21 @@ import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; -import com.mojang.brigadier.suggestion.SuggestionProvider; -import dev.xpple.betterconfig.command.suggestion.EnumSuggestionProvider; -import dev.xpple.betterconfig.impl.AbstractConfigImpl; import dev.xpple.betterconfig.impl.BetterConfigImpl; +import dev.xpple.betterconfig.impl.ModConfigImpl; import net.minecraft.commands.CommandBuildContext; import net.minecraft.commands.CommandSourceStack; import net.minecraft.network.chat.Component; public class ConfigCommand extends AbstractConfigCommand { - @Override - protected > SuggestionProvider enumSuggestionProvider(Class type) { - return new EnumSuggestionProvider<>(type); - } - - @Override - protected DynamicCommandExceptionType invalidEnumException() { - return new DynamicCommandExceptionType(value -> Component.translatable("argument.enum.invalid", value)); - } - private ConfigCommand() { super("config"); } @SuppressWarnings("unchecked") public static void register(CommandDispatcher dispatcher, CommandBuildContext buildContext) { - dispatcher.register(new ConfigCommand().create(BetterConfigImpl.getModConfigs().values().stream().map(modConfig -> (AbstractConfigImpl) modConfig).toList(), buildContext).requires(source -> source.hasPermission(4))); + dispatcher.register(new ConfigCommand().create(BetterConfigImpl.getModConfigs().values().stream().map(modConfig -> (ModConfigImpl) modConfig).toList(), buildContext).requires(source -> source.hasPermission(4))); } @Override @@ -41,43 +28,43 @@ protected int comment(CommandSourceStack source, String config, String comment) } @Override - protected int get(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config) { - source.sendSuccess(() -> Component.translatableWithFallback("betterconfig.commands.config.get", "%s is currently set to %s.", config, abstractConfig.asString(config)), false); + protected int get(CommandSourceStack source, ModConfigImpl modConfig, String config) { + source.sendSuccess(() -> Component.translatableWithFallback("betterconfig.commands.config.get", "%s is currently set to %s.", config, modConfig.asString(config)), false); return Command.SINGLE_SUCCESS; } @Override - protected int reset(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config) { - abstractConfig.reset(config); - source.sendSuccess(() -> Component.translatableWithFallback("betterconfig.commands.config.reset", "%s has been reset to %s.", config, abstractConfig.asString(config)), true); + protected int reset(CommandSourceStack source, ModConfigImpl modConfig, String config) { + modConfig.reset(config); + source.sendSuccess(() -> Component.translatableWithFallback("betterconfig.commands.config.reset", "%s has been reset to %s.", config, modConfig.asString(config)), true); return Command.SINGLE_SUCCESS; } @Override - protected int set(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { - abstractConfig.set(config, value); - source.sendSuccess(() -> Component.translatableWithFallback("betterconfig.commands.config.set", "%s has been set to %s.", config, abstractConfig.asString(config)), true); + protected int set(CommandSourceStack source, ModConfigImpl modConfig, String config, Object value) throws CommandSyntaxException { + modConfig.set(config, value); + source.sendSuccess(() -> Component.translatableWithFallback("betterconfig.commands.config.set", "%s has been set to %s.", config, modConfig.asString(config)), true); return Command.SINGLE_SUCCESS; } @Override - protected int add(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { - abstractConfig.add(config, value); - source.sendSuccess(() -> Component.translatableWithFallback("betterconfig.commands.config.add", "%s has been added to %s.", abstractConfig.asString(value), config), true); + protected int add(CommandSourceStack source, ModConfigImpl modConfig, String config, Object value) throws CommandSyntaxException { + modConfig.add(config, value); + source.sendSuccess(() -> Component.translatableWithFallback("betterconfig.commands.config.add", "%s has been added to %s.", modConfig.asString(value), config), true); return Command.SINGLE_SUCCESS; } @Override - protected int put(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config, Object key, Object value) throws CommandSyntaxException { - abstractConfig.put(config, key, value); - source.sendSuccess(() -> Component.translatableWithFallback("betterconfig.commands.config.put", "The mapping %s=%s has been added to %s.", abstractConfig.asString(key), abstractConfig.asString(value), config), true); + protected int put(CommandSourceStack source, ModConfigImpl modConfig, String config, Object key, Object value) throws CommandSyntaxException { + modConfig.put(config, key, value); + source.sendSuccess(() -> Component.translatableWithFallback("betterconfig.commands.config.put", "The mapping %s=%s has been added to %s.", modConfig.asString(key), modConfig.asString(value), config), true); return Command.SINGLE_SUCCESS; } @Override - protected int remove(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { - abstractConfig.remove(config, value); - source.sendSuccess(() -> Component.translatableWithFallback("betterconfig.commands.config.remove", "%s has been removed from %s.", abstractConfig.asString(value), config), true); + protected int remove(CommandSourceStack source, ModConfigImpl modConfig, String config, Object value) throws CommandSyntaxException { + modConfig.remove(config, value); + source.sendSuccess(() -> Component.translatableWithFallback("betterconfig.commands.config.remove", "%s has been removed from %s.", modConfig.asString(value), config), true); return Command.SINGLE_SUCCESS; } } diff --git a/fabric/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java b/fabric/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java deleted file mode 100644 index f56287e..0000000 --- a/fabric/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java +++ /dev/null @@ -1,21 +0,0 @@ -package dev.xpple.betterconfig.command.suggestion; - -import com.mojang.brigadier.context.CommandContext; -import com.mojang.brigadier.suggestion.Suggestions; -import com.mojang.brigadier.suggestion.SuggestionsBuilder; -import net.minecraft.commands.SharedSuggestionProvider; - -import java.util.Arrays; -import java.util.concurrent.CompletableFuture; - -public class EnumSuggestionProvider> extends AbstractEnumSuggestionProvider { - - public EnumSuggestionProvider(Class enumClass) { - super(enumClass); - } - - @Override - public CompletableFuture getSuggestions(CommandContext context, SuggestionsBuilder builder) { - return SharedSuggestionProvider.suggest(Arrays.stream(this.enumClass.getEnumConstants()).map(Enum::name), builder); - } -} diff --git a/fabric/src/main/java/dev/xpple/betterconfig/impl/FabricPlatform.java b/fabric/src/main/java/dev/xpple/betterconfig/impl/FabricPlatform.java index b510556..1f40b95 100644 --- a/fabric/src/main/java/dev/xpple/betterconfig/impl/FabricPlatform.java +++ b/fabric/src/main/java/dev/xpple/betterconfig/impl/FabricPlatform.java @@ -1,10 +1,32 @@ package dev.xpple.betterconfig.impl; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.SuggestionProvider; +import dev.xpple.betterconfig.BetterConfig; import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.network.chat.Component; + +import java.nio.file.Path; +import java.util.Arrays; public class FabricPlatform implements Platform { + @Override + public Path getConfigsPath(String modId) { + return BetterConfig.MOD_PATH.resolve(modId).resolve("config.json"); + } + @Override public Class getCommandSourceClass() { return SharedSuggestionProvider.class; } + + @Override + public DynamicCommandExceptionType invalidEnumException() { + return new DynamicCommandExceptionType(value -> Component.translatable("argument.enum.invalid", value)); + } + + @Override + public > SuggestionProvider enumSuggestionProvider(Class type) { + return (context, builder) -> SharedSuggestionProvider.suggest(Arrays.stream(type.getEnumConstants()).map(Enum::name), builder); + } } diff --git a/fabric/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java b/fabric/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java deleted file mode 100644 index cc2593c..0000000 --- a/fabric/src/main/java/dev/xpple/betterconfig/impl/ModConfigImpl.java +++ /dev/null @@ -1,37 +0,0 @@ -package dev.xpple.betterconfig.impl; - -import com.google.gson.Gson; -import com.mojang.brigadier.arguments.ArgumentType; -import dev.xpple.betterconfig.BetterConfig; -import dev.xpple.betterconfig.api.ModConfig; -import net.minecraft.commands.CommandBuildContext; -import net.minecraft.commands.SharedSuggestionProvider; - -import java.nio.file.Path; -import java.util.Map; -import java.util.function.Function; - -public class ModConfigImpl extends AbstractConfigImpl implements ModConfig { - - private final String modId; - - public ModConfigImpl(String modId, Class configsClass, Gson gson, Map, Function>> arguments) { - super(configsClass, gson, arguments); - this.modId = modId; - } - - @Override - public String getModId() { - return this.modId; - } - - @Override - public Path getConfigsPath() { - return BetterConfig.MOD_PATH.resolve(this.modId).resolve("config.json"); - } - - @Override - public String getIdentifier() { - return this.getModId(); - } -} diff --git a/fabric/src/testmod/java/dev/xpple/betterconfig/TestMod.java b/fabric/src/testmod/java/dev/xpple/betterconfig/TestMod.java index cac75f0..5a5650f 100644 --- a/fabric/src/testmod/java/dev/xpple/betterconfig/TestMod.java +++ b/fabric/src/testmod/java/dev/xpple/betterconfig/TestMod.java @@ -2,7 +2,8 @@ import dev.xpple.betterconfig.api.ModConfigBuilder; import net.fabricmc.api.DedicatedServerModInitializer; -import net.fabricmc.fabric.api.command.v2.ArgumentTypeRegistry; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.arguments.blocks.BlockInput; import net.minecraft.commands.arguments.blocks.BlockStateArgument; import net.minecraft.commands.synchronization.SingletonArgumentInfo; @@ -15,7 +16,7 @@ public class TestMod implements DedicatedServerModInitializer { public void onInitializeServer() { //ArgumentTypeRegistry.registerArgumentType(new ResourceLocation("testmod", "block"), BlockArgumentType.class, SingletonArgumentInfo.contextFree(BlockArgumentType::block)); - new ModConfigBuilder("testmod", Configs.class) + new ModConfigBuilder("testmod", Configs.class) .registerTypeHierarchy(Block.class, new BlockAdapter(), BlockWrappedArgumentType::block) .registerTypeHierarchy(BlockInput.class, new BlockStateAdapter(), BlockStateArgument::block) .registerTypeHierarchy((Class>) (Class) StructureType.class, new StructureAdapter(), StructureArgumentType::structure) diff --git a/fabric/src/testmod/java/dev/xpple/betterconfig/TestModClient.java b/fabric/src/testmod/java/dev/xpple/betterconfig/TestModClient.java index e196556..6f878a6 100644 --- a/fabric/src/testmod/java/dev/xpple/betterconfig/TestModClient.java +++ b/fabric/src/testmod/java/dev/xpple/betterconfig/TestModClient.java @@ -2,6 +2,8 @@ import dev.xpple.betterconfig.api.ModConfigBuilder; import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.commands.CommandBuildContext; import net.minecraft.commands.arguments.blocks.BlockInput; import net.minecraft.commands.arguments.blocks.BlockStateArgument; import net.minecraft.world.level.block.Block; @@ -10,7 +12,7 @@ public class TestModClient implements ClientModInitializer { @Override public void onInitializeClient() { - new ModConfigBuilder("testmodclient", Configs.class) + new ModConfigBuilder("testmodclient", Configs.class) .registerTypeHierarchy(Block.class, new BlockAdapter(), BlockArgumentType::block) .registerTypeHierarchy(BlockInput.class, new BlockStateAdapter(), BlockStateArgument::block) .registerTypeHierarchy((Class>) (Class) StructureType.class, new StructureAdapter(), StructureArgumentType::structure) diff --git a/gradle.properties b/gradle.properties index 74c7b31..1b20a4d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,10 +13,10 @@ minecraft_version=1.21 # Fabric Properties # check these on https://fabricmc.net/develop # https://ldtteam.jfrog.io/ui/native/parchmentmc-public/org/parchmentmc/data/ -fabric_api_version=0.100.1+1.21 -parchment_mappings=parchment-1.20.6:2024.06.02@zip +fabric_api_version=0.101.2+1.21 +parchment_mappings=parchment-1.21:2024.07.28@zip fabric_loader_version=0.15.11 # Paper Properties -paper_api_version=1.20.6-R0.1-SNAPSHOT -plugin_yml_paper_api_version=1.20.6 +paper_api_version=1.21-R0.1-SNAPSHOT +plugin_yml_paper_api_version=1.21 diff --git a/paper/build.gradle b/paper/build.gradle index 2088094..57183c6 100644 --- a/paper/build.gradle +++ b/paper/build.gradle @@ -22,10 +22,6 @@ repositories { name = "papermc-repo" url = "https://repo.papermc.io/repository/maven-public/" } - maven { - name = "sonatype" - url = "https://oss.sonatype.org/content/groups/public/" - } } configurations { diff --git a/paper/src/main/java/dev/xpple/betterconfig/api/BetterConfigAPI.java b/paper/src/main/java/dev/xpple/betterconfig/api/BetterConfigAPI.java deleted file mode 100644 index 35f130c..0000000 --- a/paper/src/main/java/dev/xpple/betterconfig/api/BetterConfigAPI.java +++ /dev/null @@ -1,17 +0,0 @@ -package dev.xpple.betterconfig.api; - -import dev.xpple.betterconfig.impl.BetterConfigImpl; - -public interface BetterConfigAPI { - - static BetterConfigAPI getInstance() { - return BetterConfigImpl.INSTANCE; - } - - /** - * Get the configurations for the specified plugin. - * @param pluginName the plugin's name - * @return the configurations for the specified plugin - */ - PluginConfig getPluginConfig(String pluginName); -} diff --git a/paper/src/main/java/dev/xpple/betterconfig/api/PluginConfig.java b/paper/src/main/java/dev/xpple/betterconfig/api/PluginConfig.java deleted file mode 100644 index 7c0bd36..0000000 --- a/paper/src/main/java/dev/xpple/betterconfig/api/PluginConfig.java +++ /dev/null @@ -1,9 +0,0 @@ -package dev.xpple.betterconfig.api; - -public interface PluginConfig extends AbstractConfig { - /** - * Get the name of the plugin of this configuration. - * @return the plugin's name - */ - String getPluginName(); -} diff --git a/paper/src/main/java/dev/xpple/betterconfig/api/PluginConfigBuilder.java b/paper/src/main/java/dev/xpple/betterconfig/api/PluginConfigBuilder.java deleted file mode 100644 index 162ee96..0000000 --- a/paper/src/main/java/dev/xpple/betterconfig/api/PluginConfigBuilder.java +++ /dev/null @@ -1,26 +0,0 @@ -package dev.xpple.betterconfig.api; - -import dev.xpple.betterconfig.impl.BetterConfigImpl; -import dev.xpple.betterconfig.impl.BetterConfigInternals; -import dev.xpple.betterconfig.impl.PluginConfigImpl; -import io.papermc.paper.command.brigadier.CommandSourceStack; - -public class PluginConfigBuilder extends AbstractConfigBuilder { - - private final String pluginName; - - public PluginConfigBuilder(String pluginName, Class configsClass) { - super(configsClass); - this.pluginName = pluginName; - } - - @Override - public void build() { - PluginConfigImpl pluginConfig = new PluginConfigImpl(this.pluginName, this.configsClass, this.builder.create(), this.arguments); - if (BetterConfigImpl.getPluginConfigs().putIfAbsent(this.pluginName, pluginConfig) == null) { - BetterConfigInternals.init(pluginConfig); - return; - } - throw new IllegalArgumentException(this.pluginName); - } -} 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 22c0569..9c12f7c 100644 --- a/paper/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java +++ b/paper/src/main/java/dev/xpple/betterconfig/command/ConfigCommand.java @@ -2,35 +2,22 @@ import com.mojang.brigadier.Command; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; -import com.mojang.brigadier.suggestion.SuggestionProvider; import com.mojang.brigadier.tree.LiteralCommandNode; -import dev.xpple.betterconfig.command.suggestion.EnumSuggestionProvider; -import dev.xpple.betterconfig.impl.AbstractConfigImpl; import dev.xpple.betterconfig.impl.BetterConfigImpl; +import dev.xpple.betterconfig.impl.ModConfigImpl; import io.papermc.paper.command.brigadier.CommandSourceStack; -import io.papermc.paper.command.brigadier.MessageComponentSerializer; import net.kyori.adventure.text.Component; import org.bukkit.Server; public class ConfigCommand extends AbstractConfigCommand { - @Override - protected > SuggestionProvider enumSuggestionProvider(Class type) { - return new EnumSuggestionProvider<>(type); - } - - @Override - protected DynamicCommandExceptionType invalidEnumException() { - return new DynamicCommandExceptionType(value -> MessageComponentSerializer.message().serialize(Component.translatable("argument.enum.invalid", Component.text(String.valueOf(value))))); - } - private ConfigCommand() { super("config"); } + @SuppressWarnings("unchecked") public static LiteralCommandNode build() { - return new ConfigCommand().create(BetterConfigImpl.getPluginConfigs().values(), null).requires(source -> source.getSender().hasPermission("betterconfig.config")).build(); + return new ConfigCommand().create(BetterConfigImpl.getModConfigs().values().stream().map(modConfig -> (ModConfigImpl) modConfig).toList(), null).requires(source -> source.getSender().hasPermission("betterconfig.config")).build(); } @Override @@ -41,48 +28,48 @@ protected int comment(CommandSourceStack source, String config, String comment) } @Override - protected int get(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config) { - Component component = Component.translatable("betterconfig.commands.config.get", "%s is currently set to %s.", Component.text(config), Component.text(abstractConfig.asString(config))); + protected int get(CommandSourceStack source, ModConfigImpl modConfig, String config) { + Component component = Component.translatable("betterconfig.commands.config.get", "%s is currently set to %s.", Component.text(config), Component.text(modConfig.asString(config))); source.getSender().sendMessage(component); return Command.SINGLE_SUCCESS; } @Override - protected int reset(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config) { - abstractConfig.reset(config); - Component component = Component.translatable("betterconfig.commands.config.reset", "%s has been reset to %s.", Component.text(config), Component.text(abstractConfig.asString(config))); + protected int reset(CommandSourceStack source, ModConfigImpl modConfig, String config) { + modConfig.reset(config); + Component component = Component.translatable("betterconfig.commands.config.reset", "%s has been reset to %s.", Component.text(config), Component.text(modConfig.asString(config))); source.getSender().getServer().broadcast(component, Server.BROADCAST_CHANNEL_ADMINISTRATIVE); return Command.SINGLE_SUCCESS; } @Override - protected int set(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { - abstractConfig.set(config, value); - Component component = Component.translatable("betterconfig.commands.config.set", "%s has been set to %s.", Component.text(config), Component.text(abstractConfig.asString(config))); + protected int set(CommandSourceStack source, ModConfigImpl modConfig, String config, Object value) throws CommandSyntaxException { + modConfig.set(config, value); + Component component = Component.translatable("betterconfig.commands.config.set", "%s has been set to %s.", Component.text(config), Component.text(modConfig.asString(config))); source.getSender().getServer().broadcast(component, Server.BROADCAST_CHANNEL_ADMINISTRATIVE); return Command.SINGLE_SUCCESS; } @Override - protected int add(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { - abstractConfig.add(config, value); - Component component = Component.translatable("betterconfig.commands.config.add", "%s has been added to %s.", Component.text(abstractConfig.asString(value)), Component.text(config)); + protected int add(CommandSourceStack source, ModConfigImpl modConfig, String config, Object value) throws CommandSyntaxException { + modConfig.add(config, value); + Component component = Component.translatable("betterconfig.commands.config.add", "%s has been added to %s.", Component.text(modConfig.asString(value)), Component.text(config)); source.getSender().getServer().broadcast(component, Server.BROADCAST_CHANNEL_ADMINISTRATIVE); return Command.SINGLE_SUCCESS; } @Override - protected int put(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config, Object key, Object value) throws CommandSyntaxException { - abstractConfig.put(config, key, value); - Component component = Component.translatable("betterconfig.commands.config.put", "The mapping %s=%s has been added to %s.", Component.text(abstractConfig.asString(key)), Component.text(abstractConfig.asString(value)), Component.text(config)); + protected int put(CommandSourceStack source, ModConfigImpl modConfig, String config, Object key, Object value) throws CommandSyntaxException { + modConfig.put(config, key, value); + Component component = Component.translatable("betterconfig.commands.config.put", "The mapping %s=%s has been added to %s.", Component.text(modConfig.asString(key)), Component.text(modConfig.asString(value)), Component.text(config)); source.getSender().getServer().broadcast(component, Server.BROADCAST_CHANNEL_ADMINISTRATIVE); return Command.SINGLE_SUCCESS; } @Override - protected int remove(CommandSourceStack source, AbstractConfigImpl abstractConfig, String config, Object value) throws CommandSyntaxException { - abstractConfig.remove(config, value); - Component component = Component.translatable("betterconfig.commands.config.remove", "%s has been removed from %s.", Component.text(abstractConfig.asString(value)), Component.text(config)); + protected int remove(CommandSourceStack source, ModConfigImpl modConfig, String config, Object value) throws CommandSyntaxException { + modConfig.remove(config, value); + Component component = Component.translatable("betterconfig.commands.config.remove", "%s has been removed from %s.", Component.text(modConfig.asString(value)), Component.text(config)); source.getSender().getServer().broadcast(component, Server.BROADCAST_CHANNEL_ADMINISTRATIVE); return Command.SINGLE_SUCCESS; } diff --git a/paper/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java b/paper/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java deleted file mode 100644 index 5d43f47..0000000 --- a/paper/src/main/java/dev/xpple/betterconfig/command/suggestion/EnumSuggestionProvider.java +++ /dev/null @@ -1,20 +0,0 @@ -package dev.xpple.betterconfig.command.suggestion; - -import com.mojang.brigadier.context.CommandContext; -import com.mojang.brigadier.suggestion.Suggestions; -import com.mojang.brigadier.suggestion.SuggestionsBuilder; - -import java.util.Arrays; -import java.util.concurrent.CompletableFuture; - -public class EnumSuggestionProvider> extends AbstractEnumSuggestionProvider { - - public EnumSuggestionProvider(Class enumClass) { - super(enumClass); - } - - @Override - public CompletableFuture getSuggestions(CommandContext context, SuggestionsBuilder builder) { - return SuggestionProviderHelper.suggestMatching(Arrays.stream(this.enumClass.getEnumConstants()).map(Enum::name), builder); - } -} diff --git a/paper/src/main/java/dev/xpple/betterconfig/impl/BetterConfigImpl.java b/paper/src/main/java/dev/xpple/betterconfig/impl/BetterConfigImpl.java deleted file mode 100644 index c04c7de..0000000 --- a/paper/src/main/java/dev/xpple/betterconfig/impl/BetterConfigImpl.java +++ /dev/null @@ -1,27 +0,0 @@ -package dev.xpple.betterconfig.impl; - -import dev.xpple.betterconfig.api.BetterConfigAPI; -import dev.xpple.betterconfig.api.PluginConfig; - -import java.util.HashMap; -import java.util.Map; - -public class BetterConfigImpl implements BetterConfigAPI { - - private static final Map pluginConfigs = new HashMap<>(); - - @Override - public PluginConfig getPluginConfig(String pluginName) { - PluginConfig pluginConfig = pluginConfigs.get(pluginName); - if (pluginConfig == null) { - throw new IllegalArgumentException(pluginName); - } - return pluginConfig; - } - - public static Map getPluginConfigs() { - return pluginConfigs; - } - - public static final BetterConfigImpl INSTANCE = new BetterConfigImpl(); -} diff --git a/paper/src/main/java/dev/xpple/betterconfig/impl/PaperPlatform.java b/paper/src/main/java/dev/xpple/betterconfig/impl/PaperPlatform.java index be3948c..618f75a 100644 --- a/paper/src/main/java/dev/xpple/betterconfig/impl/PaperPlatform.java +++ b/paper/src/main/java/dev/xpple/betterconfig/impl/PaperPlatform.java @@ -1,10 +1,34 @@ package dev.xpple.betterconfig.impl; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.SuggestionProvider; +import dev.xpple.betterconfig.BetterConfig; +import dev.xpple.betterconfig.command.suggestion.SuggestionProviderHelper; import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.MessageComponentSerializer; +import net.kyori.adventure.text.Component; + +import java.nio.file.Path; +import java.util.Arrays; public class PaperPlatform implements Platform { + @Override + public Path getConfigsPath(String modId) { + return BetterConfig.PLUGIN_PATH.resolve(modId).resolve("config.json"); + } + @Override public Class getCommandSourceClass() { return CommandSourceStack.class; } + + @Override + public DynamicCommandExceptionType invalidEnumException() { + return new DynamicCommandExceptionType(value -> MessageComponentSerializer.message().serialize(Component.translatable("argument.enum.invalid").arguments(Component.text(String.valueOf(value))))); + } + + @Override + public > SuggestionProvider enumSuggestionProvider(Class type) { + return (context, builder) -> SuggestionProviderHelper.suggestMatching(Arrays.stream(type.getEnumConstants()).map(Enum::name), builder); + } } diff --git a/paper/src/main/java/dev/xpple/betterconfig/impl/PluginConfigImpl.java b/paper/src/main/java/dev/xpple/betterconfig/impl/PluginConfigImpl.java deleted file mode 100644 index f0fe9ec..0000000 --- a/paper/src/main/java/dev/xpple/betterconfig/impl/PluginConfigImpl.java +++ /dev/null @@ -1,36 +0,0 @@ -package dev.xpple.betterconfig.impl; - -import com.google.gson.Gson; -import com.mojang.brigadier.arguments.ArgumentType; -import dev.xpple.betterconfig.BetterConfig; -import dev.xpple.betterconfig.api.PluginConfig; -import io.papermc.paper.command.brigadier.CommandSourceStack; - -import java.nio.file.Path; -import java.util.Map; -import java.util.function.Function; - -public class PluginConfigImpl extends AbstractConfigImpl implements PluginConfig { - - private final String pluginName; - - public PluginConfigImpl(String pluginName, Class configsClass, Gson gson, Map, Function>> arguments) { - super(configsClass, gson, arguments); - this.pluginName = pluginName; - } - - @Override - public String getPluginName() { - return this.pluginName; - } - - @Override - public Path getConfigsPath() { - return BetterConfig.PLUGIN_PATH.resolve(this.pluginName).resolve("config.json"); - } - - @Override - public String getIdentifier() { - return this.getPluginName(); - } -} diff --git a/paper/src/testplugin/java/dev/xpple/betterconfig/TestPlugin.java b/paper/src/testplugin/java/dev/xpple/betterconfig/TestPlugin.java index d66ee7f..aa548b5 100644 --- a/paper/src/testplugin/java/dev/xpple/betterconfig/TestPlugin.java +++ b/paper/src/testplugin/java/dev/xpple/betterconfig/TestPlugin.java @@ -1,6 +1,6 @@ package dev.xpple.betterconfig; -import dev.xpple.betterconfig.api.PluginConfigBuilder; +import dev.xpple.betterconfig.api.ModConfigBuilder; import io.papermc.paper.command.brigadier.argument.ArgumentTypes; import org.bukkit.Material; import org.bukkit.block.BlockState; @@ -13,7 +13,7 @@ public class TestPlugin extends JavaPlugin { @Override public void onEnable() { - new PluginConfigBuilder(PLUGIN_NAME, Configs.class) + new ModConfigBuilder<>(PLUGIN_NAME, Configs.class) .registerType(Material.class, new MaterialAdapter(), BlockMaterialArgumentType::block) .registerTypeHierarchy(BlockState.class, new BlockStateAdapter(), ArgumentTypes::blockState) .registerTypeHierarchy(Structure.class, new StructureAdapter(), StructureArgumentType::structure) From 7f57c61991d77bacc74ad14a87461ae3b8fbd748 Mon Sep 17 00:00:00 2001 From: xpple Date: Mon, 5 Aug 2024 23:51:34 +0200 Subject: [PATCH 22/28] Update Gradle --- common/build.gradle | 23 +++++++++------- fabric/build.gradle | 31 +++++++++------------- fabric/src/main/resources/fabric.mod.json | 2 +- gradle.properties | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 43453 -> 43504 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 5 +++- gradlew.bat | 2 ++ paper/build.gradle | 10 ++++--- 9 files changed, 41 insertions(+), 36 deletions(-) diff --git a/common/build.gradle b/common/build.gradle index 0044b6a..20b5b47 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -1,13 +1,12 @@ plugins { - id 'fabric-loom' version '1.6-SNAPSHOT' + id 'fabric-loom' version '1.7-SNAPSHOT' } -sourceCompatibility = JavaVersion.VERSION_21 -targetCompatibility = JavaVersion.VERSION_21 - -archivesBaseName = project.archives_base_name -version = project.base_version -group = project.maven_group +base { + archivesName = project.archives_base_name + version = project.base_version + group = project.maven_group +} repositories { maven { @@ -16,7 +15,6 @@ repositories { } dependencies { - // To change the versions see the gradle.properties file minecraft "com.mojang:minecraft:${project.minecraft_version}" mappings loom.layered { officialMojangMappings { @@ -30,8 +28,15 @@ tasks.withType(JavaCompile).configureEach { it.options.release = 21 } +java { + withSourcesJar() + + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} + jar { from("LICENSE") { - rename {"${it}_${project.archivesBaseName}"} + rename {"${it}_${project.base.archivesName.get()}"} } } diff --git a/fabric/build.gradle b/fabric/build.gradle index b3256a8..fc2ca6b 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -1,14 +1,13 @@ plugins { - id 'fabric-loom' version '1.6-SNAPSHOT' + id 'fabric-loom' version '1.7-SNAPSHOT' id 'maven-publish' } -sourceCompatibility = JavaVersion.VERSION_21 -targetCompatibility = JavaVersion.VERSION_21 - -archivesBaseName = "${project.archives_base_name}-fabric" -version = project.base_version -group = project.maven_group +base { + archivesName = "${project.archives_base_name}-fabric" + version = project.base_version + group = project.maven_group +} loom { splitEnvironmentSourceSets() @@ -78,13 +77,7 @@ dependencies { } modImplementation "net.fabricmc:fabric-loader:${project.fabric_loader_version}" - // Fabric API. This is technically optional, but you probably want it anyway. - modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}" - - // Uncomment the following line to enable the deprecated Fabric API modules. - // These are included in the Fabric API production distribution and allow you to update your mod to the latest modules at a later more convenient time. - - // modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}" + modImplementation fabricApi.module("fabric-command-api-v2", project.fabric_api_version) } processResources { @@ -100,15 +93,15 @@ tasks.withType(JavaCompile).configureEach { } java { - // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task - // if it is present. - // If you remove this line, sources will not be generated. withSourcesJar() + + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 } jar { from("LICENSE") { - rename {"${it}_${project.archivesBaseName}"} + rename {"${it}_${project.base.archivesName.get()}"} } dependsOn ':common:remapJar' from { @@ -122,7 +115,7 @@ jar { publishing { publications { mavenJava(MavenPublication) { - artifactId project.archivesBaseName + artifactId project.archives_base_name from components.java } } diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index fecee18..7d32445 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -33,7 +33,7 @@ "fabricloader": ">=${fabric_loader_version}", "minecraft": "1.21.x", "java": ">=21", - "fabric-api": "*" + "fabric-command-api-v2": "*" }, "custom": { "modmenu": { diff --git a/gradle.properties b/gradle.properties index 1b20a4d..cea32c0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G org.gradle.parallel=true # BetterConfig Properties -base_version=1.2.1-multi-platform +base_version=1.3-multi-platform maven_group=dev.xpple archives_base_name=betterconfig diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e6441136f3d4ba8a0da8d277868979cfbc8ad796..2c3521197d7c4586c843d1d3e9090525f1898cde 100644 GIT binary patch delta 8703 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 Ojj7^59?Sdh$^Qpp*~F>< delta 8662 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a441313..09523c0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index b740cf1..f5feea6 100644 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradlew.bat b/gradlew.bat index 25da30d..9d21a21 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## diff --git a/paper/build.gradle b/paper/build.gradle index 57183c6..183a6eb 100644 --- a/paper/build.gradle +++ b/paper/build.gradle @@ -3,9 +3,11 @@ plugins { id 'maven-publish' } -archivesBaseName = "${project.archives_base_name}-paper" -group = project.maven_group -version = project.base_version +base { + archivesName = "${project.archives_base_name}-paper" + group = project.maven_group + version = project.base_version +} sourceSets { testplugin { @@ -114,7 +116,7 @@ jar { publishing { publications { mavenJava(MavenPublication) { - artifactId project.archivesBaseName + artifactId project.archives_base_name from components.java } } From 46d244538679cf840683b326766bd93d320f02c9 Mon Sep 17 00:00:00 2001 From: xpple Date: Mon, 5 Aug 2024 23:57:12 +0200 Subject: [PATCH 23/28] Use minecraft_version property --- fabric/build.gradle | 2 +- fabric/src/main/resources/fabric.mod.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fabric/build.gradle b/fabric/build.gradle index fc2ca6b..fd48d5f 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -81,7 +81,7 @@ dependencies { } processResources { - def props = [base_version: project.version, fabric_loader_version: project.fabric_loader_version] + def props = [base_version: project.version, minecraft_version: project.minecraft_version, fabric_loader_version: project.fabric_loader_version] inputs.properties props filesMatching("fabric.mod.json") { expand props diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 7d32445..75f6c56 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -31,7 +31,7 @@ ], "depends": { "fabricloader": ">=${fabric_loader_version}", - "minecraft": "1.21.x", + "minecraft": "${minecraft_version}.x", "java": ">=21", "fabric-command-api-v2": "*" }, From f023414ded183ae95dba1cb5a952baad4d0bfcf3 Mon Sep 17 00:00:00 2001 From: xpple Date: Tue, 6 Aug 2024 00:03:00 +0200 Subject: [PATCH 24/28] base_version -> version --- common/build.gradle | 2 +- fabric/build.gradle | 6 +++--- fabric/src/main/resources/fabric.mod.json | 2 +- gradle.properties | 2 +- paper/build.gradle | 6 +++--- paper/src/main/resources/plugin.yml | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/common/build.gradle b/common/build.gradle index 20b5b47..d35b270 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -4,7 +4,7 @@ plugins { base { archivesName = project.archives_base_name - version = project.base_version + version = project.version group = project.maven_group } diff --git a/fabric/build.gradle b/fabric/build.gradle index fd48d5f..b73e80b 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -5,7 +5,7 @@ plugins { base { archivesName = "${project.archives_base_name}-fabric" - version = project.base_version + version = project.version group = project.maven_group } @@ -81,7 +81,7 @@ dependencies { } processResources { - def props = [base_version: project.version, minecraft_version: project.minecraft_version, fabric_loader_version: project.fabric_loader_version] + def props = [version: project.version, minecraft_version: project.minecraft_version, fabric_loader_version: project.fabric_loader_version] inputs.properties props filesMatching("fabric.mod.json") { expand props @@ -115,7 +115,7 @@ jar { publishing { publications { mavenJava(MavenPublication) { - artifactId project.archives_base_name + artifactId project.base.archivesName.get() from components.java } } diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 75f6c56..60e9b8c 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -1,7 +1,7 @@ { "schemaVersion": 1, "id": "betterconfig", - "version": "${base_version}", + "version": "${version}", "name": "BetterConfig", "description": "A very powerful and easy to use command based configuration library for servers and clients.", "authors": [ diff --git a/gradle.properties b/gradle.properties index cea32c0..2f9d040 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G org.gradle.parallel=true # BetterConfig Properties -base_version=1.3-multi-platform +version=1.3-multi-platform maven_group=dev.xpple archives_base_name=betterconfig diff --git a/paper/build.gradle b/paper/build.gradle index 183a6eb..d49d59b 100644 --- a/paper/build.gradle +++ b/paper/build.gradle @@ -6,7 +6,7 @@ plugins { base { archivesName = "${project.archives_base_name}-paper" group = project.maven_group - version = project.base_version + version = project.version } sourceSets { @@ -38,7 +38,7 @@ dependencies { } processResources { - def props = [base_version: project.version, plugin_yml_paper_api_version: project.plugin_yml_paper_api_version] + def props = [version: project.version, plugin_yml_paper_api_version: project.plugin_yml_paper_api_version] inputs.properties props filteringCharset 'UTF-8' filesMatching('plugin.yml') { @@ -116,7 +116,7 @@ jar { publishing { publications { mavenJava(MavenPublication) { - artifactId project.archives_base_name + artifactId project.base.archivesName.get() from components.java } } diff --git a/paper/src/main/resources/plugin.yml b/paper/src/main/resources/plugin.yml index 3961b8f..7f7334a 100644 --- a/paper/src/main/resources/plugin.yml +++ b/paper/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: BetterConfig -version: '${base_version}' +version: '${version}' description: A very powerful and easy to use command based configuration library for servers and clients. author: xpple website: https://xpple.dev/ From 8517aad5b381cfeebaedbb989d1f5d181aa4a2a0 Mon Sep 17 00:00:00 2001 From: xpple Date: Tue, 6 Aug 2024 00:07:10 +0200 Subject: [PATCH 25/28] Remove sources jar --- common/build.gradle | 2 -- fabric/build.gradle | 2 -- 2 files changed, 4 deletions(-) diff --git a/common/build.gradle b/common/build.gradle index d35b270..92949bf 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -29,8 +29,6 @@ tasks.withType(JavaCompile).configureEach { } java { - withSourcesJar() - sourceCompatibility = JavaVersion.VERSION_21 targetCompatibility = JavaVersion.VERSION_21 } diff --git a/fabric/build.gradle b/fabric/build.gradle index b73e80b..109cb4b 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -93,8 +93,6 @@ tasks.withType(JavaCompile).configureEach { } java { - withSourcesJar() - sourceCompatibility = JavaVersion.VERSION_21 targetCompatibility = JavaVersion.VERSION_21 } From c32b07c8af0bd5c157de48f0cce282bdd76d4255 Mon Sep 17 00:00:00 2001 From: xpple Date: Tue, 6 Aug 2024 00:40:13 +0200 Subject: [PATCH 26/28] Update README --- README.md | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 99bc32f..763ed9e 100644 --- a/README.md +++ b/README.md @@ -14,19 +14,24 @@ public class Configs { ``` Finally, register your `Configs` class. - For Fabric users, register the `Configs` class in your mod's `onInitialize(Client)` method. Replace `` with your -mod's id. - ```java - new ModConfigBuilder(, Configs.class).build(); - ``` +mod's id. Sometimes you may omit the generics and just do `<>` instead. + - On clients: + ```java + new ModConfigBuilder(, Configs.class).build(); + ``` + - On servers: + ```java + new ModConfigBuilder(, Configs.class).build(); + ``` - For Paper users, register the `Configs` class in your plugin's `onEnable` method. Replace `` with your plugin's name. ```java - new ModConfigBuilder(, Configs.class).build(); + new ModConfigBuilder<>(, Configs.class).build(); ``` That's it! Now you can access `exampleString` through `Configs.exampleString`. You can edit `exampleString` by using the config command. - On Fabric there are different commands for the client and server. For both, replace `` with your mod's id. - - On the client, execute `/cconfig exampleString set `. + - On clients, execute `/cconfig exampleString set `. - On servers, execute `/config exampleString set `. - On Paper servers, execute `/config exampleString set `. Replace `` with your plugin's name. @@ -37,7 +42,7 @@ the options `add`, `put` and `remove` available. Moreover, you can define your o configurations with arbitrary types. To do this, all you have to do is register the (de)serialiser when you build your config. For instance, to create configurations with type `Block` you can do ```java -new ModConfigBuilder(, Configs.class) +new ModConfigBuilder<>(, Configs.class) .registerTypeHierarchy(Block.class, new BlockAdapter(), BlockArgumentType::block) .build(); ``` @@ -74,7 +79,8 @@ And many more things! For some illustrative examples, see the `Configs` class fo [Paper](paper/src/testplugin/java/dev/xpple/betterconfig/Configs.java). ## Installation -Replace `${version}` with the artifact version. Append `-fabric` for Fabric and `-paper` for Paper. +Replace `${version}` with the artifact version. Append `-fabric` for Fabric and `-paper` for Paper to the base artifact +name. You may choose between my own maven repository and GitHub's package repository. ### My own From 6d04c4f770a5865cb3ccf3562c474a27a902b2df Mon Sep 17 00:00:00 2001 From: xpple Date: Tue, 6 Aug 2024 00:45:46 +0200 Subject: [PATCH 27/28] Reset version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 2f9d040..b50df51 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G org.gradle.parallel=true # BetterConfig Properties -version=1.3-multi-platform +version=1.3 maven_group=dev.xpple archives_base_name=betterconfig From 7e3952e2799470be44aa9a3e0b25451ea5e7d767 Mon Sep 17 00:00:00 2001 From: xpple Date: Tue, 6 Aug 2024 00:53:08 +0200 Subject: [PATCH 28/28] version -> mod_version --- common/build.gradle | 2 +- fabric/build.gradle | 4 ++-- gradle.properties | 2 +- paper/build.gradle | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/common/build.gradle b/common/build.gradle index 92949bf..8ae0d73 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -4,7 +4,7 @@ plugins { base { archivesName = project.archives_base_name - version = project.version + version = project.mod_version group = project.maven_group } diff --git a/fabric/build.gradle b/fabric/build.gradle index 109cb4b..0d0cc69 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -5,7 +5,7 @@ plugins { base { archivesName = "${project.archives_base_name}-fabric" - version = project.version + version = project.mod_version group = project.maven_group } @@ -81,7 +81,7 @@ dependencies { } processResources { - def props = [version: project.version, minecraft_version: project.minecraft_version, fabric_loader_version: project.fabric_loader_version] + def props = [version: project.mod_version, minecraft_version: project.minecraft_version, fabric_loader_version: project.fabric_loader_version] inputs.properties props filesMatching("fabric.mod.json") { expand props diff --git a/gradle.properties b/gradle.properties index b50df51..dd5b4de 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G org.gradle.parallel=true # BetterConfig Properties -version=1.3 +mod_version=1.3 maven_group=dev.xpple archives_base_name=betterconfig diff --git a/paper/build.gradle b/paper/build.gradle index d49d59b..aea6c83 100644 --- a/paper/build.gradle +++ b/paper/build.gradle @@ -6,7 +6,7 @@ plugins { base { archivesName = "${project.archives_base_name}-paper" group = project.maven_group - version = project.version + version = project.mod_version } sourceSets { @@ -38,7 +38,7 @@ dependencies { } processResources { - def props = [version: project.version, plugin_yml_paper_api_version: project.plugin_yml_paper_api_version] + def props = [version: project.mod_version, plugin_yml_paper_api_version: project.plugin_yml_paper_api_version] inputs.properties props filteringCharset 'UTF-8' filesMatching('plugin.yml') {