diff --git a/src/main/java/mods/betterfoliage/BlockRenderTypeOverride.java b/src/main/java/mods/betterfoliage/BlockRenderTypeOverride.java
index cb9257b..5a4e253 100644
--- a/src/main/java/mods/betterfoliage/BlockRenderTypeOverride.java
+++ b/src/main/java/mods/betterfoliage/BlockRenderTypeOverride.java
@@ -10,7 +10,7 @@ public class BlockRenderTypeOverride {
public static IRenderTypeProvider provider = null;
public static interface IRenderTypeProvider {
- public int getRenderType(Block block);
+ public int getRenderType(int original, Block block);
}
/** Entry point from transformed RenderBlocks class. If no provider is given,
@@ -18,7 +18,7 @@ public class BlockRenderTypeOverride {
* @param block block instance
* @return block render type
*/
- public static int getRenderType(Block block) {
- return provider == null ? block.getRenderType() : provider.getRenderType(block);
+ public static int getRenderTypeOverride(int orig, Block block) {
+ return provider == null ? orig : provider.getRenderType(orig, block);
}
}
\ No newline at end of file
diff --git a/src/main/java/mods/betterfoliage/client/BetterFoliageClient.java b/src/main/java/mods/betterfoliage/client/BetterFoliageClient.java
index e481fbf..8aa8fa7 100644
--- a/src/main/java/mods/betterfoliage/client/BetterFoliageClient.java
+++ b/src/main/java/mods/betterfoliage/client/BetterFoliageClient.java
@@ -57,15 +57,18 @@ public class BetterFoliageClient implements IRenderTypeProvider, ILeafTextureRec
}
}
- public int getRenderType(Block block) {
+ public int getRenderType(int original, Block block) {
+ // universal sign for DON'T RENDER ME!
+ if (original == -1) return original;
+
if (Config.grassEnabled && block instanceof BlockGrass) return grassRenderId;
if (Config.leavesEnabled)
for (Class> clazz : blockLeavesClasses)
- if (clazz.isAssignableFrom(block.getClass()))
+ if (clazz.isAssignableFrom(block.getClass()) && (original == 0 || original >= 42))
return leavesRenderId;
- return block.getRenderType();
+ return original;
}
public boolean isLeafTexture(TextureAtlasSprite icon) {
diff --git a/src/main/java/mods/betterfoliage/common/util/DeobfNames.java b/src/main/java/mods/betterfoliage/common/util/DeobfNames.java
index f3d9d0c..797ddac 100644
--- a/src/main/java/mods/betterfoliage/common/util/DeobfNames.java
+++ b/src/main/java/mods/betterfoliage/common/util/DeobfNames.java
@@ -22,6 +22,12 @@ public class DeobfNames {
/** Obfuscated signature of BlockRenderTypeOverride.getRenderType(Block) */
public static final String BRTO_GRT_SIG_OBF = "(Lahu;)I";
+ /** MCP signature of BlockRenderTypeOverride.getRenderType(Block) */
+ public static final String BRTO_GRTO_SIG_MCP = "(ILnet/minecraft/block/Block;)I";
+
+ /** Obfuscated signature of BlockRenderTypeOverride.getRenderType(Block) */
+ public static final String BRTO_GRTO_SIG_OBF = "(ILahu;)I";
+
/** MCP name of SimpleReloadableResourceManager.domainResourceManagers */
public static final String SRRM_DRM_MCP = "domainResourceManagers";
diff --git a/src/main/java/mods/betterfoliage/loader/BetterFoliageLoader.java b/src/main/java/mods/betterfoliage/loader/BetterFoliageLoader.java
index a5bd141..a8951af 100644
--- a/src/main/java/mods/betterfoliage/loader/BetterFoliageLoader.java
+++ b/src/main/java/mods/betterfoliage/loader/BetterFoliageLoader.java
@@ -5,6 +5,7 @@ import java.util.Map;
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
@IFMLLoadingPlugin.MCVersion("1.7.2")
+@IFMLLoadingPlugin.TransformerExclusions({"mods.betterfoliage.loader"})
public class BetterFoliageLoader implements IFMLLoadingPlugin {
public String[] getASMTransformerClass() {
diff --git a/src/main/java/mods/betterfoliage/loader/BetterFoliageTransformer.java b/src/main/java/mods/betterfoliage/loader/BetterFoliageTransformer.java
index b264f41..011f40f 100644
--- a/src/main/java/mods/betterfoliage/loader/BetterFoliageTransformer.java
+++ b/src/main/java/mods/betterfoliage/loader/BetterFoliageTransformer.java
@@ -1,63 +1,27 @@
package mods.betterfoliage.loader;
import mods.betterfoliage.common.util.DeobfNames;
-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.Opcodes;
-import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.VarInsnNode;
-/** Transformer overriding the first line of RenderBlocks.renderBlockByRenderType()
- * with the following instruction:
- * int l = mods.betterfoliage.BlockRenderTypeOverride.getRenderType(block);
- *
- * @author octarine-noise
- */
-public class BetterFoliageTransformer implements IClassTransformer {
+public class BetterFoliageTransformer extends EZTransformerBase {
- Logger log = LogManager.getLogger("BetterFoliageCore");
-
- public byte[] transform(String name, String transformedName, byte[] basicClass) {
- if (basicClass == null) return null;
-
- if (transformedName.equals("net.minecraft.client.renderer.RenderBlocks")) {
- log.info(String.format("Found class %s", transformedName));
- ClassNode classNode = new ClassNode();
- ClassReader classReader = new ClassReader(basicClass);
- classReader.accept(classNode, 0);
-
- for (MethodNode mn : classNode.methods) {
- boolean found = false;
- boolean obf = false;
- if (mn.desc.equals(DeobfNames.RB_RBBRT_SIG_MCP) && (mn.name.equals(DeobfNames.RB_RBBRT_NAME_MCP))) {
- found = true;
- } else if (mn.desc.equals(DeobfNames.RB_RBBRT_SIG_OBF) && (mn.name.equals(DeobfNames.RB_RBBRT_NAME_OBF))) {
- found = true;
- obf = true;
- }
- if (found) {
- log.info("Overriding RenderBlocks.renderBlockByRenderType()");
- int invokeNodeIdx = 0;
- for (int idx = 0; idx < mn.instructions.size(); idx++) if (mn.instructions.get(idx) instanceof MethodInsnNode) {
- invokeNodeIdx = idx;
- break;
- }
- mn.instructions.remove(mn.instructions.get(invokeNodeIdx));
- MethodInsnNode replacement = new MethodInsnNode(Opcodes.INVOKESTATIC, "mods/betterfoliage/BlockRenderTypeOverride", "getRenderType", obf ? DeobfNames.BRTO_GRT_SIG_OBF : DeobfNames.BRTO_GRT_SIG_MCP);
- mn.instructions.insertBefore(mn.instructions.get(invokeNodeIdx), replacement);
- break;
- }
- }
-
- ClassWriter writer = new ClassWriter(0);
- classNode.accept(writer);
- return writer.toByteArray();
- }
- return basicClass;
+ @MethodTransform(className="net.minecraft.client.renderer.RenderBlocks",
+ obf=@MethodMatch(name=DeobfNames.RB_RBBRT_NAME_OBF, signature=DeobfNames.RB_RBBRT_SIG_OBF),
+ deobf=@MethodMatch(name=DeobfNames.RB_RBBRT_NAME_MCP, signature=DeobfNames.RB_RBBRT_SIG_MCP),
+ log="Adding RenderBlocks.renderBlockByRenderType() render type ovverride")
+ public void handleRenderBlockOverride(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.ILOAD, 5),
+ new VarInsnNode(Opcodes.ALOAD, 1),
+ new MethodInsnNode(Opcodes.INVOKESTATIC, "mods/betterfoliage/BlockRenderTypeOverride", "getRenderTypeOverride", obf ? DeobfNames.BRTO_GRTO_SIG_OBF : DeobfNames.BRTO_GRTO_SIG_MCP),
+ new VarInsnNode(Opcodes.ISTORE, 5)
+ );
}
}
diff --git a/src/main/java/mods/betterfoliage/loader/EZTransformerBase.java b/src/main/java/mods/betterfoliage/loader/EZTransformerBase.java
new file mode 100644
index 0000000..dba9c7b
--- /dev/null
+++ b/src/main/java/mods/betterfoliage/loader/EZTransformerBase.java
@@ -0,0 +1,128 @@
+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);
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ public static @interface MethodMatch {
+ public String name();
+ public String signature();
+ }
+
+ @Target(ElementType.METHOD)
+ @Retention(RetentionPolicy.RUNTIME)
+ public static @interface MethodTransform {
+ public String className();
+ public MethodMatch deobf();
+ public MethodMatch obf();
+ public String log();
+ }
+
+ protected Logger logger = LogManager.getLogger(getClass().getSimpleName());
+
+ public byte[] transform(String name, String transformedName, byte[] basicClass) {
+ // 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
+ MethodTransform annot = classMethod.getAnnotation(MethodTransform.class);
+ if (annot == null) continue;
+ if (classMethod.getParameterTypes().length != 2) continue;
+ if (!classMethod.getParameterTypes()[0].equals(MethodNode.class)) continue;
+ if (!classMethod.getParameterTypes()[1].equals(boolean.class)) continue;
+
+ // try to find specified method in class
+ if (!transformedName.equals(annot.className())) continue;
+ for (MethodNode methodNode : classNode.methods) {
+ Boolean obf = null;
+ if (methodNode.name.equals(annot.obf().name()) && methodNode.desc.equals(annot.obf().signature())) {
+ obf = true;
+ } else if (methodNode.name.equals(annot.deobf().name()) && methodNode.desc.equals(annot.deobf().signature())) {
+ obf = false;
+ }
+
+ if (obf != null) {
+ // transform
+ hasTransformed = true;
+ try {
+ classMethod.invoke(this, new Object[] {methodNode, obf});
+ logger.info(String.format("%s: SUCCESS", annot.log()));
+ } catch (Exception e) {
+ logger.info(String.format("%s: FAILURE", annot.log()));
+ }
+ break;
+ }
+ }
+ }
+
+ // return result
+ ClassWriter writer = new ClassWriter(0);
+ if (hasTransformed) classNode.accept(writer);
+ return !hasTransformed ? basicClass : writer.toByteArray();
+ }
+
+ 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);
+ }
+}