From 98f29ec5c30d23999fce37d7daf7aba8f10f25d3 Mon Sep 17 00:00:00 2001 From: isXander Date: Wed, 16 Aug 2023 12:56:15 +0100 Subject: Add @OverrideName and @OverrideFormat --- .../yacl3/config/v2/api/ReadOnlyFieldAccess.java | 4 +++ .../config/v2/api/autogen/OverrideFormatter.java | 17 +++++++++++ .../yacl3/config/v2/api/autogen/OverrideName.java | 18 ++++++++++++ .../config/v2/api/autogen/SimpleOptionFactory.java | 14 +++++++-- .../config/v2/impl/ReflectionFieldAccess.java | 7 +++++ .../yacl3/config/v2/impl/autogen/AutoGenUtils.java | 34 ++++++++++++++++++++++ .../yacl3/config/v2/impl/autogen/BooleanImpl.java | 2 +- .../config/v2/impl/autogen/DoubleFieldImpl.java | 2 +- .../config/v2/impl/autogen/DoubleSliderImpl.java | 2 +- .../config/v2/impl/autogen/EnumCyclerImpl.java | 4 +-- .../config/v2/impl/autogen/FloatFieldImpl.java | 2 +- .../config/v2/impl/autogen/FloatSliderImpl.java | 2 +- .../yacl3/config/v2/impl/autogen/IntFieldImpl.java | 2 +- .../config/v2/impl/autogen/IntSliderImpl.java | 2 +- .../config/v2/impl/autogen/LongFieldImpl.java | 2 +- .../config/v2/impl/autogen/LongSliderImpl.java | 2 +- 16 files changed, 103 insertions(+), 13 deletions(-) create mode 100644 common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OverrideFormatter.java create mode 100644 common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OverrideName.java create mode 100644 common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/AutoGenUtils.java (limited to 'common/src/main/java/dev/isxander/yacl3/config/v2') 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 1a1c29a..566d60d 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 @@ -1,6 +1,8 @@ package dev.isxander.yacl3.config.v2.api; +import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import java.util.Optional; /** * An abstract interface for accessing properties of an instance of a field. @@ -29,4 +31,6 @@ public interface ReadOnlyFieldAccess { * @return the class of the field. */ Class typeClass(); + + Optional getAnnotation(Class annotationClass); } diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OverrideFormatter.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OverrideFormatter.java new file mode 100644 index 0000000..f97395c --- /dev/null +++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OverrideFormatter.java @@ -0,0 +1,17 @@ +package dev.isxander.yacl3.config.v2.api.autogen; + +import dev.isxander.yacl3.api.controller.ValueFormatter; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Allows you to specify a custom {@link ValueFormatter} for a field. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface OverrideFormatter { + Class> value(); +} diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OverrideName.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OverrideName.java new file mode 100644 index 0000000..8b73cec --- /dev/null +++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OverrideName.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; + +/** + * Overrides the name of an auto-generated option. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface OverrideName { + /** + * The translation key to use for the option's name. + */ + String value() default ""; +} 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 1816fbc..bf886ae 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 @@ -6,6 +6,7 @@ import dev.isxander.yacl3.api.OptionFlag; import dev.isxander.yacl3.api.controller.ControllerBuilder; import dev.isxander.yacl3.config.v2.api.ConfigField; import dev.isxander.yacl3.config.v2.impl.FieldBackedBinding; +import dev.isxander.yacl3.config.v2.impl.autogen.AutoGenUtils; import net.minecraft.client.Minecraft; import net.minecraft.locale.Language; import net.minecraft.network.chat.Component; @@ -14,6 +15,7 @@ import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.Nullable; import java.lang.annotation.Annotation; +import java.util.Optional; import java.util.Set; public abstract class SimpleOptionFactory implements OptionFactory { @@ -23,7 +25,14 @@ public abstract class SimpleOptionFactory implements Op .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, optionAccess, opt)) + .controller(opt -> { + ControllerBuilder builder = this.createController(annotation, field, optionAccess, opt); + + Optional customFormatter = field.access().getAnnotation(OverrideFormatter.class); + AutoGenUtils.addCustomFormatterToController(builder, customFormatter, field.access()); + + return builder; + }) .available(this.available(annotation, field, optionAccess)) .flags(this.flags(annotation, field, optionAccess)) .listener((opt, v) -> this.listener(annotation, field, optionAccess, opt, v)) @@ -36,7 +45,8 @@ public abstract class SimpleOptionFactory implements Op protected abstract ControllerBuilder createController(A annotation, ConfigField field, OptionAccess storage, Option option); protected MutableComponent name(A annotation, ConfigField field, OptionAccess storage) { - return Component.translatable(this.getTranslationKey(field, null)); + Optional customName = field.access().getAnnotation(OverrideName.class); + return Component.translatable(customName.map(OverrideName::value).orElse(this.getTranslationKey(field, null))); } protected OptionDescription.Builder description(T value, A annotation, ConfigField field, OptionAccess storage) { diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/ReflectionFieldAccess.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/ReflectionFieldAccess.java index 8bb7fc0..e102344 100644 --- a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/ReflectionFieldAccess.java +++ b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/ReflectionFieldAccess.java @@ -3,8 +3,10 @@ package dev.isxander.yacl3.config.v2.impl; import dev.isxander.yacl3.config.v2.api.FieldAccess; import dev.isxander.yacl3.config.v2.impl.autogen.YACLAutoGenException; +import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Type; +import java.util.Optional; public record ReflectionFieldAccess(Field field, Object instance) implements FieldAccess { @Override @@ -39,4 +41,9 @@ public record ReflectionFieldAccess(Field field, Object instance) implements public Class typeClass() { return (Class) field.getType(); } + + @Override + public Optional getAnnotation(Class annotationClass) { + return Optional.ofNullable(field.getAnnotation(annotationClass)); + } } diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/AutoGenUtils.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/AutoGenUtils.java new file mode 100644 index 0000000..ecd4157 --- /dev/null +++ b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/AutoGenUtils.java @@ -0,0 +1,34 @@ +package dev.isxander.yacl3.config.v2.impl.autogen; + +import dev.isxander.yacl3.api.controller.ControllerBuilder; +import dev.isxander.yacl3.api.controller.ValueFormattableController; +import dev.isxander.yacl3.api.controller.ValueFormatter; +import dev.isxander.yacl3.config.v2.api.ReadOnlyFieldAccess; +import dev.isxander.yacl3.config.v2.api.autogen.OverrideFormatter; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Optional; + +@ApiStatus.Internal +public final class AutoGenUtils { + public static void addCustomFormatterToController(ControllerBuilder controller, Optional formatter, ReadOnlyFieldAccess field) { + formatter.ifPresent(formatterClass -> { + if (controller instanceof ValueFormattableController) { + ValueFormattableController typedBuilder; + try { + typedBuilder = (ValueFormattableController) controller; + } catch (ClassCastException e) { + throw new YACLAutoGenException("'%s': The formatter class on @CustomFormatter is of incorrect type. Expected %s, got %s.".formatted(field.name(), field.type().getTypeName(), formatterClass.value().getTypeParameters()[0].getName())); + } + + try { + typedBuilder.formatValue((ValueFormatter) formatterClass.value().getConstructor().newInstance()); + } catch (Exception e) { + throw new YACLAutoGenException("'%s': Failed to instantiate formatter class %s.".formatted(field.name(), formatterClass.value().getName()), e); + } + } else { + throw new YACLAutoGenException("Attempted to use @CustomFormatter on an option factory for field '%s' that uses a controller that does not support this.".formatted(field.name())); + } + }); + } +} 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 78b42e2..b41836a 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 @@ -18,7 +18,7 @@ public class BooleanImpl extends SimpleOptionFactory case ON_OFF -> builder.onOffFormatter(); case YES_NO -> builder.yesNoFormatter(); case TRUE_FALSE -> builder.trueFalseFormatter(); - case CUSTOM -> builder.valueFormatter(v -> Component.translatable(getTranslationKey(field, "fmt." + v))); + case CUSTOM -> builder.formatValue(v -> Component.translatable(getTranslationKey(field, "fmt." + v))); } return builder; } 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 16b9654..d53d0f6 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 @@ -14,7 +14,7 @@ public class DoubleFieldImpl extends SimpleOptionFactory { @Override protected ControllerBuilder createController(DoubleField annotation, ConfigField field, OptionAccess storage, Option option) { return DoubleFieldControllerBuilder.create(option) - .valueFormatter(v -> { + .formatValue(v -> { String key = null; if (v == annotation.min()) key = getTranslationKey(field, "fmt.min"); 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 e1281d2..5221012 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 @@ -14,7 +14,7 @@ public class DoubleSliderImpl extends SimpleOptionFactory @Override protected ControllerBuilder createController(DoubleSlider annotation, ConfigField field, OptionAccess storage, Option option) { return DoubleSliderControllerBuilder.create(option) - .valueFormatter(v -> { + .formatValue(v -> { String key = null; if (v == annotation.min()) key = getTranslationKey(field, "fmt.min"); 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 f577c40..f15d862 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 @@ -33,9 +33,9 @@ public class EnumCyclerImpl extends SimpleOptionFactory> { var builder = CyclingListControllerBuilder.create(option) .values(values); if (NameableEnum.class.isAssignableFrom(field.access().typeClass())) { - builder.valueFormatter(v -> ((NameableEnum) v).getDisplayName()); + builder.formatValue(v -> ((NameableEnum) v).getDisplayName()); } else { - builder.valueFormatter(v -> Component.translatable("yacl3.config.enum.%s.%s".formatted(field.access().typeClass().getSimpleName(), v.name().toLowerCase()))); + builder.formatValue(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 a5eace2..def5169 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 @@ -14,7 +14,7 @@ public class FloatFieldImpl extends SimpleOptionFactory { @Override protected ControllerBuilder createController(FloatField annotation, ConfigField field, OptionAccess storage, Option option) { return FloatFieldControllerBuilder.create(option) - .valueFormatter(v -> { + .formatValue(v -> { String key = null; if (v == annotation.min()) key = getTranslationKey(field, "fmt.min"); 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 ec735a0..6424bea 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 @@ -14,7 +14,7 @@ public class FloatSliderImpl extends SimpleOptionFactory { @Override protected ControllerBuilder createController(FloatSlider annotation, ConfigField field, OptionAccess storage, Option option) { return FloatSliderControllerBuilder.create(option) - .valueFormatter(v -> { + .formatValue(v -> { String key = null; if (v == annotation.min()) key = getTranslationKey(field, "fmt.min"); 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 51e42a8..e5f4e71 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 @@ -14,7 +14,7 @@ public class IntFieldImpl extends SimpleOptionFactory { @Override protected ControllerBuilder createController(IntField annotation, ConfigField field, OptionAccess storage, Option option) { return IntegerFieldControllerBuilder.create(option) - .valueFormatter(v -> { + .formatValue(v -> { String key = getTranslationKey(field, "fmt." + v); if (Language.getInstance().has(key)) return Component.translatable(key); 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 1b6c09f..d650837 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 @@ -14,7 +14,7 @@ public class IntSliderImpl extends SimpleOptionFactory { @Override protected ControllerBuilder createController(IntSlider annotation, ConfigField field, OptionAccess storage, Option option) { return IntegerSliderControllerBuilder.create(option) - .valueFormatter(v -> { + .formatValue(v -> { String key = getTranslationKey(field, "fmt." + v); if (Language.getInstance().has(key)) return Component.translatable(key); 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 09e0255..41d20ca 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 @@ -14,7 +14,7 @@ public class LongFieldImpl extends SimpleOptionFactory { @Override protected ControllerBuilder createController(LongField annotation, ConfigField field, OptionAccess storage, Option option) { return LongFieldControllerBuilder.create(option) - .valueFormatter(v -> { + .formatValue(v -> { String key = getTranslationKey(field, "fmt." + v); if (Language.getInstance().has(key)) return Component.translatable(key); 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 6317e81..3c1f778 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 @@ -14,7 +14,7 @@ public class LongSliderImpl extends SimpleOptionFactory { @Override protected ControllerBuilder createController(LongSlider annotation, ConfigField field, OptionAccess storage, Option option) { return LongSliderControllerBuilder.create(option) - .valueFormatter(v -> { + .formatValue(v -> { String key = getTranslationKey(field, "fmt." + v); if (Language.getInstance().has(key)) return Component.translatable(key); -- cgit