Skip to content

Commit

Permalink
Add support for stripping environment interfaces
Browse files Browse the repository at this point in the history
Fixes #991
  • Loading branch information
Su5eD committed Apr 8, 2024
1 parent 34d6206 commit 96cdbd4
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -135,7 +134,7 @@ private List<IModFile> locateFabricMods(Iterable<IModFile> discoveredMods) {
Collection<? super IModFile> ignoredModFiles = new ArrayList<>();
// Remove mods loaded by FML
List<JarTransformer.TransformableJar> 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<JarTransformer.TransformableJar> candidates = DependencyResolver.resolveDependencies(uniqueJars, parentToChildren, loadedModFiles);
// Get renamer library classpath
List<Path> renameLibs = loadedModFiles.stream().map(modFile -> modFile.getSecureJar().getRootPath()).toList();
Expand Down Expand Up @@ -318,7 +317,6 @@ private static List<JarTransformer.TransformableJar> handleDuplicateMods(List<Ja
}

private static boolean shouldIgnoreMod(ConnectorLoaderModMetadata metadata, Collection<String> loadedModIds) {
if (!metadata.loadsInEnvironment(FabricLoader.getInstance().getEnvironmentType())) return true;
String id = metadata.getId();
return ConnectorUtil.DISABLED_MODS.contains(id) || loadedModIds.contains(id);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public static List<JarTransformer.TransformableJar> resolveDependencies(Collecti
List<JarTransformer.TransformableJar> 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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -16,19 +14,27 @@
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;
import java.util.List;

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<MethodNode> removeMethods = new ArrayList<>();
for (MethodNode method : classNode.methods) {
if (remove(method.invisibleAnnotations)) {
Expand Down Expand Up @@ -71,6 +77,40 @@ private static List<MethodNode> getMethodLambdas(ClassNode cls, MethodNode metho
return list;
}

private static boolean stripEnvironmentInterface(List<String> interfaces, @Nullable List<AnnotationNode> 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<String> interfaces, AnnotationHandle handle) {
boolean removed = false;
List<AnnotationNode> annotations = handle.<List<AnnotationNode>>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<String> interfaces, AnnotationHandle handle) {
boolean strip = handle.<String[]>getValue("value").map(h -> readEnvType(h.get()) != CURRENT_ENV).orElse(false);
if (strip) {
Type itf = handle.<Type>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<AnnotationNode> annotations) {
if (annotations != null) {
Expand All @@ -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);
}
}

0 comments on commit 96cdbd4

Please sign in to comment.