diff --git a/src/main/java/com/moulberry/mixinconstraints/annotations/IfDevEnvironment.java b/src/main/java/com/moulberry/mixinconstraints/annotations/IfDevEnvironment.java index 2a6912e..babb228 100644 --- a/src/main/java/com/moulberry/mixinconstraints/annotations/IfDevEnvironment.java +++ b/src/main/java/com/moulberry/mixinconstraints/annotations/IfDevEnvironment.java @@ -1,6 +1,7 @@ package com.moulberry.mixinconstraints.annotations; import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; diff --git a/src/main/java/com/moulberry/mixinconstraints/annotations/IfMinecraftVersion.java b/src/main/java/com/moulberry/mixinconstraints/annotations/IfMinecraftVersion.java index 03b3969..b813b59 100644 --- a/src/main/java/com/moulberry/mixinconstraints/annotations/IfMinecraftVersion.java +++ b/src/main/java/com/moulberry/mixinconstraints/annotations/IfMinecraftVersion.java @@ -1,6 +1,7 @@ package com.moulberry.mixinconstraints.annotations; import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; diff --git a/src/main/java/com/moulberry/mixinconstraints/annotations/IfModAbsent.java b/src/main/java/com/moulberry/mixinconstraints/annotations/IfModAbsent.java index 80e6c8f..7e024d6 100644 --- a/src/main/java/com/moulberry/mixinconstraints/annotations/IfModAbsent.java +++ b/src/main/java/com/moulberry/mixinconstraints/annotations/IfModAbsent.java @@ -1,10 +1,12 @@ package com.moulberry.mixinconstraints.annotations; import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +@Repeatable(IfModAbsents.class) @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) public @interface IfModAbsent { diff --git a/src/main/java/com/moulberry/mixinconstraints/annotations/IfModAbsents.java b/src/main/java/com/moulberry/mixinconstraints/annotations/IfModAbsents.java new file mode 100644 index 0000000..f970748 --- /dev/null +++ b/src/main/java/com/moulberry/mixinconstraints/annotations/IfModAbsents.java @@ -0,0 +1,14 @@ +package com.moulberry.mixinconstraints.annotations; + +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.TYPE, ElementType.FIELD, ElementType.METHOD}) +public @interface IfModAbsents { + + IfModAbsent[] value(); + +} diff --git a/src/main/java/com/moulberry/mixinconstraints/annotations/IfModLoaded.java b/src/main/java/com/moulberry/mixinconstraints/annotations/IfModLoaded.java index 1209a53..0f3d65a 100644 --- a/src/main/java/com/moulberry/mixinconstraints/annotations/IfModLoaded.java +++ b/src/main/java/com/moulberry/mixinconstraints/annotations/IfModLoaded.java @@ -1,10 +1,12 @@ package com.moulberry.mixinconstraints.annotations; import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +@Repeatable(IfModLoadeds.class) @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD}) public @interface IfModLoaded { diff --git a/src/main/java/com/moulberry/mixinconstraints/annotations/IfModLoadeds.java b/src/main/java/com/moulberry/mixinconstraints/annotations/IfModLoadeds.java new file mode 100644 index 0000000..57c4b96 --- /dev/null +++ b/src/main/java/com/moulberry/mixinconstraints/annotations/IfModLoadeds.java @@ -0,0 +1,14 @@ +package com.moulberry.mixinconstraints.annotations; + +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.TYPE, ElementType.FIELD, ElementType.METHOD}) +public @interface IfModLoadeds { + + IfModLoaded[] value(); + +} diff --git a/src/main/java/com/moulberry/mixinconstraints/checker/AnnotationChecker.java b/src/main/java/com/moulberry/mixinconstraints/checker/AnnotationChecker.java index 462cea5..c249384 100755 --- a/src/main/java/com/moulberry/mixinconstraints/checker/AnnotationChecker.java +++ b/src/main/java/com/moulberry/mixinconstraints/checker/AnnotationChecker.java @@ -4,18 +4,20 @@ import com.moulberry.mixinconstraints.annotations.IfDevEnvironment; import com.moulberry.mixinconstraints.annotations.IfMinecraftVersion; import com.moulberry.mixinconstraints.annotations.IfModAbsent; +import com.moulberry.mixinconstraints.annotations.IfModAbsents; import com.moulberry.mixinconstraints.annotations.IfModLoaded; -import org.jetbrains.annotations.ApiStatus; +import com.moulberry.mixinconstraints.annotations.IfModLoadeds; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AnnotationNode; import java.util.List; -@ApiStatus.Internal public class AnnotationChecker { private static final String IF_MOD_LOADED_DESC = Type.getDescriptor(IfModLoaded.class); + private static final String IF_MOD_LOADEDS_DESC = Type.getDescriptor(IfModLoadeds.class); private static final String IS_MOD_ABSENT_DESC = Type.getDescriptor(IfModAbsent.class); + private static final String IF_MOD_ABSENTS_DESC = Type.getDescriptor(IfModAbsents.class); private static final String IF_DEV_ENVIRONMENT_DESC = Type.getDescriptor(IfDevEnvironment.class); private static final String IF_MINECRAFT_VERSION_DESC = Type.getDescriptor(IfMinecraftVersion.class); @@ -24,7 +26,6 @@ public static boolean isConstraintAnnotationNode(AnnotationNode node) { IF_DEV_ENVIRONMENT_DESC.equals(node.desc) || IF_MINECRAFT_VERSION_DESC.equals(node.desc); } - @SuppressWarnings({"BooleanMethodIsAlwaysInverted", "DuplicatedCode"}) public static boolean checkAnnotationNode(AnnotationNode node) { if (IF_MOD_LOADED_DESC.equals(node.desc)) { @@ -43,6 +44,21 @@ public static boolean checkAnnotationNode(AnnotationNode node) { } return pass; + } else if (IF_MOD_LOADEDS_DESC.equals(node.desc)) { + List ifModLoadeds = getAnnotationValue(node, "value", List.of()); + for (IfModLoaded ifModLoaded : ifModLoadeds) { + boolean pass = ConstraintChecker.checkModLoaded(ifModLoaded.value(), List.of(ifModLoaded.aliases()), ifModLoaded.minVersion(), ifModLoaded.maxVersion()); + + if (MixinConstraints.VERBOSE) { + String result = pass ? "PASS" : "FAILED"; + MixinConstraints.LOGGER.info("@IfModLoaded(value={}, minVersion={}, maxVersion={}) {}", ifModLoaded.value(), ifModLoaded.minVersion(), ifModLoaded.maxVersion(), result); + } + + if (!pass) { + return false; + } + } + return true; } else if (IS_MOD_ABSENT_DESC.equals(node.desc)) { String value = getAnnotationValue(node, "value", ""); if (value.isEmpty()) throw new IllegalArgumentException("modid must not be empty"); @@ -59,6 +75,21 @@ public static boolean checkAnnotationNode(AnnotationNode node) { } return pass; + } else if (IF_MOD_ABSENTS_DESC.equals(node.desc)) { + List ifModAbsents = getAnnotationValue(node, "value", List.of()); + for (IfModAbsent ifModAbsent : ifModAbsents) { + boolean pass = ConstraintChecker.checkModAbsent(ifModAbsent.value(), List.of(ifModAbsent.aliases()), ifModAbsent.minVersion(), ifModAbsent.maxVersion()); + + if (MixinConstraints.VERBOSE) { + String result = pass ? "PASS" : "FAILED"; + MixinConstraints.LOGGER.info("@IfModAbsent(value={}, minVersion={}, maxVersion={}) {}", ifModAbsent.value(), ifModAbsent.minVersion(), ifModAbsent.maxVersion(), result); + } + + if (!pass) { + return false; + } + } + return true; } else if (IF_DEV_ENVIRONMENT_DESC.equals(node.desc)) { boolean negate = getAnnotationValue(node, "negate", false); diff --git a/src/main/java/com/moulberry/mixinconstraints/checker/ConstraintChecker.java b/src/main/java/com/moulberry/mixinconstraints/checker/ConstraintChecker.java index c3592f9..0acf540 100755 --- a/src/main/java/com/moulberry/mixinconstraints/checker/ConstraintChecker.java +++ b/src/main/java/com/moulberry/mixinconstraints/checker/ConstraintChecker.java @@ -1,9 +1,7 @@ package com.moulberry.mixinconstraints.checker; import com.moulberry.mixinconstraints.util.Abstractions; -import org.jetbrains.annotations.ApiStatus; -@ApiStatus.Internal public class ConstraintChecker { /** * Check if *ANY* of the modIds provided are loaded diff --git a/src/main/java/com/moulberry/mixinconstraints/util/MixinHacks.java b/src/main/java/com/moulberry/mixinconstraints/util/MixinHacks.java index e91a103..f97ad73 100644 --- a/src/main/java/com/moulberry/mixinconstraints/util/MixinHacks.java +++ b/src/main/java/com/moulberry/mixinconstraints/util/MixinHacks.java @@ -1,6 +1,5 @@ package com.moulberry.mixinconstraints.util; -import org.jetbrains.annotations.ApiStatus; import org.objectweb.asm.tree.*; import org.spongepowered.asm.mixin.MixinEnvironment; import org.spongepowered.asm.mixin.extensibility.IMixinInfo; @@ -23,7 +22,6 @@ * Most of this class is adapted from MixinExtras's {@code MixinInternals} class, by LlamaLad7. * MixinExtras is licensed under the MIT License: here. */ -@ApiStatus.Internal @SuppressWarnings("unchecked") public final class MixinHacks { private static final MethodHandle TARGET_CLASS_CONTEXT_MIXINS; @@ -90,7 +88,7 @@ public static List> getMixinsFor(ITargetClassContext } private static void addExtension(List extensions, IExtension newExtension) { - extensions.addFirst(newExtension); + extensions.add(0, newExtension); // If this runs before our extensions it will fail since we're not done generating our bytecode. List lateExtensions = new ArrayList<>();