get rid of annotations in class transformer
This commit is contained in:
@@ -22,7 +22,7 @@ minecraft {
|
|||||||
|
|
||||||
jar.baseName = 'BetterFoliage'
|
jar.baseName = 'BetterFoliage'
|
||||||
group = 'com.github.octarine-noise'
|
group = 'com.github.octarine-noise'
|
||||||
version='0.9.7b'
|
version='0.9.7b-hotfix1'
|
||||||
|
|
||||||
processResources {
|
processResources {
|
||||||
inputs.property "version", project.version
|
inputs.property "version", project.version
|
||||||
|
|||||||
@@ -1,17 +1,26 @@
|
|||||||
package mods.betterfoliage.loader;
|
package mods.betterfoliage.loader;
|
||||||
|
|
||||||
import org.objectweb.asm.Opcodes;
|
import net.minecraft.launchwrapper.IClassTransformer;
|
||||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
|
||||||
import org.objectweb.asm.tree.FieldInsnNode;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.objectweb.asm.tree.MethodInsnNode;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.objectweb.asm.ClassReader;
|
||||||
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import org.objectweb.asm.tree.MethodNode;
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
import org.objectweb.asm.tree.VarInsnNode;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
import cpw.mods.fml.relauncher.FMLInjectionData;
|
import cpw.mods.fml.relauncher.FMLInjectionData;
|
||||||
|
|
||||||
public class BetterFoliageTransformer extends EZTransformerBase {
|
public class BetterFoliageTransformer implements IClassTransformer {
|
||||||
|
|
||||||
|
protected Iterable<MethodTransformerBase> transformers = ImmutableList.<MethodTransformerBase>of(
|
||||||
|
new TransformRenderBlockOverride(),
|
||||||
|
new TransformShaderModBlockOverride()
|
||||||
|
);
|
||||||
|
|
||||||
|
protected Logger logger = LogManager.getLogger(getClass().getSimpleName());
|
||||||
|
|
||||||
public BetterFoliageTransformer() {
|
public BetterFoliageTransformer() {
|
||||||
String mcVersion = FMLInjectionData.data()[4].toString();
|
String mcVersion = FMLInjectionData.data()[4].toString();
|
||||||
@@ -21,35 +30,49 @@ public class BetterFoliageTransformer extends EZTransformerBase {
|
|||||||
DeobfHelper.init();
|
DeobfHelper.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@MethodTransform(className="net.minecraft.client.renderer.RenderBlocks",
|
@Override
|
||||||
methodName="renderBlockByRenderType",
|
public byte[] transform(String name, String transformedName, byte[] basicClass) {
|
||||||
signature="(Lnet/minecraft/block/Block;III)Z",
|
// ???
|
||||||
log="Applying RenderBlocks.renderBlockByRenderType() render type ovverride")
|
if (basicClass == null) return null;
|
||||||
public void handleRenderBlockOverride(MethodNode method) {
|
|
||||||
AbstractInsnNode invokeGetRenderType = findNext(method.instructions.getFirst(), matchInvokeAny());
|
// read class
|
||||||
AbstractInsnNode storeRenderType = findNext(invokeGetRenderType, matchOpcode(Opcodes.ISTORE));
|
ClassNode classNode = new ClassNode();
|
||||||
insertAfter(method.instructions, storeRenderType,
|
ClassReader classReader = new ClassReader(basicClass);
|
||||||
new VarInsnNode(Opcodes.ALOAD, 0),
|
classReader.accept(classNode, 0);
|
||||||
new FieldInsnNode(Opcodes.GETFIELD, className("net/minecraft/client/renderer/RenderBlocks"), element("blockAccess"), signature("Lnet/minecraft/world/IBlockAccess;")),
|
boolean hasTransformed = false;
|
||||||
new VarInsnNode(Opcodes.ILOAD, 2),
|
|
||||||
new VarInsnNode(Opcodes.ILOAD, 3),
|
for (MethodTransformerBase transformer : transformers) {
|
||||||
new VarInsnNode(Opcodes.ILOAD, 4),
|
// try to find specified method in class
|
||||||
new VarInsnNode(Opcodes.ALOAD, 1),
|
if (!transformedName.equals(transformer.getClassName())) continue;
|
||||||
new VarInsnNode(Opcodes.ILOAD, 5),
|
|
||||||
new MethodInsnNode(Opcodes.INVOKESTATIC, "mods/betterfoliage/client/BetterFoliageClient", "getRenderTypeOverride", signature("(Lnet/minecraft/world/IBlockAccess;IIILnet/minecraft/block/Block;I)I")),
|
logger.debug(String.format("Found class: %s -> %s", name, transformedName));
|
||||||
new VarInsnNode(Opcodes.ISTORE, 5)
|
for (MethodNode methodNode : classNode.methods) {
|
||||||
);
|
logger.trace(String.format("Checking method: %s, sig: %s", methodNode.name, methodNode.desc));
|
||||||
|
Boolean isObfuscated = null;
|
||||||
|
if (methodNode.name.equals(DeobfHelper.transformElementName(transformer.getMethodName())) && methodNode.desc.equals(DeobfHelper.transformSignature(transformer.getSignature()))) {
|
||||||
|
isObfuscated = true;
|
||||||
|
} else if (methodNode.name.equals(transformer.getMethodName()) && methodNode.desc.equals(transformer.getSignature())) {
|
||||||
|
isObfuscated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@MethodTransform(className="shadersmodcore.client.Shaders",
|
if (isObfuscated != null) {
|
||||||
methodName="pushEntity",
|
// transform
|
||||||
signature="(Lnet/minecraft/client/renderer/RenderBlocks;Lnet/minecraft/block/Block;III)V",
|
hasTransformed = true;
|
||||||
log="Applying Shaders.pushEntity() block id ovverride")
|
try {
|
||||||
public void handleGLSLBlockIDOverride(MethodNode method) {
|
transformer.transform(methodNode, isObfuscated);
|
||||||
AbstractInsnNode arrayStore = findNext(method.instructions.getFirst(), matchOpcode(Opcodes.IASTORE));
|
logger.info(String.format("%s: SUCCESS", transformer.getLogMessage()));
|
||||||
insertAfter(method.instructions, arrayStore.getPrevious(),
|
} catch (Exception e) {
|
||||||
new VarInsnNode(Opcodes.ALOAD, 1),
|
logger.info(String.format("%s: FAILURE", transformer.getLogMessage()));
|
||||||
new MethodInsnNode(Opcodes.INVOKESTATIC, "mods/betterfoliage/client/ShadersModIntegration", "getBlockIdOverride", signature("(ILnet/minecraft/block/Block;)I"))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return result
|
||||||
|
ClassWriter writer = new ClassWriter(0);
|
||||||
|
if (hasTransformed) classNode.accept(writer);
|
||||||
|
return !hasTransformed ? basicClass : writer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,153 +0,0 @@
|
|||||||
package mods.betterfoliage.loader;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
import net.minecraft.launchwrapper.IClassTransformer;
|
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import org.objectweb.asm.ClassReader;
|
|
||||||
import org.objectweb.asm.ClassWriter;
|
|
||||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
|
||||||
import org.objectweb.asm.tree.InsnList;
|
|
||||||
import org.objectweb.asm.tree.MethodInsnNode;
|
|
||||||
import org.objectweb.asm.tree.MethodNode;
|
|
||||||
|
|
||||||
public class EZTransformerBase implements IClassTransformer {
|
|
||||||
|
|
||||||
public static interface IInstructionMatch {
|
|
||||||
public boolean matches(AbstractInsnNode node);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Target(ElementType.METHOD)
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public static @interface MethodTransform {
|
|
||||||
public String className();
|
|
||||||
public String methodName();
|
|
||||||
public String signature();
|
|
||||||
public String log();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Logger logger = LogManager.getLogger(getClass().getSimpleName());
|
|
||||||
|
|
||||||
protected Boolean isObfuscated;
|
|
||||||
|
|
||||||
public byte[] transform(String name, String transformedName, byte[] basicClass) {
|
|
||||||
// ???
|
|
||||||
if (basicClass == null) return null;
|
|
||||||
|
|
||||||
// read class
|
|
||||||
ClassNode classNode = new ClassNode();
|
|
||||||
ClassReader classReader = new ClassReader(basicClass);
|
|
||||||
classReader.accept(classNode, 0);
|
|
||||||
boolean hasTransformed = false;
|
|
||||||
|
|
||||||
for (Method classMethod : getClass().getMethods()) {
|
|
||||||
// check for annotated method with correct signature
|
|
||||||
String aClassName = null;
|
|
||||||
String aMethodName = null;
|
|
||||||
String aSignature = null;
|
|
||||||
String aLog = null;
|
|
||||||
synchronized (this) {
|
|
||||||
MethodTransform annotation = classMethod.getAnnotation(MethodTransform.class);
|
|
||||||
if (annotation != null) {
|
|
||||||
aClassName = annotation.className();
|
|
||||||
aMethodName = annotation.methodName();
|
|
||||||
aSignature = annotation.signature();
|
|
||||||
aLog = annotation.log();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aClassName == null) continue;
|
|
||||||
if (classMethod.getParameterTypes().length != 1) continue;
|
|
||||||
if (!classMethod.getParameterTypes()[0].equals(MethodNode.class)) continue;
|
|
||||||
|
|
||||||
// try to find specified method in class
|
|
||||||
if (!transformedName.equals(aClassName)) continue;
|
|
||||||
logger.debug(String.format("Found class: %s -> %s", name, transformedName));
|
|
||||||
for (MethodNode methodNode : classNode.methods) {
|
|
||||||
logger.trace(String.format("Checking method: %s, sig: %s", methodNode.name, methodNode.desc));
|
|
||||||
isObfuscated = null;
|
|
||||||
if (methodNode.name.equals(DeobfHelper.transformElementName(aMethodName)) && methodNode.desc.equals(DeobfHelper.transformSignature(aSignature))) {
|
|
||||||
isObfuscated = true;
|
|
||||||
} else if (methodNode.name.equals(aMethodName) && methodNode.desc.equals(aSignature)) {
|
|
||||||
isObfuscated = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isObfuscated != null) {
|
|
||||||
// transform
|
|
||||||
hasTransformed = true;
|
|
||||||
try {
|
|
||||||
classMethod.invoke(this, new Object[] {methodNode});
|
|
||||||
logger.info(String.format("%s: SUCCESS", aLog));
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.info(String.format("%s: FAILURE", aLog));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// return result
|
|
||||||
ClassWriter writer = new ClassWriter(0);
|
|
||||||
if (hasTransformed) classNode.accept(writer);
|
|
||||||
return !hasTransformed ? basicClass : writer.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String className(String className) {
|
|
||||||
return isObfuscated ? DeobfHelper.transformClassName(className) : className;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String element(String fieldName) {
|
|
||||||
return isObfuscated ? DeobfHelper.transformElementName(fieldName) : fieldName;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String signature(String signature) {
|
|
||||||
return isObfuscated ? DeobfHelper.transformSignature(signature) : signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected AbstractInsnNode findNext(AbstractInsnNode start, IInstructionMatch match) {
|
|
||||||
AbstractInsnNode current = start;
|
|
||||||
while(current != null) {
|
|
||||||
if (match.matches(current)) break;
|
|
||||||
current = current.getNext();
|
|
||||||
}
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected AbstractInsnNode findPrevious(AbstractInsnNode start, IInstructionMatch match) {
|
|
||||||
AbstractInsnNode current = start;
|
|
||||||
while(current != null) {
|
|
||||||
if (match.matches(current)) break;
|
|
||||||
current = current.getPrevious();
|
|
||||||
}
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static IInstructionMatch matchInvokeAny() {
|
|
||||||
return new IInstructionMatch() {
|
|
||||||
public boolean matches(AbstractInsnNode node) {
|
|
||||||
return node instanceof MethodInsnNode;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static IInstructionMatch matchOpcode(final int opcode) {
|
|
||||||
return new IInstructionMatch() {
|
|
||||||
public boolean matches(AbstractInsnNode node) {
|
|
||||||
return node.getOpcode() == opcode;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static void insertAfter(InsnList insnList, AbstractInsnNode node, AbstractInsnNode... added) {
|
|
||||||
InsnList listAdd = new InsnList();
|
|
||||||
for (AbstractInsnNode inst : added) listAdd.add(inst);
|
|
||||||
insnList.insert(node, listAdd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package mods.betterfoliage.loader;
|
||||||
|
|
||||||
|
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||||
|
import org.objectweb.asm.tree.InsnList;
|
||||||
|
import org.objectweb.asm.tree.MethodInsnNode;
|
||||||
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
|
|
||||||
|
public abstract class MethodTransformerBase {
|
||||||
|
|
||||||
|
public static interface IInstructionMatch {
|
||||||
|
public boolean matches(AbstractInsnNode node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract String getClassName();
|
||||||
|
public abstract String getMethodName();
|
||||||
|
public abstract String getSignature();
|
||||||
|
public abstract String getLogMessage();
|
||||||
|
|
||||||
|
public abstract void transform(MethodNode method, boolean obf);
|
||||||
|
|
||||||
|
protected static String className(String className, boolean isObfuscated) {
|
||||||
|
return isObfuscated ? DeobfHelper.transformClassName(className) : className;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static String element(String fieldName, boolean isObfuscated) {
|
||||||
|
return isObfuscated ? DeobfHelper.transformElementName(fieldName) : fieldName;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static String signature(String signature, boolean isObfuscated) {
|
||||||
|
return isObfuscated ? DeobfHelper.transformSignature(signature) : signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractInsnNode findNext(AbstractInsnNode start, IInstructionMatch match) {
|
||||||
|
AbstractInsnNode current = start;
|
||||||
|
while(current != null) {
|
||||||
|
if (match.matches(current)) break;
|
||||||
|
current = current.getNext();
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractInsnNode findPrevious(AbstractInsnNode start, IInstructionMatch match) {
|
||||||
|
AbstractInsnNode current = start;
|
||||||
|
while(current != null) {
|
||||||
|
if (match.matches(current)) break;
|
||||||
|
current = current.getPrevious();
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IInstructionMatch matchInvokeAny() {
|
||||||
|
return new IInstructionMatch() {
|
||||||
|
public boolean matches(AbstractInsnNode node) {
|
||||||
|
return node instanceof MethodInsnNode;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IInstructionMatch matchOpcode(final int opcode) {
|
||||||
|
return new IInstructionMatch() {
|
||||||
|
public boolean matches(AbstractInsnNode node) {
|
||||||
|
return node.getOpcode() == opcode;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void insertAfter(InsnList insnList, AbstractInsnNode node, AbstractInsnNode... added) {
|
||||||
|
InsnList listAdd = new InsnList();
|
||||||
|
for (AbstractInsnNode inst : added) listAdd.add(inst);
|
||||||
|
insnList.insert(node, listAdd);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package mods.betterfoliage.loader;
|
||||||
|
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||||
|
import org.objectweb.asm.tree.FieldInsnNode;
|
||||||
|
import org.objectweb.asm.tree.MethodInsnNode;
|
||||||
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
|
import org.objectweb.asm.tree.VarInsnNode;
|
||||||
|
|
||||||
|
public class TransformRenderBlockOverride extends MethodTransformerBase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getClassName() {
|
||||||
|
return "net.minecraft.client.renderer.RenderBlocks";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMethodName() {
|
||||||
|
return "renderBlockByRenderType";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSignature() {
|
||||||
|
return "(Lnet/minecraft/block/Block;III)Z";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLogMessage() {
|
||||||
|
return "Applying RenderBlocks.renderBlockByRenderType() render type ovverride";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void transform(MethodNode method, boolean obf) {
|
||||||
|
AbstractInsnNode invokeGetRenderType = findNext(method.instructions.getFirst(), matchInvokeAny());
|
||||||
|
AbstractInsnNode storeRenderType = findNext(invokeGetRenderType, matchOpcode(Opcodes.ISTORE));
|
||||||
|
insertAfter(method.instructions, storeRenderType,
|
||||||
|
new VarInsnNode(Opcodes.ALOAD, 0),
|
||||||
|
new FieldInsnNode(Opcodes.GETFIELD, className("net/minecraft/client/renderer/RenderBlocks", obf), element("blockAccess", obf), signature("Lnet/minecraft/world/IBlockAccess;", obf)),
|
||||||
|
new VarInsnNode(Opcodes.ILOAD, 2),
|
||||||
|
new VarInsnNode(Opcodes.ILOAD, 3),
|
||||||
|
new VarInsnNode(Opcodes.ILOAD, 4),
|
||||||
|
new VarInsnNode(Opcodes.ALOAD, 1),
|
||||||
|
new VarInsnNode(Opcodes.ILOAD, 5),
|
||||||
|
new MethodInsnNode(Opcodes.INVOKESTATIC, "mods/betterfoliage/client/BetterFoliageClient", "getRenderTypeOverride", signature("(Lnet/minecraft/world/IBlockAccess;IIILnet/minecraft/block/Block;I)I", obf)),
|
||||||
|
new VarInsnNode(Opcodes.ISTORE, 5)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package mods.betterfoliage.loader;
|
||||||
|
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||||
|
import org.objectweb.asm.tree.MethodInsnNode;
|
||||||
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
|
import org.objectweb.asm.tree.VarInsnNode;
|
||||||
|
|
||||||
|
public class TransformShaderModBlockOverride extends MethodTransformerBase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getClassName() {
|
||||||
|
return "shadersmodcore.client.Shaders";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMethodName() {
|
||||||
|
return "pushEntity";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSignature() {
|
||||||
|
return "(Lnet/minecraft/client/renderer/RenderBlocks;Lnet/minecraft/block/Block;III)V";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLogMessage() {
|
||||||
|
return "Applying Shaders.pushEntity() block id ovverride";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void transform(MethodNode method, boolean obf) {
|
||||||
|
AbstractInsnNode arrayStore = findNext(method.instructions.getFirst(), matchOpcode(Opcodes.IASTORE));
|
||||||
|
insertAfter(method.instructions, arrayStore.getPrevious(),
|
||||||
|
new VarInsnNode(Opcodes.ALOAD, 1),
|
||||||
|
new MethodInsnNode(Opcodes.INVOKESTATIC, "mods/betterfoliage/client/ShadersModIntegration", "getBlockIdOverride", signature("(ILnet/minecraft/block/Block;)I", obf))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user