LibJF/libjf-unsafe-v0/src/main/java/io/gitlab/jfronny/libjf/unsafe/asm/AsmTransformer.java

165 lines
6.0 KiB
Java
Raw Normal View History

2021-09-27 20:55:48 +02:00
package io.gitlab.jfronny.libjf.unsafe.asm;
import io.gitlab.jfronny.libjf.Flags;
import io.gitlab.jfronny.libjf.LibJf;
2021-09-27 20:55:48 +02:00
import io.gitlab.jfronny.libjf.unsafe.asm.patch.Patch;
2021-09-29 18:52:43 +02:00
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.MappingResolver;
2021-09-27 20:55:48 +02:00
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode;
2021-10-06 19:01:48 +02:00
import org.spongepowered.asm.mixin.MixinEnvironment;
import org.spongepowered.asm.mixin.transformer.IMixinTransformer;
import org.spongepowered.asm.mixin.transformer.ext.IExtensionRegistry;
2021-09-27 20:55:48 +02:00
import org.spongepowered.asm.transformers.MixinClassWriter;
2021-10-16 14:45:52 +02:00
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
2023-03-11 21:24:59 +01:00
import java.util.*;
2021-09-29 18:52:43 +02:00
2021-10-06 19:01:48 +02:00
public class AsmTransformer implements IMixinTransformer {
2021-09-29 18:52:43 +02:00
public static AsmTransformer INSTANCE;
public static final MappingResolver MAPPING_RESOLVER = FabricLoader.getInstance().getMappingResolver();
public static final String INTERMEDIARY = "intermediary";
2021-10-06 19:01:48 +02:00
public IMixinTransformer delegate;
2021-10-16 14:45:52 +02:00
public Set<BakedAsmConfig> asmConfigs;
2021-09-29 18:52:43 +02:00
private AsmConfig currentConfig = null;
2021-10-16 14:45:52 +02:00
private boolean export;
private boolean debugLog;
2021-10-16 14:45:52 +02:00
public void init() {
Set<Flags.BooleanFlag> flags = Flags.getBoolFlags("asm.export");
flags.removeIf(flag -> !flag.value());
export = !flags.isEmpty();
2021-10-16 14:45:52 +02:00
if (export) {
Set<String> flagNames = new LinkedHashSet<>();
for (Flags.BooleanFlag flag : flags) {
flagNames.add(flag.source());
}
LibJf.LOGGER.info("Exporting ASM due to: " + String.join(", ", flagNames));
}
flags = Flags.getBoolFlags("asm.log");
flags.removeIf(flag -> !flag.value());
debugLog = !flags.isEmpty();
if (debugLog) {
Set<String> flagNames = new LinkedHashSet<>();
for (Flags.BooleanFlag flag : flags) {
flagNames.add(flag.source());
}
LibJf.LOGGER.info("Logging ASM logs due to: " + String.join(", ", flagNames));
2021-10-16 14:45:52 +02:00
}
}
2021-09-27 20:55:48 +02:00
public boolean debugLogsEnabled() {
return debugLog;
}
2021-10-06 19:01:48 +02:00
@Override
public void audit(MixinEnvironment environment) {
delegate.audit(environment);
}
@Override
public List<String> 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);
}
2021-09-27 20:55:48 +02:00
@Override
2021-09-28 20:31:54 +02:00
public byte[] transformClassBytes(String name, String transformedName, byte[] classBytes) {
classBytes = delegate.transformClassBytes(name, transformedName, classBytes);
2021-12-29 23:25:28 +01:00
if (classBytes == null || name == null) return classBytes;
if (isClassUnmoddable(name, null)) {
if (debugLogsEnabled()) LibJf.LOGGER.info("Skipping " + name);
2021-09-28 20:31:54 +02:00
return classBytes;
}
2021-09-27 20:55:48 +02:00
2021-09-29 18:52:43 +02:00
ClassNode klazz = new ClassNode();
2021-09-28 20:31:54 +02:00
ClassReader reader = new ClassReader(classBytes);
2021-12-29 23:25:28 +01:00
reader.accept(klazz, ClassReader.EXPAND_FRAMES);
2021-09-29 18:52:43 +02:00
for (AsmConfig config : asmConfigs) {
currentConfig = config;
if (!isClassUnmoddable(name, config)) {
for (Patch patch : config.getPatches()) {
2021-12-29 23:25:28 +01:00
try {
patch.apply(klazz);
}
catch (Throwable t) {
LibJf.LOGGER.error("Could not apply patch: " + patch.getClass() + " on " + name, t);
2021-12-29 23:25:28 +01:00
}
2021-09-29 18:52:43 +02:00
}
}
2021-09-27 20:55:48 +02:00
}
2021-09-29 18:52:43 +02:00
currentConfig = null;
2021-09-27 20:55:48 +02:00
2021-12-29 23:25:28 +01:00
ClassWriter writer = new MixinClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
2021-09-29 18:52:43 +02:00
try {
klazz.accept(writer);
}
catch (NullPointerException t) {
LibJf.LOGGER.error("Could not transform " + transformedName, t);
2021-09-29 18:52:43 +02:00
return null;
}
2021-09-28 20:31:54 +02:00
classBytes = writer.toByteArray();
2021-10-16 14:45:52 +02:00
if (export) {
try {
Path path = FabricLoader.getInstance().getGameDir().resolve("libjf").resolve("asm").resolve(name.replace('.', '/') + ".class");
if (!Files.exists(path)) Files.createDirectories(path.getParent());
Files.write(path, classBytes);
} catch (IOException e) {
LibJf.LOGGER.error("Could not export modified bytecode", e);
2021-10-16 14:45:52 +02:00
}
}
2021-09-29 18:52:43 +02:00
return classBytes;
}
2021-10-06 19:01:48 +02:00
@Override
public byte[] transformClass(MixinEnvironment environment, String name, byte[] classBytes) {
return delegate.transformClass(environment, name, classBytes);
}
@Override
public boolean transformClass(MixinEnvironment environment, String name, ClassNode classNode) {
return delegate.transformClass(environment, name, classNode);
}
@Override
public byte[] generateClass(MixinEnvironment environment, String name) {
return delegate.generateClass(environment, name);
}
@Override
public boolean generateClass(MixinEnvironment environment, String name, ClassNode classNode) {
return delegate.generateClass(environment, name, classNode);
}
@Override
public IExtensionRegistry getExtensions() {
return delegate.getExtensions();
}
public static boolean isClassUnmoddable(String className, AsmConfig config) {
2021-12-29 23:25:28 +01:00
className = className.replace('/', '.');
if (className.startsWith("org.objectweb.asm")
|| className.startsWith("org.spongepowered.asm")
2021-09-29 18:52:43 +02:00
//|| className.startsWith("net.fabricmc.loader")
//|| className.startsWith("io.gitlab.jfronny.libjf.unsafe.asm")
)
return true;
if (config == null) return false;
Set<String> classes = config.skipClasses();
if (classes == null) return false;
return classes.contains(MAPPING_RESOLVER.unmapClassName(INTERMEDIARY, className));
}
public AsmConfig getCurrentConfig() {
return currentConfig;
2021-09-27 20:55:48 +02:00
}
}