aboutsummaryrefslogtreecommitdiff
path: root/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 /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 'src/main/java/dev/isxander/yacl3/config')
-rw-r--r--src/main/java/dev/isxander/yacl3/config/ConfigEntry.java15
-rw-r--r--src/main/java/dev/isxander/yacl3/config/ConfigInstance.java50
-rw-r--r--src/main/java/dev/isxander/yacl3/config/GsonConfigInstance.java259
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/ConfigClassHandler.java107
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/ConfigField.java40
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/ConfigSerializer.java64
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/FieldAccess.java14
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/ReadOnlyFieldAccess.java36
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/SerialEntry.java39
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/SerialField.java16
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/AutoGen.java32
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/AutoGenField.java12
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Boolean.java41
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/ColorField.java21
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/CustomDescription.java12
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/CustomFormat.java17
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/CustomImage.java69
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/CustomName.java18
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/DoubleField.java46
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/DoubleSlider.java48
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Dropdown.java43
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/EnumCycler.java35
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/FloatField.java46
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/FloatSlider.java48
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/FormatTranslation.java25
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/IntField.java41
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/IntSlider.java35
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/ItemField.java17
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Label.java18
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/ListGroup.java60
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/LongField.java41
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/LongSlider.java35
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/MasterTickBox.java26
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OptionAccess.java35
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OptionFactory.java40
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/SimpleOptionFactory.java138
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/StringField.java17
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/autogen/TickBox.java17
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/api/serializer/GsonConfigSerializerBuilder.java98
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/ConfigClassHandlerImpl.java274
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/ConfigFieldImpl.java75
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/FieldBackedBinding.java22
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/ReflectionFieldAccess.java49
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/AutoGenUtils.java54
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/BooleanImpl.java25
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/ColorFieldImpl.java19
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/DoubleFieldImpl.java32
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/DoubleSliderImpl.java33
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/DropdownImpl.java19
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/EmptyCustomImageFactory.java17
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/EnumCyclerImpl.java42
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/FloatFieldImpl.java32
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/FloatSliderImpl.java33
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/IntFieldImpl.java28
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/IntSliderImpl.java29
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/ItemFieldImpl.java17
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/LabelImpl.java16
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/ListGroupImpl.java102
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/LongFieldImpl.java28
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/LongSliderImpl.java29
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/MasterTickBoxImpl.java25
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/OptionAccessImpl.java44
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/OptionFactoryRegistry.java64
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/StringFieldImpl.java16
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/TickBoxImpl.java16
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/YACLAutoGenException.java11
-rw-r--r--src/main/java/dev/isxander/yacl3/config/v2/impl/serializer/GsonConfigSerializer.java275
67 files changed, 3197 insertions, 0 deletions
diff --git a/src/main/java/dev/isxander/yacl3/config/ConfigEntry.java b/src/main/java/dev/isxander/yacl3/config/ConfigEntry.java
new file mode 100644
index 0000000..066cf42
--- /dev/null
+++ b/src/main/java/dev/isxander/yacl3/config/ConfigEntry.java
@@ -0,0 +1,15 @@
+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/src/main/java/dev/isxander/yacl3/config/ConfigInstance.java b/src/main/java/dev/isxander/yacl3/config/ConfigInstance.java
new file mode 100644
index 0000000..31d4ca2
--- /dev/null
+++ b/src/main/java/dev/isxander/yacl3/config/ConfigInstance.java
@@ -0,0 +1,50 @@
+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/src/main/java/dev/isxander/yacl3/config/GsonConfigInstance.java b/src/main/java/dev/isxander/yacl3/config/GsonConfigInstance.java
new file mode 100644
index 0000000..c47afe2
--- /dev/null
+++ b/src/main/java/dev/isxander/yacl3/config/GsonConfigInstance.java
@@ -0,0 +1,259 @@
+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())
+ /*? if >1.20.4 { *//*
+ .registerTypeHierarchyAdapter(Component.class, new Component.SerializerAdapter(RegistryAccess.EMPTY))
+ *//*? } elif =1.20.4 {*/
+ .registerTypeHierarchyAdapter(Component.class, new Component.SerializerAdapter())
+ /*? } else {*//*
+ .registerTypeHierarchyAdapter(Component.class, new Component.Serializer())
+ *//*?}*/
+ .registerTypeHierarchyAdapter(Style.class, /*? if >=1.20.4 {*/new GsonConfigSerializer.StyleTypeAdapter()/*?} else {*//*new Style.Serializer()*//*?}*/)
+ .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()
+ /*? if >1.20.4 { *//*
+ .registerTypeHierarchyAdapter(Component.class, new Component.SerializerAdapter(RegistryAccess.EMPTY))
+ *//*? } elif =1.20.4 {*/
+ .registerTypeHierarchyAdapter(Component.class, new Component.SerializerAdapter())
+ /*? } else {*//*
+ .registerTypeHierarchyAdapter(Component.class, new Component.Serializer())
+ *//*?}*/
+ .registerTypeHierarchyAdapter(Style.class, /*? if >=1.20.4 {*/new GsonConfigSerializer.StyleTypeAdapter()/*?} else {*//*new Style.Serializer()*//*?}*/)
+ .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/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigClassHandler.java b/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigClassHandler.java
new file mode 100644
index 0000000..d94280f
--- /dev/null
+++ b/