diff options
author | isXander <xander@isxander.dev> | 2023-08-15 16:13:54 +0100 |
---|---|---|
committer | isXander <xander@isxander.dev> | 2023-08-15 16:13:54 +0100 |
commit | 9f72a09a5b2afc99b08a79bda84f91ef51c0f4d0 (patch) | |
tree | 56c7214bf95fa50e2469762b972cb6163f5f1b14 | |
parent | 3e30af10ab48aa64fa659834a863a4e3067d5542 (diff) | |
download | YetAnotherConfigLib-9f72a09a5b2afc99b08a79bda84f91ef51c0f4d0.tar.gz YetAnotherConfigLib-9f72a09a5b2afc99b08a79bda84f91ef51c0f4d0.tar.bz2 YetAnotherConfigLib-9f72a09a5b2afc99b08a79bda84f91ef51c0f4d0.zip |
Add javadoc to config api v2
55 files changed, 664 insertions, 117 deletions
diff --git a/common/src/main/java/dev/isxander/yacl3/api/YetAnotherConfigLib.java b/common/src/main/java/dev/isxander/yacl3/api/YetAnotherConfigLib.java index 5213e90..76f1ed7 100644 --- a/common/src/main/java/dev/isxander/yacl3/api/YetAnotherConfigLib.java +++ b/common/src/main/java/dev/isxander/yacl3/api/YetAnotherConfigLib.java @@ -53,7 +53,7 @@ public interface YetAnotherConfigLib { } static <T> YetAnotherConfigLib create(ConfigClassHandler<T> configHandler, ConfigBackedBuilder<T> builder) { - return builder.build(configHandler.defaults(), configHandler.instance(), createBuilder().save(configHandler.serializer()::serialize)).build(); + return builder.build(configHandler.defaults(), configHandler.instance(), createBuilder().save(configHandler.serializer()::save)).build(); } /** 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 index 645a8e8..470eba0 100644 --- 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 @@ -6,34 +6,88 @@ 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(); + /** + * The serializer for this config class. + * Manages saving and loading of the config with fields + * annotated with {@link SerialEntry}. + */ 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); - Builder<T> autoGen(boolean autoGen); - 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 index 1cd8739..181a4d4 100644 --- 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 @@ -4,14 +4,37 @@ 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(); - Optional<AutoGenField<T>> autoGen(); + /** + * 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 index 999221d..13d6e08 100644 --- 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 @@ -1,5 +1,10 @@ package dev.isxander.yacl3.config.v2.api; +/** + * The base class for config serializers, + * offering a method to save and load. + * @param <T> + */ public abstract class ConfigSerializer<T> { protected final ConfigClassHandler<T> config; @@ -7,7 +12,15 @@ public abstract class ConfigSerializer<T> { this.config = config; } - public abstract void serialize(); + /** + * 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(); - public abstract void deserialize(); + /** + * Loads all fields in the config class. + */ + public abstract void load(); } 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 index a961172..ea30cd8 100644 --- 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 @@ -1,5 +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/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 index 1146e68..1a1c29a 100644 --- 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 @@ -2,12 +2,31 @@ package dev.isxander.yacl3.config.v2.api; import java.lang.reflect.Type; +/** + * 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(); } 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 index e5ba001..d87283a 100644 --- 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 @@ -5,10 +5,24 @@ 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 ""; } 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 index 01c00d6..6337565 100644 --- 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 @@ -2,6 +2,9 @@ package dev.isxander.yacl3.config.v2.api; import java.util.Optional; +/** + * The backing interface for the {@link SerialEntry} annotation. + */ public interface SerialField { String serialName(); 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 index 8abcb60..4187caf 100644 --- 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 @@ -5,10 +5,28 @@ 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 index 48db22d..7f751fb 100644 --- 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 @@ -2,7 +2,10 @@ package dev.isxander.yacl3.config.v2.api.autogen; import java.util.Optional; -public interface AutoGenField<T> { +/** + * 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 index bb948ac..5598389 100644 --- 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 @@ -5,6 +5,12 @@ 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 { @@ -12,10 +18,24 @@ public @interface Boolean { 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/ColorRGBA.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/ColorRGBA.java index dc5b8ff..7e76e27 100644 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/ColorRGBA.java +++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/ColorRGBA.java @@ -5,8 +5,17 @@ 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 ColorRGBA { + /** + * 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/DoubleField.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/DoubleField.java index 225fe8e..963cefd 100644 --- 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 @@ -5,12 +5,42 @@ 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 { - double min(); + /** + * 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; - double max(); + /** + * 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 index 47c7b00..268f6a4 100644 --- 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 @@ -5,14 +5,44 @@ 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/EnumCycler.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/EnumCycler.java index 5545c13..98d94f9 100644 --- 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 @@ -1,13 +1,32 @@ 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>> { 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 index a14b36a..1e7e71e 100644 --- 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 @@ -5,12 +5,42 @@ 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 { - float min(); + /** + * 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; - float max(); + /** + * 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 index 8d1d8e5..19ae9db 100644 --- 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 @@ -5,14 +5,44 @@ 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/IntField.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/IntField.java index 88b5827..9945d01 100644 --- 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 @@ -5,10 +5,37 @@ 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 { - int min(); + /** + * 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; - int max(); + /** + * 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 index 05be857..7fd2282 100644 --- 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 @@ -5,12 +5,31 @@ 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/Label.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Label.java index 7a8ef22..41e026f 100644 --- 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 @@ -5,6 +5,13 @@ 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 index 0853ba4..c664f71 100644 --- 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 @@ -10,21 +10,51 @@ 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, OptionStorage storage, Option<T> option); + 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 index 80a29ad..01c3a7e 100644 --- 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 @@ -5,10 +5,37 @@ 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 { - long min(); + /** + * 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; - long max(); + /** + * 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 index c77b3d3..5563bd0 100644 --- 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 @@ -5,12 +5,31 @@ 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 index 67c311d..70dee1a 100644 --- 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 @@ -5,10 +5,22 @@ 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 new file mode 100644 index 0000000..c55afe4 --- /dev/null +++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OptionAccess.java @@ -0,0 +1,35 @@ +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 index 2e3a537..515a40b 100644 --- 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 @@ -6,9 +6,34 @@ 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> { - Option<T> createOption(A annotation, ConfigField<T> field, OptionStorage storage); + /** + * 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/OptionStorage.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OptionStorage.java deleted file mode 100644 index f90fc29..0000000 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OptionStorage.java +++ /dev/null @@ -1,12 +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; - -public interface OptionStorage { - @Nullable Option<?> getOption(String fieldName); - - void scheduleOptionOperation(String fieldName, Consumer<Option<?>> optionConsumer); -} 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 index c532f29..1816fbc 100644 --- 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 @@ -18,28 +18,28 @@ 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, OptionStorage storage) { + public Option<T> createOption(A annotation, ConfigField<T> field, OptionAccess optionAccess) { Option<T> option = Option.<T>createBuilder() - .name(this.name(annotation, field, storage)) - .description(v -> this.description(v, annotation, field, storage).build()) + .name(this.name(annotation, field, optionAccess)) + .description(v -> this.description(v, annotation, field, optionAccess).build()) .binding(new FieldBackedBinding<>(field.access(), field.defaultAccess())) - .controller(opt -> this.createController(annotation, field, storage, opt)) - .available(this.available(annotation, field, storage)) - .flags(this.flags(annotation, field, storage)) - .listener((opt, v) -> this.listener(annotation, field, storage, opt, v)) + .controller(opt -> this.createController(annotation, field, optionAccess, opt)) + .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, storage, option); + postInit(annotation, field, optionAccess, option); return option; } - protected abstract ControllerBuilder<T> createController(A annotation, ConfigField<T> field, OptionStorage storage, Option<T> option); + protected abstract ControllerBuilder<T> createController(A annotation, ConfigField<T> field, OptionAccess storage, Option<T> option); - protected MutableComponent name(A annotation, ConfigField<T> field, OptionStorage storage) { + protected MutableComponent name(A annotation, ConfigField<T> field, OptionAccess storage) { return Component.translatable(this.getTranslationKey(field, null)); } - protected OptionDescription.Builder description(T value, A annotation, ConfigField<T> field, OptionStorage storage) { + protected OptionDescription.Builder description(T value, A annotation, ConfigField<T> field, OptionAccess storage) { OptionDescription.Builder builder = OptionDescription.createBuilder(); String key = this.getTranslationKey(field, "desc"); @@ -63,19 +63,19 @@ public abstract class SimpleOptionFactory<A extends Annotation, T> implements Op return builder; } - protected boolean available(A annotation, ConfigField<T> field, OptionStorage storage) { + protected boolean available(A annotation, ConfigField<T> field, OptionAccess storage) { return true; } - protected Set<OptionFlag> flags(A annotation, ConfigField<T> field, OptionStorage storage) { + protected Set<OptionFlag> flags(A annotation, ConfigField<T> field, OptionAccess storage) { return Set.of(); } - protected void listener(A annotation, ConfigField<T> field, OptionStorage storage, Option<T> option, T value) { + protected void listener(A annotation, ConfigField<T> field, OptionAccess storage, Option<T> option, T value) { } - protected void postInit(A annotation, ConfigField<T> field, OptionStorage storage, Option<T> option) { + protected void postInit(A annotation, ConfigField<T> field, OptionAccess storage, Option<T> option) { } 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 index c30a75e..50d638e 100644 --- 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 @@ -5,6 +5,12 @@ 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 index 413a32d..0a88c14 100644 --- 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 @@ -5,6 +5,12 @@ 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/GsonConfigSerializerBuilder.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/serializer/GsonConfigSerializerBuilder.java index e871b7c..49b3999 100644 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/GsonConfigSerializerBuilder.java +++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/serializer/GsonConfigSerializerBuilder.java @@ -1,8 +1,10 @@ -package dev.isxander.yacl3.config.v2.api; +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.impl.serializer.GsonConfigSerializer; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Style; @@ -11,6 +13,17 @@ 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); @@ -64,6 +77,12 @@ public interface GsonConfigSerializerBuilder<T> { */ GsonConfigSerializerBuilder<T> appendGsonBuilder(UnaryOperator<GsonBuilder> gsonBuilder); + /** + * Writes the json under JSON5 spec, allowing comments. + * + * @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 index df0af15..4851da7 100644 --- 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 @@ -3,14 +3,13 @@ package dev.isxander.yacl3.config.v2.impl; import dev.isxander.yacl3.api.*; import dev.isxander.yacl3.config.v2.api.*; import dev.isxander.yacl3.config.v2.api.autogen.AutoGen; -import dev.isxander.yacl3.config.v2.api.autogen.OptionStorage; +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.OptionStorageImpl; +import dev.isxander.yacl3.config.v2.impl.autogen.OptionAccessImpl; import dev.isxander.yacl3.config.v2.impl.autogen.YACLAutoGenException; 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.util.Arrays; @@ -27,10 +26,10 @@ public class ConfigClassHandlerImpl<T> implements ConfigClassHandler<T> { private final T instance, defaults; - public ConfigClassHandlerImpl(Class<T> configClass, ResourceLocation id, Function<ConfigClassHandler<T>, ConfigSerializer<T>> serializerFactory, boolean autoGen) { + public ConfigClassHandlerImpl(Class<T> configClass, ResourceLocation id, Function<ConfigClassHandler<T>, ConfigSerializer<T>> serializerFactory) { this.configClass = configClass; this.id = id; - this.supportsAutoGen = YACLPlatform.getEnvironment().isClient() && autoGen; + this.supportsAutoGen = YACLPlatform.getEnvironment().isClient(); try { Constructor<T> constructor = configClass.getDeclaredConstructor(); @@ -84,7 +83,7 @@ public class ConfigClassHandlerImpl<T> implements ConfigClassHandler<T> { 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."); } - OptionStorageImpl storage = new OptionStorageImpl(); + OptionAccessImpl storage = new OptionAccessImpl(); Map<String, CategoryAndGroups> categories = new LinkedHashMap<>(); for (ConfigField<?> configField : fields()) { configField.autoGen().ifPresent(autoGen -> { @@ -108,17 +107,18 @@ public class ConfigClassHandlerImpl<T> implements ConfigClassHandler<T> { group.option(option); }); } + storage.checkBadOperations(); categories.values().forEach(CategoryAndGroups::finaliseGroups); YetAnotherConfigLib.Builder yaclBuilder = YetAnotherConfigLib.createBuilder() - .save(this.serializer()::serialize) + .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, OptionStorage storage) { + 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()))); } @@ -132,7 +132,6 @@ public class ConfigClassHandlerImpl<T> implements ConfigClassHandler<T> { private final Class<T> configClass; private ResourceLocation id; private Function<ConfigClassHandler<T>, ConfigSerializer<T>> serializerFactory; - private boolean autoGen; public BuilderImpl(Class<T> configClass) { this.configClass = configClass; @@ -151,14 +150,8 @@ public class ConfigClassHandlerImpl<T> implements ConfigClassHandler<T> { } @Override - public Builder<T> autoGen(boolean autoGen) { - this.autoGen = autoGen; - return this; - } - - @Override public ConfigClassHandler<T> build() { - return new ConfigClassHandlerImpl<>(configClass, id, serializerFactory, autoGen); + return new ConfigClassHandlerImpl<>(configClass, id, serializerFactory); } } 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 index 3d79e7e..0c879a2 100644 --- 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 @@ -12,7 +12,7 @@ public class ConfigFieldImpl<T> implements ConfigField<T> { private final ReadOnlyFieldAccess<T> defaultField; private final ConfigClassHandler<?> parent; private final Optional<SerialField> serial; - private final Optional<AutoGenField<T>> autoGen; + private final Optional<AutoGenField> autoGen; public ConfigFieldImpl(FieldAccess<T> field, ReadOnlyFieldAccess<T> defaultField, ConfigClassHandler<?> parent, @Nullable SerialEntry config, @Nullable AutoGen autoGen) { this.field = field; @@ -58,12 +58,12 @@ public class ConfigFieldImpl<T> implements ConfigField<T> { } @Override - public Optional<AutoGenField<T>> autoGen() { + public Optional<AutoGenField> autoGen() { return this.autoGen; } private record SerialFieldImpl(String serialName, Optional<String> comment) implements SerialField { } - private record AutoGenFieldImpl<T>(String category, Optional<String> group) implements AutoGenField<T> { + private record AutoGenFieldImpl<T>(String category, Optional<String> group) implements AutoGenField { } } 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 index 74eab90..78b42e2 100644 --- 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 @@ -6,19 +6,19 @@ 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.OptionStorage; +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, OptionStorage storage, Option<java.lang.Boolean> option) { + 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.valueFormatter(v -> Component.translatable(getTranslationKey(field, java.lang.Boolean.toString(v)))); + case CUSTOM -> builder.valueFormatter(v -> Component.translatable(getTranslationKey(field, "fmt." + v))); } return builder; } diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/ColorRGBAImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/ColorRGBAImpl.java index 4bbeca1..81d62bb 100644 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/ColorRGBAImpl.java +++ b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/ColorRGBAImpl.java @@ -6,13 +6,13 @@ 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.ColorRGBA; -import dev.isxander.yacl3.config.v2.api.autogen.OptionStorage; +import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; import java.awt.Color; public class ColorRGBAImpl extends SimpleOptionFactory<ColorRGBA, Color> { @Override - protected ControllerBuilder<Color> createController(ColorRGBA annotation, ConfigField<Color> field, OptionStorage storage, Option<Color> option) { + protected ControllerBuilder<Color> createController(ColorRGBA 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 index 46dace4..16b9654 100644 --- 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 @@ -5,14 +5,14 @@ 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.OptionStorage; +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, OptionStorage storage, Option<Double> option) { + protected ControllerBuilder<Double> createController(DoubleField annotation, ConfigField<Double> field, OptionAccess storage, Option<Double> option) { return DoubleFieldControllerBuilder.create(option) .valueFormatter(v -> { String key = null; 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 index 1a397bd..e1281d2 100644 --- 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 @@ -6,13 +6,13 @@ 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.OptionStorage; +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, OptionStorage storage, Option<Double> option) { + protected ControllerBuilder<Double> createController(DoubleSlider annotation, ConfigField<Double> field, OptionAccess storage, Option<Double> option) { return DoubleSliderControllerBuilder.create(option) .valueFormatter(v -> { String key = null; 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 index e42ab3f..f577c40 100644 --- 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 @@ -7,7 +7,7 @@ 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.OptionStorage; +import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; import net.minecraft.network.chat.Component; import java.util.Arrays; @@ -16,7 +16,7 @@ import java.util.stream.IntStream; public class EnumCyclerImpl extends SimpleOptionFactory<EnumCycler, Enum<?>> { @Override - protected ControllerBuilder<Enum<?>> createController(EnumCycler annotation, ConfigField<Enum<?>> field, OptionStorage storage, Option<Enum<?>> option) { + 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) { @@ -35,7 +35,7 @@ public class EnumCyclerImpl extends SimpleOptionFactory<EnumCycler, Enum<?>> { if (NameableEnum.class.isAssignableFrom(field.access().typeClass())) { builder.valueFormatter(v -> ((NameableEnum) v).getDisplayName()); } else { - builder.valueFormatter(v -> Component.translatable(getTranslationKey(field, "fmt." + v.name().toLowerCase()))); + builder.valueFormatter(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 index 1c613f9..a5eace2 100644 --- 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 @@ -5,14 +5,14 @@ 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.OptionStorage; +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, OptionStorage storage, Option<Float> option) { + protected ControllerBuilder<Float> createController(FloatField annotation, ConfigField<Float> field, OptionAccess storage, Option<Float> option) { return FloatFieldControllerBuilder.create(option) .valueFormatter(v -> { String key = null; 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 index 7a098e1..ec735a0 100644 --- 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 @@ -6,13 +6,13 @@ 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.OptionStorage; +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, OptionStorage storage, Option<Float> option) { + protected ControllerBuilder<Float> createController(FloatSlider annotation, ConfigField<Float> field, OptionAccess storage, Option<Float> option) { return FloatSliderControllerBuilder.create(option) .valueFormatter(v -> { String key = null; 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 index 26d6c1f..51e42a8 100644 --- 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 @@ -5,14 +5,14 @@ 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.OptionStorage; +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, OptionStorage storage, Option<Integer> option) { + protected ControllerBuilder<Integer> createController(IntField annotation, ConfigField<Integer> field, OptionAccess storage, Option<Integer> option) { return IntegerFieldControllerBuilder.create(option) .valueFormatter(v -> { String key = getTranslationKey(field, "fmt." + v); 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 index 5f6e88e..1b6c09f 100644 --- 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 @@ -6,13 +6,13 @@ 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.OptionStorage; +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, OptionStorage storage, Option<Integer> option) { + protected ControllerBuilder<Integer> createController(IntSlider annotation, ConfigField<Integer> field, OptionAccess storage, Option<Integer> option) { return IntegerSliderControllerBuilder.create(option) .valueFormatter(v -> { String key = getTranslationKey(field, "fmt." + v); 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 index 6585652..6f9b368 100644 --- 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 @@ -5,12 +5,12 @@ 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.OptionStorage; +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, OptionStorage storage) { + 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 index c94be2e..f78d4ba 100644 --- 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 @@ -6,7 +6,7 @@ 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.OptionStorage; +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; @@ -20,7 +20,11 @@ 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, OptionStorage storage) { + 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()); @@ -28,8 +32,11 @@ public class ListGroupImpl<T> implements OptionFactory<ListGroup, List<T>> { .name(Component.translatable(this.getTranslationKey(field, null))) .description(this.description(field)) .initial(valueFactory::provideNewValue) - .controller(opt -> controllerFactory.createController(annotation, field, storage, opt)) + .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(); } 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 index fd38763..e35fdd0 100644 --- 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 @@ -5,14 +5,14 @@ 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.LongField; -import dev.isxander.yacl3.config.v2.api.autogen.OptionStorage; +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, OptionStorage storage, Option<Long> option) { + protected ControllerBuilder<Long> createController(LongField annotation, ConfigField<Long> field, OptionAccess storage, Option<Long> option) { return LongSliderControllerBuilder.create(option) .valueFormatter(v -> { String key = getTranslationKey(field, "fmt." + v); 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 index 5850315..6317e81 100644 --- 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 @@ -2,19 +2,17 @@ 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.api.controller.LongSliderControllerBuilder; import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.api.autogen.IntSlider; import dev.isxander.yacl3.config.v2.api.autogen.LongSlider; -import dev.isxander.yacl3.config.v2.api.autogen.OptionStorage; +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, OptionStorage storage, Option<Long> option) { + protected ControllerBuilder<Long> createController(LongSlider annotation, ConfigField<Long> field, OptionAccess storage, Option<Long> option) { return LongSliderControllerBuilder.create(option) .valueFormatter(v -> { String key = getTranslationKey(field, "fmt." + v); 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 index 367b4d0..2d37f03 100644 --- 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 @@ -6,16 +6,16 @@ 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.OptionStorage; +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, OptionStorage storage, Option<Boolean> option) { + 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, OptionStorage storage, Option<Boolean> option, Boolean value) { + 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/OptionStorageImpl.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/OptionAccessImpl.java index 80147d8..579f776 100644 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/OptionStorageImpl.java +++ b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/OptionAccessImpl.java @@ -1,14 +1,15 @@ package dev.isxander.yacl3.config.v2.impl.autogen; import dev.isxander.yacl3.api.Option; -import dev.isxander.yacl3.config.v2.api.autogen.OptionStorage; +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 OptionStorageImpl implements OptionStorage { +public class OptionAccessImpl implements OptionAccess { private final Map<String, Option<?>> storage = new HashMap<>(); private final Map<String, Consumer<Option<?>>> scheduledOperations = new HashMap<>(); @@ -34,4 +35,10 @@ public class OptionStorageImpl implements OptionStorage { 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 index 7e440a4..fe63234 100644 --- 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 @@ -41,7 +41,7 @@ public class OptionFactoryRegistry { factoryMap.put(annotation, factory); } - public static <T> Optional<Option<T>> createOption(Field field, ConfigField<T> configField, OptionStorage storage) { + 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); 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 index 7d6c993..96b63a7 100644 --- 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 @@ -5,12 +5,12 @@ 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.OptionStorage; +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, OptionStorage storage, Option<String> option) { + 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 index 72ef046..050257c 100644 --- 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 @@ -5,12 +5,12 @@ 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.OptionStorage; +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, OptionStorage storage, Option<Boolean> option) { + 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/serializer/GsonConfigSerializer.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/serializer/GsonConfigSerializer.java index c59d20b..1df9cfb 100644 --- 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 @@ -2,6 +2,7 @@ package dev.isxander.yacl3.config.v2.impl.serializer; import com.google.gson.*; import dev.isxander.yacl3.config.v2.api.*; +import dev.isxander.yacl3.config.v2.api.serializer.GsonConfigSerializerBuilder; import dev.isxander.yacl3.impl.utils.YACLConstants; import dev.isxander.yacl3.platform.YACLPlatform; import net.minecraft.network.chat.Component; @@ -18,9 +19,7 @@ import java.lang.reflect.Type; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.function.UnaryOperator; @@ -39,7 +38,7 @@ public class GsonConfigSerializer<T> extends ConfigSerializer<T> { } @Override - public void serialize() { + public void save() { YACLConstants.LOGGER.info("Serializing {} to '{}'", config.configClass(), path); try (StringWriter stringWriter = new StringWriter()) { @@ -76,10 +75,10 @@ public class GsonConfigSerializer<T> extends ConfigSerializer<T> { } @Override - public void deserialize() { + public void load() { if (!Files.exists(path)) { YACLConstants.LOGGER.info("Config file '{}' does not exist. Creating it with default values.", path); - serialize(); + save(); return; } diff --git a/test-common/src/main/java/dev/isxander/yacl3/test/ConfigTest.java b/test-common/src/main/java/dev/isxander/yacl3/test/ConfigTest.java index e633061..fc07120 100644 --- a/test-common/src/main/java/dev/isxander/yacl3/test/ConfigTest.java +++ b/test-common/src/main/java/dev/isxander/yacl3/test/ConfigTest.java @@ -2,7 +2,7 @@ package dev.isxander.yacl3.test; import dev.isxander.yacl3.config.v2.api.ConfigClassHandler; import dev.isxander.yacl3.config.v2.api.SerialEntry; -import dev.isxander.yacl3.config.v2.api.GsonConfigSerializerBuilder; +import dev.isxander.yacl3.config.v2.api.serializer.GsonConfigSerializerBuilder; import dev.isxander.yacl3.platform.YACLPlatform; import java.awt.*; diff --git a/test-common/src/main/java/dev/isxander/yacl3/test/ConfigV2Test.java b/test-common/src/main/java/dev/isxander/yacl3/test/ConfigV2Test.java index 04b7db0..462bef8 100644 --- a/test-common/src/main/java/dev/isxander/yacl3/test/ConfigV2Test.java +++ b/test-common/src/main/java/dev/isxander/yacl3/test/ConfigV2Test.java @@ -7,7 +7,7 @@ import dev.isxander.yacl3.api.controller.ControllerBuilder; import dev.isxander.yacl3.api.controller.StringControllerBuilder; import dev.isxander.yacl3.config.v2.api.ConfigClassHandler; import dev.isxander.yacl3.config.v2.api.ConfigField; -import dev.isxander.yacl3.config.v2.api.GsonConfigSerializerBuilder; +import dev.isxander.yacl3.config.v2.api.serializer.GsonConfigSerializerBuilder; import dev.isxander.yacl3.config.v2.api.SerialEntry; import dev.isxander.yacl3.config.v2.api.autogen.*; import dev.isxander.yacl3.platform.YACLPlatform; @@ -23,7 +23,6 @@ public class ConfigV2Test { .setPath(YACLPlatform.getConfigDir().resolve("yacl-test-v2.json5")) .setJson5(true) .build()) - .autoGen(true) .build(); @AutoGen(category = "test", group = "master_test") @@ -69,7 +68,7 @@ public class ConfigV2Test { public static class TestListControllerFactory implements ListGroup.ControllerFactory<String> { @Override - public ControllerBuilder<String> createController(ListGroup annotation, ConfigField<List<String>> field, OptionStorage storage, Option<String> option) { + public ControllerBuilder<String> createController(ListGroup annotation, ConfigField<List<String>> field, OptionAccess storage, Option<String> option) { return StringControllerBuilder.create(option); } } diff --git a/test-common/src/main/java/dev/isxander/yacl3/test/GuiTest.java b/test-common/src/main/java/dev/isxander/yacl3/test/GuiTest.java index 4953d0c..6430c48 100644 --- a/test-common/src/main/java/dev/isxander/yacl3/test/GuiTest.java +++ b/test-common/src/main/java/dev/isxander/yacl3/test/GuiTest.java @@ -45,7 +45,7 @@ public class GuiTest { .option(ButtonOption.createBuilder() .name(Component.literal("Auto-gen test")) .action((screen, opt) -> { - ConfigV2Test.INSTANCE.serializer().deserialize(); + ConfigV2Test.INSTANCE.serializer().load(); Minecraft.getInstance().setScreen(ConfigV2Test.INSTANCE.generateGui().generateScreen(screen)); }) .build()) @@ -64,7 +64,7 @@ public class GuiTest { private static Screen getFullTestSuite(Screen parent) { AtomicReference<Option<Boolean>> booleanOption = new AtomicReference<>(); - ConfigTest.GSON.serializer().deserialize(); + ConfigTest.GSON.serializer().load(); return YetAnotherConfigLib.create(ConfigTest.GSON, (defaults, config, builder) -> builder .title(Component.literal("Test GUI")) .category(ConfigCategory.createBuilder() @@ -380,7 +380,7 @@ public class GuiTest { .build()) .save(() -> { Minecraft.getInstance().options.save(); - ConfigTest.GSON.serializer().serialize(); + ConfigTest.GSON.serializer().save(); }) ) .generateScreen(parent); |