diff --git a/minecraft/src/main/java/net/fabricmc/loader/impl/game/minecraft/patch/BrandingPatch.java b/minecraft/src/main/java/net/fabricmc/loader/impl/game/minecraft/patch/BrandingPatch.java index 977364956..7b0266745 100644 --- a/minecraft/src/main/java/net/fabricmc/loader/impl/game/minecraft/patch/BrandingPatch.java +++ b/minecraft/src/main/java/net/fabricmc/loader/impl/game/minecraft/patch/BrandingPatch.java @@ -20,7 +20,6 @@ import java.util.function.Consumer; import java.util.function.Function; -import org.objectweb.asm.ClassReader; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; @@ -35,12 +34,12 @@ public final class BrandingPatch extends GamePatch { @Override - public void process(FabricLauncher launcher, Function classSource, Consumer classEmitter) { + public void process(FabricLauncher launcher, Function classSource, Consumer classEmitter) { for (String brandClassName : new String[] { "net.minecraft.client.ClientBrandRetriever", "net.minecraft.server.MinecraftServer" }) { - ClassNode brandClass = readClass(classSource.apply(brandClassName)); + ClassNode brandClass = classSource.apply(brandClassName); if (brandClass != null) { if (applyBrandingPatch(brandClass)) { diff --git a/minecraft/src/main/java/net/fabricmc/loader/impl/game/minecraft/patch/EntrypointPatch.java b/minecraft/src/main/java/net/fabricmc/loader/impl/game/minecraft/patch/EntrypointPatch.java index 8858165dc..e697ffd77 100644 --- a/minecraft/src/main/java/net/fabricmc/loader/impl/game/minecraft/patch/EntrypointPatch.java +++ b/minecraft/src/main/java/net/fabricmc/loader/impl/game/minecraft/patch/EntrypointPatch.java @@ -21,7 +21,6 @@ import java.util.function.Consumer; import java.util.function.Function; -import org.objectweb.asm.ClassReader; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.AbstractInsnNode; @@ -62,7 +61,7 @@ private void finishEntrypoint(EnvType type, ListIterator it) { } @Override - public void process(FabricLauncher launcher, Function classSource, Consumer classEmitter) { + public void process(FabricLauncher launcher, Function classSource, Consumer classEmitter) { EnvType type = launcher.getEnvironmentType(); String entrypoint = launcher.getEntrypoint(); Version gameVersion = getGameVersion(); @@ -74,7 +73,7 @@ public void process(FabricLauncher launcher, Function class String gameEntrypoint = null; boolean serverHasFile = true; boolean isApplet = entrypoint.contains("Applet"); - ClassNode mainClass = readClass(classSource.apply(entrypoint)); + ClassNode mainClass = classSource.apply(entrypoint); if (mainClass == null) { throw new RuntimeException("Could not load main class " + entrypoint + "!"); @@ -189,7 +188,7 @@ public void process(FabricLauncher launcher, Function class if (gameEntrypoint.equals(entrypoint) || is20w22aServerOrHigher) { gameClass = mainClass; } else { - gameClass = readClass(classSource.apply(gameEntrypoint)); + gameClass = classSource.apply(gameEntrypoint); if (gameClass == null) throw new RuntimeException("Could not load game class " + gameEntrypoint + "!"); } @@ -527,22 +526,22 @@ public void process(FabricLauncher launcher, Function class } } - private boolean hasSuperClass(String cls, String superCls, Function classSource) { + private boolean hasSuperClass(String cls, String superCls, Function classSource) { if (cls.contains("$") || (!cls.startsWith("net/minecraft") && cls.contains("/"))) { return false; } - ClassReader reader = classSource.apply(cls); + ClassNode classNode = classSource.apply(cls); - return reader != null && reader.getSuperName().equals(superCls); + return classNode != null && classNode.superName.equals(superCls); } - private boolean hasStrInMethod(String cls, String methodName, String methodDesc, String str, Function classSource) { + private boolean hasStrInMethod(String cls, String methodName, String methodDesc, String str, Function classSource) { if (cls.contains("$") || (!cls.startsWith("net/minecraft") && cls.contains("/"))) { return false; } - ClassNode node = readClass(classSource.apply(cls)); + ClassNode node = classSource.apply(cls); if (node == null) return false; for (MethodNode method : node.methods) { diff --git a/minecraft/src/main/java/net/fabricmc/loader/impl/game/minecraft/patch/EntrypointPatchFML125.java b/minecraft/src/main/java/net/fabricmc/loader/impl/game/minecraft/patch/EntrypointPatchFML125.java index bed7cfeac..24e36d041 100644 --- a/minecraft/src/main/java/net/fabricmc/loader/impl/game/minecraft/patch/EntrypointPatchFML125.java +++ b/minecraft/src/main/java/net/fabricmc/loader/impl/game/minecraft/patch/EntrypointPatchFML125.java @@ -40,7 +40,7 @@ public class EntrypointPatchFML125 extends GamePatch { private static final String TO_INTERNAL = "cpw/mods/fml/common/ModClassLoader"; @Override - public void process(FabricLauncher launcher, Function classSource, Consumer classEmitter) { + public void process(FabricLauncher launcher, Function classSource, Consumer classEmitter) { if (classSource.apply(TO) != null && classSource.apply("cpw.mods.fml.relauncher.FMLRelauncher") == null) { if (!(launcher instanceof Knot)) { diff --git a/minecraft/src/main/java/net/fabricmc/loader/impl/game/minecraft/patch/TinyFDPatch.java b/minecraft/src/main/java/net/fabricmc/loader/impl/game/minecraft/patch/TinyFDPatch.java index 37dc8b4e0..4c00555fa 100644 --- a/minecraft/src/main/java/net/fabricmc/loader/impl/game/minecraft/patch/TinyFDPatch.java +++ b/minecraft/src/main/java/net/fabricmc/loader/impl/game/minecraft/patch/TinyFDPatch.java @@ -20,7 +20,6 @@ import java.util.function.Consumer; import java.util.function.Function; -import org.objectweb.asm.ClassReader; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; @@ -47,7 +46,7 @@ public final class TinyFDPatch extends GamePatch { private static final String DIALOG_TITLE = "Select settings file (.json)"; @Override - public void process(FabricLauncher launcher, Function classSource, Consumer classEmitter) { + public void process(FabricLauncher launcher, Function classSource, Consumer classEmitter) { if (launcher.getEnvironmentType() != EnvType.CLIENT) { // Fix should only be applied to clients. return; @@ -61,7 +60,7 @@ public void process(FabricLauncher launcher, Function class className = FabricLoader.getInstance().getMappingResolver().mapClassName("intermediary", MORE_OPTIONS_DIALOG_CLASS_NAME); } - final ClassNode classNode = readClass(classSource.apply(className)); + final ClassNode classNode = classSource.apply(className); if (classNode == null) { // Class is not present in this version, nothing to do. diff --git a/src/main/java/net/fabricmc/loader/impl/game/patch/GamePatch.java b/src/main/java/net/fabricmc/loader/impl/game/patch/GamePatch.java index f31562bbf..9eefe5d09 100644 --- a/src/main/java/net/fabricmc/loader/impl/game/patch/GamePatch.java +++ b/src/main/java/net/fabricmc/loader/impl/game/patch/GamePatch.java @@ -23,7 +23,6 @@ import java.util.function.Predicate; import java.util.stream.Collectors; -import org.objectweb.asm.ClassReader; import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; @@ -33,14 +32,6 @@ import net.fabricmc.loader.impl.launch.FabricLauncher; public abstract class GamePatch { - protected static ClassNode readClass(ClassReader reader) { - if (reader == null) return null; - - ClassNode node = new ClassNode(); - reader.accept(node, 0); - return node; - } - protected FieldNode findField(ClassNode node, Predicate predicate) { return node.fields.stream().filter(predicate).findAny().orElse(null); } @@ -128,5 +119,5 @@ protected boolean isPublicInstance(int access) { return ((access & 0x0F) == (Opcodes.ACC_PUBLIC | 0 /* non-static */)); } - public abstract void process(FabricLauncher launcher, Function classSource, Consumer classEmitter); + public abstract void process(FabricLauncher launcher, Function classSource, Consumer classEmitter); } diff --git a/src/main/java/net/fabricmc/loader/impl/game/patch/GameTransformer.java b/src/main/java/net/fabricmc/loader/impl/game/patch/GameTransformer.java index 0a06710c6..ee9dd362b 100644 --- a/src/main/java/net/fabricmc/loader/impl/game/patch/GameTransformer.java +++ b/src/main/java/net/fabricmc/loader/impl/game/patch/GameTransformer.java @@ -67,29 +67,23 @@ public void locateEntrypoints(FabricLauncher launcher, List gameJars) { patchedClasses = new HashMap<>(); try (SimpleClassPath cp = new SimpleClassPath(gameJars)) { - Function classSource = name -> { - byte[] data = patchedClasses.get(name); + Map patchedClassNodes = new HashMap<>(); - if (data != null) { - return new ClassReader(data); + final Function classSource = name -> { + // Reuse previously patched classes if available + if (patchedClassNodes.containsKey(name)) { + return patchedClassNodes.get(name); } - try { - CpEntry entry = cp.getEntry(LoaderUtil.getClassFileName(name)); - if (entry == null) return null; - - try (InputStream is = entry.getInputStream()) { - return new ClassReader(is); - } catch (IOException | ZipError e) { - throw new RuntimeException(String.format("error reading %s in %s: %s", name, LoaderUtil.normalizePath(entry.getOrigin()), e), e); - } - } catch (IOException e) { - throw ExceptionUtil.wrap(e); - } + return readClassNode(cp, name); }; for (GamePatch patch : patches) { - patch.process(launcher, classSource, this::addPatchedClass); + patch.process(launcher, classSource, classNode -> patchedClassNodes.put(classNode.name, classNode)); + } + + for (ClassNode patchedClassNode : patchedClassNodes.values()) { + addPatchedClass(patchedClassNode); } } catch (IOException e) { throw ExceptionUtil.wrap(e); @@ -99,6 +93,27 @@ public void locateEntrypoints(FabricLauncher launcher, List gameJars) { entrypointsLocated = true; } + private ClassNode readClassNode(SimpleClassPath classpath, String name) { + byte[] data = patchedClasses.get(name); + + if (data != null) { + return readClass(new ClassReader(data)); + } + + try { + CpEntry entry = classpath.getEntry(LoaderUtil.getClassFileName(name)); + if (entry == null) return null; + + try (InputStream is = entry.getInputStream()) { + return readClass(new ClassReader(is)); + } catch (IOException | ZipError e) { + throw new RuntimeException(String.format("error reading %s in %s: %s", name, LoaderUtil.normalizePath(entry.getOrigin()), e), e); + } + } catch (IOException e) { + throw ExceptionUtil.wrap(e); + } + } + /** * This must run first, contractually! * @param className The class name, @@ -107,4 +122,12 @@ public void locateEntrypoints(FabricLauncher launcher, List gameJars) { public byte[] transform(String className) { return patchedClasses.get(className); } + + private static ClassNode readClass(ClassReader reader) { + if (reader == null) return null; + + ClassNode node = new ClassNode(); + reader.accept(node, 0); + return node; + } }