package io.gitlab.jfronny.libjf.unsafe.asm; import io.gitlab.jfronny.libjf.LibJf; import io.gitlab.jfronny.libjf.unsafe.asm.patch.Patch; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.MappingResolver; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.tree.ClassNode; import org.spongepowered.asm.mixin.MixinEnvironment; import org.spongepowered.asm.mixin.transformer.IMixinTransformer; import org.spongepowered.asm.mixin.transformer.ext.IExtensionRegistry; import org.spongepowered.asm.transformers.MixinClassWriter; import java.util.List; import java.util.Set; public class AsmTransformer implements IMixinTransformer { public static AsmTransformer INSTANCE; public static final MappingResolver MAPPING_RESOLVER = FabricLoader.getInstance().getMappingResolver(); public static final String INTERMEDIARY = "intermediary"; public IMixinTransformer delegate; public Set asmConfigs; private AsmConfig currentConfig = null; @Override public void audit(MixinEnvironment environment) { delegate.audit(environment); } @Override public List reload(String mixinClass, ClassNode classNode) { return delegate.reload(mixinClass, classNode); } @Override public boolean computeFramesForClass(MixinEnvironment environment, String name, ClassNode classNode) { return delegate.computeFramesForClass(environment, name, classNode); } @Override public byte[] transformClassBytes(String name, String transformedName, byte[] classBytes) { classBytes = delegate.transformClassBytes(name, transformedName, classBytes); if (classBytes == null || name == null) return classBytes; if (isClassUnmoddable(name, null)) { if (LibJf.DEV) LibJf.LOGGER.info("Skipping " + name); return classBytes; } ClassNode klazz = new ClassNode(); ClassReader reader = new ClassReader(classBytes); reader.accept(klazz, ClassReader.EXPAND_FRAMES); //ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG //if ((klazz.access & Opcodes.ACC_INTERFACE) != 0) { // return classBytes; //} for (AsmConfig config : asmConfigs) { currentConfig = config; if (!isClassUnmoddable(name, config)) { for (Patch patch : config.getPatches()) { patch.apply(klazz); } } } currentConfig = null; ClassWriter writer = new MixinClassWriter(reader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); try { klazz.accept(writer); } catch (NullPointerException t) { LibJf.LOGGER.error("Could not transform " + transformedName, t); return null; } classBytes = writer.toByteArray(); //MixinEnvironment.getCurrentEnvironment(); return classBytes; } @Override public byte[] transformClass(MixinEnvironment environment, String name, byte[] classBytes) { LibJf.LOGGER.error("transformClass called"); return delegate.transformClass(environment, name, classBytes); } @Override public boolean transformClass(MixinEnvironment environment, String name, ClassNode classNode) { LibJf.LOGGER.error("transformClass called"); return delegate.transformClass(environment, name, classNode); } @Override public byte[] generateClass(MixinEnvironment environment, String name) { LibJf.LOGGER.error("generateClass called"); return delegate.generateClass(environment, name); } @Override public boolean generateClass(MixinEnvironment environment, String name, ClassNode classNode) { LibJf.LOGGER.error("generateClass called"); return delegate.generateClass(environment, name, classNode); } @Override public IExtensionRegistry getExtensions() { return delegate.getExtensions(); } public static boolean isClassUnmoddable(String className, AsmConfig config) { if (className.replace('/', '.').startsWith("org.objectweb.asm") //|| className.startsWith("net.fabricmc.loader") //|| className.startsWith("io.gitlab.jfronny.libjf.unsafe.asm") ) return true; if (config == null) return false; Set classes = config.skipClasses(); if (classes == null) return false; return classes.contains(MAPPING_RESOLVER.unmapClassName(INTERMEDIARY, className)); } public AsmConfig getCurrentConfig() { return currentConfig; } }