diff --git a/src/main/java/dev/su5ed/sinytra/connector/locator/ConnectorLocator.java b/src/main/java/dev/su5ed/sinytra/connector/locator/ConnectorLocator.java index ae519a56..da30ef5e 100644 --- a/src/main/java/dev/su5ed/sinytra/connector/locator/ConnectorLocator.java +++ b/src/main/java/dev/su5ed/sinytra/connector/locator/ConnectorLocator.java @@ -9,7 +9,6 @@ import dev.su5ed.sinytra.connector.loader.ConnectorEarlyLoader; import dev.su5ed.sinytra.connector.loader.ConnectorLoaderModMetadata; import dev.su5ed.sinytra.connector.transformer.jar.JarTransformer; -import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.impl.metadata.NestedJarEntry; import net.minecraftforge.fml.loading.ClasspathLocatorUtils; import net.minecraftforge.fml.loading.EarlyLoadingException; @@ -135,7 +134,7 @@ private List locateFabricMods(Iterable discoveredMods) { Collection ignoredModFiles = new ArrayList<>(); // Remove mods loaded by FML List uniqueJars = handleDuplicateMods(discoveredJars, discoveredNestedJars, loadedModInfos, ignoredModFiles); - // Ensure we have all required dependencies before transforming + // Ensure we have all required dependencies before transforming, remove side-only mods List candidates = DependencyResolver.resolveDependencies(uniqueJars, parentToChildren, loadedModFiles); // Get renamer library classpath List renameLibs = loadedModFiles.stream().map(modFile -> modFile.getSecureJar().getRootPath()).toList(); @@ -318,7 +317,6 @@ private static List handleDuplicateMods(List loadedModIds) { - if (!metadata.loadsInEnvironment(FabricLoader.getInstance().getEnvironmentType())) return true; String id = metadata.getId(); return ConnectorUtil.DISABLED_MODS.contains(id) || loadedModIds.contains(id); } diff --git a/src/main/java/dev/su5ed/sinytra/connector/locator/DependencyResolver.java b/src/main/java/dev/su5ed/sinytra/connector/locator/DependencyResolver.java index 52ca5953..ffe3827e 100644 --- a/src/main/java/dev/su5ed/sinytra/connector/locator/DependencyResolver.java +++ b/src/main/java/dev/su5ed/sinytra/connector/locator/DependencyResolver.java @@ -69,6 +69,7 @@ public static List resolveDependencies(Collecti List candidateJars = resolved.stream() .map(jarToCandidate.inverse()::get) .filter(Objects::nonNull) + .filter(jar -> jar.modPath().metadata().modMetadata().loadsInEnvironment(envType)) .toList(); LOGGER.info("Dependency resolution found {} candidates to load", candidateJars.size()); return candidateJars; diff --git a/src/main/java/dev/su5ed/sinytra/connector/transformer/patch/EnvironmentStripperTransformer.java b/src/main/java/dev/su5ed/sinytra/connector/transformer/patch/EnvironmentStripperTransformer.java index 87d82b83..6ab196bb 100644 --- a/src/main/java/dev/su5ed/sinytra/connector/transformer/patch/EnvironmentStripperTransformer.java +++ b/src/main/java/dev/su5ed/sinytra/connector/transformer/patch/EnvironmentStripperTransformer.java @@ -1,11 +1,9 @@ package dev.su5ed.sinytra.connector.transformer.patch; -import org.sinytra.adapter.patch.api.ClassTransform; -import org.sinytra.adapter.patch.api.Patch; -import org.sinytra.adapter.patch.api.PatchContext; -import org.sinytra.adapter.patch.selector.AnnotationValueHandle; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import net.fabricmc.api.EnvironmentInterface; +import net.fabricmc.api.EnvironmentInterfaces; import net.fabricmc.loader.api.FabricLoader; import org.jetbrains.annotations.Nullable; import org.objectweb.asm.Handle; @@ -16,6 +14,11 @@ import org.objectweb.asm.tree.FieldNode; import org.objectweb.asm.tree.InvokeDynamicInsnNode; import org.objectweb.asm.tree.MethodNode; +import org.sinytra.adapter.patch.api.ClassTransform; +import org.sinytra.adapter.patch.api.Patch; +import org.sinytra.adapter.patch.api.PatchContext; +import org.sinytra.adapter.patch.selector.AnnotationHandle; +import org.sinytra.adapter.patch.selector.AnnotationValueHandle; import java.util.ArrayList; import java.util.Iterator; @@ -23,12 +26,15 @@ public class EnvironmentStripperTransformer implements ClassTransform { private static final String ENVIRONMENT_ANNOTATION = Type.getDescriptor(Environment.class); + private static final String ENVIRONMENT_INTERFACE_DESCRIPTOR = Type.getDescriptor(EnvironmentInterface.class); + private static final String ENVIRONMENT_INTERFACES_DESCRIPTOR = Type.getDescriptor(EnvironmentInterfaces.class); private static final EnvType CURRENT_ENV = FabricLoader.getInstance().getEnvironmentType(); private static final String LAMBDA_PREFIX = "lambda$"; @Override public Patch.Result apply(ClassNode classNode, @Nullable AnnotationValueHandle annotation, PatchContext context) { - boolean applied = false; + boolean applied = stripEnvironmentInterface(classNode.interfaces, classNode.invisibleAnnotations); + List removeMethods = new ArrayList<>(); for (MethodNode method : classNode.methods) { if (remove(method.invisibleAnnotations)) { @@ -71,6 +77,40 @@ private static List getMethodLambdas(ClassNode cls, MethodNode metho return list; } + private static boolean stripEnvironmentInterface(List interfaces, @Nullable List annotations) { + if (annotations != null) { + boolean removed = false; + for (AnnotationNode annotation : annotations) { + if (ENVIRONMENT_INTERFACE_DESCRIPTOR.equals(annotation.desc) && stripInterface(interfaces, new AnnotationHandle(annotation)) + || ENVIRONMENT_INTERFACES_DESCRIPTOR.equals(annotation.desc) && stripInterfaces(interfaces, new AnnotationHandle(annotation)) + ) { + removed = true; + } + } + return removed; + } + return false; + } + + private static boolean stripInterfaces(List interfaces, AnnotationHandle handle) { + boolean removed = false; + List annotations = handle.>getValue("value").map(AnnotationValueHandle::get).orElse(List.of()); + for (AnnotationNode annotation : annotations) { + removed |= stripInterface(interfaces, new AnnotationHandle(annotation)); + } + return removed; + } + + private static boolean stripInterface(List interfaces, AnnotationHandle handle) { + boolean strip = handle.getValue("value").map(h -> readEnvType(h.get()) != CURRENT_ENV).orElse(false); + if (strip) { + Type itf = handle.getValue("itf").orElseThrow().get(); + interfaces.remove(itf.getInternalName()); + return true; + } + return false; + } + // We strip annotations ahead of time to avoid class resolution issues leading to CNFEs private static boolean remove(@Nullable List annotations) { if (annotations != null) { @@ -88,11 +128,15 @@ private static boolean remove(AnnotationNode node) { throw new IllegalArgumentException("Unexpected " + node.values.size() + " values for annotation " + node.desc); } String[] args = (String[]) node.values.get(1); + EnvType type = readEnvType(args); + return CURRENT_ENV != type; + } + + private static EnvType readEnvType(String[] args) { if (args.length != 2) { - throw new IllegalArgumentException("Unexpected size of annotation value array" + args.length + " for " + node.desc); + throw new IllegalArgumentException("Unexpected size of annotation value array" + args.length); } String side = args[1]; - EnvType type = EnvType.valueOf(side); - return CURRENT_ENV != type; + return EnvType.valueOf(side); } }