diff --git a/src/main/java/org/violetmoon/zeta/annotation/ConditionalMixin.java b/src/main/java/org/violetmoon/zeta/annotation/ConditionalMixin.java new file mode 100644 index 0000000..ac01826 --- /dev/null +++ b/src/main/java/org/violetmoon/zeta/annotation/ConditionalMixin.java @@ -0,0 +1,23 @@ +package org.violetmoon.zeta.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Make a mixin depend on conditions to work + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface ConditionalMixin { + /** + * Only load mixin if requirements are fulfilled + */ + Requirement[] require() default {}; + + /** + * Don't load mixin if any of the requirements are fulfilled, higher priority then require + */ + Requirement[] conflict() default {}; +} diff --git a/src/main/java/org/violetmoon/zeta/annotation/Requirement.java b/src/main/java/org/violetmoon/zeta/annotation/Requirement.java new file mode 100644 index 0000000..a0a9dd0 --- /dev/null +++ b/src/main/java/org/violetmoon/zeta/annotation/Requirement.java @@ -0,0 +1,22 @@ +package org.violetmoon.zeta.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface Requirement { + /** + * List of mod-id's + */ + String[] value(); + + /** + * Versions | Doesnt work yet + */ + String[] versionPredicates() default {}; + + /** + * if true, then mixin is applied when x mod is present otherwise not + */ + boolean applyIfPresent() default true; +} diff --git a/src/main/java/org/violetmoon/zeta/api/ConditionalMixinManager.java b/src/main/java/org/violetmoon/zeta/api/ConditionalMixinManager.java new file mode 100644 index 0000000..6b2871c --- /dev/null +++ b/src/main/java/org/violetmoon/zeta/api/ConditionalMixinManager.java @@ -0,0 +1,50 @@ +package org.violetmoon.zeta.api; + +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AnnotationNode; +import org.spongepowered.asm.service.MixinService; +import org.spongepowered.asm.util.Annotations; +import org.violetmoon.zeta.Zeta; +import org.violetmoon.zeta.annotation.ConditionalMixin; +import org.violetmoon.zeta.annotation.Requirement; + +import java.io.IOException; +import java.util.List; + +public class ConditionalMixinManager { + public static boolean shouldApply(Zeta zeta, String targetClassName, String mixinClassName) { + try { + List annotationNodes = MixinService.getService().getBytecodeProvider().getClassNode(targetClassName).visibleAnnotations; + if (annotationNodes == null) return true; + + boolean shouldApply = true; + for (AnnotationNode node : annotationNodes) { + if (node.desc.equals(Type.getDescriptor(ConditionalMixin.class))) { + List requirements = Annotations.getValue(node, "require", Requirement.class); + for (Requirement req : requirements) { + String[] modids = req.value(); + boolean applyIfPresent = req.applyIfPresent(); + + boolean areModsLoaded = areModsLoaded(zeta, modids); + + shouldApply = areModsLoaded == applyIfPresent; + Zeta.GLOBAL_LOG.info("{}: {} is{}being applied because the mod(s) {} are{}loaded", zeta.modid, targetClassName, shouldApply ? " " : " not ", modids, areModsLoaded ? " " : " not "); + } + } + } + + return shouldApply; + } catch (IOException | ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + private static boolean areModsLoaded(Zeta zeta, String[] modids) { + for (String mod : modids) { + if (zeta.isModLoaded(mod)) { + return true; + } + } + return false; + } +}