mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-06-17 14:21:08 +00:00
Fabric/Quilt fertilization support
This commit is contained in:
@@ -11,6 +11,11 @@ dependencies {
|
||||
annotationProcessor("net.fabricmc:sponge-mixin:${Versions.Mod.mixin}")
|
||||
annotationProcessor("dev.architectury:architectury-loom:${Versions.Mod.architecuryLoom}")
|
||||
|
||||
modImplementation("com.github.the-glitch-network:minecraft-gudasm:${Versions.Mod.minecraftGudAsm}") {
|
||||
exclude("net.fabricmc")
|
||||
exclude("net.fabricmc.fabric-api")
|
||||
}
|
||||
|
||||
implementation(project(path = ":platforms:mixin-common", configuration = "namedElements")) { isTransitive = false }
|
||||
|
||||
minecraft("com.mojang:minecraft:${Versions.Mod.minecraft}")
|
||||
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
package com.dfsek.terra.lifecycle.asm;
|
||||
|
||||
import com.dfsek.terra.mod.util.FertilizableUtil;
|
||||
|
||||
import net.gudenau.minecraft.asm.api.v1.Identifier;
|
||||
import net.gudenau.minecraft.asm.api.v1.Transformer;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.InsnList;
|
||||
import org.objectweb.asm.tree.InsnNode;
|
||||
import org.objectweb.asm.tree.JumpInsnNode;
|
||||
import org.objectweb.asm.tree.LabelNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.dfsek.terra.lifecycle.util.ASMUtil;
|
||||
import com.dfsek.terra.lifecycle.util.LoaderUtil;
|
||||
|
||||
import org.objectweb.asm.tree.VarInsnNode;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.ACC_STATIC;
|
||||
|
||||
|
||||
public class FertilizableASM implements Transformer {
|
||||
|
||||
private static String fertilizableClassName = LoaderUtil.INSTANCE.mapClassName("intermediary", "net.minecraft.class_2256");
|
||||
|
||||
private static String fertilizableGrowMethodSignatureBase = String.format("(L%1$s;L%2$s;L%3$s;L%4$s;)",
|
||||
LoaderUtil.INSTANCE.mapClassName("intermediary", "net.minecraft.class_3218").replace(".", "/"),
|
||||
LoaderUtil.INSTANCE.mapClassName("intermediary", "net.minecraft.class_5819").replace(".", "/"),
|
||||
LoaderUtil.INSTANCE.mapClassName("intermediary", "net.minecraft.class_2338").replace(".", "/"),
|
||||
LoaderUtil.INSTANCE.mapClassName("intermediary", "net.minecraft.class_2680").replace(".", "/"));
|
||||
|
||||
private static String fertilizableGrowMethodSignature = fertilizableGrowMethodSignatureBase + "V";
|
||||
|
||||
private static String fertilizableGrowMethodName = LoaderUtil.INSTANCE.mapMethodName("intermediary", "net.minecraft.class_2256", "method_9652", "(Lnet/minecraft/class_3218;Lnet/minecraft/class_5819;Lnet/minecraft/class_2338;Lnet/minecraft/class_2680;)V");
|
||||
|
||||
@Override
|
||||
public Identifier getName() {
|
||||
return new Identifier("terra", "asm_test");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handlesClass(String name, String transformedName) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean transform(ClassNode classNode, Flags flags) {
|
||||
try {
|
||||
if (ASMUtil.inheritsFrom(classNode, fertilizableClassName.replace(".", "/"))) {
|
||||
for (MethodNode method : classNode.methods) {
|
||||
if (method.name.equals(fertilizableGrowMethodName)) {
|
||||
if ((method.access & ACC_STATIC) == 0) {
|
||||
if(method.desc.equals(fertilizableGrowMethodSignature)) {
|
||||
InsnList list = new InsnList();
|
||||
list.add(new VarInsnNode(Opcodes.ALOAD, 1));
|
||||
list.add(new VarInsnNode(Opcodes.ALOAD, 2));
|
||||
list.add(new VarInsnNode(Opcodes.ALOAD, 3));
|
||||
list.add(new VarInsnNode(Opcodes.ALOAD, 4));
|
||||
list.add(new MethodInsnNode(Opcodes.INVOKESTATIC, FertilizableUtil.class.getName().replace(".", "/"), "grow", fertilizableGrowMethodSignatureBase + "Z", false));
|
||||
LabelNode jmp = new LabelNode();
|
||||
list.add(new JumpInsnNode(Opcodes.IFNE, jmp));
|
||||
list.add(new InsnNode(Opcodes.RETURN));
|
||||
list.add(jmp);
|
||||
method.instructions.insertBefore(method.instructions.getFirst(), list);
|
||||
flags.requestFrames();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.dfsek.terra.lifecycle.util;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import static org.objectweb.asm.ClassReader.SKIP_CODE;
|
||||
import static org.objectweb.asm.ClassReader.SKIP_DEBUG;
|
||||
import static org.objectweb.asm.ClassReader.SKIP_FRAMES;
|
||||
|
||||
|
||||
public class ASMUtil {
|
||||
static final ThreadLocal<WeakHashMap<String, WeakHashMap<String, Boolean>>> INHERITANCE_CACHE = new ThreadLocal<>();
|
||||
|
||||
public static boolean inheritsFrom(ClassNode classNode, String interfaceName) throws IOException {
|
||||
if (INHERITANCE_CACHE.get() == null) {
|
||||
INHERITANCE_CACHE.set(new WeakHashMap<>());
|
||||
}
|
||||
return inheritsFromInternal(classNode, interfaceName);
|
||||
}
|
||||
|
||||
protected static boolean inheritsFromInternal(ClassNode classNode, String interfaceName) throws IOException {
|
||||
if (INHERITANCE_CACHE.get().containsKey(classNode.name)) {
|
||||
if (INHERITANCE_CACHE.get().get(classNode.name).containsKey(interfaceName)) {
|
||||
return INHERITANCE_CACHE.get().get(classNode.name).get(interfaceName);
|
||||
}
|
||||
}
|
||||
for (String parent : classNode.interfaces) {
|
||||
if (checkClass(parent, interfaceName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (checkClass(classNode.superName, interfaceName)) {
|
||||
return true;
|
||||
}
|
||||
INHERITANCE_CACHE.get().getOrDefault(classNode.name, new WeakHashMap<>()).put(interfaceName, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static boolean checkClass(String name, String interfaceName) throws IOException {
|
||||
if (name.startsWith("java/")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isClass = name.equals(interfaceName);
|
||||
INHERITANCE_CACHE.get().getOrDefault(name, new WeakHashMap<>()).put(interfaceName, isClass);
|
||||
if (isClass) {
|
||||
return true;
|
||||
}
|
||||
ClassNode node = new ClassNode();
|
||||
new ClassReader(name).accept(node, SKIP_CODE | SKIP_DEBUG | SKIP_FRAMES);
|
||||
return inheritsFromInternal(node, interfaceName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.dfsek.terra.lifecycle.util;
|
||||
|
||||
public abstract class LoaderUtil {
|
||||
public static LoaderUtil INSTANCE;
|
||||
|
||||
public abstract String mapClassName(String namespace, String className);
|
||||
|
||||
public abstract String mapMethodName(String namespace, String owner, String name, String descriptor);
|
||||
}
|
||||
Reference in New Issue
Block a user