Hello, so I have gotten replacing classes and inserting my own methods into Base Classes down but, I am having trouble with something I have been working on.
I am trying to modify a line of existing code but am not 100% on how to go around doing this...
Would I have to remove the line and then add in my code later or is there any examples around.
I am trying to replace this line in BlockDynamicLiquid... Note: This is 1.7.2
if (this.field_149815_a >= 2 && this.blockMaterial == Material.water)
Hello, so I have gotten replacing classes and inserting my own methods into Base Classes down but, I am having trouble with something I have been working on.
I am trying to modify a line of existing code but am not 100% on how to go around doing this...
Would I have to remove the line and then add in my code later or is there any examples around.
I am trying to replace this line in BlockDynamicLiquid... Note: This is 1.7.2
if (this.field_149815_a >= 2 && this.blockMaterial == Material.water)
Turns out that it was a very simple change... The only problem with how I chose to do it is that it may interfere with another mods custom liquid if they extend BlockDynamicLiquid...
You can't just make something static. You would need to change every single class that accesses that variable, and much of the code would be broken with a static reference. Since it's public, all you need to do is get a hold of the actual instance of the Timer.
You can't just make something static. You would need to change every single class that accesses that variable, and much of the code would be broken with a static reference. Since it's public, all you need to do is get a hold of the actual instance of the Timer.
Well originally I just replaced the Timer with my own custom Timer that only changed it to static. It didn't conflict with anything in 1.6.4...
Ignore the comments those are just leftover from the OP
public class ClassTransformer implements net.minecraft.launchwrapper.IClassTransformer {@Overridepublic byte[] transform(String arg0, String arg1, byte[] arg2) {if (arg0.equals("atv")) {System.out.println("********* INSIDE OBFUSCATED EXPLOSION TRANSFORMER ABOUT TO PATCH: " + arg0);return patchClassASM(arg0, arg2, true);}if (arg0.equals("net.minecraft.client.Minecraft")) {System.out.println("********* INSIDE EXPLOSION TRANSFORMER ABOUT TO PATCH: " + arg0);return patchClassASM(arg0, arg2, false);}return arg2;}public byte[] patchClassASM(String name, byte[] bytes, boolean obfuscated) {String targetMethodName = "";if(obfuscated == true)targetMethodName ="k";elsetargetMethodName ="runTick";//set up ASM class manipulation stuff. Consult the ASM docs for detailsClassNode classNode = new ClassNode();ClassReader classReader = new ClassReader(bytes);classReader.accept(classNode, 0);//Now we loop over all of the methods declared inside the Explosion class until we get to the targetMethodName "doExplosionB"// find method to inject [email protected]("unchecked")Iterator methods = classNode.methods.iterator();while(methods.hasNext()){MethodNode m = methods.next();System.out.println("********* Method Name: "+m.name + " Desc:" + m.desc);int fdiv_index = -1;//Check if this is doExplosionB and it's method signature is (Z)V which means that it accepts a boolean (Z) and returns a void (V)if ((m.name.equals(targetMethodName) &amp;&amp; m.desc.equals("()V"))){System.out.println("********* Inside target method!");// find interesting instructions in method, there is a single FDIV instruction we use as target//System.out.println("m.instructions.size = " + m.instructions.size());AbstractInsnNode currentNode = null;AbstractInsnNode targetNode = null;@SuppressWarnings("unchecked")Iterator iter = m.instructions.iterator();int index = -1;//Loop over the instruction set and find the instruction FDIV which does the division of 1/explosionSizewhile (iter.hasNext() &amp;&amp; index < 700){index++;currentNode = iter.next();AbstractInsnNode nextNode = currentNode.getNext();AbstractInsnNode thirdNode = nextNode.getNext();System.out.println("********* index : " + index + " currentNode.getOpcode() = " + currentNode.getOpcode() + " Type: " + currentNode.getType());if (currentNode.getType() == 15 &amp;&amp; currentNode.getOpcode()==-1 &amp;&amp; nextNode.getType() == 14 &amp;&amp; thirdNode.getType() == 2){targetNode = currentNode;fdiv_index = index;}}AbstractInsnNode addNode = m.instructions.get(fdiv_index);AbstractInsnNode invVirt = m.instructions.get(fdiv_index );if(invVirt.getOpcode() == -1){if(invVirt.getType() == 15){System.out.println("INVOKEVIRTUAL opcode is " + invVirt.getOpcode() + " METHOD_INSN type is " + invVirt.getType() );}}InsnList toInject = new InsnList();toInject.add(new MethodInsnNode(184, "tim/Base", "onKeyPressed", "()V"));m.instructions.insertBefore(targetNode, toInject);System.out.println("Patching Complete!");break;}}//ASM specific for cleaning up and returning the final bytes for JVM processing.ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);classNode.accept(writer);return writer.toByteArray();}}
I'm having a bit of a problem where my Coremod is being recognized by Forge, but the transform method is not being called and therefore the patch is not being applied. I'm currently just adapting the OP's code and trying to get it to work on my system, but the printlns are not being displayed in the console output. Here are the files:
package timeTraveler.core;
import java.util.Map;
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
import cpw.mods.fml.relauncher.IFMLLoadingPlugin.MCVersion;
@MCVersion(value = "1.6.4")
public class TTLoadingPlugin implements IFMLLoadingPlugin {
@Override
public String[] getASMTransformerClass()
{
//This will return the name of the class "mod.culegooner.ExplosionDropsCore.EDClassTransformer"
return new String[]{TTClassTransformer.class.getName()};
}
@Override
public String getModContainerClass()
{
//This is the name of our container "timeTraveler.TimeTraveler"
return TTDummyContainer.class.getName();
}
@Override
public String getSetupClass()
{
// TODO Auto-generated method stub
return null;
}
@Override
public void injectData(Map<String, Object> data)
{
}
}
package timeTraveler.core;
import static org.objectweb.asm.Opcodes.FDIV;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
import static org.objectweb.asm.tree.AbstractInsnNode.METHOD_INSN;
import java.util.Iterator;
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.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
public class TTClassTransformer implements net.minecraft.launchwrapper.IClassTransformer
{
@Override
public byte[] transform(String arg0, String arg1, byte[] arg2)
{
if (arg0.equals("abq"))
{
System.out.println("********* INSIDE OBFUSCATED EXPLOSION TRANSFORMER ABOUT TO PATCH: " + arg0);
return patchClassASM(arg0, arg2, true);
}
if (arg0.equals("net.minecraft.world.Explosion"))
{
System.out.println("********* INSIDE EXPLOSION TRANSFORMER ABOUT TO PATCH: " + arg0);
return patchClassASM(arg0, arg2, false);
}
return arg2;
}
public byte[] patchClassASM(String name, byte[] bytes, boolean obfuscated)
{
String targetMethodName = "";
if(obfuscated == true)
targetMethodName ="a";
else
targetMethodName ="doExplosionB";
//set up ASM class manipulation stuff. Consult the ASM docs for details
ClassNode classNode = new ClassNode();
ClassReader classReader = new ClassReader(bytes);
classReader.accept(classNode, 0);
//Now we loop over all of the methods declared inside the Explosion class until we get to the targetMethodName "doExplosionB"
// find method to inject into
@SuppressWarnings("unchecked")
Iterator<MethodNode> methods = classNode.methods.iterator();
while(methods.hasNext())
{
MethodNode m = methods.next();
System.out.println("********* Method Name: "+m.name + " Desc:" + m.desc);
int fdiv_index = -1;
//Check if this is doExplosionB and it's method signature is (Z)V which means that it accepts a boolean (Z) and returns a void (V)
if ((m.name.equals(targetMethodName) && m.desc.equals("(Z)V")))
{
System.out.println("********* Inside target method!");
// find interesting instructions in method, there is a single FDIV instruction we use as target
//System.out.println("m.instructions.size = " + m.instructions.size());
AbstractInsnNode currentNode = null;
AbstractInsnNode targetNode = null;
@SuppressWarnings("unchecked")
Iterator<AbstractInsnNode> iter = m.instructions.iterator();
int index = -1;
//Loop over the instruction set and find the instruction FDIV which does the division of 1/explosionSize
while (iter.hasNext())
{
index++;
currentNode = iter.next();
System.out.println("********* index : " + index + " currentNode.getOpcode() = " + currentNode.getOpcode());
//Found it! save the index location of instruction FDIV and the node for this instruction
if (currentNode.getOpcode() == FDIV)
{
targetNode = currentNode;
fdiv_index = index;
}
}
/*
2013-07-05 18:32:29 [INFO] [STDOUT] ********* index : 334 currentNode.getOpcode() = 25
2013-07-05 18:32:29 [INFO] [STDOUT] ********* index : 335 currentNode.getOpcode() = 180
2013-07-05 18:32:29 [INFO] [STDOUT] ********* index : 336 currentNode.getOpcode() = 110
*/
System.out.println("********* fdiv_index should be 336 -> " + fdiv_index);
if (targetNode == null)
{
System.out.println("Did not find all necessary target nodes! ABANDON CLASS!");
return bytes;
}
if (fdiv_index == -1)
{
System.out.println("Did not find all necessary target nodes! ABANDON CLASS!");
return bytes;
}
/*
//now we want the save nods that load the variable explosionSize and the division instruction:
The line in Explosion.java that we want to modify is:
var25.dropBlockAsItemWithChance(this.worldObj, var4, var5, var6, this.worldObj.getBlockMetadata(var4, var5, var6), 1.0F / this.explosionSize, 0);
The code we are looking for is the following in bytecode:
mv.visitInsn(FCONST_1);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, "net/minecraft/src/Explosion", "explosionSize", "F");
mv.visitInsn(FDIV);
mv.visitInsn(ICONST_0);
mv.visitMethodInsn(INVOKEVIRTUAL, "net/minecraft/src/Block", "dropBlockAsItemWithChance", "(Lnet/minecraft/src/World;IIIIFI)V");
*/
AbstractInsnNode remNode1 = m.instructions.get(fdiv_index-2); // mv.visitVarInsn(ALOAD, 0);
AbstractInsnNode remNode2 = m.instructions.get(fdiv_index-1); // mv.visitFieldInsn(GETFIELD, "net/minecraft/src/Explosion", "explosionSize", "F");
AbstractInsnNode remNode3 = m.instructions.get(fdiv_index); // mv.visitInsn(FDIV);
//This part is just to show how if the opcode we are looking for is an invokevirtual
AbstractInsnNode invVirt = m.instructions.get(fdiv_index+2);
if(invVirt.getOpcode() == INVOKEVIRTUAL)
{
if(invVirt.getType() == METHOD_INSN){
System.out.println("INVOKEVIRTUAL opcode is " + invVirt.getOpcode() + " METHOD_INSN type is " + invVirt.getType() );
MethodInsnNode testMethod = (MethodInsnNode)invVirt; //only do this cast if the getType match to a MethodInsnNode!! look at the javadoc for the other types!
System.out.println("INVOKEVIRTUAL :" + testMethod.owner + " , " + testMethod.name + " , " + testMethod.desc );
}
}
//just remove these nodes from the instruction set, this will prevent the instruction FCONST_1 to be divided.
m.instructions.remove(remNode1);
m.instructions.remove(remNode2);
m.instructions.remove(remNode3);
//in this commented section, i'll just illustrate how to inject a call to a static method if your instruction is a little more advanced than just removing a couple of instruction:
/*
//To add new instructions, such as calling a static method can be done like so:
// make new instruction list
InsnList toInject = new InsnList();
toInject.add(new VarInsnNode(ALOAD, 0));
toInject.add(new MethodInsnNode(INVOKESTATIC, "mod/culegooner/MyStaticClass", "myStaticMethod", "()V"));
// inject new instruction list into method instruction list
m.instructions.insert(targetNode, toInject);
*/
System.out.println("Patching Complete!");
break;
}
}
//ASM specific for cleaning up and returning the final bytes for JVM processing.
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
classNode.accept(writer);
return writer.toByteArray();
}
}
Here is the console output:
Feb 22, 2014 2:22:13 PM net.minecraft.launchwrapper.LogWrapper log
INFO: Loading tweak class name cpw.mods.fml.common.launcher.FMLTweaker
Feb 22, 2014 2:22:13 PM net.minecraft.launchwrapper.LogWrapper log
INFO: Using primary tweak class name cpw.mods.fml.common.launcher.FMLTweaker
Feb 22, 2014 2:22:13 PM net.minecraft.launchwrapper.LogWrapper log
INFO: Calling tweak class cpw.mods.fml.common.launcher.FMLTweaker
2014-02-22 14:22:13 [INFO] [ForgeModLoader] Forge Mod Loader version 6.99.19.964 for Minecraft 1.6.4 loading
2014-02-22 14:22:13 [INFO] [ForgeModLoader] Java is Java HotSpot(TM) 64-Bit Server VM, version 1.7.0_09, running on Windows 7:amd64:6.1, installed at C:\Users\Will\Desktop\eclipse-jee-juno-SR2-win32-x86_64\eclipse\jre
2014-02-22 14:22:13 [INFO] [ForgeModLoader] Managed to load a deobfuscated Minecraft name- we are in a deobfuscated environment. Skipping runtime deobfuscation
2014-02-22 14:22:13 [INFO] [ForgeModLoader] Found a command line coremod : timeTraveler.core.TTLoadingPlugin
2014-02-22 14:22:13 [INFO] [ForgeModLoader] Loading tweak class name cpw.mods.fml.common.launcher.FMLInjectionAndSortingTweaker
2014-02-22 14:22:13 [INFO] [ForgeModLoader] Loading tweak class name cpw.mods.fml.common.launcher.FMLDeobfTweaker
2014-02-22 14:22:13 [INFO] [ForgeModLoader] Calling tweak class cpw.mods.fml.common.launcher.FMLInjectionAndSortingTweaker
2014-02-22 14:22:13 [INFO] [ForgeModLoader] Calling tweak class cpw.mods.fml.common.launcher.FMLInjectionAndSortingTweaker
2014-02-22 14:22:13 [INFO] [ForgeModLoader] Calling tweak class cpw.mods.fml.relauncher.CoreModManager$FMLPluginWrapper
2014-02-22 14:22:13 [INFO] [STDOUT] Loaded 40 rules from AccessTransformer config file fml_at.cfg
2014-02-22 14:22:13 [SEVERE] [ForgeModLoader] The binary patch set is missing. Either you are in a development environment, or things are not going to work!
2014-02-22 14:22:14 [SEVERE] [ForgeModLoader] The minecraft jar file:/C:/Users/Will/.gradle/caches/minecraft/net/minecraftforge/forge/1.6.4-9.11.1.964/forge-1.6.4-9.11.1.964-mcp.jar!/net/minecraft/client/ClientBrandRetriever.class appears to be corrupt! There has been CRITICAL TAMPERING WITH MINECRAFT, it is highly unlikely minecraft will work! STOP NOW, get a clean copy and try again!
2014-02-22 14:22:14 [SEVERE] [ForgeModLoader] FML has been ordered to ignore the invalid or missing minecraft certificate. This is very likely to cause a problem!
2014-02-22 14:22:14 [SEVERE] [ForgeModLoader] Technical information: ClientBrandRetriever was at jar:file:/C:/Users/Will/.gradle/caches/minecraft/net/minecraftforge/forge/1.6.4-9.11.1.964/forge-1.6.4-9.11.1.964-mcp.jar!/net/minecraft/client/ClientBrandRetriever.class, there were 0 certificates for it
2014-02-22 14:22:14 [SEVERE] [ForgeModLoader] FML appears to be missing any signature data. This is not a good thing
2014-02-22 14:22:14 [INFO] [ForgeModLoader] Calling tweak class cpw.mods.fml.relauncher.CoreModManager$FMLPluginWrapper
2014-02-22 14:22:14 [INFO] [STDOUT] Loaded 110 rules from AccessTransformer config file forge_at.cfg
2014-02-22 14:22:14 [INFO] [ForgeModLoader] Calling tweak class cpw.mods.fml.relauncher.CoreModManager$FMLPluginWrapper
2014-02-22 14:22:14 [INFO] [ForgeModLoader] Calling tweak class cpw.mods.fml.common.launcher.FMLDeobfTweaker
2014-02-22 14:22:14 [INFO] [ForgeModLoader] Launching wrapped minecraft {net.minecraft.client.main.Main}
2014-02-22 14:22:15 [INFO] [Minecraft-Client] Setting user: Charsmud
2014-02-22 14:22:16 [INFO] [Minecraft-Client] LWJGL Version: 2.9.0
2014-02-22 14:22:16 [INFO] [STDERR] javax.imageio.IIOException: Can't read input file!
2014-02-22 14:22:16 [INFO] [STDERR] at javax.imageio.ImageIO.read(Unknown Source)
2014-02-22 14:22:16 [INFO] [STDERR] at net.minecraft.client.Minecraft.readImage(Minecraft.java:558)
2014-02-22 14:22:16 [INFO] [STDERR] at net.minecraft.client.Minecraft.startGame(Minecraft.java:419)
2014-02-22 14:22:16 [INFO] [STDERR] at net.minecraft.client.Minecraft.run(Minecraft.java:808)
2014-02-22 14:22:16 [INFO] [STDERR] at net.minecraft.client.main.Main.main(Main.java:101)
2014-02-22 14:22:16 [INFO] [STDERR] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
2014-02-22 14:22:16 [INFO] [STDERR] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
2014-02-22 14:22:16 [INFO] [STDERR] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
2014-02-22 14:22:16 [INFO] [STDERR] at java.lang.reflect.Method.invoke(Unknown Source)
2014-02-22 14:22:16 [INFO] [STDERR] at net.minecraft.launchwrapper.Launch.launch(Launch.java:131)
2014-02-22 14:22:16 [INFO] [STDERR] at net.minecraft.launchwrapper.Launch.main(Launch.java:27)
2014-02-22 14:22:16 [INFO] [Minecraft-Client] Reloading ResourceManager: Default
2014-02-22 14:22:16 [INFO] [MinecraftForge] Attempting early MinecraftForge initialization
2014-02-22 14:22:16 [INFO] [STDOUT] MinecraftForge v9.11.1.964 Initialized
2014-02-22 14:22:16 [INFO] [ForgeModLoader] MinecraftForge v9.11.1.964 Initialized
2014-02-22 14:22:16 [INFO] [STDOUT] Replaced 112 ore recipies
2014-02-22 14:22:16 [INFO] [MinecraftForge] Completed early MinecraftForge initialization
2014-02-22 14:22:16 [INFO] [ForgeModLoader] Reading custom logging properties from C:\Users\Will\Documents\GitHub\TimeTraveler\config\logging.properties
2014-02-22 14:22:16 [OFF] [ForgeModLoader] Logging level for ForgeModLoader logging is set to ALL
2014-02-22 14:22:17 [INFO] [ForgeModLoader] Searching C:\Users\Will\Documents\GitHub\TimeTraveler\mods for mods
2014-02-22 14:22:19 [SEVERE] [ForgeModLoader] FML has detected a mod that is using a package name based on 'net.minecraft.src' : net.minecraft.src.Start. This is generally a severe programming error. There should be no mod code in the minecraft namespace. MOVE YOUR MOD! If you're in eclipse, select your source code and 'refactor' it into a new package. Go on. DO IT NOW!
2014-02-22 14:22:19 [SEVERE] [ForgeModLoader] FML has detected a mod that is using a package name based on 'net.minecraft.src' : net.minecraft.src.FMLRenderAccessLibrary. This is generally a severe programming error. There should be no mod code in the minecraft namespace. MOVE YOUR MOD! If you're in eclipse, select your source code and 'refactor' it into a new package. Go on. DO IT NOW!
2014-02-22 14:22:19 [INFO] [ForgeModLoader] Forge Mod Loader has identified 5 mods to load
2014-02-22 14:22:19 [INFO] [mcp] Activating mod mcp
2014-02-22 14:22:19 [INFO] [FML] Activating mod FML
2014-02-22 14:22:19 [INFO] [Forge] Activating mod Forge
2014-02-22 14:22:19 [INFO] [TimeTraveler] Activating mod TimeTraveler
2014-02-22 14:22:19 [INFO] [charsmud_timetraveler] Activating mod charsmud_timetraveler
2014-02-22 14:22:19 [WARNING] [Time Traveler] Mod Time Traveler is missing a pack.mcmeta file, things may not work well
2014-02-22 14:22:19 [INFO] [Minecraft-Client] Reloading ResourceManager: Default, FMLFileResourcePack:Forge Mod Loader, FMLFileResourcePack:Minecraft Forge, FMLFileResourcePack:Time Traveler
2014-02-22 14:22:19 [INFO] [ForgeModLoader] Registering Forge Packet Handler
2014-02-22 14:22:19 [INFO] [ForgeModLoader] Succeeded registering Forge Packet Handler
2014-02-22 14:22:20 [INFO] [ForgeModLoader] Configured a dormant chunk cache size of 0
2014-02-22 14:22:24 [INFO] [ForgeModLoader] Forge Mod Loader has successfully loaded 5 mods
2014-02-22 14:22:24 [WARNING] [Time Traveler] Mod Time Traveler is missing a pack.mcmeta file, things may not work well
2014-02-22 14:22:24 [INFO] [Minecraft-Client] Reloading ResourceManager: Default, FMLFileResourcePack:Forge Mod Loader, FMLFileResourcePack:Minecraft Forge, FMLFileResourcePack:Time Traveler
2014-02-22 14:22:24 [SEVERE] [Minecraft-Client] Using missing texture, unable to load: minecraft:textures/blocks/MISSING_ICON_TILE_254_BlockParadoxCondenser.png
2014-02-22 14:22:24 [SEVERE] [Minecraft-Client] Using missing texture, unable to load: minecraft:textures/blocks/MISSING_ICON_TILE_250_TimeTravel.png
2014-02-22 14:22:24 [SEVERE] [Minecraft-Client] Using missing texture, unable to load: charsmud_timetraveler:textures/items/item.Flashback.png
2014-02-22 14:22:24 [INFO] [STDOUT]
2014-02-22 14:22:24 [INFO] [STDOUT] Starting up SoundSystem...
2014-02-22 14:22:24 [INFO] [STDOUT] Initializing LWJGL OpenAL
2014-02-22 14:22:24 [INFO] [STDOUT] (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org)
2014-02-22 14:22:24 [INFO] [STDOUT] OpenAL initialized.
2014-02-22 14:22:25 [INFO] [STDOUT]
2014-02-22 14:22:26 [SEVERE] [Minecraft-Client] Realms: Server not available!
I'm having a bit of a problem where my Coremod is being recognized by Forge, but the transform method is not being called and therefore the patch is not being applied. I'm currently just adapting the OP's code and trying to get it to work on my system, but the printlns are not being displayed in the console output. Here are the files:
package timeTraveler.core;
import java.util.Map;
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
import cpw.mods.fml.relauncher.IFMLLoadingPlugin.MCVersion;
@MCVersion(value = "1.6.4")
public class TTLoadingPlugin implements IFMLLoadingPlugin {
@Override
public String[] getASMTransformerClass()
{
//This will return the name of the class "mod.culegooner.ExplosionDropsCore.EDClassTransformer"
return new String[]{TTClassTransformer.class.getName()};
}
@Override
public String getModContainerClass()
{
//This is the name of our container "timeTraveler.TimeTraveler"
return TTDummyContainer.class.getName();
}
@Override
public String getSetupClass()
{
// TODO Auto-generated method stub
return null;
}
@Override
public void injectData(Map<String, Object> data)
{
}
}
package timeTraveler.core;
import static org.objectweb.asm.Opcodes.FDIV;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
import static org.objectweb.asm.tree.AbstractInsnNode.METHOD_INSN;
import java.util.Iterator;
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.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
public class TTClassTransformer implements net.minecraft.launchwrapper.IClassTransformer
{
@Override
public byte[] transform(String arg0, String arg1, byte[] arg2)
{
if (arg0.equals("abq"))
{
System.out.println("********* INSIDE OBFUSCATED EXPLOSION TRANSFORMER ABOUT TO PATCH: " + arg0);
return patchClassASM(arg0, arg2, true);
}
if (arg0.equals("net.minecraft.world.Explosion"))
{
System.out.println("********* INSIDE EXPLOSION TRANSFORMER ABOUT TO PATCH: " + arg0);
return patchClassASM(arg0, arg2, false);
}
return arg2;
}
public byte[] patchClassASM(String name, byte[] bytes, boolean obfuscated)
{
String targetMethodName = "";
if(obfuscated == true)
targetMethodName ="a";
else
targetMethodName ="doExplosionB";
//set up ASM class manipulation stuff. Consult the ASM docs for details
ClassNode classNode = new ClassNode();
ClassReader classReader = new ClassReader(bytes);
classReader.accept(classNode, 0);
//Now we loop over all of the methods declared inside the Explosion class until we get to the targetMethodName "doExplosionB"
// find method to inject into
@SuppressWarnings("unchecked")
Iterator<MethodNode> methods = classNode.methods.iterator();
while(methods.hasNext())
{
MethodNode m = methods.next();
System.out.println("********* Method Name: "+m.name + " Desc:" + m.desc);
int fdiv_index = -1;
//Check if this is doExplosionB and it's method signature is (Z)V which means that it accepts a boolean (Z) and returns a void (V)
if ((m.name.equals(targetMethodName) && m.desc.equals("(Z)V")))
{
System.out.println("********* Inside target method!");
// find interesting instructions in method, there is a single FDIV instruction we use as target
//System.out.println("m.instructions.size = " + m.instructions.size());
AbstractInsnNode currentNode = null;
AbstractInsnNode targetNode = null;
@SuppressWarnings("unchecked")
Iterator<AbstractInsnNode> iter = m.instructions.iterator();
int index = -1;
//Loop over the instruction set and find the instruction FDIV which does the division of 1/explosionSize
while (iter.hasNext())
{
index++;
currentNode = iter.next();
System.out.println("********* index : " + index + " currentNode.getOpcode() = " + currentNode.getOpcode());
//Found it! save the index location of instruction FDIV and the node for this instruction
if (currentNode.getOpcode() == FDIV)
{
targetNode = currentNode;
fdiv_index = index;
}
}
/*
2013-07-05 18:32:29 [INFO] [STDOUT] ********* index : 334 currentNode.getOpcode() = 25
2013-07-05 18:32:29 [INFO] [STDOUT] ********* index : 335 currentNode.getOpcode() = 180
2013-07-05 18:32:29 [INFO] [STDOUT] ********* index : 336 currentNode.getOpcode() = 110
*/
System.out.println("********* fdiv_index should be 336 -> " + fdiv_index);
if (targetNode == null)
{
System.out.println("Did not find all necessary target nodes! ABANDON CLASS!");
return bytes;
}
if (fdiv_index == -1)
{
System.out.println("Did not find all necessary target nodes! ABANDON CLASS!");
return bytes;
}
/*
//now we want the save nods that load the variable explosionSize and the division instruction:
The line in Explosion.java that we want to modify is:
var25.dropBlockAsItemWithChance(this.worldObj, var4, var5, var6, this.worldObj.getBlockMetadata(var4, var5, var6), 1.0F / this.explosionSize, 0);
The code we are looking for is the following in bytecode:
mv.visitInsn(FCONST_1);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, "net/minecraft/src/Explosion", "explosionSize", "F");
mv.visitInsn(FDIV);
mv.visitInsn(ICONST_0);
mv.visitMethodInsn(INVOKEVIRTUAL, "net/minecraft/src/Block", "dropBlockAsItemWithChance", "(Lnet/minecraft/src/World;IIIIFI)V");
*/
AbstractInsnNode remNode1 = m.instructions.get(fdiv_index-2); // mv.visitVarInsn(ALOAD, 0);
AbstractInsnNode remNode2 = m.instructions.get(fdiv_index-1); // mv.visitFieldInsn(GETFIELD, "net/minecraft/src/Explosion", "explosionSize", "F");
AbstractInsnNode remNode3 = m.instructions.get(fdiv_index); // mv.visitInsn(FDIV);
//This part is just to show how if the opcode we are looking for is an invokevirtual
AbstractInsnNode invVirt = m.instructions.get(fdiv_index+2);
if(invVirt.getOpcode() == INVOKEVIRTUAL)
{
if(invVirt.getType() == METHOD_INSN){
System.out.println("INVOKEVIRTUAL opcode is " + invVirt.getOpcode() + " METHOD_INSN type is " + invVirt.getType() );
MethodInsnNode testMethod = (MethodInsnNode)invVirt; //only do this cast if the getType match to a MethodInsnNode!! look at the javadoc for the other types!
System.out.println("INVOKEVIRTUAL :" + testMethod.owner + " , " + testMethod.name + " , " + testMethod.desc );
}
}
//just remove these nodes from the instruction set, this will prevent the instruction FCONST_1 to be divided.
m.instructions.remove(remNode1);
m.instructions.remove(remNode2);
m.instructions.remove(remNode3);
//in this commented section, i'll just illustrate how to inject a call to a static method if your instruction is a little more advanced than just removing a couple of instruction:
/*
//To add new instructions, such as calling a static method can be done like so:
// make new instruction list
InsnList toInject = new InsnList();
toInject.add(new VarInsnNode(ALOAD, 0));
toInject.add(new MethodInsnNode(INVOKESTATIC, "mod/culegooner/MyStaticClass", "myStaticMethod", "()V"));
// inject new instruction list into method instruction list
m.instructions.insert(targetNode, toInject);
*/
System.out.println("Patching Complete!");
break;
}
}
//ASM specific for cleaning up and returning the final bytes for JVM processing.
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
classNode.accept(writer);
return writer.toByteArray();
}
}
Here is the console output:
Feb 22, 2014 2:22:13 PM net.minecraft.launchwrapper.LogWrapper log
INFO: Loading tweak class name cpw.mods.fml.common.launcher.FMLTweaker
Feb 22, 2014 2:22:13 PM net.minecraft.launchwrapper.LogWrapper log
INFO: Using primary tweak class name cpw.mods.fml.common.launcher.FMLTweaker
Feb 22, 2014 2:22:13 PM net.minecraft.launchwrapper.LogWrapper log
INFO: Calling tweak class cpw.mods.fml.common.launcher.FMLTweaker
2014-02-22 14:22:13 [INFO] [ForgeModLoader] Forge Mod Loader version 6.99.19.964 for Minecraft 1.6.4 loading
2014-02-22 14:22:13 [INFO] [ForgeModLoader] Java is Java HotSpot(TM) 64-Bit Server VM, version 1.7.0_09, running on Windows 7:amd64:6.1, installed at C:\Users\Will\Desktop\eclipse-jee-juno-SR2-win32-x86_64\eclipse\jre
2014-02-22 14:22:13 [INFO] [ForgeModLoader] Managed to load a deobfuscated Minecraft name- we are in a deobfuscated environment. Skipping runtime deobfuscation
2014-02-22 14:22:13 [INFO] [ForgeModLoader] Found a command line coremod : timeTraveler.core.TTLoadingPlugin
2014-02-22 14:22:13 [INFO] [ForgeModLoader] Loading tweak class name cpw.mods.fml.common.launcher.FMLInjectionAndSortingTweaker
2014-02-22 14:22:13 [INFO] [ForgeModLoader] Loading tweak class name cpw.mods.fml.common.launcher.FMLDeobfTweaker
2014-02-22 14:22:13 [INFO] [ForgeModLoader] Calling tweak class cpw.mods.fml.common.launcher.FMLInjectionAndSortingTweaker
2014-02-22 14:22:13 [INFO] [ForgeModLoader] Calling tweak class cpw.mods.fml.common.launcher.FMLInjectionAndSortingTweaker
2014-02-22 14:22:13 [INFO] [ForgeModLoader] Calling tweak class cpw.mods.fml.relauncher.CoreModManager$FMLPluginWrapper
2014-02-22 14:22:13 [INFO] [STDOUT] Loaded 40 rules from AccessTransformer config file fml_at.cfg
2014-02-22 14:22:13 [SEVERE] [ForgeModLoader] The binary patch set is missing. Either you are in a development environment, or things are not going to work!
2014-02-22 14:22:14 [SEVERE] [ForgeModLoader] The minecraft jar file:/C:/Users/Will/.gradle/caches/minecraft/net/minecraftforge/forge/1.6.4-9.11.1.964/forge-1.6.4-9.11.1.964-mcp.jar!/net/minecraft/client/ClientBrandRetriever.class appears to be corrupt! There has been CRITICAL TAMPERING WITH MINECRAFT, it is highly unlikely minecraft will work! STOP NOW, get a clean copy and try again!
2014-02-22 14:22:14 [SEVERE] [ForgeModLoader] FML has been ordered to ignore the invalid or missing minecraft certificate. This is very likely to cause a problem!
2014-02-22 14:22:14 [SEVERE] [ForgeModLoader] Technical information: ClientBrandRetriever was at jar:file:/C:/Users/Will/.gradle/caches/minecraft/net/minecraftforge/forge/1.6.4-9.11.1.964/forge-1.6.4-9.11.1.964-mcp.jar!/net/minecraft/client/ClientBrandRetriever.class, there were 0 certificates for it
2014-02-22 14:22:14 [SEVERE] [ForgeModLoader] FML appears to be missing any signature data. This is not a good thing
2014-02-22 14:22:14 [INFO] [ForgeModLoader] Calling tweak class cpw.mods.fml.relauncher.CoreModManager$FMLPluginWrapper
2014-02-22 14:22:14 [INFO] [STDOUT] Loaded 110 rules from AccessTransformer config file forge_at.cfg
2014-02-22 14:22:14 [INFO] [ForgeModLoader] Calling tweak class cpw.mods.fml.relauncher.CoreModManager$FMLPluginWrapper
2014-02-22 14:22:14 [INFO] [ForgeModLoader] Calling tweak class cpw.mods.fml.common.launcher.FMLDeobfTweaker
2014-02-22 14:22:14 [INFO] [ForgeModLoader] Launching wrapped minecraft {net.minecraft.client.main.Main}
2014-02-22 14:22:15 [INFO] [Minecraft-Client] Setting user: Charsmud
2014-02-22 14:22:16 [INFO] [Minecraft-Client] LWJGL Version: 2.9.0
2014-02-22 14:22:16 [INFO] [STDERR] javax.imageio.IIOException: Can't read input file!
2014-02-22 14:22:16 [INFO] [STDERR] at javax.imageio.ImageIO.read(Unknown Source)
2014-02-22 14:22:16 [INFO] [STDERR] at net.minecraft.client.Minecraft.readImage(Minecraft.java:558)
2014-02-22 14:22:16 [INFO] [STDERR] at net.minecraft.client.Minecraft.startGame(Minecraft.java:419)
2014-02-22 14:22:16 [INFO] [STDERR] at net.minecraft.client.Minecraft.run(Minecraft.java:808)
2014-02-22 14:22:16 [INFO] [STDERR] at net.minecraft.client.main.Main.main(Main.java:101)
2014-02-22 14:22:16 [INFO] [STDERR] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
2014-02-22 14:22:16 [INFO] [STDERR] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
2014-02-22 14:22:16 [INFO] [STDERR] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
2014-02-22 14:22:16 [INFO] [STDERR] at java.lang.reflect.Method.invoke(Unknown Source)
2014-02-22 14:22:16 [INFO] [STDERR] at net.minecraft.launchwrapper.Launch.launch(Launch.java:131)
2014-02-22 14:22:16 [INFO] [STDERR] at net.minecraft.launchwrapper.Launch.main(Launch.java:27)
2014-02-22 14:22:16 [INFO] [Minecraft-Client] Reloading ResourceManager: Default
2014-02-22 14:22:16 [INFO] [MinecraftForge] Attempting early MinecraftForge initialization
2014-02-22 14:22:16 [INFO] [STDOUT] MinecraftForge v9.11.1.964 Initialized
2014-02-22 14:22:16 [INFO] [ForgeModLoader] MinecraftForge v9.11.1.964 Initialized
2014-02-22 14:22:16 [INFO] [STDOUT] Replaced 112 ore recipies
2014-02-22 14:22:16 [INFO] [MinecraftForge] Completed early MinecraftForge initialization
2014-02-22 14:22:16 [INFO] [ForgeModLoader] Reading custom logging properties from C:\Users\Will\Documents\GitHub\TimeTraveler\config\logging.properties
2014-02-22 14:22:16 [OFF] [ForgeModLoader] Logging level for ForgeModLoader logging is set to ALL
2014-02-22 14:22:17 [INFO] [ForgeModLoader] Searching C:\Users\Will\Documents\GitHub\TimeTraveler\mods for mods
2014-02-22 14:22:19 [SEVERE] [ForgeModLoader] FML has detected a mod that is using a package name based on 'net.minecraft.src' : net.minecraft.src.Start. This is generally a severe programming error. There should be no mod code in the minecraft namespace. MOVE YOUR MOD! If you're in eclipse, select your source code and 'refactor' it into a new package. Go on. DO IT NOW!
2014-02-22 14:22:19 [SEVERE] [ForgeModLoader] FML has detected a mod that is using a package name based on 'net.minecraft.src' : net.minecraft.src.FMLRenderAccessLibrary. This is generally a severe programming error. There should be no mod code in the minecraft namespace. MOVE YOUR MOD! If you're in eclipse, select your source code and 'refactor' it into a new package. Go on. DO IT NOW!
2014-02-22 14:22:19 [INFO] [ForgeModLoader] Forge Mod Loader has identified 5 mods to load
2014-02-22 14:22:19 [INFO] [mcp] Activating mod mcp
2014-02-22 14:22:19 [INFO] [FML] Activating mod FML
2014-02-22 14:22:19 [INFO] [Forge] Activating mod Forge
2014-02-22 14:22:19 [INFO] [TimeTraveler] Activating mod TimeTraveler
2014-02-22 14:22:19 [INFO] [charsmud_timetraveler] Activating mod charsmud_timetraveler
2014-02-22 14:22:19 [WARNING] [Time Traveler] Mod Time Traveler is missing a pack.mcmeta file, things may not work well
2014-02-22 14:22:19 [INFO] [Minecraft-Client] Reloading ResourceManager: Default, FMLFileResourcePack:Forge Mod Loader, FMLFileResourcePack:Minecraft Forge, FMLFileResourcePack:Time Traveler
2014-02-22 14:22:19 [INFO] [ForgeModLoader] Registering Forge Packet Handler
2014-02-22 14:22:19 [INFO] [ForgeModLoader] Succeeded registering Forge Packet Handler
2014-02-22 14:22:20 [INFO] [ForgeModLoader] Configured a dormant chunk cache size of 0
2014-02-22 14:22:24 [INFO] [ForgeModLoader] Forge Mod Loader has successfully loaded 5 mods
2014-02-22 14:22:24 [WARNING] [Time Traveler] Mod Time Traveler is missing a pack.mcmeta file, things may not work well
2014-02-22 14:22:24 [INFO] [Minecraft-Client] Reloading ResourceManager: Default, FMLFileResourcePack:Forge Mod Loader, FMLFileResourcePack:Minecraft Forge, FMLFileResourcePack:Time Traveler
2014-02-22 14:22:24 [SEVERE] [Minecraft-Client] Using missing texture, unable to load: minecraft:textures/blocks/MISSING_ICON_TILE_254_BlockParadoxCondenser.png
2014-02-22 14:22:24 [SEVERE] [Minecraft-Client] Using missing texture, unable to load: minecraft:textures/blocks/MISSING_ICON_TILE_250_TimeTravel.png
2014-02-22 14:22:24 [SEVERE] [Minecraft-Client] Using missing texture, unable to load: charsmud_timetraveler:textures/items/item.Flashback.png
2014-02-22 14:22:24 [INFO] [STDOUT]
2014-02-22 14:22:24 [INFO] [STDOUT] Starting up SoundSystem...
2014-02-22 14:22:24 [INFO] [STDOUT] Initializing LWJGL OpenAL
2014-02-22 14:22:24 [INFO] [STDOUT] (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org)
2014-02-22 14:22:24 [INFO] [STDOUT] OpenAL initialized.
2014-02-22 14:22:25 [INFO] [STDOUT]
2014-02-22 14:22:26 [SEVERE] [Minecraft-Client] Realms: Server not available!
Any ideas on how to get this working?
I think your problem might be here:
2014-02-22 14:22:14 [SEVERE] [ForgeModLoader] The minecraft jar file:/C:/Users/Will/.gradle/caches/minecraft/net/minecraftforge/forge/1.6.4-9.11.1.964/forge-1.6.4-9.11.1.964-mcp.jar!/net/minecraft/client/ClientBrandRetriever.class appears to be corrupt! There has been CRITICAL TAMPERING WITH MINECRAFT, it is highly unlikely minecraft will work! STOP NOW, get a clean copy and try again!
EDIT: Ignore that. I'll look into it more when I have time.
2014-02-22 14:22:14 [SEVERE] [ForgeModLoader] The minecraft jar file:/C:/Users/Will/.gradle/caches/minecraft/net/minecraftforge/forge/1.6.4-9.11.1.964/forge-1.6.4-9.11.1.964-mcp.jar!/net/minecraft/client/ClientBrandRetriever.class appears to be corrupt! There has been CRITICAL TAMPERING WITH MINECRAFT, it is highly unlikely minecraft will work! STOP NOW, get a clean copy and try again!
This has nothing to do with any of his/her problems. This error pops up due to the fact that FML directly patches this ClientBrandRetriever.class when the development environment is setup, causing it to appear modified by someone when reality FML just doesn't check to see whether or not it was applied using a binary patch or a direct patch.
Thanks for the tutorial culegooner ... worked wonders to override a class after a few missteps.
I'm using 1.6.4 and I didn't see anything in the tutorial about using the dummy ModContainer ... but I found what I needed in your source code on GitHub, so thanks for sharing.
It might help someone else if I document the missteps ...
culegooner mentions a runtime crash in the tutorial in the dev environment using the class file from reobfuscate_srg. I had a MethodNotFound exception in the middle of the minecraft code - using the version from bin fixed it for me.
According to the decompiler, the reobfuscate_srg version is somehow not deobfuscating the method names?
When the class being overridden is called from the coremod code (e.g. calling it from the ModContainer init), it works under eclipse but crashes with a "ClassDefNotFound" error if run as a fully packaged JAR & using obfuscated minecraft. This happens after the modified class has successfully been trapped and overridden. No idea why ... probably something to do with the obfuscation. Removing the reference to the overridden class fixed the problem.
This has nothing to do with any of his/her problems. This error pops up due to the fact that FML directly patches this ClientBrandRetriever.class when the development environment is setup, causing it to appear modified by someone when reality FML just doesn't check to see whether or not it was applied using a binary patch or a direct patch.
Just a note, LexManos will hunt you down and rip out your heart if you use the full class overwrite (for ANY reason), and yell at you if you use the patching (when there are other ways around it).
not to mention the full class overwrite 1. makes for bad mod compatability and 2. kinda violates the MC EULA (I'm looking at you, OptiFine!)
You managed to decompile and continue without me giving source code? O_O Bro, you are a god. Of course do whatever the [REDACTED] you want!!!! Good luck on it
I am trying to modify a line of existing code but am not 100% on how to go around doing this...
Would I have to remove the line and then add in my code later or is there any examples around.
I am trying to replace this line in BlockDynamicLiquid... Note: This is 1.7.2
With this:
Thanks
-
View User Profile
-
View Posts
-
Send Message
Curse Premium-tlf
Well I actually ended up just removing the ... It works as I want it to but I am not sure how it will hold up when other mods and custom liquid...
-
View User Profile
-
View Posts
-
Send Message
Curse Premium-tlf
Infinite Liquids.... Its what lets water make new source blocks... http://grim3212.wikispaces.com/Infinite+Lava
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumTurns out that it was a very simple change... The only problem with how I chose to do it is that it may interfere with another mods custom liquid if they extend BlockDynamicLiquid...
https://www.grim3212.com/grim-pack
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumI am trying to access this field in Minecrafts Timer class.
I need it to be static unless there is another way to access and modify this variable that I am unaware of...
Thanks
https://www.grim3212.com/grim-pack
-
View User Profile
-
View Posts
-
Send Message
Curse PremiumWell originally I just replaced the Timer with my own custom Timer that only changed it to static. It didn't conflict with anything in 1.6.4...
https://www.grim3212.com/grim-pack
http://pastebin.com/A7SMrdTy
-
View User Profile
-
View Posts
-
Send Message
Curse Premium-tlf
-
View User Profile
-
View Posts
-
Send Message
Curse Premiumpackage timeTraveler.core; import java.util.Map; import cpw.mods.fml.relauncher.IFMLLoadingPlugin; import cpw.mods.fml.relauncher.IFMLLoadingPlugin.MCVersion; @MCVersion(value = "1.6.4") public class TTLoadingPlugin implements IFMLLoadingPlugin { @Override public String[] getASMTransformerClass() { //This will return the name of the class "mod.culegooner.ExplosionDropsCore.EDClassTransformer" return new String[]{TTClassTransformer.class.getName()}; } @Override public String getModContainerClass() { //This is the name of our container "timeTraveler.TimeTraveler" return TTDummyContainer.class.getName(); } @Override public String getSetupClass() { // TODO Auto-generated method stub return null; } @Override public void injectData(Map<String, Object> data) { } }package timeTraveler.core; import java.util.Arrays; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; import cpw.mods.fml.common.DummyModContainer; import cpw.mods.fml.common.LoadController; import cpw.mods.fml.common.ModMetadata; import cpw.mods.fml.common.event.FMLConstructionEvent; import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLPostInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; public class TTDummyContainer extends DummyModContainer { public TTDummyContainer() { super(new ModMetadata()); ModMetadata meta = getMetadata(); meta.modId = "TimeTraveler"; meta.name = "TimeTraveler"; meta.version = "@[email protected]"; meta.credits = "Roll Credits ..."; meta.authorList = Arrays.asList("Charsmud"); meta.description = ""; meta.url = "https://github.com/culegooner/CreeperBurnCore"; meta.updateUrl = ""; meta.screenshots = new String[0]; meta.logoFile = ""; } @Override public boolean registerBus(EventBus bus, LoadController controller) { bus.register(this); return true; } @Subscribe public void modConstruction(FMLConstructionEvent evt){ } @Subscribe public void preInit(FMLPreInitializationEvent evt) { } @Subscribe public void init(FMLInitializationEvent evt) { } @Subscribe public void postInit(FMLPostInitializationEvent evt) { } }package timeTraveler.core; import static org.objectweb.asm.Opcodes.FDIV; import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; import static org.objectweb.asm.tree.AbstractInsnNode.METHOD_INSN; import java.util.Iterator; 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.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; public class TTClassTransformer implements net.minecraft.launchwrapper.IClassTransformer { @Override public byte[] transform(String arg0, String arg1, byte[] arg2) { if (arg0.equals("abq")) { System.out.println("********* INSIDE OBFUSCATED EXPLOSION TRANSFORMER ABOUT TO PATCH: " + arg0); return patchClassASM(arg0, arg2, true); } if (arg0.equals("net.minecraft.world.Explosion")) { System.out.println("********* INSIDE EXPLOSION TRANSFORMER ABOUT TO PATCH: " + arg0); return patchClassASM(arg0, arg2, false); } return arg2; } public byte[] patchClassASM(String name, byte[] bytes, boolean obfuscated) { String targetMethodName = ""; if(obfuscated == true) targetMethodName ="a"; else targetMethodName ="doExplosionB"; //set up ASM class manipulation stuff. Consult the ASM docs for details ClassNode classNode = new ClassNode(); ClassReader classReader = new ClassReader(bytes); classReader.accept(classNode, 0); //Now we loop over all of the methods declared inside the Explosion class until we get to the targetMethodName "doExplosionB" // find method to inject into @SuppressWarnings("unchecked") Iterator<MethodNode> methods = classNode.methods.iterator(); while(methods.hasNext()) { MethodNode m = methods.next(); System.out.println("********* Method Name: "+m.name + " Desc:" + m.desc); int fdiv_index = -1; //Check if this is doExplosionB and it's method signature is (Z)V which means that it accepts a boolean (Z) and returns a void (V) if ((m.name.equals(targetMethodName) && m.desc.equals("(Z)V"))) { System.out.println("********* Inside target method!"); // find interesting instructions in method, there is a single FDIV instruction we use as target //System.out.println("m.instructions.size = " + m.instructions.size()); AbstractInsnNode currentNode = null; AbstractInsnNode targetNode = null; @SuppressWarnings("unchecked") Iterator<AbstractInsnNode> iter = m.instructions.iterator(); int index = -1; //Loop over the instruction set and find the instruction FDIV which does the division of 1/explosionSize while (iter.hasNext()) { index++; currentNode = iter.next(); System.out.println("********* index : " + index + " currentNode.getOpcode() = " + currentNode.getOpcode()); //Found it! save the index location of instruction FDIV and the node for this instruction if (currentNode.getOpcode() == FDIV) { targetNode = currentNode; fdiv_index = index; } } /* 2013-07-05 18:32:29 [INFO] [STDOUT] ********* index : 334 currentNode.getOpcode() = 25 2013-07-05 18:32:29 [INFO] [STDOUT] ********* index : 335 currentNode.getOpcode() = 180 2013-07-05 18:32:29 [INFO] [STDOUT] ********* index : 336 currentNode.getOpcode() = 110 */ System.out.println("********* fdiv_index should be 336 -> " + fdiv_index); if (targetNode == null) { System.out.println("Did not find all necessary target nodes! ABANDON CLASS!"); return bytes; } if (fdiv_index == -1) { System.out.println("Did not find all necessary target nodes! ABANDON CLASS!"); return bytes; } /* //now we want the save nods that load the variable explosionSize and the division instruction: The line in Explosion.java that we want to modify is: var25.dropBlockAsItemWithChance(this.worldObj, var4, var5, var6, this.worldObj.getBlockMetadata(var4, var5, var6), 1.0F / this.explosionSize, 0); The code we are looking for is the following in bytecode: mv.visitInsn(FCONST_1); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, "net/minecraft/src/Explosion", "explosionSize", "F"); mv.visitInsn(FDIV); mv.visitInsn(ICONST_0); mv.visitMethodInsn(INVOKEVIRTUAL, "net/minecraft/src/Block", "dropBlockAsItemWithChance", "(Lnet/minecraft/src/World;IIIIFI)V"); */ AbstractInsnNode remNode1 = m.instructions.get(fdiv_index-2); // mv.visitVarInsn(ALOAD, 0); AbstractInsnNode remNode2 = m.instructions.get(fdiv_index-1); // mv.visitFieldInsn(GETFIELD, "net/minecraft/src/Explosion", "explosionSize", "F"); AbstractInsnNode remNode3 = m.instructions.get(fdiv_index); // mv.visitInsn(FDIV); //This part is just to show how if the opcode we are looking for is an invokevirtual AbstractInsnNode invVirt = m.instructions.get(fdiv_index+2); if(invVirt.getOpcode() == INVOKEVIRTUAL) { if(invVirt.getType() == METHOD_INSN){ System.out.println("INVOKEVIRTUAL opcode is " + invVirt.getOpcode() + " METHOD_INSN type is " + invVirt.getType() ); MethodInsnNode testMethod = (MethodInsnNode)invVirt; //only do this cast if the getType match to a MethodInsnNode!! look at the javadoc for the other types! System.out.println("INVOKEVIRTUAL :" + testMethod.owner + " , " + testMethod.name + " , " + testMethod.desc ); } } //just remove these nodes from the instruction set, this will prevent the instruction FCONST_1 to be divided. m.instructions.remove(remNode1); m.instructions.remove(remNode2); m.instructions.remove(remNode3); //in this commented section, i'll just illustrate how to inject a call to a static method if your instruction is a little more advanced than just removing a couple of instruction: /* //To add new instructions, such as calling a static method can be done like so: // make new instruction list InsnList toInject = new InsnList(); toInject.add(new VarInsnNode(ALOAD, 0)); toInject.add(new MethodInsnNode(INVOKESTATIC, "mod/culegooner/MyStaticClass", "myStaticMethod", "()V")); // inject new instruction list into method instruction list m.instructions.insert(targetNode, toInject); */ System.out.println("Patching Complete!"); break; } } //ASM specific for cleaning up and returning the final bytes for JVM processing. ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); classNode.accept(writer); return writer.toByteArray(); } }Here is the console output:
Feb 22, 2014 2:22:13 PM net.minecraft.launchwrapper.LogWrapper log INFO: Loading tweak class name cpw.mods.fml.common.launcher.FMLTweaker Feb 22, 2014 2:22:13 PM net.minecraft.launchwrapper.LogWrapper log INFO: Using primary tweak class name cpw.mods.fml.common.launcher.FMLTweaker Feb 22, 2014 2:22:13 PM net.minecraft.launchwrapper.LogWrapper log INFO: Calling tweak class cpw.mods.fml.common.launcher.FMLTweaker 2014-02-22 14:22:13 [INFO] [ForgeModLoader] Forge Mod Loader version 6.99.19.964 for Minecraft 1.6.4 loading 2014-02-22 14:22:13 [INFO] [ForgeModLoader] Java is Java HotSpot(TM) 64-Bit Server VM, version 1.7.0_09, running on Windows 7:amd64:6.1, installed at C:\Users\Will\Desktop\eclipse-jee-juno-SR2-win32-x86_64\eclipse\jre 2014-02-22 14:22:13 [INFO] [ForgeModLoader] Managed to load a deobfuscated Minecraft name- we are in a deobfuscated environment. Skipping runtime deobfuscation 2014-02-22 14:22:13 [INFO] [ForgeModLoader] Found a command line coremod : timeTraveler.core.TTLoadingPlugin 2014-02-22 14:22:13 [INFO] [ForgeModLoader] Loading tweak class name cpw.mods.fml.common.launcher.FMLInjectionAndSortingTweaker 2014-02-22 14:22:13 [INFO] [ForgeModLoader] Loading tweak class name cpw.mods.fml.common.launcher.FMLDeobfTweaker 2014-02-22 14:22:13 [INFO] [ForgeModLoader] Calling tweak class cpw.mods.fml.common.launcher.FMLInjectionAndSortingTweaker 2014-02-22 14:22:13 [INFO] [ForgeModLoader] Calling tweak class cpw.mods.fml.common.launcher.FMLInjectionAndSortingTweaker 2014-02-22 14:22:13 [INFO] [ForgeModLoader] Calling tweak class cpw.mods.fml.relauncher.CoreModManager$FMLPluginWrapper 2014-02-22 14:22:13 [INFO] [STDOUT] Loaded 40 rules from AccessTransformer config file fml_at.cfg 2014-02-22 14:22:13 [SEVERE] [ForgeModLoader] The binary patch set is missing. Either you are in a development environment, or things are not going to work! 2014-02-22 14:22:14 [SEVERE] [ForgeModLoader] The minecraft jar file:/C:/Users/Will/.gradle/caches/minecraft/net/minecraftforge/forge/1.6.4-9.11.1.964/forge-1.6.4-9.11.1.964-mcp.jar!/net/minecraft/client/ClientBrandRetriever.class appears to be corrupt! There has been CRITICAL TAMPERING WITH MINECRAFT, it is highly unlikely minecraft will work! STOP NOW, get a clean copy and try again! 2014-02-22 14:22:14 [SEVERE] [ForgeModLoader] FML has been ordered to ignore the invalid or missing minecraft certificate. This is very likely to cause a problem! 2014-02-22 14:22:14 [SEVERE] [ForgeModLoader] Technical information: ClientBrandRetriever was at jar:file:/C:/Users/Will/.gradle/caches/minecraft/net/minecraftforge/forge/1.6.4-9.11.1.964/forge-1.6.4-9.11.1.964-mcp.jar!/net/minecraft/client/ClientBrandRetriever.class, there were 0 certificates for it 2014-02-22 14:22:14 [SEVERE] [ForgeModLoader] FML appears to be missing any signature data. This is not a good thing 2014-02-22 14:22:14 [INFO] [ForgeModLoader] Calling tweak class cpw.mods.fml.relauncher.CoreModManager$FMLPluginWrapper 2014-02-22 14:22:14 [INFO] [STDOUT] Loaded 110 rules from AccessTransformer config file forge_at.cfg 2014-02-22 14:22:14 [INFO] [ForgeModLoader] Calling tweak class cpw.mods.fml.relauncher.CoreModManager$FMLPluginWrapper 2014-02-22 14:22:14 [INFO] [ForgeModLoader] Calling tweak class cpw.mods.fml.common.launcher.FMLDeobfTweaker 2014-02-22 14:22:14 [INFO] [ForgeModLoader] Launching wrapped minecraft {net.minecraft.client.main.Main} 2014-02-22 14:22:15 [INFO] [Minecraft-Client] Setting user: Charsmud 2014-02-22 14:22:16 [INFO] [Minecraft-Client] LWJGL Version: 2.9.0 2014-02-22 14:22:16 [INFO] [STDERR] javax.imageio.IIOException: Can't read input file! 2014-02-22 14:22:16 [INFO] [STDERR] at javax.imageio.ImageIO.read(Unknown Source) 2014-02-22 14:22:16 [INFO] [STDERR] at net.minecraft.client.Minecraft.readImage(Minecraft.java:558) 2014-02-22 14:22:16 [INFO] [STDERR] at net.minecraft.client.Minecraft.startGame(Minecraft.java:419) 2014-02-22 14:22:16 [INFO] [STDERR] at net.minecraft.client.Minecraft.run(Minecraft.java:808) 2014-02-22 14:22:16 [INFO] [STDERR] at net.minecraft.client.main.Main.main(Main.java:101) 2014-02-22 14:22:16 [INFO] [STDERR] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 2014-02-22 14:22:16 [INFO] [STDERR] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) 2014-02-22 14:22:16 [INFO] [STDERR] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) 2014-02-22 14:22:16 [INFO] [STDERR] at java.lang.reflect.Method.invoke(Unknown Source) 2014-02-22 14:22:16 [INFO] [STDERR] at net.minecraft.launchwrapper.Launch.launch(Launch.java:131) 2014-02-22 14:22:16 [INFO] [STDERR] at net.minecraft.launchwrapper.Launch.main(Launch.java:27) 2014-02-22 14:22:16 [INFO] [Minecraft-Client] Reloading ResourceManager: Default 2014-02-22 14:22:16 [INFO] [MinecraftForge] Attempting early MinecraftForge initialization 2014-02-22 14:22:16 [INFO] [STDOUT] MinecraftForge v9.11.1.964 Initialized 2014-02-22 14:22:16 [INFO] [ForgeModLoader] MinecraftForge v9.11.1.964 Initialized 2014-02-22 14:22:16 [INFO] [STDOUT] Replaced 112 ore recipies 2014-02-22 14:22:16 [INFO] [MinecraftForge] Completed early MinecraftForge initialization 2014-02-22 14:22:16 [INFO] [ForgeModLoader] Reading custom logging properties from C:\Users\Will\Documents\GitHub\TimeTraveler\config\logging.properties 2014-02-22 14:22:16 [OFF] [ForgeModLoader] Logging level for ForgeModLoader logging is set to ALL 2014-02-22 14:22:17 [INFO] [ForgeModLoader] Searching C:\Users\Will\Documents\GitHub\TimeTraveler\mods for mods 2014-02-22 14:22:19 [SEVERE] [ForgeModLoader] FML has detected a mod that is using a package name based on 'net.minecraft.src' : net.minecraft.src.Start. This is generally a severe programming error. There should be no mod code in the minecraft namespace. MOVE YOUR MOD! If you're in eclipse, select your source code and 'refactor' it into a new package. Go on. DO IT NOW! 2014-02-22 14:22:19 [SEVERE] [ForgeModLoader] FML has detected a mod that is using a package name based on 'net.minecraft.src' : net.minecraft.src.FMLRenderAccessLibrary. This is generally a severe programming error. There should be no mod code in the minecraft namespace. MOVE YOUR MOD! If you're in eclipse, select your source code and 'refactor' it into a new package. Go on. DO IT NOW! 2014-02-22 14:22:19 [INFO] [ForgeModLoader] Forge Mod Loader has identified 5 mods to load 2014-02-22 14:22:19 [INFO] [mcp] Activating mod mcp 2014-02-22 14:22:19 [INFO] [FML] Activating mod FML 2014-02-22 14:22:19 [INFO] [Forge] Activating mod Forge 2014-02-22 14:22:19 [INFO] [TimeTraveler] Activating mod TimeTraveler 2014-02-22 14:22:19 [INFO] [charsmud_timetraveler] Activating mod charsmud_timetraveler 2014-02-22 14:22:19 [WARNING] [Time Traveler] Mod Time Traveler is missing a pack.mcmeta file, things may not work well 2014-02-22 14:22:19 [INFO] [Minecraft-Client] Reloading ResourceManager: Default, FMLFileResourcePack:Forge Mod Loader, FMLFileResourcePack:Minecraft Forge, FMLFileResourcePack:Time Traveler 2014-02-22 14:22:19 [INFO] [ForgeModLoader] Registering Forge Packet Handler 2014-02-22 14:22:19 [INFO] [ForgeModLoader] Succeeded registering Forge Packet Handler 2014-02-22 14:22:20 [INFO] [ForgeModLoader] Configured a dormant chunk cache size of 0 2014-02-22 14:22:24 [INFO] [ForgeModLoader] Forge Mod Loader has successfully loaded 5 mods 2014-02-22 14:22:24 [WARNING] [Time Traveler] Mod Time Traveler is missing a pack.mcmeta file, things may not work well 2014-02-22 14:22:24 [INFO] [Minecraft-Client] Reloading ResourceManager: Default, FMLFileResourcePack:Forge Mod Loader, FMLFileResourcePack:Minecraft Forge, FMLFileResourcePack:Time Traveler 2014-02-22 14:22:24 [SEVERE] [Minecraft-Client] Using missing texture, unable to load: minecraft:textures/blocks/MISSING_ICON_TILE_254_BlockParadoxCondenser.png 2014-02-22 14:22:24 [SEVERE] [Minecraft-Client] Using missing texture, unable to load: minecraft:textures/blocks/MISSING_ICON_TILE_250_TimeTravel.png 2014-02-22 14:22:24 [SEVERE] [Minecraft-Client] Using missing texture, unable to load: charsmud_timetraveler:textures/items/item.Flashback.png 2014-02-22 14:22:24 [INFO] [STDOUT] 2014-02-22 14:22:24 [INFO] [STDOUT] Starting up SoundSystem... 2014-02-22 14:22:24 [INFO] [STDOUT] Initializing LWJGL OpenAL 2014-02-22 14:22:24 [INFO] [STDOUT] (The LWJGL binding of OpenAL. For more information, see http://www.lwjgl.org) 2014-02-22 14:22:24 [INFO] [STDOUT] OpenAL initialized. 2014-02-22 14:22:25 [INFO] [STDOUT] 2014-02-22 14:22:26 [SEVERE] [Minecraft-Client] Realms: Server not available!-
View User Profile
-
View Posts
-
Send Message
Curse PremiumEDIT: Ignore that. I'll look into it more when I have time.
-tlf
This has nothing to do with any of his/her problems. This error pops up due to the fact that FML directly patches this ClientBrandRetriever.class when the development environment is setup, causing it to appear modified by someone when reality FML just doesn't check to see whether or not it was applied using a binary patch or a direct patch.
I'm using 1.6.4 and I didn't see anything in the tutorial about using the dummy ModContainer ... but I found what I needed in your source code on GitHub, so thanks for sharing.
It might help someone else if I document the missteps ...
culegooner mentions a runtime crash in the tutorial in the dev environment using the class file from reobfuscate_srg. I had a MethodNotFound exception in the middle of the minecraft code - using the version from bin fixed it for me.
According to the decompiler, the reobfuscate_srg version is somehow not deobfuscating the method names?
When the class being overridden is called from the coremod code (e.g. calling it from the ModContainer init), it works under eclipse but crashes with a "ClassDefNotFound" error if run as a fully packaged JAR & using obfuscated minecraft. This happens after the modified class has successfully been trapped and overridden. No idea why ... probably something to do with the obfuscation. Removing the reference to the overridden class fixed the problem.
-
View User Profile
-
View Posts
-
Send Message
Curse Premium-tlf
-
View User Profile
-
View Posts
-
Send Message
Curse Premium-
View User Profile
-
View Posts
-
Send Message
Curse PremiumPatreon
- Buggi -
My Humble YouTube Channel
https://www.youtube.com/c/FlexibleGames
Featuring in-depth and technical gameplay with games like Minecraft, Factorio, and others.