diff options
4 files changed, 97 insertions, 5 deletions
diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OverrideImage.java b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OverrideImage.java new file mode 100644 index 0000000..649121a --- /dev/null +++ b/common/src/main/java/dev/isxander/yacl3/config/v2/api/autogen/OverrideImage.java @@ -0,0 +1,27 @@ +package dev.isxander.yacl3.config.v2.api.autogen; + +import dev.isxander.yacl3.config.v2.api.ConfigField; +import dev.isxander.yacl3.config.v2.impl.autogen.EmptyCustomImageFactory; +import dev.isxander.yacl3.gui.ImageRenderer; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface OverrideImage { + String value() default ""; + + int width() default 0; + int height() default 0; + + Class<? extends CustomImageFactory<?>> factory() default EmptyCustomImageFactory.class; + + interface CustomImageFactory<T> { + CompletableFuture<Optional<ImageRenderer>> createImage(T value, ConfigField<T> field, OptionAccess access); + } +} 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 bf886ae..0ab6369 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 @@ -7,6 +7,8 @@ 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 dev.isxander.yacl3.config.v2.impl.autogen.EmptyCustomImageFactory; +import dev.isxander.yacl3.config.v2.impl.autogen.YACLAutoGenException; import net.minecraft.client.Minecraft; import net.minecraft.locale.Language; import net.minecraft.network.chat.Component; @@ -63,11 +65,44 @@ public abstract class SimpleOptionFactory<A extends Annotation, T> implements Op } } - 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); + Optional<OverrideImage> imageOverrideOpt = field.access().getAnnotation(OverrideImage.class); + if (imageOverrideOpt.isPresent()) { + OverrideImage imageOverride = imageOverrideOpt.get(); + + if (!imageOverride.factory().equals(EmptyCustomImageFactory.class)) { + OverrideImage.CustomImageFactory<T> imageFactory; + try { + imageFactory = (OverrideImage.CustomImageFactory<T>) AutoGenUtils.constructNoArgsClass( + imageOverride.factory(), + () -> "'%s': The factory class on @OverrideImage has no no-args constructor.".formatted(field.access().name()), + () -> "'%s': Failed to instantiate factory class %s.".formatted(field.access().name(), imageOverride.factory().getName()) + ); + } catch (ClassCastException e) { + throw new YACLAutoGenException("'%s': The factory class on @OverrideImage is of incorrect type. Expected %s, got %s.".formatted(field.access().name(), field.access().type().getTypeName(), imageOverride.factory().getTypeParameters()[0].getName())); + } + + builder.customImage(imageFactory.createImage(value, field, storage)); + } else if (!imageOverride.value().isEmpty()) { + String path = imageOverride.value(); + ResourceLocation imageLocation = new ResourceLocation(field.parent().id().getNamespace(), path); + String extension = path.substring(path.lastIndexOf('.') + 1); + + switch (extension) { + case "png", "jpg", "jpeg" -> builder.image(imageLocation, imageOverride.width(), imageOverride.height()); + case "webp" -> builder.webpImage(imageLocation); + case "gif" -> builder.gifImage(imageLocation); + default -> throw new YACLAutoGenException("'%s': Invalid image extension '%s' on @OverrideImage. Expected: ('png','jpg','webp','gif')".formatted(field.access().name(), extension)); + } + } else { + throw new YACLAutoGenException("'%s': @OverrideImage has no value or factory class.".formatted(field.access().name())); + } + } else { + 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; 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 index ecd4157..6bde931 100644 --- 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 @@ -8,6 +8,9 @@ import dev.isxander.yacl3.config.v2.api.autogen.OverrideFormatter; import org.jetbrains.annotations.ApiStatus; import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; @ApiStatus.Internal public final class AutoGenUtils { @@ -31,4 +34,14 @@ public final class AutoGenUtils { } }); } + + public static <T> T constructNoArgsClass(Class<T> clazz, Supplier<String> constructorNotFoundConsumer, Supplier<String> constructorFailedConsumer) { + try { + return clazz.getConstructor().newInstance(); + } catch (NoSuchMethodException e) { + throw new YACLAutoGenException(constructorNotFoundConsumer.get(), e); + } catch (Exception e) { + throw new YACLAutoGenException(constructorFailedConsumer.get(), e); + } + } } diff --git a/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/EmptyCustomImageFactory.java b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/EmptyCustomImageFactory.java new file mode 100644 index 0000000..f6949e7 --- /dev/null +++ b/common/src/main/java/dev/isxander/yacl3/config/v2/impl/autogen/EmptyCustomImageFactory.java @@ -0,0 +1,17 @@ +package dev.isxander.yacl3.config.v2.impl.autogen; + +import dev.isxander.yacl3.config.v2.api.ConfigField; +import dev.isxander.yacl3.config.v2.api.autogen.OptionAccess; +import dev.isxander.yacl3.config.v2.api.autogen.OverrideImage; +import dev.isxander.yacl3.gui.ImageRenderer; + +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +public class EmptyCustomImageFactory implements OverrideImage.CustomImageFactory<Object> { + + @Override + public CompletableFuture<Optional<ImageRenderer>> createImage(Object value, ConfigField<Object> field, OptionAccess access) { + throw new IllegalStateException(); + } +} |