diff options
| author | isxander <xander@isxander.dev> | 2024-04-11 18:43:06 +0100 |
|---|---|---|
| committer | isxander <xander@isxander.dev> | 2024-04-11 18:43:06 +0100 |
| commit | 04fe933f4c24817100f3101f088accf55a621f8a (patch) | |
| tree | feff94ca3ab4484160e69a24f4ee38522381950e /src/main/java/dev/isxander/yacl3/config/v2 | |
| parent | 831b894fdb7fe3e173d81387c8f6a2402b8ccfa9 (diff) | |
| download | YetAnotherConfigLib-04fe933f4c24817100f3101f088accf55a621f8a.tar.gz YetAnotherConfigLib-04fe933f4c24817100f3101f088accf55a621f8a.tar.bz2 YetAnotherConfigLib-04fe933f4c24817100f3101f088accf55a621f8a.zip | |
Extremely fragile and broken multiversion build with stonecutter
Diffstat (limited to 'src/main/java/dev/isxander/yacl3/config/v2')
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 |
