aboutsummaryrefslogtreecommitdiff
path: root/common/src/main/java/dev/isxander/yacl3/config
diff options
context:
space:
mode:
authorisxander <xander@isxander.dev>2024-04-11 18:43:06 +0100
committerisxander <xander@isxander.dev>2024-04-11 18:43:06 +0100
commit04fe933f4c24817100f3101f088accf55a621f8a (patch)
treefeff94ca3ab4484160e69a24f4ee38522381950e /common/src/main/java/dev/isxander/yacl3/config
parent831b894fdb7fe3e173d81387c8f6a2402b8ccfa9 (diff)
downloadYetAnotherConfigLib-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')
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/ConfigEntry.java15
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/ConfigInstance.java50
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/GsonConfigInstance.java247
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigClassHandler.java107
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigField.java40
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigSerializer.java64
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/FieldAccess.java14
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/ReadOnlyFieldAccess.java36
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/SerialEntry.java39
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/SerialField.java16
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/AutoGen.java32
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/AutoGenField.java12
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Boolean.java41
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/ColorField.java21
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/CustomDescription.java12
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/CustomFormat.java17
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/CustomImage.java69
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/CustomName.java18
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/DoubleField.java46
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/DoubleSlider.java48
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Dropdown.java43
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/EnumCycler.java35
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/FloatField.java46
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/FloatSlider.java48
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/FormatTranslation.java25
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/IntField.java41
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/IntSlider.java35
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/ItemField.java17
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Label.java18
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/ListGroup.java60
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/LongField.java41
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/LongSlider.java35
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/MasterTickBox.java26
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OptionAccess.java35
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OptionFactory.java40
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/SimpleOptionFactory.java138
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/StringField.java17
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/TickBox.java17
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/serializer/GsonConfigSerializerBuilder.java98
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/ConfigClassHandlerImpl.java274
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/ConfigFieldImpl.java75
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/FieldBackedBinding.java22
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/ReflectionFieldAccess.java49
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/AutoGenUtils.java54
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/BooleanImpl.java25
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/ColorFieldImpl.java19
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/DoubleFieldImpl.java32
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/DoubleSliderImpl.java33
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/DropdownImpl.java19
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/EmptyCustomImageFactory.java17
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/EnumCyclerImpl.java42
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/FloatFieldImpl.java32
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/FloatSliderImpl.java33
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/IntFieldImpl.java28
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/IntSliderImpl.java29
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/ItemFieldImpl.java17
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/LabelImpl.java16
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/ListGroupImpl.java102
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/LongFieldImpl.java28
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/LongSliderImpl.java29
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/MasterTickBoxImpl.java25
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/OptionAccessImpl.java44
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/OptionFactoryRegistry.java64
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/StringFieldImpl.java16
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/TickBoxImpl.java16
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/YACLAutoGenException.java11
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/serializer/GsonConfigSerializer.java269
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);
- }
- }
-}