aboutsummaryrefslogtreecommitdiff
path: root/common/src
diff options
context:
space:
mode:
authorisXander <xandersmith2008@gmail.com>2023-08-14 23:27:45 +0100
committerisXander <xandersmith2008@gmail.com>2023-08-14 23:27:45 +0100
commitb3355266572deef1a5c3e494ad162c592383e455 (patch)
tree876510a21e27d0052cb7a1501c0295a427c9dc3c /common/src
parentd37e147dbb4db44a921533b572aed3e54b5c6a42 (diff)
downloadYetAnotherConfigLib-b3355266572deef1a5c3e494ad162c592383e455.tar.gz
YetAnotherConfigLib-b3355266572deef1a5c3e494ad162c592383e455.tar.bz2
YetAnotherConfigLib-b3355266572deef1a5c3e494ad162c592383e455.zip
More-or-less complete API for YACL auto-gen
Diffstat (limited to 'common/src')
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigClassHandler.java5
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigField.java12
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/FieldAccess.java11
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/OptionFactory.java12
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/ReadOnlyFieldAccess.java11
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/SerialEntry.java (renamed from common/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigEntry.java)8
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/SerialField.java9
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/SimpleOptionFactory.java82
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/AutoGen.java14
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/AutoGenField.java9
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Boolean.java21
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/DoubleSlider.java18
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/FloatSlider.java18
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/IntSlider.java16
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Label.java11
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/MasterTickBox.java14
-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/TickBox.java11
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/ConfigClassHandlerImpl.java83
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/ConfigFieldImpl.java83
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/DefaultOptionFactory.java18
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/FieldBackedBinding.java22
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/OptionStorageImpl.java37
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/BooleanImpl.java25
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/DoubleSliderImpl.java30
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/FloatSliderImpl.java30
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/IntSliderImpl.java26
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/LabelImpl.java16
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/MasterTickBoxImpl.java27
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/OptionFactoryRegistry.java54
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/TickBoxImpl.java16
-rw-r--r--common/src/main/java/dev/isxander/yacl3/config/v2/impl/serializer/GsonConfigSerializer.java33
-rw-r--r--common/src/main/java/dev/isxander/yacl3/gui/controllers/string/StringControllerElement.java44
-rw-r--r--common/src/main/java/dev/isxander/yacl3/gui/utils/UndoRedoHelper.java42
34 files changed, 768 insertions, 112 deletions
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 22e471f..645a8e8 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
@@ -2,6 +2,7 @@ package dev.isxander.yacl3.config.v2.api;
import dev.isxander.yacl3.api.YetAnotherConfigLib;
import dev.isxander.yacl3.config.v2.impl.ConfigClassHandlerImpl;
+import net.minecraft.resources.ResourceLocation;
import java.util.function.Function;
@@ -14,6 +15,8 @@ public interface ConfigClassHandler<T> {
ConfigField<?>[] fields();
+ ResourceLocation id();
+
YetAnotherConfigLib generateGui();
boolean supportsAutoGen();
@@ -25,6 +28,8 @@ public interface ConfigClassHandler<T> {
}
interface Builder<T> {
+ Builder<T> id(ResourceLocation id);
+
Builder<T> serializer(Function<ConfigClassHandler<T>, ConfigSerializer<T>> serializerFactory);
Builder<T> autoGen(boolean autoGen);
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 26a309f..1cd8739 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
@@ -1,17 +1,17 @@
package dev.isxander.yacl3.config.v2.api;
-import org.jetbrains.annotations.Nullable;
+import dev.isxander.yacl3.config.v2.api.autogen.AutoGenField;
import java.util.Optional;
public interface ConfigField<T> {
- String serialName();
+ FieldAccess<T> access();
- Optional<String> comment();
+ ReadOnlyFieldAccess<T> defaultAccess();
- FieldAccess<T> access();
+ ConfigClassHandler<?> parent();
- @Nullable OptionFactory<T> factory();
+ Optional<SerialField> serial();
- boolean supportsFactory();
+ Optional<AutoGenField<T>> autoGen();
}
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 aed9801..a961172 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,14 +1,5 @@
package dev.isxander.yacl3.config.v2.api;
-import java.lang.reflect.Type;
-
-public interface FieldAccess<T> {
- T get();
-
+public interface FieldAccess<T> extends ReadOnlyFieldAccess<T> {
void set(T value);
-
- String name();
-
- Type type();
-
}
diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/OptionFactory.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/OptionFactory.java
index aabfcf0..9d53e79 100644
--- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/OptionFactory.java
+++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/OptionFactory.java
@@ -1,9 +1,15 @@
package dev.isxander.yacl3.config.v2.api;
import dev.isxander.yacl3.api.Option;
+import dev.isxander.yacl3.config.v2.api.autogen.OptionStorage;
+import dev.isxander.yacl3.config.v2.impl.autogen.OptionFactoryRegistry;
-public interface OptionFactory<T> {
- Option<T> create(ConfigField<T> field);
+import java.lang.annotation.Annotation;
- Class<T> type();
+public interface OptionFactory<A extends Annotation, T> {
+ Option<T> createOption(A annotation, ConfigField<T> field, OptionStorage storage);
+
+ 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/ReadOnlyFieldAccess.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/ReadOnlyFieldAccess.java
new file mode 100644
index 0000000..5b71e58
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/ReadOnlyFieldAccess.java
@@ -0,0 +1,11 @@
+package dev.isxander.yacl3.config.v2.api;
+
+import java.lang.reflect.Type;
+
+public interface ReadOnlyFieldAccess<T> {
+ T get();
+
+ String name();
+
+ Type type();
+}
diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigEntry.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/SerialEntry.java
index 8b95c3f..e5ba001 100644
--- a/common/src/main/java/dev/isxander/yacl3/config/v2/api/ConfigEntry.java
+++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/SerialEntry.java
@@ -1,7 +1,5 @@
package dev.isxander.yacl3.config.v2.api;
-import dev.isxander.yacl3.config.v2.impl.DefaultOptionFactory;
-
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -9,10 +7,8 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
-public @interface ConfigEntry {
- Class<? extends OptionFactory<?>> factory() default DefaultOptionFactory.class;
-
- String serialName() default "";
+public @interface SerialEntry {
+ String value() default "";
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
new file mode 100644
index 0000000..01c00d6
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/SerialField.java
@@ -0,0 +1,9 @@
+package dev.isxander.yacl3.config.v2.api;
+
+import java.util.Optional;
+
+public interface SerialField {
+ String serialName();
+
+ Optional<String> comment();
+}
diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/SimpleOptionFactory.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/SimpleOptionFactory.java
new file mode 100644
index 0000000..5c6894e
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/SimpleOptionFactory.java
@@ -0,0 +1,82 @@
+package dev.isxander.yacl3.config.v2.api;
+
+import dev.isxander.yacl3.api.Option;
+import dev.isxander.yacl3.api.OptionDescription;
+import dev.isxander.yacl3.api.OptionFlag;
+import dev.isxander.yacl3.api.controller.ControllerBuilder;
+import dev.isxander.yacl3.config.v2.api.autogen.OptionStorage;
+import dev.isxander.yacl3.config.v2.impl.FieldBackedBinding;
+import net.minecraft.client.Minecraft;
+import net.minecraft.locale.Language;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.MutableComponent;
+import net.minecraft.resources.ResourceLocation;
+import org.jetbrains.annotations.Nullable;
+
+import java.lang.annotation.Annotation;
+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) {
+ Option<T> option = Option.<T>createBuilder()
+ .name(this.name(annotation, field, storage))
+ .description(v -> this.description(v, annotation, field, storage).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))
+ .build();
+
+ postInit(annotation, field, storage, option);
+ return option;
+ }
+
+ protected abstract ControllerBuilder<T> createController(A annotation, ConfigField<T> field, OptionStorage storage, Option<T> option);
+
+ protected MutableComponent name(A annotation, ConfigField<T> field, OptionStorage storage) {
+ return Component.translatable(this.getTranslationKey(field, null));
+ }
+
+ protected OptionDescription.Builder description(T value, A annotation, ConfigField<T> field, OptionStorage storage) {
+ OptionDescription.Builder builder = OptionDescription.createBuilder();
+
+ String key = this.getTranslationKey(field, "desc");
+ if (Language.getInstance().has(key)) {
+ builder.text(Component.translatable(key));
+ } else {
+ key += ".";
+ int i = 0;
+ while (Language.getInstance().has(key + i++)) {
+ builder.text(Component.translatable(key + i));
+ }
+ }
+
+ String imagePath = "textures/yacl3/" + field.parent().id().getPath() + "/" + field.access().name() + ".webp";
+ imagePath = imagePath.toLowerCase().replaceAll("[^a-z0-9/._:-]", "_");
+ ResourceLocation imageLocation = new ResourceLocation(field.parent().id().getNamespace(), imagePath);
+ if (Minecraft.getInstance().getResourceManager().getResource(imageLocation).isPresent()) {
+ builder.webpImage(imageLocation);
+ }
+
+ return builder;
+ }
+
+ protected boolean available(A annotation, ConfigField<T> field, OptionStorage storage) {
+ return true;
+ }
+
+ protected Set<OptionFlag> flags(A annotation, ConfigField<T> field, OptionStorage storage) {
+ return Set.of();
+ }
+
+ protected void postInit(A annotation, ConfigField<T> field, OptionStorage storage, Option<T> option) {
+
+ }
+
+ protected String getTranslationKey(ConfigField<T> field, @Nullable String suffix) {
+ String key = "yacl3.config.%s.%s".formatted(field.parent().id().toString(), field.access().name());
+ if (suffix != null) key += "." + suffix;
+ return key;
+ }
+}
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
new file mode 100644
index 0000000..8abcb60
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/AutoGen.java
@@ -0,0 +1,14 @@
+package dev.isxander.yacl3.config.v2.api.autogen;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface AutoGen {
+ String category();
+
+ 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
new file mode 100644
index 0000000..48db22d
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/AutoGenField.java
@@ -0,0 +1,9 @@
+package dev.isxander.yacl3.config.v2.api.autogen;
+
+import java.util.Optional;
+
+public interface AutoGenField<T> {
+ 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
new file mode 100644
index 0000000..bb948ac
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Boolean.java
@@ -0,0 +1,21 @@
+package dev.isxander.yacl3.config.v2.api.autogen;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Boolean {
+ enum Formatter {
+ YES_NO,
+ TRUE_FALSE,
+ ON_OFF,
+ CUSTOM,
+ }
+
+ Formatter formatter() default Formatter.TRUE_FALSE;
+
+ boolean colored() default false;
+}
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
new file mode 100644
index 0000000..47c7b00
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/DoubleSlider.java
@@ -0,0 +1,18 @@
+package dev.isxander.yacl3.config.v2.api.autogen;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface DoubleSlider {
+ double min();
+
+ double max();
+
+ double step();
+
+ String format() default "%.2f";
+}
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
new file mode 100644
index 0000000..8d1d8e5
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/FloatSlider.java
@@ -0,0 +1,18 @@
+package dev.isxander.yacl3.config.v2.api.autogen;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface FloatSlider {
+ float min();
+
+ float max();
+
+ float step();
+
+ String format() default "%.1f";
+}
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
new file mode 100644
index 0000000..05be857
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/IntSlider.java
@@ -0,0 +1,16 @@
+package dev.isxander.yacl3.config.v2.api.autogen;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface IntSlider {
+ int min();
+
+ int max();
+
+ 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
new file mode 100644
index 0000000..7a8ef22
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/Label.java
@@ -0,0 +1,11 @@
+package dev.isxander.yacl3.config.v2.api.autogen;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Label {
+}
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
new file mode 100644
index 0000000..67c311d
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/MasterTickBox.java
@@ -0,0 +1,14 @@
+package dev.isxander.yacl3.config.v2.api.autogen;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface MasterTickBox {
+ String[] value();
+
+ boolean invert() default false;
+}
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
new file mode 100644
index 0000000..f90fc29
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OptionStorage.java
@@ -0,0 +1,12 @@
+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/TickBox.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/TickBox.java
new file mode 100644
index 0000000..413a32d
--- /dev/null
+++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/TickBox.java
@@ -0,0 +1,11 @@
+package dev.isxander.yacl3.config.v2.api.autogen;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface TickBox {
+}
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 62aa9b6..b9274e9 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
@@ -1,24 +1,33 @@
package dev.isxander.yacl3.config.v2.impl;
-import dev.isxander.yacl3.api.YetAnotherConfigLib;
+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.impl.autogen.OptionFactoryRegistry;
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;
+import java.util.LinkedHashMap;
+import java.util.Map;
import java.util.function.Function;
public class ConfigClassHandlerImpl<T> implements ConfigClassHandler<T> {
private final Class<T> configClass;
+ private final ResourceLocation id;
private final boolean supportsAutoGen;
private final ConfigSerializer<T> serializer;
private final ConfigField<?>[] fields;
private final T instance, defaults;
- public ConfigClassHandlerImpl(Class<T> configClass, Function<ConfigClassHandler<T>, ConfigSerializer<T>> serializerFactory, boolean autoGen) {
+ public ConfigClassHandlerImpl(Class<T> configClass, ResourceLocation id, Function<ConfigClassHandler<T>, ConfigSerializer<T>> serializerFactory, boolean autoGen) {
this.configClass = configClass;
+ this.id = id;
this.supportsAutoGen = YACLPlatform.getEnvironment().isClient() && autoGen;
try {
@@ -30,8 +39,9 @@ public class ConfigClassHandlerImpl<T> implements ConfigClassHandler<T> {
}
this.fields = Arrays.stream(configClass.getDeclaredFields())
- .filter(field -> field.isAnnotationPresent(ConfigEntry.class))
- .map(field -> new ConfigFieldImpl<>(this.supportsAutoGen(), field.getAnnotation(ConfigEntry.class), new ReflectionFieldAccess<>(field, instance)))
+ .peek(field -> field.setAccessible(true))
+ .filter(field -> field.isAnnotationPresent(SerialEntry.class) || field.isAnnotationPresent(AutoGen.class))
+ .map(field -> new ConfigFieldImpl<>(new ReflectionFieldAccess<>(field, instance), new ReflectionFieldAccess<>(field, defaults), this, field.getAnnotation(SerialEntry.class), field.getAnnotation(AutoGen.class)))
.toArray(ConfigField[]::new);
this.serializer = serializerFactory.apply(this);
}
@@ -57,6 +67,11 @@ public class ConfigClassHandlerImpl<T> implements ConfigClassHandler<T> {
}
@Override
+ public ResourceLocation id() {
+ return this.id;
+ }
+
+ @Override
public boolean supportsAutoGen() {
return this.supportsAutoGen;
}
@@ -65,7 +80,43 @@ public class ConfigClassHandlerImpl<T> implements ConfigClassHandler<T> {
public YetAnotherConfigLib generateGui() {
Validate.isTrue(supportsAutoGen(), "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.");
- throw new IllegalStateException();
+ OptionStorageImpl storage = new OptionStorageImpl();
+ Map<String, CategoryAndGroups> categories = new LinkedHashMap<>();
+ for (ConfigField<?> configField : fields()) {
+ configField.autoGen().ifPresent(autoGen -> {
+ CategoryAndGroups groups = categories.computeIfAbsent(
+ autoGen.category(),
+ k -> new CategoryAndGroups(
+ ConfigCategory.createBuilder()
+ .name(Component.translatable("yacl3.config.%s.category.%s".formatted(id().toString(), k))),
+ new LinkedHashMap<>()
+ )
+ );
+ OptionAddable group = groups.groups().computeIfAbsent(autoGen.group().orElse(""), k -> {
+ if (k.isEmpty())
+ return groups.category();
+ return OptionGroup.createBuilder()
+ .name(Component.translatable("yacl3.config.%s.category.%s.group.%s".formatted(id().toString(), autoGen.category(), k)));
+ });
+
+ Option<?> option = createOption(configField, storage);
+ storage.putOption(configField.access().name(), option);
+ group.option(option);
+ });
+ }
+ categories.values().forEach(CategoryAndGroups::finaliseGroups);
+
+ YetAnotherConfigLib.Builder yaclBuilder = YetAnotherConfigLib.createBuilder()
+ .save(this.serializer()::serialize)
+ .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) {
+ return OptionFactoryRegistry.createOption(((ReflectionFieldAccess<?>) configField.access()).field(), configField, storage)
+ .orElseThrow(() -> new IllegalStateException("Failed to create option for field %s".formatted(configField.access().name())));
}
@Override
@@ -75,6 +126,7 @@ public class ConfigClassHandlerImpl<T> implements ConfigClassHandler<T> {
public static class BuilderImpl<T> implements Builder<T> {
private final Class<T> configClass;
+ private ResourceLocation id;
private Function<ConfigClassHandler<T>, ConfigSerializer<T>> serializerFactory;
private boolean autoGen;
@@ -83,6 +135,12 @@ public class ConfigClassHandlerImpl<T> implements ConfigClassHandler<T> {
}
@Override
+ public Builder<T> id(ResourceLocation id) {
+ this.id = id;
+ return this;
+ }
+
+ @Override
public Builder<T> serializer(Function<ConfigClassHandler<T>, ConfigSerializer<T>> serializerFactory) {
this.serializerFactory = serializerFactory;
return this;
@@ -90,12 +148,23 @@ public class ConfigClassHandlerImpl<T> implements ConfigClassHandler<T> {
@Override
public Builder<T> autoGen(boolean autoGen) {
- throw new IllegalArgumentException();
+ this.autoGen = autoGen;
+ return this;