aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorisXander <xander@isxander.dev>2023-08-15 16:13:54 +0100
committerisXander <xander@isxander.dev>2023-08-15 16:13:54 +0100
commit9f72a09a5b2afc99b08a79bda84f91ef51c0f4d0 (patch)
tree56c7214bf95fa50e2469762b972cb6163f5f1b14
parent3e30af10ab48aa64fa659834a863a4e3067d5542 (diff)
downloadYetAnotherConfigLib-9f72a09a5b2afc99b08a79bda84f91ef51c0f4d0.tar.gz
YetAnotherConfigLib-9f72a09a5b2afc99b08a79bda84f91ef51c0f4d0.tar.bz2
YetAnotherConfigLib-9f72a09a5b2afc99b08a79bda84f91ef51c0f4d0.zip
Add javadoc to config api v2
-rw-r--r--common/src/main/java/dev/isxander/yacl3/api/YetAnotherConfigLib.java2
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigClassHandler.java58
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigField.java25
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigSerializer.java17
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/FieldAccess.java9
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/ReadOnlyFieldAccess.java19
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/SerialEntry.java14
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/SerialField.java3
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/AutoGen.java18
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/AutoGenField.java5
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Boolean.java20
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/ColorRGBA.java9
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/DoubleField.java34
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/DoubleSlider.java30
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/EnumCycler.java19
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/FloatField.java34
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/FloatSlider.java30
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/IntField.java31
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/IntSlider.java19
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Label.java7
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/ListGroup.java32
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/LongField.java31
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/LongSlider.java19
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/MasterTickBox.java12
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OptionAccess.java35
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OptionFactory.java27
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OptionStorage.java12
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/SimpleOptionFactory.java30
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/StringField.java6
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/TickBox.java6
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/serializer/GsonConfigSerializerBuilder.java (renamed from common/src/main/java/dev/isxander/yacl3/config/v2/api/GsonConfigSerializerBuilder.java)21
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/ConfigClassHandlerImpl.java25
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/ConfigFieldImpl.java6
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/BooleanImpl.java6
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/ColorRGBAImpl.java4
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/DoubleFieldImpl.java4
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/DoubleSliderImpl.java4
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/EnumCyclerImpl.java6
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/FloatFieldImpl.java4
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/FloatSliderImpl.java4
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/IntFieldImpl.java4
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/IntSliderImpl.java4
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/LabelImpl.java4
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/ListGroupImpl.java13
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/LongFieldImpl.java4
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/LongSliderImpl.java6
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/MasterTickBoxImpl.java6
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/OptionAccessImpl.java (renamed from common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/OptionStorageImpl.java)11
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/OptionFactoryRegistry.java2
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/StringFieldImpl.java4
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/TickBoxImpl.java4
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/serializer/GsonConfigSerializer.java9
-rw-r--r--test-common/src/main/java/dev/isxander/yacl3/test/ConfigTest.java2
-rw-r--r--test-common/src/main/java/dev/isxander/yacl3/test/ConfigV2Test.java5
-rw-r--r--test-common/src/main/java/dev/isxander/yacl3/test/GuiTest.java6
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);