diff options
author | isxander <xander@isxander.dev> | 2024-04-11 18:43:06 +0100 |
---|---|---|
committer | isxander <xander@isxander.dev> | 2024-04-11 18:43:06 +0100 |
commit | 04fe933f4c24817100f3101f088accf55a621f8a (patch) | |
tree | feff94ca3ab4484160e69a24f4ee38522381950e /common/src/main/java/dev/isxander/yacl3/config | |
parent | 831b894fdb7fe3e173d81387c8f6a2402b8ccfa9 (diff) | |
download | YetAnotherConfigLib-04fe933f4c24817100f3101f088accf55a621f8a.tar.gz YetAnotherConfigLib-04fe933f4c24817100f3101f088accf55a621f8a.tar.bz2 YetAnotherConfigLib-04fe933f4c24817100f3101f088accf55a621f8a.zip |
Extremely fragile and broken multiversion build with stonecutter
Diffstat (limited to 'common/src/main/java/dev/isxander/yacl3/config')
67 files changed, 0 insertions, 3179 deletions
diff --git a/common/src/main/java/dev/isxander/yacl3/config/ConfigEntry.java b/common/src/main/java/dev/isxander/yacl3/config/ConfigEntry.java deleted file mode 100644 index 066cf42..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/ConfigEntry.java +++ /dev/null @@ -1,15 +0,0 @@ -package dev.isxander.yacl3.config; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * @deprecated Use {@link dev.isxander.yacl3.config.v2.api.SerialEntry} instead. - */ -@Deprecated -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface ConfigEntry { -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/ConfigInstance.java b/common/src/main/java/dev/isxander/yacl3/config/ConfigInstance.java deleted file mode 100644 index 31d4ca2..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/ConfigInstance.java +++ /dev/null @@ -1,50 +0,0 @@ -package dev.isxander.yacl3.config; - -import java.lang.reflect.InvocationTargetException; - -/** - * Responsible for handing the actual config data type. - * Holds the instance along with a final default instance - * to reference default values for options and should not be changed. - * - * Abstract methods to save and load the class, implementations are responsible for - * how it saves and load. - * - * @param <T> config data type - * @deprecated upgrade to config v2 {@link dev.isxander.yacl3.config.v2.api.ConfigClassHandler} - */ -@Deprecated -public abstract class ConfigInstance<T> { - private final Class<T> configClass; - private final T defaultInstance; - private T instance; - - public ConfigInstance(Class<T> configClass) { - this.configClass = configClass; - - try { - this.defaultInstance = this.instance = configClass.getConstructor().newInstance(); - } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { - throw new IllegalStateException(String.format("Could not create default instance of config for %s. Make sure there is a default constructor!", this.configClass.getSimpleName())); - } - } - - public abstract void save(); - public abstract void load(); - - public T getConfig() { - return this.instance; - } - - protected void setConfig(T instance) { - this.instance = instance; - } - - public T getDefaults() { - return this.defaultInstance; - } - - public Class<T> getConfigClass() { - return this.configClass; - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/GsonConfigInstance.java b/common/src/main/java/dev/isxander/yacl3/config/GsonConfigInstance.java deleted file mode 100644 index 91749ba..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/GsonConfigInstance.java +++ /dev/null @@ -1,247 +0,0 @@ -package dev.isxander.yacl3.config; - -import com.google.gson.*; -import dev.isxander.yacl3.config.v2.impl.serializer.GsonConfigSerializer; -import dev.isxander.yacl3.gui.utils.ItemRegistryHelper; -import dev.isxander.yacl3.impl.utils.YACLConstants; -import net.minecraft.core.RegistryAccess; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.Style; -import net.minecraft.world.item.Item; - -import java.awt.*; -import java.io.IOException; -import java.lang.reflect.Type; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import java.util.function.UnaryOperator; - -/** - * Uses GSON to serialize and deserialize config data from JSON to a file. - * <p> - * Only fields annotated with {@link ConfigEntry} are included in the JSON. - * {@link Component}, {@link Style} and {@link Color} have default type adapters, so there is no need to provide them in your GSON instance. - * GSON is automatically configured to format fields as {@code lower_camel_case}. - * - * @param <T> config data type - * @deprecated upgrade to config v2 {@link dev.isxander.yacl3.config.v2.api.ConfigClassHandler} with {@link dev.isxander.yacl3.config.v2.api.serializer.GsonConfigSerializerBuilder} - * <pre> - * {@code - * public class MyConfig { - * public static ConfigClassHandler<MyConfig> HANDLER = ConfigClassHandler.createBuilder(MyConfig.class) - * .id(new ResourceLocation("modid", "config")) - * .serializer(config -> GsonConfigSerializerBuilder.create(config) - * .setPath(FabricLoader.getInstance().getConfigDir().resolve("my_mod.json") - * .build()) - * .build(); - * - * @SerialEntry public boolean myBoolean = true; - * } - * } - * </pre> - */ -@Deprecated -public class GsonConfigInstance<T> extends ConfigInstance<T> { - private final Gson gson; - private final Path path; - - @Deprecated - public GsonConfigInstance(Class<T> configClass, Path path) { - this(configClass, path, new GsonBuilder()); - } - - @Deprecated - public GsonConfigInstance(Class<T> configClass, Path path, Gson gson) { - this(configClass, path, gson.newBuilder()); - } - - @Deprecated - public GsonConfigInstance(Class<T> configClass, Path path, UnaryOperator<GsonBuilder> builder) { - this(configClass, path, builder.apply(new GsonBuilder())); - } - - @Deprecated - public GsonConfigInstance(Class<T> configClass, Path path, GsonBuilder builder) { - super(configClass); - this.path = path; - this.gson = builder - .setExclusionStrategies(new ConfigExclusionStrategy()) - .registerTypeHierarchyAdapter(Component.class, new Component.SerializerAdapter(RegistryAccess.EMPTY)) - .registerTypeHierarchyAdapter(Style.class, new GsonConfigSerializer.StyleTypeAdapter()) - .registerTypeHierarchyAdapter(Color.class, new ColorTypeAdapter()) - .registerTypeHierarchyAdapter(Item.class, new ItemTypeAdapter()) - .serializeNulls() - .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) - .create(); - } - - private GsonConfigInstance(Class<T> configClass, Path path, Gson gson, boolean fromBuilder) { - super(configClass); - this.path = path; - this.gson = gson; - } - - @Override - public void save() { - try { - YACLConstants.LOGGER.info("Saving {}...", getConfigClass().getSimpleName()); - Files.writeString(path, gson.toJson(getConfig()), StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE); - } catch (IOException e) { - e.printStackTrace(); - } - } - - @Override - public void load() { - try { - if (Files.notExists(path)) { - save(); - return; - } - - YACLConstants.LOGGER.info("Loading {}...", getConfigClass().getSimpleName()); - setConfig(gson.fromJson(Files.readString(path), getConfigClass())); - } catch (IOException e) { - e.printStackTrace(); - } - } - - public Path getPath() { - return this.path; - } - - private static class ConfigExclusionStrategy implements ExclusionStrategy { - @Override - public boolean shouldSkipField(FieldAttributes fieldAttributes) { - return fieldAttributes.getAnnotation(ConfigEntry.class) == null; - } - - @Override - public boolean shouldSkipClass(Class<?> aClass) { - return false; - } - } - - public static class ColorTypeAdapter implements JsonSerializer<Color>, JsonDeserializer<Color> { - @Override - public Color deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { - return new Color(jsonElement.getAsInt(), true); - } - - @Override - public JsonElement serialize(Color color, Type type, JsonSerializationContext jsonSerializationContext) { - return new JsonPrimitive(color.getRGB()); - } - } - public static class ItemTypeAdapter implements JsonSerializer<Item>, JsonDeserializer<Item> { - @Override - public Item deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { - return ItemRegistryHelper.getItemFromName(jsonElement.getAsString()); - } - - @Override - public JsonElement serialize(Item item, Type type, JsonSerializationContext jsonSerializationContext) { - return new JsonPrimitive(BuiltInRegistries.ITEM.getKey(item).toString()); - } - } - - /** - * Creates a builder for a GSON config instance. - * @param configClass the config class - * @return a new builder - * @param <T> the config type - */ - public static <T> Builder<T> createBuilder(Class<T> configClass) { - return new Builder<>(configClass); - } - - public static class Builder<T> { - private final Class<T> configClass; - private Path path; - private UnaryOperator<GsonBuilder> gsonBuilder = builder -> builder - .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) - .serializeNulls() - .registerTypeHierarchyAdapter(Component.class, new Component.SerializerAdapter(RegistryAccess.EMPTY)) - .registerTypeHierarchyAdapter(Style.class, new GsonConfigSerializer.StyleTypeAdapter()) - .registerTypeHierarchyAdapter(Color.class, new ColorTypeAdapter()) - .registerTypeHierarchyAdapter(Item.class, new ItemTypeAdapter()); - - private Builder(Class<T> configClass) { - this.configClass = configClass; - } - - /** - * Sets the file path to save and load the config from. - */ - public Builder<T> setPath(Path path) { - this.path = path; - return this; - } - - /** - * Sets the GSON instance to use. Overrides all YACL defaults such as: - * <ul> - * <li>lower_camel_case field naming policy</li> - * <li>null serialization</li> - * <li>{@link Component}, {@link Style} and {@link Color} type adapters</li> - * </ul> - * Still respects the exclusion strategy to only serialize {@link ConfigEntry} - * but these can be added to with setExclusionStrategies. - * - * @param gsonBuilder gson builder to use - */ - public Builder<T> overrideGsonBuilder(GsonBuilder gsonBuilder) { - this.gsonBuilder = builder -> gsonBuilder; - return this; - } - - /** - * Sets the GSON instance to use. Overrides all YACL defaults such as: - * <ul> - * <li>lower_camel_case field naming policy</li> - * <li>null serialization</li> - * <li>{@link Component}, {@link Style} and {@link Color} type adapters</li> - * </ul> - * Still respects the exclusion strategy to only serialize {@link ConfigEntry} - * but these can be added to with setExclusionStrategies. - * - * @param gson gson instance to be converted to a builder - */ - public Builder<T> overrideGsonBuilder(Gson gson) { - return this.overrideGsonBuilder(gson.newBuilder()); - } - - /** - * Appends extra configuration to a GSON builder. - * This is the intended way to add functionality to the GSON instance. - * <p> - * By default, YACL sets the GSON with the following options: - * <ul> - * <li>lower_camel_case field naming policy</li> - * <li>null serialization</li> - * <li>{@link Component}, {@link Style} and {@link Color} type adapters</li> - * </ul> - * - * @param gsonBuilder the function to apply to the builder - */ - public Builder<T> appendGsonBuilder(UnaryOperator<GsonBuilder> gsonBuilder) { - UnaryOperator<GsonBuilder> prev = this.gsonBuilder; - this.gsonBuilder = builder -> gsonBuilder.apply(prev.apply(builder)); - return this; - } - - /** - * Builds the config instance. - * @return the built config instance - */ - public GsonConfigInstance<T> build() { - UnaryOperator<GsonBuilder> gsonBuilder = builder -> this.gsonBuilder.apply(builder) - .addSerializationExclusionStrategy(new ConfigExclusionStrategy()) - .addDeserializationExclusionStrategy(new ConfigExclusionStrategy()); - - return new GsonConfigInstance<>(configClass, path, gsonBuilder.apply(new GsonBuilder()).create(), true); - } - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigClassHandler.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigClassHandler.java deleted file mode 100644 index d94280f..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigClassHandler.java +++ /dev/null @@ -1,107 +0,0 @@ -package dev.isxander.yacl3.config.v2.api; - -import dev.isxander.yacl3.api.YetAnotherConfigLib; -import dev.isxander.yacl3.config.v2.impl.ConfigClassHandlerImpl; -import net.minecraft.resources.ResourceLocation; - -import java.util.function.Function; - -/** - * Represents a handled config class. - * - * @param <T> the backing config class to be managed - */ -public interface ConfigClassHandler<T> { - /** - * Gets the working instance of the config class. - * This should be used to get and set fields like usual. - */ - T instance(); - - /** - * Gets a second instance of the config class that - * should be used to get default values only. No fields - * should be modified in this instance. - */ - T defaults(); - - /** - * Gets the class of the config. - */ - Class<T> configClass(); - - /** - * Get all eligible fields in the config class. - * They could either be annotated with {@link dev.isxander.yacl3.config.v2.api.autogen.AutoGen} - * or {@link SerialEntry}, do not assume that a field has both of these. - */ - ConfigField<?>[] fields(); - - /** - * The unique identifier of this config handler. - */ - ResourceLocation id(); - - /** - * Auto-generates a GUI for this config class. - * This throws an exception if auto-gen is not supported. - */ - YetAnotherConfigLib generateGui(); - - /** - * Whether this config class supports auto-gen. - * If on a dedicated server, this returns false. - */ - boolean supportsAutoGen(); - - /** - * Safely loads the config class using the provided serializer. - * @return if the config was loaded successfully - */ - boolean load(); - - /** - * Safely saves the config class using the provided serializer. - */ - void save(); - - /** - * The serializer for this config class. - * Manages saving and loading of the config with fields - * annotated with {@link SerialEntry}. - * - * @deprecated use {@link #load()} and {@link #save()} instead. - */ - @Deprecated - ConfigSerializer<T> serializer(); - - /** - * Creates a builder for a config class. - * - * @param configClass the config class to build - * @param <T> the type of the config class - * @return the builder - */ - static <T> Builder<T> createBuilder(Class<T> configClass) { - return new ConfigClassHandlerImpl.BuilderImpl<>(configClass); - } - - interface Builder<T> { - /** - * The unique identifier of this config handler. - * The namespace should be your modid. - * - * @return this builder - */ - Builder<T> id(ResourceLocation id); - - /** - * The function to create the serializer for this config class. - * - * @return this builder - */ - Builder<T> serializer(Function<ConfigClassHandler<T>, ConfigSerializer<T>> serializerFactory); - - ConfigClassHandler<T> build(); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigField.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigField.java deleted file mode 100644 index 181a4d4..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigField.java +++ /dev/null @@ -1,40 +0,0 @@ -package dev.isxander.yacl3.config.v2.api; - -import dev.isxander.yacl3.config.v2.api.autogen.AutoGenField; - -import java.util.Optional; - -/** - * Represents a field in a config class. - * This is used to get all metadata on a field, - * and access the field and its default value. - * - * @param <T> the field's type - */ -public interface ConfigField<T> { - /** - * Gets the accessor for the field on the main instance. - * (Accessed through {@link ConfigClassHandler#instance()}) - */ - FieldAccess<T> access(); - - /** - * Gets the accessor for the field on the default instance. - */ - ReadOnlyFieldAccess<T> defaultAccess(); - - /** - * @return the parent config class handler that manages this field. - */ - ConfigClassHandler<?> parent(); - - /** - * The serial entry metadata for this field, if it exists. - */ - Optional<SerialField> serial(); - - /** - * The auto-gen metadata for this field, if it exists. - */ - Optional<AutoGenField> autoGen(); -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigSerializer.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigSerializer.java deleted file mode 100644 index 4ac988c..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigSerializer.java +++ /dev/null @@ -1,64 +0,0 @@ -package dev.isxander.yacl3.config.v2.api; - -import java.util.Map; - -/** - * The base class for config serializers, - * offering a method to save and load. - * @param <T> the config class to be (de)serialized - */ -public abstract class ConfigSerializer<T> { - protected final ConfigClassHandler<T> config; - - public ConfigSerializer(ConfigClassHandler<T> config) { - this.config = config; - } - - /** - * Saves all fields in the config class. - * This can be done any way as it's abstract, but most - * commonly it is saved to a file. - */ - public abstract void save(); - - /** - * Loads all fields into the config class. - * @param bufferAccessMap a map of the field accesses. instead of directly setting the field with - * {@link ConfigField#access()}, use this parameter. This loads into a temporary object, - * and the class handler handles pushing these changes to the instance. - * @return the result of the load - */ - public LoadResult loadSafely(Map<ConfigField<?>, FieldAccess<?>> bufferAccessMap) { - this.load(); - return LoadResult.NO_CHANGE; - } - - /** - * Loads all fields in the config class. - * - * @deprecated use {@link #loadSafely(Map)} instead. - */ - @Deprecated - public void load() { - throw new IllegalArgumentException("load() is deprecated, use loadSafely() instead."); - } - - public enum LoadResult { - /** - * Indicates that the config was loaded successfully and the temporary object should be applied. - */ - SUCCESS, - /** - * Indicates that the config was not loaded successfully and the load should be abandoned. - */ - FAILURE, - /** - * Indicates that the config has not changed after a load and the temporary object should be ignored. - */ - NO_CHANGE, - /** - * Indicates the config was loaded successfully, but the config should be re-saved straight away. - */ - DIRTY - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/FieldAccess.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/FieldAccess.java deleted file mode 100644 index ea30cd8..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/FieldAccess.java +++ /dev/null @@ -1,14 +0,0 @@ -package dev.isxander.yacl3.config.v2.api; - -/** - * A writable field instance access. - * - * @param <T> the type of the field - */ -public interface FieldAccess<T> extends ReadOnlyFieldAccess<T> { - /** - * Sets the value of the field. - * @param value the value to set - */ - void set(T value); -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/ReadOnlyFieldAccess.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/ReadOnlyFieldAccess.java deleted file mode 100644 index 566d60d..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/ReadOnlyFieldAccess.java +++ /dev/null @@ -1,36 +0,0 @@ -package dev.isxander.yacl3.config.v2.api; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; -import java.util.Optional; - -/** - * An abstract interface for accessing properties of an instance of a field. - * You do not need to worry about exceptions as the implementation - * will handle them. - * - * @param <T> the type of the field - */ -public interface ReadOnlyFieldAccess<T> { - /** - * @return the current value of the field. - */ - T get(); - - /** - * @return the name of the field. - */ - String name(); - - /** - * @return the type of the field. - */ - Type type(); - - /** - * @return the class of the field. - */ - Class<T> typeClass(); - - <A extends Annotation> Optional<A> getAnnotation(Class<A> annotationClass); -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/SerialEntry.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/SerialEntry.java deleted file mode 100644 index 94bf785..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/SerialEntry.java +++ /dev/null @@ -1,39 +0,0 @@ -package dev.isxander.yacl3.config.v2.api; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Marks a field as serializable, so it can be used in a {@link ConfigSerializer}. - * Any field without this annotation will not be saved or loaded, but can still be turned - * into an auto-generated option. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface SerialEntry { - /** - * The serial name of the field. - * If empty, the serializer will decide the name. - */ - String value() default ""; - - /** - * The comment to add to the field. - * Some serializers may not support this. - * If empty, the serializer will not add a comment. - */ - String comment() default ""; - - /** - * Whether the field is required in the loaded config to be valid. - * If it's not, the config will be marked as dirty and re-saved with the default value. - */ - boolean required() default true; - - /** - * Whether the field can be null. - */ - boolean nullable() default false; -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/SerialField.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/SerialField.java deleted file mode 100644 index cf6abfc..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/SerialField.java +++ /dev/null @@ -1,16 +0,0 @@ -package dev.isxander.yacl3.config.v2.api; - -import java.util.Optional; - -/** - * The backing interface for the {@link SerialEntry} annotation. - */ -public interface SerialField { - String serialName(); - - Optional<String> comment(); - - boolean required(); - - boolean nullable(); -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/AutoGen.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/AutoGen.java deleted file mode 100644 index 4187caf..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/AutoGen.java +++ /dev/null @@ -1,32 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Any field that is annotated with this will generate a config option - * in the auto-generated config GUI. This should be paired with an - * {@link OptionFactory} annotation to define how to create the option. - * Some examples of this are {@link TickBox}, {@link FloatSlider}, {@link Label} or {@link StringField}. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface AutoGen { - /** - * Should be the id of the category. This is used to group options. - * The translation keys also use this. Category IDs can be set as a - * {@code private static final String} and used in the annotation to prevent - * repeating yourself. - */ - String category(); - - /** - * If left blank, the option will go in the root group, where it is - * listed at the top of the category with no group header. If set, - * this also appends to the translation key. Group IDs can be reused - * between multiple categories. - */ - String group() default ""; -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/AutoGenField.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/AutoGenField.java deleted file mode 100644 index 7f751fb..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/AutoGenField.java +++ /dev/null @@ -1,12 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import java.util.Optional; - -/** - * Backing interface for the {@link AutoGen} annotation. - */ -public interface AutoGenField { - String category(); - - Optional<String> group(); -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Boolean.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Boolean.java deleted file mode 100644 index 5598389..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Boolean.java +++ /dev/null @@ -1,41 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * An option factory. - * <p> - * This creates a regular option with a - * {@link dev.isxander.yacl3.api.controller.BooleanControllerBuilder} controller. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface Boolean { - enum Formatter { - YES_NO, - TRUE_FALSE, - ON_OFF, - /** - * Uses the translation keys: - * <ul> - * <li>true: {@code yacl3.config.$configId.$fieldName.fmt.true}</li> - * <li>false: {@code yacl3.config.$configId.$fieldName.fmt.false}</li> - * </ul> - */ - CUSTOM, - } - - /** - * The format used to display the boolean. - */ - Formatter formatter() default Formatter.TRUE_FALSE; - - /** - * Whether to color the formatted text green and red - * depending on the value: true or false respectively. - */ - boolean colored() default false; -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/ColorField.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/ColorField.java deleted file mode 100644 index 74937b4..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/ColorField.java +++ /dev/null @@ -1,21 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * An option factory. - * <p> - * This creates a regular option with a - * {@link dev.isxander.yacl3.api.controller.ColorControllerBuilder} controller. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface ColorField { - /** - * Whether to show/allow the alpha channel in the color field. - */ - boolean allowAlpha() default false; -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/CustomDescription.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/CustomDescription.java deleted file mode 100644 index 08624b4..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/CustomDescription.java +++ /dev/null @@ -1,12 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface CustomDescription { - String[] value() default ""; -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/CustomFormat.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/CustomFormat.java deleted file mode 100644 index 15f6336..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/CustomFormat.java +++ /dev/null @@ -1,17 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import dev.isxander.yacl3.api.controller.ValueFormatter; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Allows you to specify a custom {@link ValueFormatter} for a field. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface CustomFormat { - Class<? extends ValueFormatter<?>> value(); -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/CustomImage.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/CustomImage.java deleted file mode 100644 index d193f42..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/CustomImage.java +++ /dev/null @@ -1,69 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.impl.autogen.EmptyCustomImageFactory; -import dev.isxander.yacl3.gui.image.ImageRenderer; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; - -/** - * Defines a custom image for an option. - * Without this annotation, the option factory will look - * for the resource {@code modid:textures/yacl3/$config_id_path/$fieldName.webp}. - * WEBP was chosen as the default format because file sizes are greatly reduced, - * which is important to keep your JAR size down, if you're so bothered. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface CustomImage { - /** - * The resource path to the image, a {@link net.minecraft.resources.ResourceLocation} - * is constructed with the namespace being the modid of the config, and the path being - * this value. - * <p> - * The following file formats are supported: - * <ul> - * <li>{@code .png}</li> - * <li>{@code .webp}</li> - * <li>{@code .jpg}, {@code .jpeg}</li> - * <li>{@code .gif} - <strong>HIGHLY DISCOURAGED DUE TO LARGE FILE SIZE</strong></li> - * </ul> - * <p> - * If left blank, then {@link CustomImage#factory()} is used. - */ - String value() default ""; - - /** - * The width of the image, in pixels. - * <strong>This is only required when using a PNG with {@link CustomImage#value()}</strong> - */ - int width() default 0; - - /** - * The width of the image, in pixels. - * <strong>This is only required when using a PNG with {@link CustomImage#value()}</strong> - */ - int height() default 0; - - /** - * The factory to create the image with. - * For the average user, this should not be used as it breaks out of the - * API-safe environment where things could change at any time, but required - * when creating anything advanced with the {@link ImageRenderer}. - * <p> - * The factory should contain a public, no-args constructor that will be - * invoked via reflection. - * - * @return the class of the factory - */ - Class<? extends CustomImageFactory<?>> factory() default EmptyCustomImageFactory.class; - - interface CustomImageFactory<T> { - CompletableFuture<ImageRenderer> createImage(T value, ConfigField<T> field, OptionAccess access); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/CustomName.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/CustomName.java deleted file mode 100644 index aa235bb..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/CustomName.java +++ /dev/null @@ -1,18 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Overrides the name of an auto-generated option. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface CustomName { - /** - * The translation key to use for the option's name. - */ - String value() default ""; -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/DoubleField.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/DoubleField.java deleted file mode 100644 index 963cefd..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/DoubleField.java +++ /dev/null @@ -1,46 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * A regular option factory. - * <p> - * This creates a regular option with a - * {@link dev.isxander.yacl3.api.controller.DoubleFieldControllerBuilder} controller. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface DoubleField { - /** - * The minimum value of the field. If a user enters a value less - * than this, it will be clamped to this value. - * <p> - * If this is set to {@code -Double.MAX_VALUE}, there will be no minimum. - * <p> - * If the current value is at this minimum, if available, - * the translation key {@code yacl3.config.$configId.$fieldName.fmt.min} - * will be used. - */ - double min() default -Double.MAX_VALUE; - - /** - * The maximum value of the field. If a user enters a value more - * than this, it will be clamped to this value. - * <p> - * If this is set to {@code Double.MAX_VALUE}, there will be no minimum. - * <p> - * If the current value is at this maximum, if available, - * the translation key {@code yacl3.config.$configId.$fieldName.fmt.max} - * will be used. - */ - double max() default Double.MAX_VALUE; - - /** - * The format used to display the double. - * This is the syntax used in {@link String#format(String, Object...)}. - */ - String format() default "%.2f"; -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/DoubleSlider.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/DoubleSlider.java deleted file mode 100644 index 268f6a4..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/DoubleSlider.java +++ /dev/null @@ -1,48 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * A regular option factory. - * <p> - * This creates a regular option with a - * {@link dev.isxander.yacl3.api.controller.DoubleSliderControllerBuilder} controller. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface DoubleSlider { - /** - * The minimum value of the slider. - * <p> - * If the current value is at this minimum, if available, - * the translation key {@code yacl3.config.$configId.$fieldName.fmt.min} - * will be used. - */ - double min(); - - /** - * The maximum value of the slider. - * <p> - * If the current value is at this maximum, if available, - * the translation key {@code yacl3.config.$configId.$fieldName.fmt.max} - * will be used. - */ - double max(); - - /** - * The step size of this slider. - * For example, if this is set to 0.1, the slider will - * increment/decrement by 0.1 when dragging, no less, no more and - * will always be a multiple of 0.1. - */ - double step(); - - /** - * The format used to display the double. - * This is the syntax used in {@link String#format(String, Object...)}. - */ - String format() default "%.2f"; -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Dropdown.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Dropdown.java deleted file mode 100644 index 44239d5..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Dropdown.java +++ /dev/null @@ -1,43 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * An option factory. - * <p> - * This creates a regular option with a - * {@link dev.isxander.yacl3.api.controller.DropdownStringControllerBuilder} controller. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface Dropdown { - /** - * The allowed values for the field. These will be shown in a dropdown - * that the user can filter and select from. - * <p> - * Only values in this list will be accepted and written to the config - * file, unless {@link #allow()} is set to ${@code ALLOW_ANY}. - * <p> - * Empty string is a valid value only if it appears in this list, or if - * {@link #allow()} is set to {@code ALLOW_EMPTY} or {@code ALLOW_ANY}. - */ - String[] values(); - - /** - * Whether to accept the empty string as a valid value if it does not - * already appear in {@link #values()}. If it already appears there, - * the value of this does not apply. - */ - boolean allowEmptyValue() default false; - - /** - * Whether to accept any string as a valid value. The list of strings - * supplied in {@link #values()} are only used as dropdown suggestions. - * Empty strings are still prohibited unless the empty string appears in - * {@link #values()} or {@link #allowEmptyValue()}. - */ - boolean allowAnyValue() default false; -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/EnumCycler.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/EnumCycler.java deleted file mode 100644 index 98d94f9..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/EnumCycler.java +++ /dev/null @@ -1,35 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import dev.isxander.yacl3.api.NameableEnum; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * An option factory. - * <p> - * This creates a regular option with a {@link dev.isxander.yacl3.api.controller.CyclingListControllerBuilder} - * controller. If the enum implements {@link CyclableEnum}, the allowed values will be used from that, - * rather than every single enum constant in the class. If not, {@link EnumCycler#allowedOrdinals()} is used. - * <p> - * There are two methods of formatting for enum values. First, if the enum implements - * {@link dev.isxander.yacl3.api.NameableEnum}, {@link NameableEnum#getDisplayName()} is used. - * Otherwise, the translation key {@code yacl3.config.enum.$enumClassName.$enumName} where - * {@code $enumClassName} is the exact name of the class and {@code $enumName} is equal to the lower - * case of {@link Enum#name()}. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface EnumCycler { - /** - * The allowed ordinals of the enum class. If empty, all ordinals are allowed. - * This is only used if the enum does not implement {@link CyclableEnum}. - */ - int[] allowedOrdinals() default {}; - - interface CyclableEnum<T extends Enum<T>> { - T[] allowedValues(); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/FloatField.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/FloatField.java deleted file mode 100644 index 1e7e71e..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/FloatField.java +++ /dev/null @@ -1,46 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * A regular option factory. - * <p> - * This creates a regular option with a - * {@link dev.isxander.yacl3.api.controller.FloatFieldControllerBuilder} controller. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface FloatField { - /** - * The minimum value of the field. If a user enters a value less - * than this, it will be clamped to this value. - * <p> - * If this is set to {@code -Float.MAX_VALUE}, there will be no minimum. - * <p> - * If the current value is at this minimum, if available, - * the translation key {@code yacl3.config.$configId.$fieldName.fmt.min} - * will be used. - */ - float min() default -Float.MAX_VALUE; - - /** - * The maximum value of the field. If a user enters a value more - * than this, it will be clamped to this value. - * <p> - * If this is set to {@code Float.MAX_VALUE}, there will be no minimum. - * <p> - * If the current value is at this maximum, if available, - * the translation key {@code yacl3.config.$configId.$fieldName.fmt.max} - * will be used. - */ - float max() default Float.MAX_VALUE; - - /** - * The format used to display the float. - * This is the syntax used in {@link String#format(String, Object...)}. - */ - String format() default "%.1f"; -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/FloatSlider.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/FloatSlider.java deleted file mode 100644 index 19ae9db..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/FloatSlider.java +++ /dev/null @@ -1,48 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * A regular option factory. - * <p> - * This creates a regular option with a - * {@link dev.isxander.yacl3.api.controller.FloatSliderControllerBuilder} controller. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface FloatSlider { - /** - * The minimum value of the slider. - * <p> - * If the current value is at this minimum, if available, - * the translation key {@code yacl3.config.$configId.$fieldName.fmt.min} - * will be used. - */ - float min(); - - /** - * The maximum value of the slider. - * <p> - * If the current value is at this maximum, if available, - * the translation key {@code yacl3.config.$configId.$fieldName.fmt.max} - * will be used. - */ - float max(); - - /** - * The step size of this slider. - * For example, if this is set to 0.1, the slider will - * increment/decrement by 0.1 when dragging, no less, no more and - * will always be a multiple of 0.1. - */ - float step(); - - /** - * The format used to display the float. - * This is the syntax used in {@link String#format(String, Object...)}. - */ - String format() default "%.1f"; -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/FormatTranslation.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/FormatTranslation.java deleted file mode 100644 index 7cc4ded..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/FormatTranslation.java +++ /dev/null @@ -1,25 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Allows you to specify a custom value formatter - * in the form of a translation key. - * <p> - * Without this annotation, the value will be formatted - * according to the option factory, implementation details - * for that should be found in the javadoc for the factory. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface FormatTranslation { - /** - * The translation key for the value formatter. - * One parameter is passed to this key: the option's value, - * using {@link Object#toString()}. - */ - String value() default ""; -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/IntField.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/IntField.java deleted file mode 100644 index 9945d01..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/IntField.java +++ /dev/null @@ -1,41 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * A regular option factory. - * <p> - * This creates a regular option with a - * {@link dev.isxander.yacl3.api.controller.IntegerFieldControllerBuilder} controller. - * <p> - * If available, the translation key {@code yacl3.config.$configId.$fieldName.fmt.$value} - * is used where {@code $value} is the current value of the option, for example, {@code 5}. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface IntField { - /** - * The minimum value of the field. If a user enters a value less - * than this, it will be clamped to this value. - * <p> - * If this is set to {@code Integer.MIN_VALUE}, there will be no minimum. - */ - int min() default Integer.MIN_VALUE; - - /** - * The minimum value of the field. If a user enters a value more - * than this, it will be clamped to this value. - * <p> - * If this is set to {@code Integer.MAX_VALUE}, there will be no minimum. - */ - int max() default Integer.MAX_VALUE; - - /** - * The format used to display the integer. - * This is the syntax used in {@link String#format(String, Object...)}. - */ - String format() default "%.0f"; -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/IntSlider.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/IntSlider.java deleted file mode 100644 index 7fd2282..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/IntSlider.java +++ /dev/null @@ -1,35 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * A regular option factory. - * <p> - * This creates a regular option with a - * {@link dev.isxander.yacl3.api.controller.IntegerSliderControllerBuilder} controller. - * <p> - * If available, the translation key {@code yacl3.config.$configId.$fieldName.fmt.$value} - * is used where {@code $value} is the current value of the option, for example, {@code 5}. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface IntSlider { - /** - * The minimum value of the slider. - */ - int min(); - - /** - * The maximum value of the slider. - */ - int max(); - - /** - * The format used to display the integer. - * This is the syntax used in {@link String#format(String, Object...)}. - */ - int step(); -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/ItemField.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/ItemField.java deleted file mode 100644 index 84d2c7a..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/ItemField.java +++ /dev/null @@ -1,17 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * An option factory. - * <p> - * This creates a regular option with a - * {@link dev.isxander.yacl3.api.controller.ItemControllerBuilder} controller. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface ItemField { -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Label.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Label.java deleted file mode 100644 index 41e026f..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Label.java +++ /dev/null @@ -1,18 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * An option factory that creates an instance - * of a {@link dev.isxander.yacl3.api.LabelOption}. - * <p> - * The backing field can be private and final and - * must be of type {@link net.minecraft.network.chat.Component}. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface Label { -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/ListGroup.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/ListGroup.java deleted file mode 100644 index c664f71..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/ListGroup.java +++ /dev/null @@ -1,60 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.api.controller.ControllerBuilder; -import dev.isxander.yacl3.config.v2.api.ConfigField; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.List; - -/** - * An option factory. - * <p> - * This creates a List option with a custom controller. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface ListGroup { - /** - * The {@link Class} representing a class that implements {@link ValueFactory}. - * To create a new instance for the list when the user adds a new entry to the list. - * Remember this class can be shared with {@link ControllerFactory} as well. - */ - Class<? extends ValueFactory<?>> valueFactory(); - - /** - * The {@link Class} representing a class that implements {@link ControllerBuilder} - * to add a controller to every entry in the list. - * Remember this class can be shared with {@link ValueFactory} as well. - */ - Class<? extends ControllerFactory<?>> controllerFactory(); - - /** - * The maximum number of entries that can be added to the list. - * Once at this limit, the add button is disabled. - * If this is equal to {@code 0}, there is no limit. - */ - int maxEntries() default 0; - - /** - * The minimum number of entries that must be in the list. - * When at this limit, the remove button of the entries is disabled. - */ - int minEntries() default 0; - - /** - * Whether to add new entries at the bottom of the list rather than the top. - */ - boolean addEntriesToBottom() default false; - - interface ValueFactory<T> { - T provideNewValue(); - } - - interface ControllerFactory<T> { - ControllerBuilder<T> createController(ListGroup annotation, ConfigField<List<T>> field, OptionAccess storage, Option<T> option); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/LongField.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/LongField.java deleted file mode 100644 index 01c3a7e..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/LongField.java +++ /dev/null @@ -1,41 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * A regular option factory. - * <p> - * This creates a regular option with a - * {@link dev.isxander.yacl3.api.controller.LongFieldControllerBuilder} controller. - * <p> - * If available, the translation key {@code yacl3.config.$configId.$fieldName.fmt.$value} - * is used where {@code $value} is the current value of the option, for example, {@code 5}. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface LongField { - /** - * The minimum value of the field. If a user enters a value less - * than this, it will be clamped to this value. - * <p> - * If this is set to {@code Long.MIN_VALUE}, there will be no minimum. - */ - long min() default Long.MIN_VALUE; - - /** - * The maximum value of the field. If a user enters a value more - * than this, it will be clamped to this value. - * <p> - * If this is set to {@code Long.MAX_VALUE}, there will be no minimum. - */ - long max() default Long.MAX_VALUE; - - /** - * The format used to display the long. - * This is the syntax used in {@link String#format(String, Object...)}. - */ - String format() default "%.0f"; -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/LongSlider.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/LongSlider.java deleted file mode 100644 index 5563bd0..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/LongSlider.java +++ /dev/null @@ -1,35 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * A regular option factory. - * <p> - * This creates a regular option with a - * {@link dev.isxander.yacl3.api.controller.LongSliderControllerBuilder} controller. - * <p> - * If available, the translation key {@code yacl3.config.$configId.$fieldName.fmt.$value} - * is used where {@code $value} is the current value of the option, for example, {@code 5}. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface LongSlider { - /** - * The minimum value of the slider. - */ - long min(); - - /** - * The maximum value of the slider. - */ - long max(); - - /** - * The format used to display the integer. - * This is the syntax used in {@link String#format(String, Object...)}. - */ - long step(); -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/MasterTickBox.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/MasterTickBox.java deleted file mode 100644 index 70dee1a..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/MasterTickBox.java +++ /dev/null @@ -1,26 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * An option factory like {@link TickBox} but controls - * other options' availability based on its state. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface MasterTickBox { - /** - * The exact names of the fields with {@link AutoGen} annotation - * to control the availability of. - */ - String[] value(); - - /** - * Whether having the tickbox disabled should enable the options - * rather than disable. - */ - boolean invert() default false; -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OptionAccess.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OptionAccess.java deleted file mode 100644 index c55afe4..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OptionAccess.java +++ /dev/null @@ -1,35 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import dev.isxander.yacl3.api.Option; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Consumer; - -/** - * An accessor to all options that are auto-generated - * by the config system. - */ -public interface OptionAccess { - /** - * Gets an option by its field name. - * This could be null if the option hasn't been created yet. It is created - * in order of the fields in the class, so if you are trying to get an option - * lower-down in the class, this will return null. - * - * @param fieldName the exact, case-sensitive name of the field. - * @return the created option, or {@code null} if it hasn't been created yet. - */ - @Nullable Option<?> getOption(String fieldName); - - /** - * Schedules an operation to be performed on an option. - * If the option has already been created, the consumer will be - * accepted immediately upon calling this method, if not, it will - * be added to the queue of operations to be performed on the option - * once it does get created. - * - * @param fieldName the exact, case-sensitive name of the field. - * @param optionConsumer the operation to perform on the option. - */ - void scheduleOptionOperation(String fieldName, Consumer<Option<?>> optionConsumer); -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OptionFactory.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OptionFactory.java deleted file mode 100644 index 515a40b..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OptionFactory.java +++ /dev/null @@ -1,40 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.impl.autogen.OptionFactoryRegistry; - -import java.lang.annotation.Annotation; - -/** - * The backing builder for option factories' annotations. - * <p> - * If you want to make a basic option with a controller, it's recommended - * to use {@link SimpleOptionFactory} instead which is a subclass of this. - * - * @param <A> the annotation type - * @param <T> the option's binding type - */ -public interface OptionFactory<A extends Annotation, T> { - /** - * Creates an option from the given annotation, backing field, and storage. - * - * @param annotation the annotation that fields are annotated with to use this factory - * @param field the backing field - * @param optionAccess the option access to access other options in the GUI - * @return the built option to be added to the group/category - */ - Option<T> createOption(A annotation, ConfigField<T> field, OptionAccess optionAccess); - - /** - * Registers an option factory to be used by configs. - * - * @param annotationClass the class of the annotation to use a factory - * @param factory an instance of the factory - * @param <A> the type of the annotation - * @param <T> the type of the option's binding - */ - static <A extends Annotation, T> void register(Class<A> annotationClass, OptionFactory<A, T> factory) { - OptionFactoryRegistry.registerOptionFactory(annotationClass, factory); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/SimpleOptionFactory.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/SimpleOptionFactory.java deleted file mode 100644 index f7d807f..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/SimpleOptionFactory.java +++ /dev/null @@ -1,138 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.api.OptionDescription; -import dev.isxander.yacl3.api.OptionFlag; -import dev.isxander.yacl3.api.controller.ControllerBuilder; -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.impl.FieldBackedBinding; -import dev.isxander.yacl3.config.v2.impl.autogen.AutoGenUtils; -import dev.isxander.yacl3.config.v2.impl.autogen.EmptyCustomImageFactory; -import dev.isxander.yacl3.config.v2.impl.autogen.YACLAutoGenException; -import net.minecraft.client.Minecraft; -import net.minecraft.locale.Language; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.resources.ResourceLocation; -import org.jetbrains.annotations.Nullable; - -import java.lang.annotation.Annotation; -import java.util.Optional; -import java.util.Set; - -public abstract class SimpleOptionFactory<A extends Annotation, T> implements OptionFactory<A, T> { - @Override - public Option<T> createOption(A annotation, ConfigField<T> field, OptionAccess optionAccess) { - Option<T> option = Option.<T>createBuilder() - .name(this.name(annotation, field, optionAccess)) - .description(v -> this.description(v, annotation, field, optionAccess).build()) - .binding(new FieldBackedBinding<>(field.access(), field.defaultAccess())) - .controller(opt -> { - ControllerBuilder<T> builder = this.createController(annotation, field, optionAccess, opt); - - AutoGenUtils.addCustomFormatterToController(builder, field.access()); - - return builder; - }) - .available(this.available(annotation, field, optionAccess)) - .flags(this.flags(annotation, field, optionAccess)) - .listener((opt, v) -> this.listener(annotation, field, optionAccess, opt, v)) - .build(); - - postInit(annotation, field, optionAccess, option); - return option; - } - - protected abstract ControllerBuilder<T> createController(A annotation, ConfigField<T> field, OptionAccess storage, Option<T> option); - - protected MutableComponent name(A annotation, ConfigField<T> field, OptionAccess storage) { - Optional<CustomName> customName = field.access().getAnnotation(CustomName.class); - return Component.translatable(customName.map(CustomName::value).orElse(this.getTranslationKey(field, null))); - } - - protected OptionDescription.Builder description(T value, A annotation, ConfigField<T> field, OptionAccess storage) { - OptionDescription.Builder builder = OptionDescription.createBuilder(); - - String key = this.getTranslationKey(field, "desc"); - if (Language.getInstance().has(key)) { - builder.text(Component.translatable(key)); - } else { - key += "."; - int i = 1; - while (Language.getInstance().has(key + i)) { - builder.text(Component.translatable(key + i)); - i++; - } - } - - field.access().getAnnotation(CustomDescription.class).ifPresent(customDescription -> { - for (String line : customDescription.value()) { - builder.text(Component.translatable(line)); - } - }); - - Optional<CustomImage> imageOverrideOpt = field.access().getAnnotation(CustomImage.class); - if (imageOverrideOpt.isPresent()) { - CustomImage imageOverride = imageOverrideOpt.get(); - - if (!imageOverride.factory().equals(EmptyCustomImageFactory.class)) { - CustomImage.CustomImageFactory<T> imageFactory; - try { - imageFactory = (CustomImage.CustomImageFactory<T>) AutoGenUtils.constructNoArgsClass( - imageOverride.factory(), - () -> "'%s': The factory class on @OverrideImage has no no-args constructor.".formatted(field.access().name()), - () -> "'%s': Failed to instantiate factory class %s.".formatted(field.access().name(), imageOverride.factory().getName()) - ); - } catch (ClassCastException e) { - throw new YACLAutoGenException("'%s': The factory class on @OverrideImage is of incorrect type. Expected %s, got %s.".formatted(field.access().name(), field.access().type().getTypeName(), imageOverride.factory().getTypeParameters()[0].getName())); - } - - builder.customImage(imageFactory.createImage(value, field, storage).thenApply(Optional::of)); - } else if (!imageOverride.value().isEmpty()) { - String path = imageOverride.value(); - ResourceLocation imageLocation = new ResourceLocation(field.parent().id().getNamespace(), path); - String extension = path.substring(path.lastIndexOf('.') + 1); - - switch (extension) { - case "png", "jpg", "jpeg" -> builder.image(imageLocation, imageOverride.width(), imageOverride.height()); - case "webp" -> builder.webpImage(imageLocation); - case "gif" -> builder.gifImage(imageLocation); - default -> throw new YACLAutoGenException("'%s': Invalid image extension '%s' on @OverrideImage. Expected: ('png','jpg','webp','gif')".formatted(field.access().name(), extension)); - } - } else { - throw new YACLAutoGenException("'%s': @OverrideImage has no value or factory class.".formatted(field.access().name())); - } - } else { - String imagePath = "textures/yacl3/" + field.parent().id().getPath() + "/" + field.access().name() + ".webp"; - imagePath = imagePath.toLowerCase().replaceAll("[^a-z0-9/._:-]", "_"); - ResourceLocation imageLocation = new ResourceLocation(field.parent().id().getNamespace(), imagePath); - if (Minecraft.getInstance().getResourceManager().getResource(imageLocation).isPresent()) { - builder.webpImage(imageLocation); - } - } - - return builder; - } - - protected boolean available(A annotation, ConfigField<T> field, OptionAccess storage) { - return true; - } - - protected Set<OptionFlag> flags(A annotation, ConfigField<T> field, OptionAccess storage) { - return Set.of(); - } - - protected void listener(A annotation, ConfigField<T> field, OptionAccess storage, Option<T> option, T value) { - - } - - protected void postInit(A annotation, ConfigField<T> field, OptionAccess storage, Option<T> option) { - - } - - protected String getTranslationKey(ConfigField<T> field, @Nullable String suffix) { - String key = "yacl3.config.%s.%s".formatted(field.parent().id().toString(), field.access().name()); - if (suffix != null) key += "." + suffix; - return key; - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/StringField.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/StringField.java deleted file mode 100644 index 50d638e..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/StringField.java +++ /dev/null @@ -1,17 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * A regular option factory. - * <p> - * This creates a regular option with a - * {@link dev.isxander.yacl3.api.controller.StringControllerBuilder} controller. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface StringField { -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/TickBox.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/TickBox.java deleted file mode 100644 index 0a88c14..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/TickBox.java +++ /dev/null @@ -1,17 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.autogen; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * An option factory. - * <p> - * This creates a regular option with a - * {@link dev.isxander.yacl3.api.controller.TickBoxControllerBuilder} controller. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface TickBox { -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/serializer/GsonConfigSerializerBuilder.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/serializer/GsonConfigSerializerBuilder.java deleted file mode 100644 index 33003d7..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/serializer/GsonConfigSerializerBuilder.java +++ /dev/null @@ -1,98 +0,0 @@ -package dev.isxander.yacl3.config.v2.api.serializer; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import dev.isxander.yacl3.config.ConfigEntry; -import dev.isxander.yacl3.config.v2.api.ConfigClassHandler; -import dev.isxander.yacl3.config.v2.api.ConfigSerializer; -import dev.isxander.yacl3.config.v2.api.SerialEntry; -import dev.isxander.yacl3.config.v2.impl.serializer.GsonConfigSerializer; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.Style; - -import java.awt.*; -import java.nio.file.Path; -import java.util.function.UnaryOperator; - -/** - * Uses GSON to serialize and deserialize config data from JSON to a file. - * <p> - * Only fields annotated with {@link dev.isxander.yacl3.config.v2.api.SerialEntry} are included in the JSON. - * {@link Component}, {@link Style} and {@link Color} have default type adapters, so there is no need to provide them in your GSON instance. - * GSON is automatically configured to format fields as {@code lower_camel_case}. - * <p> - * Optionally, this can also be written under JSON5 spec, allowing comments. - * - * @param <T> config data type - */ -public interface GsonConfigSerializerBuilder<T> { - static <T> GsonConfigSerializerBuilder<T> create(ConfigClassHandler<T> config) { - return new GsonConfigSerializer.Builder<>(config); - } - - /** - * Sets the file path to save and load the config from. - */ - GsonConfigSerializerBuilder<T> setPath(Path path); - - /** - * Sets the GSON instance to use. Overrides all YACL defaults such as: - * <ul> - * <li>lower_camel_case field naming policy</li> - * <li>null serialization</li> - * <li>{@link Component}, {@link Style} and {@link Color} type adapters</li> - * </ul> - * Still respects the exclusion strategy to only serialize {@link ConfigEntry} - * but these can be added to with setExclusionStrategies. - * - * @param gsonBuilder gson builder to use - */ - GsonConfigSerializerBuilder<T> overrideGsonBuilder(GsonBuilder gsonBuilder); - - /** - * Sets the GSON instance to use. Overrides all YACL defaults such as: - * <ul> - * <li>lower_camel_case field naming policy</li> - * <li>null serialization</li> - * <li>{@link Component}, {@link Style} and {@link Color} type adapters</li> - * </ul> - * but these can be added to with setExclusionStrategies. - * - * @param gson gson instance to be converted to a builder - */ - GsonConfigSerializerBuilder<T> overrideGsonBuilder(Gson gson); - - /** - * Appends extra configuration to a GSON builder. - * This is the intended way to add functionality to the GSON instance. - * <p> - * By default, YACL sets the GSON with the following options: - * <ul> - * <li>lower_camel_case field naming policy</li> - * <li>null serialization</li> - * <li>{@link Component}, {@link Style} and {@link Color} type adapters</li> - * </ul> - * For example, if you wanted to revert YACL's lower_camel_case naming policy, - * you could do the following: - * <pre> - * {@code - * GsonConfigSerializerBuilder.create(config) - * .appendGsonBuilder(builder -> builder.setFieldNamingPolicy(FieldNamingPolicy.IDENTITY)) - * } - * </pre> - * - * @param gsonBuilder the function to apply to the builder - */ - GsonConfigSerializerBuilder<T> appendGsonBuilder(UnaryOperator<GsonBuilder> gsonBuilder); - - /** - * Writes the json under JSON5 spec, allowing the use of {@link SerialEntry#comment()}. - * If enabling this option it's recommended to use the file extension {@code .json5}. - * - * @param json5 whether to write under JSON5 spec - * @return this builder - */ - GsonConfigSerializerBuilder<T> setJson5(boolean json5); - - ConfigSerializer<T> build(); -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/ConfigClassHandlerImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/ConfigClassHandlerImpl.java deleted file mode 100644 index 813b3ab..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/ConfigClassHandlerImpl.java +++ /dev/null @@ -1,274 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl; - -import dev.isxander.yacl3.api.*; -import dev.isxander.yacl3.config.ConfigEntry; -import dev.isxander.yacl3.config.v2.api.*; -import dev.isxander.yacl3.config.v2.api.autogen.AutoGen; -import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; -import dev.isxander.yacl3.config.v2.impl.autogen.OptionFactoryRegistry; -import dev.isxander.yacl3.config.v2.impl.autogen.OptionAccessImpl; -import dev.isxander.yacl3.config.v2.impl.autogen.YACLAutoGenException; -import dev.isxander.yacl3.impl.utils.YACLConstants; -import dev.isxander.yacl3.platform.YACLPlatform; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; -import org.apache.commons.lang3.Validate; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.util.AbstractMap; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; - -public class ConfigClassHandlerImpl<T> implements ConfigClassHandler<T> { - private final Class<T> configClass; - private final ResourceLocation id; - private final boolean supportsAutoGen; - private final ConfigSerializer<T> serializer; - private final ConfigFieldImpl<?>[] fields; - - private T instance; - private final T defaults; - private final Constructor<T> noArgsConstructor; - - public ConfigClassHandlerImpl(Class<T> configClass, ResourceLocation id, Function<ConfigClassHandler<T>, ConfigSerializer<T>> serializerFactory) { - this.configClass = configClass; - this.id = id; - this.supportsAutoGen = id != null && YACLPlatform.getEnvironment().isClient(); - - try { - noArgsConstructor = configClass.getDeclaredConstructor(); - } catch (NoSuchMethodException e) { - throw new YACLAutoGenException("Failed to find no-args constructor for config class %s.".formatted(configClass.getName()), e); - } - this.instance = createNewObject(); - this.defaults = createNewObject(); - - detectOldAnnotation(configClass.getDeclaredFields()); - - this.fields = discoverFields(); - this.serializer = serializerFactory.apply(this); - } - - private ConfigFieldImpl<?>[] discoverFields() { - return Arrays.stream(configClass.getDeclaredFields()) - .peek(field -> field.setAccessible(true)) - .filter(field -> field.isAnnotationPresent(SerialEntry.class) || field.isAnnotationPresent(AutoGen.class)) - .map(field -> new ConfigFieldImpl<>( - new ReflectionFieldAccess<>(field, instance), - new ReflectionFieldAccess<>(field, defaults), - this, - field.getAnnotation(SerialEntry.class), - field.getAnnotation(AutoGen.class) - )) - .toArray(ConfigFieldImpl[]::new); - } - - @Override - public T instance() { - return this.instance; - } - - @Override - public T defaults() { - return this.defaults; - } - - @Override - public Class<T> configClass() { - return this.configClass; - } - - @Override - public ConfigFieldImpl<?>[] fields() { - return this.fields; - } - - @Override - public ResourceLocation id() { - return this.id; - } - - @Override - public boolean supportsAutoGen() { - return this.supportsAutoGen; - } - - @Override - public YetAnotherConfigLib generateGui() { - if (!supportsAutoGen()) { - throw new YACLAutoGenException("Auto GUI generation is not supported for this config class. You either need to enable it in the builder or you are attempting to create a GUI in a dedicated server environment."); - } - - boolean hasAutoGenFields = Arrays.stream(fields()).anyMatch(field -> field.autoGen().isPresent()); - - if (!hasAutoGenFields) { - throw new YACLAutoGenException("No fields in this config class are annotated with @AutoGen. You must annotate at least one field with @AutoGen to generate a GUI."); - } - - OptionAccessImpl storage = new OptionAccessImpl(); - Map<String, CategoryAndGroups> categories = new LinkedHashMap<>(); - for (ConfigField<?> configField : fields()) { - configField.autoGen().ifPresent(autoGen -> { - CategoryAndGroups groups = categories.computeIfAbsent( - autoGen.category(), - k -> new CategoryAndGroups( - ConfigCategory.createBuilder() - .name(Component.translatable("yacl3.config.%s.category.%s".formatted(id().toString(), k))), - new LinkedHashMap<>() - ) - ); - OptionAddable group = groups.groups().computeIfAbsent(autoGen.group().orElse(""), k -> { - if (k.isEmpty()) - return groups.category(); - return OptionGroup.createBuilder() - .name(Component.translatable("yacl3.config.%s.category.%s.group.%s".formatted(id().toString(), autoGen.category(), k))); - }); - - Option<?> option; - try { - option = createOption(configField, storage); - } catch (Exception e) { - throw new YACLAutoGenException("Failed to create option for field '%s'".formatted(configField.access().name()), e); - } - - storage.putOption(configField.access().name(), option); - group.option(option); - }); - } - storage.checkBadOperations(); - categories.values().forEach(CategoryAndGroups::finaliseGroups); - - YetAnotherConfigLib.Builder yaclBuilder = YetAnotherConfigLib.createBuilder() - .save(this.serializer()::save) - .title(Component.translatable("yacl3.config.%s.title".formatted(this.id().toString()))); - categories.values().forEach(category -> yaclBuilder.category(category.category().build())); - - return yaclBuilder.build(); - } - - private <U> Option<U> createOption(ConfigField<U> configField, OptionAccess storage) { - return OptionFactoryRegistry.createOption(((ReflectionFieldAccess<?>) configField.access()).field(), configField, storage) - .orElseThrow(() -> new YACLAutoGenException("Failed to create option for field %s".formatted(configField.access().name()))); - } - - @Override - public ConfigSerializer<T> serializer() { - return this.serializer; - } - - @Override - public boolean load() { - // create a new instance to load into - T newInstance = createNewObject(); - - // create field accesses for the new object - Map<ConfigFieldImpl<?>, ReflectionFieldAccess<?>> accessBufferImpl = Arrays.stream(fields()) - .map(field -> new AbstractMap.SimpleImmutableEntry<>( - field, - new ReflectionFieldAccess<>(field.access().field(), newInstance) - )) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - // convert the map into API safe field accesses - Map<ConfigField<?>, FieldAccess<?>> accessBuffer = accessBufferImpl.entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - - // attempt to load the config - ConfigSerializer.LoadResult loadResult = ConfigSerializer.LoadResult.FAILURE; - Throwable error = null; - try { - loadResult = this.serializer().loadSafely(accessBuffer); - } catch (Throwable e) { - // handle any errors later in the loadResult switch case - error = e; - } - - switch (loadResult) { - case DIRTY: - case SUCCESS: - // replace the instance with the newly created one - this.instance = newInstance; - for (ConfigFieldImpl<?> field : fields()) { - // update the field accesses to point to the correct object - ((ConfigFieldImpl<Object>) field).setFieldAccess((ReflectionFieldAccess<Object>) accessBufferImpl.get(field)); - } - - if (loadResult == ConfigSerializer.LoadResult.DIRTY) { - // if the load result is dirty, we need to save the config again - this.save(); - } - case NO_CHANGE: - return true; - case FAILURE: - YACLConstants.LOGGER.error( - "Unsuccessful load of config class '{}'. The load will be abandoned and config remains unchanged.", - configClass.getSimpleName(), error - ); - } - - return false; - } - - @Override - public void save() { - serializer().save(); - } - - private T createNewObject() { - try { - return noArgsConstructor.newInstance(); - } catch (Exception e) { - throw new YACLAutoGenException("Failed to create instance of config class '%s' with no-args constructor.".formatted(configClass.getName()), e); - } - } - - private void detectOldAnnotation(Field[] fields) { - boolean hasOldConfigEntry = Arrays.stream(fields) - .anyMatch(field -> field.isAnnotationPresent(ConfigEntry.class)); - - Validate.isTrue(!hasOldConfigEntry, "At least one field in %s is still annotated with the deprecated @ConfigEntry annotation. This is incorrect. Use @SerialEntry.".formatted(configClass.getName())); - } - - public static class BuilderImpl<T> implements Builder<T> { - private final Class<T> configClass; - private ResourceLocation id; - private Function<ConfigClassHandler<T>, ConfigSerializer<T>> serializerFactory; - - public BuilderImpl(Class<T> configClass) { - this.configClass = configClass; - } - - @Override - public Builder<T> id(ResourceLocation id) { - this.id = id; - return this; - } - - @Override - public Builder<T> serializer(Function<ConfigClassHandler<T>, ConfigSerializer<T>> serializerFactory) { - this.serializerFactory = serializerFactory; - return this; - } - - @Override - public ConfigClassHandler<T> build() { - Validate.notNull(serializerFactory, "serializerFactory must not be null"); - Validate.notNull(configClass, "configClass must not be null"); - - return new ConfigClassHandlerImpl<>(configClass, id, serializerFactory); - } - } - - private record CategoryAndGroups(ConfigCategory.Builder category, Map<String, OptionAddable> groups) { - private void finaliseGroups() { - groups.forEach((name, group) -> { - if (group instanceof OptionGroup.Builder groupBuilder) { - category.group(groupBuilder.build()); - } - }); - } - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/ConfigFieldImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/ConfigFieldImpl.java deleted file mode 100644 index aeed5ac..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/ConfigFieldImpl.java +++ /dev/null @@ -1,75 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl; - -import dev.isxander.yacl3.config.v2.api.*; -import dev.isxander.yacl3.config.v2.api.autogen.AutoGen; -import dev.isxander.yacl3.config.v2.api.autogen.AutoGenField; -import org.jetbrains.annotations.Nullable; - -import java.util.Optional; - -public class ConfigFieldImpl<T> implements ConfigField<T> { - private ReflectionFieldAccess<T> field; - private final ReflectionFieldAccess<T> defaultField; - private final ConfigClassHandler<?> parent; - private final Optional<SerialField> serial; - private final Optional<AutoGenField> autoGen; - - public ConfigFieldImpl(ReflectionFieldAccess<T> field, ReflectionFieldAccess<T> defaultField, ConfigClassHandler<?> parent, @Nullable SerialEntry config, @Nullable AutoGen autoGen) { - this.field = field; - this.defaultField = defaultField; - this.parent = parent; - - this.serial = config != null - ? Optional.of( - new SerialFieldImpl( - "".equals(config.value()) ? field.name() : config.value(), - "".equals(config.comment()) ? Optional.empty() : Optional.of(config.comment()), - config.required(), - config.nullable() - ) - ) - : Optional.empty(); - this.autoGen = autoGen != null - ? Optional.of( - new AutoGenFieldImpl<>( - autoGen.category(), - "".equals(autoGen.group()) ? Optional.empty() : Optional.of(autoGen.group()) - ) - ) - : Optional.empty(); - } - - @Override - public ReflectionFieldAccess<T> access() { - return field; - } - - public void setFieldAccess(ReflectionFieldAccess<T> field) { - this.field = field; - } - - @Override - public ReflectionFieldAccess<T> defaultAccess() { - return defaultField; - } - - @Override - public ConfigClassHandler<?> parent() { - return parent; - } - - @Override - public Optional<SerialField> serial() { - return this.serial; - } - - @Override - public Optional<AutoGenField> autoGen() { - return this.autoGen; - } - - private record SerialFieldImpl(String serialName, Optional<String> comment, boolean required, boolean nullable) implements SerialField { - } - private record AutoGenFieldImpl<T>(String category, Optional<String> group) implements AutoGenField { - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/FieldBackedBinding.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/FieldBackedBinding.java deleted file mode 100644 index f2f36e7..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/FieldBackedBinding.java +++ /dev/null @@ -1,22 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl; - -import dev.isxander.yacl3.api.Binding; -import dev.isxander.yacl3.config.v2.api.FieldAccess; -import dev.isxander.yacl3.config.v2.api.ReadOnlyFieldAccess; - -public record FieldBackedBinding<T>(FieldAccess<T> field, ReadOnlyFieldAccess<T> defaultField) implements Binding<T> { - @Override - public T getValue() { - return field.get(); - } - - @Override - public void setValue(T value) { - field.set(value); - } - - @Override - public T defaultValue() { - return defaultField.get(); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/ReflectionFieldAccess.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/ReflectionFieldAccess.java deleted file mode 100644 index e102344..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/ReflectionFieldAccess.java +++ /dev/null @@ -1,49 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl; - -import dev.isxander.yacl3.config.v2.api.FieldAccess; -import dev.isxander.yacl3.config.v2.impl.autogen.YACLAutoGenException; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.lang.reflect.Type; -import java.util.Optional; - -public record ReflectionFieldAccess<T>(Field field, Object instance) implements FieldAccess<T> { - @Override - public T get() { - try { - return (T) field.get(instance); - } catch (IllegalAccessException e) { - throw new YACLAutoGenException("Failed to access field '%s'".formatted(name()), e); - } - } - - @Override - public void set(T value) { - try { - field.set(instance, value); - } catch (IllegalAccessException e) { - throw new YACLAutoGenException("Failed to set field '%s'".formatted(name()), e); - } - } - - @Override - public String name() { - return field.getName(); - } - - @Override - public Type type() { - return field.getGenericType(); - } - - @Override - public Class<T> typeClass() { - return (Class<T>) field.getType(); - } - - @Override - public <A extends Annotation> Optional<A> getAnnotation(Class<A> annotationClass) { - return Optional.ofNullable(field.getAnnotation(annotationClass)); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/AutoGenUtils.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/AutoGenUtils.java deleted file mode 100644 index 6f614c1..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/AutoGenUtils.java +++ /dev/null @@ -1,54 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -import dev.isxander.yacl3.api.controller.ControllerBuilder; -import dev.isxander.yacl3.api.controller.ValueFormattableController; -import dev.isxander.yacl3.api.controller.ValueFormatter; -import dev.isxander.yacl3.config.v2.api.ReadOnlyFieldAccess; -import dev.isxander.yacl3.config.v2.api.autogen.CustomFormat; -import dev.isxander.yacl3.config.v2.api.autogen.FormatTranslation; -import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.ApiStatus; - -import java.util.Optional; -import java.util.function.Supplier; - -@ApiStatus.Internal -public final class AutoGenUtils { - public static <T> void addCustomFormatterToController(ControllerBuilder<T> controller, ReadOnlyFieldAccess<T> field) { - Optional<CustomFormat> formatter = field.getAnnotation(CustomFormat.class); - Optional<FormatTranslation> translation = field.getAnnotation(FormatTranslation.class); - - if (formatter.isPresent() && translation.isPresent()) { - throw new YACLAutoGenException("'%s': Cannot use both @CustomFormatter and @FormatTranslation on the same field.".formatted(field.name())); - } else if (formatter.isEmpty() && translation.isEmpty()) { - return; - } - - if (!(controller instanceof ValueFormattableController<?, ?>)) { - throw new YACLAutoGenException("Attempted to use @CustomFormatter or @FormatTranslation on an option factory for field '%s' that uses a controller that does not support this.".formatted(field.name())); - } - - ValueFormattableController<T, ?> typedBuilder = (ValueFormattableController<T, ?>) controller; - - formatter.ifPresent(formatterClass -> { - try { - typedBuilder.formatValue((ValueFormatter<T>) formatterClass.value().getConstructor().newInstance()); - } catch (Exception e) { - throw new YACLAutoGenException("'%s': Failed to instantiate formatter class %s.".formatted(field.name(), formatterClass.value().getName()), e); - } - }); - - translation.ifPresent(annotation -> - typedBuilder.formatValue(v -> Component.translatable(annotation.value(), v))); - } - - public static <T> T constructNoArgsClass(Class<T> clazz, Supplier<String> constructorNotFoundConsumer, Supplier<String> constructorFailedConsumer) { - try { - return clazz.getConstructor().newInstance(); - } catch (NoSuchMethodException e) { - throw new YACLAutoGenException(constructorNotFoundConsumer.get(), e); - } catch (Exception e) { - throw new YACLAutoGenException(constructorFailedConsumer.get(), e); - } - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/BooleanImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/BooleanImpl.java deleted file mode 100644 index b41836a..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/BooleanImpl.java +++ /dev/null @@ -1,25 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.api.controller.BooleanControllerBuilder; -import dev.isxander.yacl3.api.controller.ControllerBuilder; -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.api.autogen.SimpleOptionFactory; -import dev.isxander.yacl3.config.v2.api.autogen.Boolean; -import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; -import net.minecraft.network.chat.Component; - -public class BooleanImpl extends SimpleOptionFactory<Boolean, java.lang.Boolean> { - @Override - protected ControllerBuilder<java.lang.Boolean> createController(Boolean annotation, ConfigField<java.lang.Boolean> field, OptionAccess storage, Option<java.lang.Boolean> option) { - var builder = BooleanControllerBuilder.create(option) - .coloured(annotation.colored()); - switch (annotation.formatter()) { - case ON_OFF -> builder.onOffFormatter(); - case YES_NO -> builder.yesNoFormatter(); - case TRUE_FALSE -> builder.trueFalseFormatter(); - case CUSTOM -> builder.formatValue(v -> Component.translatable(getTranslationKey(field, "fmt." + v))); - } - return builder; - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/ColorFieldImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/ColorFieldImpl.java deleted file mode 100644 index 7910c59..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/ColorFieldImpl.java +++ /dev/null @@ -1,19 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.api.controller.ColorControllerBuilder; -import dev.isxander.yacl3.api.controller.ControllerBuilder; -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.api.autogen.SimpleOptionFactory; -import dev.isxander.yacl3.config.v2.api.autogen.ColorField; -import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; - -import java.awt.Color; - -public class ColorFieldImpl extends SimpleOptionFactory<ColorField, Color> { - @Override - protected ControllerBuilder<Color> createController(ColorField annotation, ConfigField<Color> field, OptionAccess storage, Option<Color> option) { - return ColorControllerBuilder.create(option) - .allowAlpha(annotation.allowAlpha()); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/DoubleFieldImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/DoubleFieldImpl.java deleted file mode 100644 index 6445141..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/DoubleFieldImpl.java +++ /dev/null @@ -1,32 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.api.controller.ControllerBuilder; -import dev.isxander.yacl3.api.controller.DoubleFieldControllerBuilder; -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.api.autogen.DoubleField; -import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; -import dev.isxander.yacl3.config.v2.api.autogen.SimpleOptionFactory; -import net.minecraft.locale.Language; -import net.minecraft.network.chat.Component; - -public class DoubleFieldImpl extends SimpleOptionFactory<DoubleField, Double> { - @Override - protected ControllerBuilder<Double> createController(DoubleField annotation, ConfigField<Double> field, OptionAccess storage, Option<Double> option) { - return DoubleFieldControllerBuilder.create(option) - .formatValue(v -> { - String key = null; - if (v == annotation.min()) - key = getTranslationKey(field, "fmt.min"); - else if (v == annotation.max()) - key = getTranslationKey(field, "fmt.max"); - if (key != null && Language.getInstance().has(key)) - return Component.translatable(key); - key = getTranslationKey(field, "fmt"); - if (Language.getInstance().has(key)) - return Component.translatable(key, v); - return Component.translatable(String.format(annotation.format(), v)); - }) - .range(annotation.min(), annotation.max()); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/DoubleSliderImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/DoubleSliderImpl.java deleted file mode 100644 index e6dd05d..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/DoubleSliderImpl.java +++ /dev/null @@ -1,33 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.api.controller.ControllerBuilder; -import dev.isxander.yacl3.api.controller.DoubleSliderControllerBuilder; -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.api.autogen.SimpleOptionFactory; -import dev.isxander.yacl3.config.v2.api.autogen.DoubleSlider; -import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; -import net.minecraft.locale.Language; -import net.minecraft.network.chat.Component; - -public class DoubleSliderImpl extends SimpleOptionFactory<DoubleSlider, Double> { - @Override - protected ControllerBuilder<Double> createController(DoubleSlider annotation, ConfigField<Double> field, OptionAccess storage, Option<Double> option) { - return DoubleSliderControllerBuilder.create(option) - .formatValue(v -> { - String key = null; - if (v == annotation.min()) - key = getTranslationKey(field, "fmt.min"); - else if (v == annotation.max()) - key = getTranslationKey(field, "fmt.max"); - if (key != null && Language.getInstance().has(key)) - return Component.translatable(key); - key = getTranslationKey(field, "fmt"); - if (Language.getInstance().has(key)) - return Component.translatable(key, v); - return Component.translatable(String.format(annotation.format(), v)); - }) - .range(annotation.min(), annotation.max()) - .step(annotation.step()); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/DropdownImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/DropdownImpl.java deleted file mode 100644 index c487aab..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/DropdownImpl.java +++ /dev/null @@ -1,19 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.api.controller.ControllerBuilder; -import dev.isxander.yacl3.api.controller.DropdownStringControllerBuilder; -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.api.autogen.Dropdown; -import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; -import dev.isxander.yacl3.config.v2.api.autogen.SimpleOptionFactory; - -public class DropdownImpl extends SimpleOptionFactory<Dropdown, String> { - @Override - protected ControllerBuilder<String> createController(Dropdown annotation, ConfigField<String> field, OptionAccess storage, Option<String> option) { - return DropdownStringControllerBuilder.create(option) - .values(annotation.values()) - .allowEmptyValue(annotation.allowEmptyValue()) - .allowAnyValue(annotation.allowAnyValue()); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/EmptyCustomImageFactory.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/EmptyCustomImageFactory.java deleted file mode 100644 index 1500864..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/EmptyCustomImageFactory.java +++ /dev/null @@ -1,17 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; -import dev.isxander.yacl3.config.v2.api.autogen.CustomImage; -import dev.isxander.yacl3.gui.image.ImageRenderer; - -import java.util.Optional; -import java.util.concurrent.CompletableFuture; - -public class EmptyCustomImageFactory implements CustomImage.CustomImageFactory<Object> { - - @Override - public CompletableFuture<ImageRenderer> createImage(Object value, ConfigField<Object> field, OptionAccess access) { - throw new IllegalStateException(); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/EnumCyclerImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/EnumCyclerImpl.java deleted file mode 100644 index f15d862..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/EnumCyclerImpl.java +++ /dev/null @@ -1,42 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -import dev.isxander.yacl3.api.NameableEnum; -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.api.controller.ControllerBuilder; -import dev.isxander.yacl3.api.controller.CyclingListControllerBuilder; -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.api.autogen.SimpleOptionFactory; -import dev.isxander.yacl3.config.v2.api.autogen.EnumCycler; -import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; -import net.minecraft.network.chat.Component; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.IntStream; - -public class EnumCyclerImpl extends SimpleOptionFactory<EnumCycler, Enum<?>> { - @Override - protected ControllerBuilder<Enum<?>> createController(EnumCycler annotation, ConfigField<Enum<?>> field, OptionAccess storage, Option<Enum<?>> option) { - List<? extends Enum<?>> values; - - if (option.pendingValue() instanceof EnumCycler.CyclableEnum<?> cyclableEnum) { - values = Arrays.asList(cyclableEnum.allowedValues()); - } else { - Enum<?>[] constants = field.access().typeClass().getEnumConstants(); - values = IntStream.range(0, constants.length) - .filter(ordinal -> annotation.allowedOrdinals().length == 0 || Arrays.stream(annotation.allowedOrdinals()).noneMatch(allowed -> allowed == ordinal)) - .mapToObj(ordinal -> constants[ordinal]) - .toList(); - } - - // EnumController doesn't support filtering - var builder = CyclingListControllerBuilder.create(option) - .values(values); - if (NameableEnum.class.isAssignableFrom(field.access().typeClass())) { - builder.formatValue(v -> ((NameableEnum) v).getDisplayName()); - } else { - builder.formatValue(v -> Component.translatable("yacl3.config.enum.%s.%s".formatted(field.access().typeClass().getSimpleName(), v.name().toLowerCase()))); - } - return builder; - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/FloatFieldImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/FloatFieldImpl.java deleted file mode 100644 index acdabd6..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/FloatFieldImpl.java +++ /dev/null @@ -1,32 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.api.controller.ControllerBuilder; -import dev.isxander.yacl3.api.controller.FloatFieldControllerBuilder; -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.api.autogen.FloatField; -import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; -import dev.isxander.yacl3.config.v2.api.autogen.SimpleOptionFactory; -import net.minecraft.locale.Language; -import net.minecraft.network.chat.Component; - -public class FloatFieldImpl extends SimpleOptionFactory<FloatField, Float> { - @Override - protected ControllerBuilder<Float> createController(FloatField annotation, ConfigField<Float> field, OptionAccess storage, Option<Float> option) { - return FloatFieldControllerBuilder.create(option) - .formatValue(v -> { - String key = null; - if (v == annotation.min()) - key = getTranslationKey(field, "fmt.min"); - else if (v == annotation.max()) - key = getTranslationKey(field, "fmt.max"); - if (key != null && Language.getInstance().has(key)) - return Component.translatable(key); - key = getTranslationKey(field, "fmt"); - if (Language.getInstance().has(key)) - return Component.translatable(key, v); - return Component.translatable(String.format(annotation.format(), v)); - }) - .range(annotation.min(), annotation.max()); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/FloatSliderImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/FloatSliderImpl.java deleted file mode 100644 index f22302f..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/FloatSliderImpl.java +++ /dev/null @@ -1,33 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.api.controller.ControllerBuilder; -import dev.isxander.yacl3.api.controller.FloatSliderControllerBuilder; -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.api.autogen.SimpleOptionFactory; -import dev.isxander.yacl3.config.v2.api.autogen.FloatSlider; -import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; -import net.minecraft.locale.Language; -import net.minecraft.network.chat.Component; - -public class FloatSliderImpl extends SimpleOptionFactory<FloatSlider, Float> { - @Override - protected ControllerBuilder<Float> createController(FloatSlider annotation, ConfigField<Float> field, OptionAccess storage, Option<Float> option) { - return FloatSliderControllerBuilder.create(option) - .formatValue(v -> { - String key = null; - if (v == annotation.min()) - key = getTranslationKey(field, "fmt.min"); - else if (v == annotation.max()) - key = getTranslationKey(field, "fmt.max"); - if (key != null && Language.getInstance().has(key)) - return Component.translatable(key); - key = getTranslationKey(field, "fmt"); - if (Language.getInstance().has(key)) - return Component.translatable(key, v); - return Component.translatable(String.format(annotation.format(), v)); - }) - .range(annotation.min(), annotation.max()) - .step(annotation.step()); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/IntFieldImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/IntFieldImpl.java deleted file mode 100644 index a3b759a..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/IntFieldImpl.java +++ /dev/null @@ -1,28 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.api.controller.ControllerBuilder; -import dev.isxander.yacl3.api.controller.IntegerFieldControllerBuilder; -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.api.autogen.IntField; -import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; -import dev.isxander.yacl3.config.v2.api.autogen.SimpleOptionFactory; -import net.minecraft.locale.Language; -import net.minecraft.network.chat.Component; - -public class IntFieldImpl extends SimpleOptionFactory<IntField, Integer> { - @Override - protected ControllerBuilder<Integer> createController(IntField annotation, ConfigField<Integer> field, OptionAccess storage, Option<Integer> option) { - return IntegerFieldControllerBuilder.create(option) - .formatValue(v -> { - String key = getTranslationKey(field, "fmt." + v); - if (Language.getInstance().has(key)) - return Component.translatable(key); - key = getTranslationKey(field, "fmt"); - if (Language.getInstance().has(key)) - return Component.translatable(key, v); - return Component.literal(Integer.toString(v)); - }) - .range(annotation.min(), annotation.max()); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/IntSliderImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/IntSliderImpl.java deleted file mode 100644 index b570b44..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/IntSliderImpl.java +++ /dev/null @@ -1,29 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.api.controller.ControllerBuilder; -import dev.isxander.yacl3.api.controller.IntegerSliderControllerBuilder; -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.api.autogen.SimpleOptionFactory; -import dev.isxander.yacl3.config.v2.api.autogen.IntSlider; -import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; -import net.minecraft.locale.Language; -import net.minecraft.network.chat.Component; - -public class IntSliderImpl extends SimpleOptionFactory<IntSlider, Integer> { - @Override - protected ControllerBuilder<Integer> createController(IntSlider annotation, ConfigField<Integer> field, OptionAccess storage, Option<Integer> option) { - return IntegerSliderControllerBuilder.create(option) - .formatValue(v -> { - String key = getTranslationKey(field, "fmt." + v); - if (Language.getInstance().has(key)) - return Component.translatable(key); - key = getTranslationKey(field, "fmt"); - if (Language.getInstance().has(key)) - return Component.translatable(key, v); - return Component.literal(Integer.toString(v)); - }) - .range(annotation.min(), annotation.max()) - .step(annotation.step()); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/ItemFieldImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/ItemFieldImpl.java deleted file mode 100644 index 2802f5c..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/ItemFieldImpl.java +++ /dev/null @@ -1,17 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.api.controller.ControllerBuilder; -import dev.isxander.yacl3.api.controller.ItemControllerBuilder; -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.api.autogen.ItemField; -import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; -import dev.isxander.yacl3.config.v2.api.autogen.SimpleOptionFactory; -import net.minecraft.world.item.Item; - -public class ItemFieldImpl extends SimpleOptionFactory<ItemField, Item> { - @Override - protected ControllerBuilder<Item> createController(ItemField annotation, ConfigField<Item> field, OptionAccess storage, Option<Item> option) { - return ItemControllerBuilder.create(option); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/LabelImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/LabelImpl.java deleted file mode 100644 index 6f9b368..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/LabelImpl.java +++ /dev/null @@ -1,16 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -import dev.isxander.yacl3.api.LabelOption; -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.api.autogen.OptionFactory; -import dev.isxander.yacl3.config.v2.api.autogen.Label; -import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; -import net.minecraft.network.chat.Component; - -public class LabelImpl implements OptionFactory<Label, Component> { - @Override - public Option<Component> createOption(Label annotation, ConfigField<Component> field, OptionAccess optionAccess) { - return LabelOption.create(field.access().get()); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/ListGroupImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/ListGroupImpl.java deleted file mode 100644 index f78d4ba..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/ListGroupImpl.java +++ /dev/null @@ -1,102 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -import dev.isxander.yacl3.api.ListOption; -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.api.OptionDescription; -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.api.autogen.ListGroup; -import dev.isxander.yacl3.config.v2.api.autogen.OptionFactory; -import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; -import dev.isxander.yacl3.config.v2.impl.FieldBackedBinding; -import net.minecraft.client.Minecraft; -import net.minecraft.locale.Language; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; -import org.jetbrains.annotations.Nullable; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.List; - -public class ListGroupImpl<T> implements OptionFactory<ListGroup, List<T>> { - @Override - public Option<List<T>> createOption(ListGroup annotation, ConfigField<List<T>> field, OptionAccess optionAccess) { - if (field.autoGen().orElseThrow().group().isPresent()) { - throw new YACLAutoGenException("@ListGroup fields ('%s') cannot be inside a group as lists act as groups.".formatted(field.access().name())); - } - - ListGroup.ValueFactory<T> valueFactory = createValueFactory((Class<? extends ListGroup.ValueFactory<T>>) annotation.valueFactory()); - ListGroup.ControllerFactory<T> controllerFactory = createControllerFactory((Class<? extends ListGroup.ControllerFactory<T>>) annotation.controllerFactory()); - - return ListOption.<T>createBuilder() - .name(Component.translatable(this.getTranslationKey(field, null))) - .description(this.description(field)) - .initial(valueFactory::provideNewValue) - .controller(opt -> controllerFactory.createController(annotation, field, optionAccess, opt)) - .binding(new FieldBackedBinding<>(field.access(), field.defaultAccess())) - .minimumNumberOfEntries(annotation.minEntries()) - .maximumNumberOfEntries(annotation.maxEntries() == 0 ? Integer.MAX_VALUE : annotation.maxEntries()) - .insertEntriesAtEnd(annotation.addEntriesToBottom()) - .build(); - } - - private OptionDescription description(ConfigField<List<T>> field) { - OptionDescription.Builder builder = OptionDescription.createBuilder(); - - String key = this.getTranslationKey(field, "desc"); - if (Language.getInstance().has(key)) { - builder.text(Component.translatable(key)); - } else { - key += "."; - int i = 0; - while (Language.getInstance().has(key + i++)) { - builder.text(Component.translatable(key + i)); - } - } - - String imagePath = "textures/yacl3/" + field.parent().id().getPath() + "/" + field.access().name() + ".webp"; - imagePath = imagePath.toLowerCase().replaceAll("[^a-z0-9/._:-]", "_"); - ResourceLocation imageLocation = new ResourceLocation(field.parent().id().getNamespace(), imagePath); - if (Minecraft.getInstance().getResourceManager().getResource(imageLocation).isPresent()) { - builder.webpImage(imageLocation); - } - - return builder.build(); - } - - private ListGroup.ValueFactory<T> createValueFactory(Class<? extends ListGroup.ValueFactory<T>> clazz) { - Constructor<? extends ListGroup.ValueFactory<T>> constructor; - try { - constructor = clazz.getConstructor(); - } catch (NoSuchMethodException e) { - throw new YACLAutoGenException("Could not find no-args constructor for `valueFactory` on '%s' for @ListGroup field.".formatted(clazz.getName()), e); - } - - try { - return constructor.newInstance(); - } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) { - throw new YACLAutoGenException("Couldn't invoke no-args constructor for `valueFactory` on '%s' for @ListGroup field.".formatted(clazz.getName()), e); - } - } - - private ListGroup.ControllerFactory<T> createControllerFactory(Class<? extends ListGroup.ControllerFactory<T>> clazz) { - Constructor<? extends ListGroup.ControllerFactory<T>> constructor; - try { - constructor = clazz.getConstructor(); - } catch (NoSuchMethodException e) { - throw new YACLAutoGenException("Could not find no-args constructor on `controllerFactory`, '%s' for @ListGroup field.".formatted(clazz.getName()), e); - } - - try { - return constructor.newInstance(); - } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) { - throw new YACLAutoGenException("Couldn't invoke no-args constructor on `controllerFactory`, '%s' for @ListGroup field.".formatted(clazz.getName()), e); - } - } - - private String getTranslationKey(ConfigField<List<T>> field, @Nullable String suffix) { - String key = "yacl3.config.%s.%s".formatted(field.parent().id().toString(), field.access().name()); - if (suffix != null) key += "." + suffix; - return key; - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/LongFieldImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/LongFieldImpl.java deleted file mode 100644 index 5da7d20..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/LongFieldImpl.java +++ /dev/null @@ -1,28 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.api.controller.ControllerBuilder; -import dev.isxander.yacl3.api.controller.LongFieldControllerBuilder; -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.api.autogen.LongField; -import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; -import dev.isxander.yacl3.config.v2.api.autogen.SimpleOptionFactory; -import net.minecraft.locale.Language; -import net.minecraft.network.chat.Component; - -public class LongFieldImpl extends SimpleOptionFactory<LongField, Long> { - @Override - protected ControllerBuilder<Long> createController(LongField annotation, ConfigField<Long> field, OptionAccess storage, Option<Long> option) { - return LongFieldControllerBuilder.create(option) - .formatValue(v -> { - String key = getTranslationKey(field, "fmt." + v); - if (Language.getInstance().has(key)) - return Component.translatable(key); - key = getTranslationKey(field, "fmt"); - if (Language.getInstance().has(key)) - return Component.translatable(key, v); - return Component.literal(Long.toString(v)); - }) - .range(annotation.min(), annotation.max()); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/LongSliderImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/LongSliderImpl.java deleted file mode 100644 index 95c5254..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/LongSliderImpl.java +++ /dev/null @@ -1,29 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.api.controller.ControllerBuilder; -import dev.isxander.yacl3.api.controller.LongSliderControllerBuilder; -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.api.autogen.LongSlider; -import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; -import dev.isxander.yacl3.config.v2.api.autogen.SimpleOptionFactory; -import net.minecraft.locale.Language; -import net.minecraft.network.chat.Component; - -public class LongSliderImpl extends SimpleOptionFactory<LongSlider, Long> { - @Override - protected ControllerBuilder<Long> createController(LongSlider annotation, ConfigField<Long> field, OptionAccess storage, Option<Long> option) { - return LongSliderControllerBuilder.create(option) - .formatValue(v -> { - String key = getTranslationKey(field, "fmt." + v); - if (Language.getInstance().has(key)) - return Component.translatable(key); - key = getTranslationKey(field, "fmt"); - if (Language.getInstance().has(key)) - return Component.translatable(key, v); - return Component.literal(Long.toString(v)); - }) - .range(annotation.min(), annotation.max()) - .step(annotation.step()); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/MasterTickBoxImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/MasterTickBoxImpl.java deleted file mode 100644 index 2d37f03..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/MasterTickBoxImpl.java +++ /dev/null @@ -1,25 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.api.controller.ControllerBuilder; -import dev.isxander.yacl3.api.controller.TickBoxControllerBuilder; -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.api.autogen.SimpleOptionFactory; -import dev.isxander.yacl3.config.v2.api.autogen.MasterTickBox; -import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; - -public class MasterTickBoxImpl extends SimpleOptionFactory<MasterTickBox, Boolean> { - @Override - protected ControllerBuilder<Boolean> createController(MasterTickBox annotation, ConfigField<Boolean> field, OptionAccess storage, Option<Boolean> option) { - return TickBoxControllerBuilder.create(option); - } - - @Override - protected void listener(MasterTickBox annotation, ConfigField<Boolean> field, OptionAccess storage, Option<Boolean> option, Boolean value) { - for (String child : annotation.value()) { - storage.scheduleOptionOperation(child, childOpt -> { - childOpt.setAvailable(annotation.invert() != value); - }); - } - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/OptionAccessImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/OptionAccessImpl.java deleted file mode 100644 index 579f776..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/OptionAccessImpl.java +++ /dev/null @@ -1,44 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; -import dev.isxander.yacl3.impl.utils.YACLConstants; -import org.jetbrains.annotations.Nullable; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Consumer; - -public class OptionAccessImpl implements OptionAccess { - private final Map<String, Option<?>> storage = new HashMap<>(); - private final Map<String, Consumer<Option<?>>> scheduledOperations = new HashMap<>(); - - @Override - public @Nullable Option<?> getOption(String fieldName) { - return storage.get(fieldName); - } - - @Override - public void scheduleOptionOperation(String fieldName, Consumer<Option<?>> optionConsumer) { - if (storage.containsKey(fieldName)) { - optionConsumer.accept(storage.get(fieldName)); - } else { - scheduledOperations.merge(fieldName, optionConsumer, Consumer::andThen); - } - } - - public void putOption(String fieldName, Option<?> option) { - storage.put(fieldName, option); - - Consumer<Option<?>> consumer = scheduledOperations.remove(fieldName); - if (consumer != null) { - consumer.accept(option); - } - } - - public void checkBadOperations() { - if (!scheduledOperations.isEmpty()) { - YACLConstants.LOGGER.warn("There are scheduled operations on the `OptionAccess` that tried to reference fields that do not exist. The following have been referenced that do not exist: " + String.join(", ", scheduledOperations.keySet())); - } - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/OptionFactoryRegistry.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/OptionFactoryRegistry.java deleted file mode 100644 index 4f6e3c7..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/OptionFactoryRegistry.java +++ /dev/null @@ -1,64 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.api.autogen.OptionFactory; -import dev.isxander.yacl3.config.v2.api.autogen.*; -import dev.isxander.yacl3.config.v2.api.autogen.Boolean; -import dev.isxander.yacl3.impl.utils.YACLConstants; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; - -public class OptionFactoryRegistry { - private static final Map<Class<?>, OptionFactory<?, ?>> factoryMap = new HashMap<>(); - - static { - registerOptionFactory(TickBox.class, new TickBoxImpl()); - registerOptionFactory(Boolean.class, new BooleanImpl()); - registerOptionFactory(IntSlider.class, new IntSliderImpl()); - registerOptionFactory(LongSlider.class, new LongSliderImpl()); - registerOptionFactory(FloatSlider.class, new FloatSliderImpl()); - registerOptionFactory(DoubleSlider.class, new DoubleSliderImpl()); - registerOptionFactory(IntField.class, new IntFieldImpl()); - registerOptionFactory(LongField.class, new LongFieldImpl()); - registerOptionFactory(FloatField.class, new FloatFieldImpl()); - registerOptionFactory(DoubleField.class, new DoubleFieldImpl()); - registerOptionFactory(EnumCycler.class, new EnumCyclerImpl()); - registerOptionFactory(StringField.class, new StringFieldImpl()); - registerOptionFactory(ColorField.class, new ColorFieldImpl()); - registerOptionFactory(Dropdown.class, new DropdownImpl()); - registerOptionFactory(ItemField.class, new ItemFieldImpl()); - registerOptionFactory(Label.class, new LabelImpl()); - registerOptionFactory(ListGroup.class, new ListGroupImpl<>()); - - registerOptionFactory(MasterTickBox.class, new MasterTickBoxImpl()); - } - - public static <A extends Annotation, T> void registerOptionFactory(Class<A> annotation, OptionFactory<A, T> factory) { - factoryMap.put(annotation, factory); - } - - public static <T> Optional<Option<T>> createOption(Field field, ConfigField<T> configField, OptionAccess storage) { - Annotation[] annotations = Arrays.stream(field.getAnnotations()) - .filter(annotation -> factoryMap.containsKey(annotation.annotationType())) - .toArray(Annotation[]::new); - - if (annotations.length != 1) { - YACLConstants.LOGGER.warn("Found {} option factory annotations on field {}, expected 1", annotations.length, field); - - if (annotations.length == 0) { - return Optional.empty(); - } - } - - Annotation annotation = annotations[0]; - // noinspection unchecked - OptionFactory<Annotation, T> factory = (OptionFactory<Annotation, T>) factoryMap.get(annotation.annotationType()); - return Optional.of(factory.createOption(annotation, configField, storage)); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/StringFieldImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/StringFieldImpl.java deleted file mode 100644 index 96b63a7..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/StringFieldImpl.java +++ /dev/null @@ -1,16 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.api.controller.ControllerBuilder; -import dev.isxander.yacl3.api.controller.StringControllerBuilder; -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.api.autogen.SimpleOptionFactory; -import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; -import dev.isxander.yacl3.config.v2.api.autogen.StringField; - -public class StringFieldImpl extends SimpleOptionFactory<StringField, String> { - @Override - protected ControllerBuilder<String> createController(StringField annotation, ConfigField<String> field, OptionAccess storage, Option<String> option) { - return StringControllerBuilder.create(option); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/TickBoxImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/TickBoxImpl.java deleted file mode 100644 index 050257c..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/TickBoxImpl.java +++ /dev/null @@ -1,16 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.api.controller.ControllerBuilder; -import dev.isxander.yacl3.api.controller.TickBoxControllerBuilder; -import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.api.autogen.SimpleOptionFactory; -import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; -import dev.isxander.yacl3.config.v2.api.autogen.TickBox; - -public class TickBoxImpl extends SimpleOptionFactory<TickBox, Boolean> { - @Override - protected ControllerBuilder<Boolean> createController(TickBox annotation, ConfigField<Boolean> field, OptionAccess storage, Option<Boolean> option) { - return TickBoxControllerBuilder.create(option); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/YACLAutoGenException.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/YACLAutoGenException.java deleted file mode 100644 index 68b375d..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/YACLAutoGenException.java +++ /dev/null @@ -1,11 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.autogen; - -public class YACLAutoGenException extends RuntimeException { - public YACLAutoGenException(String message) { - super(message); - } - - public YACLAutoGenException(String message, Throwable e) { - super(message, e); - } -} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/serializer/GsonConfigSerializer.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/serializer/GsonConfigSerializer.java deleted file mode 100644 index 8cd1ed4..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/serializer/GsonConfigSerializer.java +++ /dev/null @@ -1,269 +0,0 @@ -package dev.isxander.yacl3.config.v2.impl.serializer; - -import com.google.gson.*; -import com.mojang.serialization.JsonOps; -import dev.isxander.yacl3.config.GsonConfigInstance; -import dev.isxander.yacl3.config.v2.api.*; -import dev.isxander.yacl3.config.v2.api.serializer.GsonConfigSerializerBuilder; -import dev.isxander.yacl3.gui.utils.ItemRegistryHelper; -import dev.isxander.yacl3.impl.utils.YACLConstants; -import dev.isxander.yacl3.platform.YACLPlatform; -import net.minecraft.commands.ParserUtils; -import net.minecraft.core.RegistryAccess; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.Style; -import net.minecraft.world.item.Item; -import org.jetbrains.annotations.ApiStatus; -import org.quiltmc.parsers.json.JsonReader; -import org.quiltmc.parsers.json.JsonWriter; -import org.quiltmc.parsers.json.gson.GsonReader; -import org.quiltmc.parsers.json.gson.GsonWriter; - -import java.awt.*; -import java.io.IOException; -import java.io.StringWriter; -import java.lang.reflect.Type; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import java.util.Arrays; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.function.UnaryOperator; -import java.util.stream.Collectors; - -public class GsonConfigSerializer<T> extends ConfigSerializer<T> { - private final Gson gson; - private final Path path; - private final boolean json5; - - private GsonConfigSerializer(ConfigClassHandler<T> config, Path path, Gson gson, boolean json5) { - super(config); - this.gson = gson; - this.path = path; - this.json5 = json5; - } - - @Override - public void save() { - YACLConstants.LOGGER.info("Serializing {} to '{}'", config.configClass(), path); - - try (StringWriter stringWriter = new StringWriter()) { - JsonWriter jsonWriter = json5 ? JsonWriter.json5(stringWriter) : JsonWriter.json(stringWriter); - GsonWriter gsonWriter = new GsonWriter(jsonWriter); - - jsonWriter.beginObject(); - - for (ConfigField<?> field : config.fields()) { - SerialField serial = field.serial().orElse(null); - if (serial == null) continue; - - if (!json5 && serial.comment().isPresent() && YACLPlatform.isDevelopmentEnv()) { - YACLConstants.LOGGER.warn("Found comment in config field '{}', but json5 is not enabled. Enable it with `.setJson5(true)` on the `GsonConfigSerializerBuilder`. Comments will not be serialized. This warning is only visible in development environments.", serial.serialName()); - } - jsonWriter.comment(serial.comment().orElse(null)); - - jsonWriter.name(serial.serialName()); - - JsonElement element; - try { - element = gson.toJsonTree(field.access().get(), field.access().type()); - } catch (Exception e) { - YACLConstants.LOGGER.error("Failed to serialize config field '{}'. Serializing as null.", serial.serialName(), e); - jsonWriter.nullValue(); - continue; - } - - try { - gson.toJson(element, gsonWriter); - } catch (Exception e) { - YACLConstants.LOGGER.error("Failed to serialize config field '{}'. Due to the error state this JSON writer cannot continue safely and the save will be abandoned.", serial.serialName(), e); - return; - } - } - - jsonWriter.endObject(); - jsonWriter.flush(); - - Files.createDirectories(path.getParent()); - Files.writeString(path, stringWriter.toString(), StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE); - } catch (IOException e) { - YACLConstants.LOGGER.error("Failed to serialize config class '{}'.", config.configClass().getSimpleName(), e); - } - } - - @Override - public LoadResult loadSafely(Map<ConfigField<?>, FieldAccess<?>> bufferAccessMap) { - if (!Files.exists(path)) { - YACLConstants.LOGGER.info("Config file '{}' does not exist. Creating it with default values.", path); - save(); - return LoadResult.NO_CHANGE; - } - - YACLConstants.LOGGER.info("Deserializing {} from '{}'", config.configClass().getSimpleName(), path); - - Map<String, ConfigField<?>> fieldMap = Arrays.stream(config.fields()) - .filter(field -> field.serial().isPresent()) - .collect(Collectors.toMap(f -> f.serial().orElseThrow().serialName(), Function.identity())); - Set<String> missingFields = fieldMap.keySet(); - boolean dirty = false; - - try (JsonReader jsonReader = json5 ? JsonReader.json5(path) : JsonReader.json(path)) { - GsonReader gsonReader = new GsonReader(jsonReader); - - jsonReader.beginObject(); - - while (jsonReader.hasNext()) { - String name = jsonReader.nextName(); - ConfigField<?> field = fieldMap.get(name); - missingFields.remove(name); - - if (field == null) { - YACLConstants.LOGGER.warn("Found unknown config field '{}'.", name); - jsonReader.skipValue(); - continue; - } - - FieldAccess<?> bufferAccess = bufferAccessMap.get(field); - SerialField serial = field.serial().orElse(null); - if (serial == null) continue; - - JsonElement element; - try { - element = gson.fromJson(gsonReader, JsonElement.class); - } catch (Exception e) { - YACLConstants.LOGGER.error("Failed to deserialize config field '{}'. Due to the error state this JSON reader cannot be re-used and loading will be aborted.", name, e); - return LoadResult.FAILURE; - } - - if (element.isJsonNull() && !serial.nullable()) { - YACLConstants.LOGGER.warn("Found null value in non-nullable config field '{}'. Leaving field as default and marking as dirty.", name); - dirty = true; - continue; - } - - try { - bufferAccess.set(gson.fromJson(element, bufferAccess.type())); - } catch (Exception e) { - YACLConstants.LOGGER.error("Failed to deserialize config field '{}'. Leaving as default.", name, e); - } - } - - jsonReader.endObject(); - } catch (IOException e) { - YACLConstants.LOGGER.error("Failed to deserialize config class.", e); - return LoadResult.FAILURE; - } - - if (!missingFields.isEmpty()) { - for (String missingField : missingFields) { - if (fieldMap.get(missingField).serial().orElseThrow().required()) { - dirty = true; - YACLConstants.LOGGER.warn("Missing required config field '{}''. Re-saving as default.", missingField); - } - } - } - - return dirty ? LoadResult.DIRTY : LoadResult.SUCCESS; - } - - @Override - @Deprecated - @SuppressWarnings("deprecation") - public void load() { - YACLConstants.LOGGER.warn("Calling ConfigSerializer#load() directly is deprecated. Please use ConfigClassHandler#load() instead."); - config.load(); - } - - public static class StyleTypeAdapter implements JsonSerializer<Style>, JsonDeserializer<Style> { - @Override - public Style deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { - return Style.Serializer.CODEC.parse(JsonOps.INSTANCE, json).result().orElse(Style.EMPTY); - } - - @Override - public JsonElement serialize(Style src, Type typeOfSrc, JsonSerializationContext context) { - return Style.Serializer.CODEC.encodeStart(JsonOps.INSTANCE, src).result().orElse(JsonNull.INSTANCE); - } - } - - public static class ColorTypeAdapter implements JsonSerializer<Color>, JsonDeserializer<Color> { - @Override - public Color deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { - return new Color(jsonElement.getAsInt(), true); - } - - @Override - public JsonElement serialize(Color color, Type type, JsonSerializationContext jsonSerializationContext) { - return new JsonPrimitive(color.getRGB()); - } - } - - public static class ItemTypeAdapter implements JsonSerializer<Item>, JsonDeserializer<Item> { - @Override - public Item deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { - return ItemRegistryHelper.getItemFromName(jsonElement.getAsString()); - } - - @Override - public JsonElement serialize(Item item, Type type, JsonSerializationContext jsonSerializationContext) { - return new JsonPrimitive(BuiltInRegistries.ITEM.getKey(item).toString()); - } - } - - @ApiStatus.Internal - public static class Builder<T> implements GsonConfigSerializerBuilder<T> { - private final ConfigClassHandler<T> config; - private Path path; - private boolean json5; - private UnaryOperator<GsonBuilder> gsonBuilder = builder -> builder - .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) - .serializeNulls() - .registerTypeHierarchyAdapter(Component.class, new Component.SerializerAdapter(RegistryAccess.EMPTY)) - .registerTypeHierarchyAdapter(Style.class, new StyleTypeAdapter()) - .registerTypeHierarchyAdapter(Color.class, new ColorTypeAdapter()) - .registerTypeHierarchyAdapter(Item.class, new ItemTypeAdapter()) - .setPrettyPrinting(); - - public Builder(ConfigClassHandler<T> config) { - this.config = config; - } - - @Override - public Builder<T> setPath(Path path) { - this.path = path; - return this; - } - - @Override - public Builder<T> overrideGsonBuilder(GsonBuilder gsonBuilder) { - this.gsonBuilder = builder -> gsonBuilder; - return this; - } - - @Override - public Builder<T> overrideGsonBuilder(Gson gson) { - return this.overrideGsonBuilder(gson.newBuilder()); - } - - @Override - public Builder<T> appendGsonBuilder(UnaryOperator<GsonBuilder> gsonBuilder) { - UnaryOperator<GsonBuilder> prev = this.gsonBuilder; - this.gsonBuilder = builder -> gsonBuilder.apply(prev.apply(builder)); - return this; - } - - @Override - public Builder<T> setJson5(boolean json5) { - this.json5 = json5; - return this; - } - - @Override - public GsonConfigSerializer<T> build() { - return new GsonConfigSerializer<>(config, path, gsonBuilder.apply(new GsonBuilder()).create(), json5); - } - } -} |