aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/dev/isxander/yacl3/config/v2
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/v2
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/v2')
-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
64 files changed, 2873 insertions, 0 deletions
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/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigClassHandler.java
@@ -0,0 +1,107 @@
+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/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigField.java b/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigField.java
new file mode 100644
index 0000000..181a4d4
--- /dev/null
+++ b/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigField.java
@@ -0,0 +1,40 @@
+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/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigSerializer.java b/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigSerializer.java
new file mode 100644
index 0000000..4ac988c
--- /dev/null
+++ b/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigSerializer.java
@@ -0,0 +1,64 @@
+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/src/main/java/dev/isxander/yacl3/config/v2/api/FieldAccess.java b/src/main/java/dev/isxander/yacl3/config/v2/api/FieldAccess.java
new file mode 100644
index 0000000..ea30cd8
--- /dev/null
+++ b/src/main/java/dev/isxander/yacl3/config/v2/api/FieldAccess.java
@@ -0,0 +1,14 @@
+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/src/main/java/dev/isxander/yacl3/config/v2/api/ReadOnlyFieldAccess.java b/src/main/java/dev/isxander/yacl3/config/v2/api/ReadOnlyFieldAccess.java
new file mode 100644
index 0000000..566d60d
--- /dev/null
+++ b/src/main/java/dev/isxander/yacl3/config/v2/api/ReadOnlyFieldAccess.java
@@ -0,0 +1,36 @@
+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/src/main/java/dev/isxander/yacl3/config/v2/api/SerialEntry.java b/src/main/java/dev/isxander/yacl3/config/v2/api/SerialEntry.java
new file mode 100644
index 0000000..94bf785
--- /dev/null
+++ b/src/main/java/dev/isxander/yacl3/config/v2/api/SerialEntry.java
@@ -0,0 +1,39 @@
+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/src/main/java/dev/isxander/yacl3/config/v2/api/SerialField.java b/src/main/java/dev/isxander/yacl3/config/v2/api/SerialField.java
new file mode 100644
index 0000000..cf6abfc
--- /dev/null
+++ b/src/main/java/dev/isxander/yacl3/config/v2/api/SerialField.java
@@ -0,0 +1,16 @@
+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/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/AutoGen.java b/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/AutoGen.java
new file mode 100644
index 0000000..4187caf
--- /dev/null
+++ b/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/AutoGen.java
@@ -0,0 +1,32 @@
+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/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/AutoGenField.java b/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/AutoGenField.java
new file mode 100644
index 0000000..7f751fb
--- /dev/null
+++ b/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/AutoGenField.java
@@ -0,0 +1,12 @@
+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/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Boolean.java b/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Boolean.java
new file mode 100644
index 0000000..5598389
--- /dev/null
+++ b/src/main/java/d