TBH you don't need a knowledge of JVM bytecode to use the ASM in Forge, you just need a knowledge of the stack, some small reflection knowledge, and a tad knowledge of how the ASM opcodes work......
Knowing how the bytecode works is non-relevant really...but it would be useful to do something extravagant.....
I know it's a long video, but it's not very complicated and pretty straight forward. The video covers a little bit of the ASM API at the very end. You need to understand the basic concepts as you put it "stack, ASM opcodes" which this video covers well. I see no harm with it's inclusion.
The Meaning of Life, the Universe, and Everything.
Join Date:
3/7/2011
Posts:
56
Member Details
My game keeps crashing when I try to do ANYTHING with the methodnode's instructions. The error says noclassdef, but I printed out all the methods in that class about 2 lines previous. any suggestions?
My game keeps crashing when I try to do ANYTHING with the methodnode's instructions. The error says noclassdef, but I printed out all the methods in that class about 2 lines previous. any suggestions?
Great Tutorial! I tried to replace net.minecraft.client.gui.inventory.GuiEditSign and net.minecraft.client.renderer.tileentity.TileEntitySignRenderer, Forge doesn't seem to call the tranform function on those two classes.
My class transformer:
///////////////////////////////////////////////////////////////////////////////
// Package ////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
package poersch.minecraft.bettersigns;
///////////////////////////////////////////////////////////////////////////////
// Imports ////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
import java.io.File;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
///////////////////////////////////////////////////////////////////////////////
// Better Signs Mod Class Transformer /////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
public class BetterSignsModClassTransformer implements net.minecraft.launchwrapper.IClassTransformer {
///////////////////////////////////////////////////////////////////////////////
// Transform the specified classses ///////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
@Override
public byte[] transform(String name, String arg1, byte[] data) {
for(int n = 0; n < BetterSignsModLoadingPlugin.toPatch.length; n++)
if(name.equals(BetterSignsModLoadingPlugin.toPatch[n])) {
System.out.println("TEST " + name);
data = overwriteClass(name, data, BetterSignsModLoadingPlugin.location);
}
return data;
}
///////////////////////////////////////////////////////////////////////////////
// Overwrite specified class //////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
public byte[] overwriteClass(String name, byte[] data, File location) {
try {
ZipFile zip = new ZipFile(location);
ZipEntry entry = zip.getEntry(name.replace('.', '/') + ".class");
if(entry == null) {
System.out.println("[BetterSignsMod] Class " + name + " not found in " + location.getName());
} else {
InputStream zin = zip.getInputStream(entry);
data = new byte[(int) entry.getSize()];
zin.read(data);
zin.close();
System.out.println("[BetterSignsMod] Class " + name + " patched!");
}
zip.close();
} catch (Exception e) {
throw new RuntimeException("[BetterSignsMod] Error overwriting Class " + name + " from " + location.getName(), e);
}
return data;
}
}
My loading plugin:
///////////////////////////////////////////////////////////////////////////////
// Package ////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
package poersch.minecraft.bettersigns;
///////////////////////////////////////////////////////////////////////////////
// Imports ////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
import java.io.File;
import java.util.Map;
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
import cpw.mods.fml.relauncher.IFMLLoadingPlugin.MCVersion;
import cpw.mods.fml.relauncher.IFMLLoadingPlugin.TransformerExclusions;
///////////////////////////////////////////////////////////////////////////////
// Better Signs Mod FML Plugin ////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
@MCVersion(value = "1.6.1")
@TransformerExclusions( { "poersch.minecraft.bettersigns" } )
public class BetterSignsModLoadingPlugin implements IFMLLoadingPlugin {
///////////////////////////////////////////////////////////////////////////////
// Variable definitions ///////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
public static File location;
public static String[] toPatch = new String[] { "axp", "bip", "net.minecraft.client.gui.inventory.GuiEditSign", "net.minecraft.client.renderer.tileentity.TileEntitySignRenderer" };
///////////////////////////////////////////////////////////////////////////////
// Get library request class //////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
@Override
public String[] getLibraryRequestClass() {
return null;
}
///////////////////////////////////////////////////////////////////////////////
// Get ASM transformer class //////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
@Override
public String[] getASMTransformerClass() {
return new String[] { BetterSignsModClassTransformer.class.getName() };
}
///////////////////////////////////////////////////////////////////////////////
// Get mod container class ////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
@Override
public String getModContainerClass() {
return null;
}
///////////////////////////////////////////////////////////////////////////////
// Get setup class ////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
@Override
public String getSetupClass() {
return null;
}
///////////////////////////////////////////////////////////////////////////////
// Inject data ////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
@Override
public void injectData(Map<String, Object> data) {
location = (File) data.get("coremodLocation");
}
}
I tried it out and the transformer does run on those classes, The way it works is that it doesn't patch when minecraft starts. it patches when the class is about to be loaded when called.
Here's my log:
2013-07-09 06:17:38 [INFO] [STDOUT] ********* LOOP TRANSFORMER ABOUT TO PATCH: net.minecraft.client.renderer.tileentity.TileEntitySignRenderer
2013-07-09 06:17:36 [INFO] [STDOUT] ********* LOOP TRANSFORMER ABOUT TO PATCH: net.minecraft.client.gui.inventory.GuiEditSign
you can test it like so
@Override
public byte[] transform(String arg0, String arg1, byte[] arg2) {
System.out.println("********* LOOP TRANSFORMER ABOUT TO PATCH: " + arg0);
return arg2;
}
I tried it out and the transformer does run on those classes, The way it works is that it doesn't patch when minecraft starts. it patches when the class is about to be loaded when called.
Here's my log:
2013-07-09 06:17:38 [INFO] [STDOUT] ********* LOOP TRANSFORMER ABOUT TO PATCH: net.minecraft.client.renderer.tileentity.TileEntitySignRenderer
2013-07-09 06:17:36 [INFO] [STDOUT] ********* LOOP TRANSFORMER ABOUT TO PATCH: net.minecraft.client.gui.inventory.GuiEditSign
you can test it like so
@Override
public byte[] transform(String arg0, String arg1, byte[] arg2) {
System.out.println("********* LOOP TRANSFORMER ABOUT TO PATCH: " + arg0);
return arg2;
}
I got it working, thanks. But do you know how one would import a class using ASM?
the class EntityAIHelperStalker is defined in the package atomicstryker.stalkercreepers.common
isSeenByTarget is the public static method defined in EntityAIHelperStalker.
and the parameter is of type net.minecraft.entity.EntityLiving.
So yeah everything is given with it's complete name.
That doesn't seem to work, heres my code:
The method that Minecraft runs after ASM:
public void renderFirstPersonArm(EntityPlayer par1EntityPlayer)
{
GL11.glColor3f(1.0F, 1.0F, 1.0F);
//render hand here
com.bluespud.dis.reasources.INSTANCE.increase();
}
And the code of the resources class:
package com.bluespud.dis;
import com.bluespud.dis.ModelHand;
public enum reasources {
INSTANCE;
public final String path = "/mods/DHN/";
public ModelHand hand = new ModelHand();
public static float i = 0;
public static void increase()
{
i++;
}
}
PS I am just replacing the instructions of the method in the jar with the instructions of this one, and it works, but when I call something it didn't import.
What's the exact error message that you're getting?
My problem was I was loading a .obj model and it couldn't be found. However, when I try using this.object.doSomething() It crashes, and it says:
2013-07-09 16:56:19 [INFO] [STDERR] object cannot be resolved or is not a field
After I successfully ported my smaller mod to Forge (thanks to your great tutorial), I'm stuck trying to port my main mod.
It replaces 4 base classes: BlockGrass, BlockMycelium, BlockLeaves and BlockLeavesBase. And it introduces BlockGrassBase which BlockGrass and BlockMycelium inherit from. BlockGrassBase is part of my package poersch.minecraft.bettergrassandleaves.
In Eclipse I just modified the specific base classes - which works fine - but after reobfuscating the source and adding the 4 modified classes to my mod's jar, I get the following error (in my actual Minecraft) after BlockGrass got patched:
Launching in C:\Users\Poersch\AppData\Roaming\.minecraft
Running C:\Program Files\Java\jre7\bin\javaw.exe -Xmx1G -Djava.library.path=C:\Users\Poersch\AppData\Roaming\.minecraft\versions\1.6.2-Forge9.10.0.789\1.6.2-Forge9.10.0.789-natives-2035464284826 -cp C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\net\minecraftforge\minecraftforge\9.10.0.789\minecraftforge-9.10.0.789.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\net\minecraft\launchwrapper\1.3\launchwrapper-1.3.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\org\scala-lang\scala-library\2.10.2\scala-library-2.10.2.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\org\scala-lang\scala-compiler\2.10.2\scala-compiler-2.10.2.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\org\ow2\asm\asm-all\4.1\asm-all-4.1.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\net\sf\jopt-simple\jopt-simple\4.5\jopt-simple-4.5.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\lzma\lzma\0.0.1\lzma-0.0.1.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\com\paulscode\codecjorbis\20101023\codecjorbis-20101023.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\com\paulscode\codecwav\20101023\codecwav-20101023.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\com\paulscode\libraryjavasound\20101123\libraryjavasound-20101123.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\com\paulscode\librarylwjglopenal\20100824\librarylwjglopenal-20100824.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\com\paulscode\soundsystem\20120107\soundsystem-20120107.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\org\lwjgl\lwjgl\lwjgl\2.9.0\lwjgl-2.9.0.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\org\lwjgl\lwjgl\lwjgl_util\2.9.0\lwjgl_util-2.9.0.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\argo\argo\2.25_fixed\argo-2.25_fixed.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\org\bouncycastle\bcprov-jdk15on\1.47\bcprov-jdk15on-1.47.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\com\google\guava\guava\14.0\guava-14.0.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\org\apache\commons\commons-lang3\3.1\commons-lang3-3.1.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\commons-io\commons-io\2.4\commons-io-2.4.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\net\java\jinput\jinput\2.0.5\jinput-2.0.5.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\net\java\jutils\jutils\1.0.0\jutils-1.0.0.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\com\google\code\gson\gson\2.2.2\gson-2.2.2.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\versions\1.6.2-Forge9.10.0.789\1.6.2-Forge9.10.0.789.jar net.minecraft.launchwrapper.Launch --username Poersch --session token:7cbd0264022b4679a257d66795f36273:d6b2f731878b42339c14c7c4f159ddee --version 1.6.2-Forge9.10.0.789 --gameDir C:\Users\Poersch\AppData\Roaming\.minecraft --assetsDir C:\Users\Poersch\AppData\Roaming\.minecraft\assets --tweakClass cpw.mods.fml.common.launcher.FMLTweaker
---- YOU CAN CLOSE THIS LAUNCHER IF THE GAME STARTED OK ----
---- YOU CAN CLOSE THIS LAUNCHER IF THE GAME STARTED OK ----
---- YOU CAN CLOSE THIS LAUNCHER IF THE GAME STARTED OK ----
---- (We'll do this automatically later ;D) ----
Client> Jul 11, 2013 4:29:35 PM net.minecraft.launchwrapper.LogWrapper log
Client> Information: Using tweak class name cpw.mods.fml.common.launcher.FMLTweaker
Client> 2013-07-11 16:29:35 [Information] [ForgeModLoader] Forge Mod Loader version 6.2.19.789 for Minecraft 1.6.2 loading
Client> 2013-07-11 16:29:35 [Information] [ForgeModLoader] Java is Java HotSpot(TM) 64-Bit Server VM, version 1.7.0_03, running on Windows 7:amd64:6.1, installed at C:\Program Files\Java\jre7
Client> 2013-07-11 16:29:35 [Information] [STDOUT] Loaded 39 rules from AccessTransformer config file fml_at.cfg
Client> 2013-07-11 16:29:35 [Information] [STDOUT] Loaded 107 rules from AccessTransformer config file forge_at.cfg
Client> 2013-07-11 16:29:36 [Information] [ForgeModLoader] Found valid fingerprint for Minecraft Forge. Certificate fingerprint de4cf8a3f3bc15635810044c39240bf96804ea7d
Client> 2013-07-11 16:29:36 [Information] [ForgeModLoader] Found valid fingerprint for Minecraft. Certificate fingerprint cd99959656f753dc28d863b46769f7f8fbaefcfc
Client> 2013-07-11 16:29:36 [Information] [ForgeModLoader] Launching wrapped minecraft
Client> 2013-07-11 16:29:37 [Information] [Minecraft-Client] Setting user: Poersch
Client> 2013-07-11 16:29:37 [Information] [Minecraft-Client] (Session ID is token:7cbd0264022b4679a257d66795f36273:d6b2f731878b42339c14c7c4f159ddee)
Client> 2013-07-11 16:29:37 [Information] [STDOUT] [Better Grass & Leaves Mod] Class aok patched!
Client> 2013-07-11 16:29:37 [Schwerwiegend] [ForgeModLoader] Unable to launch
Client> java.lang.reflect.InvocationTargetException
Client> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
Client> at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
Client> at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
Client> at java.lang.reflect.Method.invoke(Unknown Source)
Client> at net.minecraft.launchwrapper.Launch.launch(Launch.java:57)
Client> at net.minecraft.launchwrapper.Launch.main(Launch.java:18)
Client> Caused by: java.lang.NoClassDefFoundError: net/minecraft/block/BlockGrass
Client> at net.minecraft.block.Block.<clinit>(Block.java:100)
Client> at net.minecraft.stats.StatList.func_75921_a(StatList.java:185)
Client> at net.minecraft.stats.StatList.<clinit>(StatList.java:96)
Client> at net.minecraft.client.Minecraft.<init>(Minecraft.java:327)
Client> at net.minecraft.client.main.Main.main(SourceFile:83)
Client> ... 6 more
Client> Caused by: java.lang.ClassNotFoundException: net.minecraft.block.BlockGrass
Client> at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:179)
Client> at java.lang.ClassLoader.loadClass(Unknown Source)
Client> at java.lang.ClassLoader.loadClass(Unknown Source)
Client> ... 11 more
Client> Caused by: java.lang.NoClassDefFoundError: aqw
Client> at java.lang.ClassLoader.defineClass1(Native Method)
Client> at java.lang.ClassLoader.defineClass(Unknown Source)
Client> at java.security.SecureClassLoader.defineClass(Unknown Source)
Client> at java.net.URLClassLoader.defineClass(Unknown Source)
Client> at java.net.URLClassLoader.access$100(Unknown Source)
Client> at java.net.URLClassLoader$1.run(Unknown Source)
Client> at java.net.URLClassLoader$1.run(Unknown Source)
Client> at java.security.AccessController.doPrivileged(Native Method)
Client> at java.net.URLClassLoader.findClass(Unknown Source)
Client> at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:110)
Client> at java.lang.ClassLoader.loadClass(Unknown Source)
Client> at java.lang.ClassLoader.loadClass(Unknown Source)
Client> at java.lang.ClassLoader.defineClass1(Native Method)
Client> at java.lang.ClassLoader.defineClass(Unknown Source)
Client> at java.security.SecureClassLoader.defineClass(Unknown Source)
Client> at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:171)
Client> ... 13 more
Client> Caused by: java.lang.ClassNotFoundException: aqw
Client> at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:179)
Client> at java.lang.ClassLoader.loadClass(Unknown Source)
Client> at java.lang.ClassLoader.loadClass(Unknown Source)
Client> ... 29 more
Client> Caused by: java.lang.LinkageError: loader (instance of net/minecraft/launchwrapper/LaunchClassLoader): attempted duplicate class definition for name: "net/minecraft/block/Block"
Client> at java.lang.ClassLoader.defineClass1(Native Method)
Client> at java.lang.ClassLoader.defineClass(Unknown Source)
Client> at java.security.SecureClassLoader.defineClass(Unknown Source)
Client> at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:171)
Client> ... 31 more
Game ended with no troubles detected (exit code 0)
Deleting C:\Users\Poersch\AppData\Roaming\.minecraft\versions\1.6.2-Forge9.10.0.789\1.6.2-Forge9.10.0.789-natives-2035464284826
Couldn't delete C:\Users\Poersch\AppData\Roaming\.minecraft\versions\1.6.2-Forge9.10.0.789\1.6.2-Forge9.10.0.789-natives-2035464284826 - scheduling for deletion upon exit
And if I remove BlockGrass and BlockMycelium:
Launching in C:\Users\Poersch\AppData\Roaming\.minecraft
Running C:\Program Files\Java\jre7\bin\javaw.exe -Xmx1G -Djava.library.path=C:\Users\Poersch\AppData\Roaming\.minecraft\versions\1.6.2-Forge9.10.0.789\1.6.2-Forge9.10.0.789-natives-3038151421261 -cp C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\net\minecraftforge\minecraftforge\9.10.0.789\minecraftforge-9.10.0.789.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\net\minecraft\launchwrapper\1.3\launchwrapper-1.3.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\org\scala-lang\scala-library\2.10.2\scala-library-2.10.2.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\org\scala-lang\scala-compiler\2.10.2\scala-compiler-2.10.2.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\org\ow2\asm\asm-all\4.1\asm-all-4.1.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\net\sf\jopt-simple\jopt-simple\4.5\jopt-simple-4.5.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\lzma\lzma\0.0.1\lzma-0.0.1.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\com\paulscode\codecjorbis\20101023\codecjorbis-20101023.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\com\paulscode\codecwav\20101023\codecwav-20101023.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\com\paulscode\libraryjavasound\20101123\libraryjavasound-20101123.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\com\paulscode\librarylwjglopenal\20100824\librarylwjglopenal-20100824.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\com\paulscode\soundsystem\20120107\soundsystem-20120107.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\org\lwjgl\lwjgl\lwjgl\2.9.0\lwjgl-2.9.0.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\org\lwjgl\lwjgl\lwjgl_util\2.9.0\lwjgl_util-2.9.0.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\argo\argo\2.25_fixed\argo-2.25_fixed.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\org\bouncycastle\bcprov-jdk15on\1.47\bcprov-jdk15on-1.47.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\com\google\guava\guava\14.0\guava-14.0.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\org\apache\commons\commons-lang3\3.1\commons-lang3-3.1.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\commons-io\commons-io\2.4\commons-io-2.4.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\net\java\jinput\jinput\2.0.5\jinput-2.0.5.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\net\java\jutils\jutils\1.0.0\jutils-1.0.0.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\libraries\com\google\code\gson\gson\2.2.2\gson-2.2.2.jar;C:\Users\Poersch\AppData\Roaming\.minecraft\versions\1.6.2-Forge9.10.0.789\1.6.2-Forge9.10.0.789.jar net.minecraft.launchwrapper.Launch --username Poersch --session token:785d2e613ab34d43836a498cd4a15fd5:d6b2f731878b42339c14c7c4f159ddee --version 1.6.2-Forge9.10.0.789 --gameDir C:\Users\Poersch\AppData\Roaming\.minecraft --assetsDir C:\Users\Poersch\AppData\Roaming\.minecraft\assets --tweakClass cpw.mods.fml.common.launcher.FMLTweaker
---- YOU CAN CLOSE THIS LAUNCHER IF THE GAME STARTED OK ----
---- YOU CAN CLOSE THIS LAUNCHER IF THE GAME STARTED OK ----
---- YOU CAN CLOSE THIS LAUNCHER IF THE GAME STARTED OK ----
---- (We'll do this automatically later ;D) ----
Client> Jul 11, 2013 4:46:17 PM net.minecraft.launchwrapper.LogWrapper log
Client> Information: Using tweak class name cpw.mods.fml.common.launcher.FMLTweaker
Client> 2013-07-11 16:46:17 [Information] [ForgeModLoader] Forge Mod Loader version 6.2.19.789 for Minecraft 1.6.2 loading
Client> 2013-07-11 16:46:17 [Information] [ForgeModLoader] Java is Java HotSpot(TM) 64-Bit Server VM, version 1.7.0_03, running on Windows 7:amd64:6.1, installed at C:\Program Files\Java\jre7
Client> 2013-07-11 16:46:18 [Information] [STDOUT] Loaded 39 rules from AccessTransformer config file fml_at.cfg
Client> 2013-07-11 16:46:18 [Information] [STDOUT] Loaded 107 rules from AccessTransformer config file forge_at.cfg
Client> 2013-07-11 16:46:19 [Information] [ForgeModLoader] Found valid fingerprint for Minecraft Forge. Certificate fingerprint de4cf8a3f3bc15635810044c39240bf96804ea7d
Client> 2013-07-11 16:46:19 [Information] [ForgeModLoader] Found valid fingerprint for Minecraft. Certificate fingerprint cd99959656f753dc28d863b46769f7f8fbaefcfc
Client> 2013-07-11 16:46:19 [Information] [ForgeModLoader] Launching wrapped minecraft
Client> 2013-07-11 16:46:20 [Information] [Minecraft-Client] Setting user: Poersch
Client> 2013-07-11 16:46:20 [Information] [Minecraft-Client] (Session ID is token:785d2e613ab34d43836a498cd4a15fd5:d6b2f731878b42339c14c7c4f159ddee)
Client> 2013-07-11 16:46:20 [Information] [STDOUT] [Better Grass & Leaves Mod] Class aok not found in BetterGrassAndLeavesMod[v1.6.2.A].jar
Client> 2013-07-11 16:46:20 [Information] [STDOUT] [Better Grass & Leaves Mod] Class aow patched!
Client> 2013-07-11 16:46:20 [Information] [STDOUT] [Better Grass & Leaves Mod] Class are patched!
Client> 2013-07-11 16:46:20 [Information] [STDOUT] [Better Grass & Leaves Mod] Initiated LEAF block: net.minecraft.block.BlockLeaves
Client> 2013-07-11 16:46:21 [Information] [STDOUT] [Better Grass & Leaves Mod] Class aph not found in BetterGrassAndLeavesMod[v1.6.2.A].jar
Client> 2013-07-11 16:46:21 [Schwerwiegend] [ForgeModLoader] Unable to launch
Client> java.lang.reflect.InvocationTargetException
Client> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
Client> at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
Client> at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
Client> at java.lang.reflect.Method.invoke(Unknown Source)
Client> at net.minecraft.launchwrapper.Launch.launch(Launch.java:57)
Client> at net.minecraft.launchwrapper.Launch.main(Launch.java:18)
Client> Caused by: java.lang.NoClassDefFoundError: aqw
Client> at net.minecraft.block.BlockLeavesBase.func_71857_b(BlockLeavesBase.java:60)
Client> at net.minecraft.block.Block.<clinit>(Block.java:1448)
Client> at net.minecraft.stats.StatList.func_75921_a(StatList.java:185)
Client> at net.minecraft.stats.StatList.<clinit>(StatList.java:96)
Client> at net.minecraft.client.Minecraft.<init>(Minecraft.java:327)
Client> at net.minecraft.client.main.Main.main(SourceFile:83)
Client> ... 6 more
Client> Caused by: java.lang.ClassNotFoundException: aqw
Client> at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:179)
Client> at java.lang.ClassLoader.loadClass(Unknown Source)
Client> at java.lang.ClassLoader.loadClass(Unknown Source)
Client> ... 12 more
Client> Caused by: java.lang.LinkageError: loader (instance of net/minecraft/launchwrapper/LaunchClassLoader): attempted duplicate class definition for name: "net/minecraft/block/Block"
Client> at java.lang.ClassLoader.defineClass1(Native Method)
Client> at java.lang.ClassLoader.defineClass(Unknown Source)
Client> at java.security.SecureClassLoader.defineClass(Unknown Source)
Client> at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:171)
Client> ... 14 more
Game ended with no troubles detected (exit code 0)
Deleting C:\Users\Poersch\AppData\Roaming\.minecraft\versions\1.6.2-Forge9.10.0.789\1.6.2-Forge9.10.0.789-natives-3038151421261
Couldn't delete C:\Users\Poersch\AppData\Roaming\.minecraft\versions\1.6.2-Forge9.10.0.789\1.6.2-Forge9.10.0.789-natives-3038151421261 - scheduling for deletion upon exit
Why an ClassNotFoundException in Block.class?
hmm, let me think about this one. I know for sure that you can have a base edit that calls your mod package. for example have an import to poersch.minecraft.bettergrassandleaves and have it call stuff from there directly.
but making a base inherit from you're mod? becomes a chicken or an egg first problem :/ i'll need to look into it further, in theory it should work.
my best guess is that it's just an obfuscation problem.
try to create a fresh forge development enviroment (unmodified minecraft src) and using a dummy jar that includes the your new classes. run it in the clean version and see if it patches and keeps on running normal.
i.e, run recompile.bat on your modified minecraft src and copy the changed class files directly from mcp/bin/ and not from mcp/reobf into your dummy jar. don't run reobfuscate.bat for this test.
Thank you for showing me that. One more question, is there any way to tell if the current bytecode instruction matches a specific call? For example, can I tell when
While extending custom classes doesn't seem to work, implementing interfaces does. At least I'm in the position to write a workaround. Thanks again for the great tutorial.
did you try running everything in unobfuscated mode on a clean version of forge?
Trying that would help us narrow it down considerably.
I tried looking around forge to see if they tried to make a mod extend their class, unfortunatley i didn't find any, but found that they made some base classes implement their interfaces like the blockcactus class.
Have a look at this tutorial, it might give you a good alternatives to patching directly
Thank you for showing me that. One more question, is there any way to tell if the current bytecode instruction matches a specific call? For example, can I tell when
Thank you so much for making this tutorial! It helped so much with porting my mod! I actually found a much simpler way to replace an entire class, and a simpler way to load it. I had an explanation of it written here, but chrome crashed an erased it . I can explain it to you again if you would like.
AbstractInsnNode invVirt = m.instructions.get(fdiv_index+2); //pretty sure this is the invokevirtual instruction in relation to the FDIV instruction
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!!! again look at the javadoc for the other types!
System.out.println("INVOKEVIRTUAL :" + testMethod.owner + " , " + testMethod.name + " , " + testMethod.desc );
}
}
The log looked like this:
2013-07-12 00:26:43 [INFO] [STDOUT] INVOKEVIRTUAL opcode is 182 METHOD_INSN type is 5
2013-07-12 00:26:43 [INFO] [STDOUT] INVOKEVIRTUAL :net/minecraft/block/Block , dropBlockAsItemWithChance , (Lnet/minecraft/world/World;IIIIFI)V
Then you do string comparison on owner, name and desc.
Thank you so much for making this tutorial! It helped so much with porting my mod! I actually found a much simpler way to replace an entire class, and a simpler way to load it. I had an explanation of it written here, but chrome crashed an erased it . I can explain it to you again if you would like.
I know it's a long video, but it's not very complicated and pretty straight forward. The video covers a little bit of the ASM API at the very end. You need to understand the basic concepts as you put it "stack, ASM opcodes" which this video covers well. I see no harm with it's inclusion.
Can you post your code?
I tried it out and the transformer does run on those classes, The way it works is that it doesn't patch when minecraft starts. it patches when the class is about to be loaded when called.
Here's my log:
you can test it like so
I got it working, thanks. But do you know how one would import a class using ASM?
Interesting question. I think you just give the full qualified name.
Here's an example from the code by atomicStryker:
the class EntityAIHelperStalker is defined in the package atomicstryker.stalkercreepers.common
isSeenByTarget is the public static method defined in EntityAIHelperStalker.
and the parameter is of type net.minecraft.entity.EntityLiving.
So yeah everything is given with it's complete name.
That doesn't seem to work, heres my code:
The method that Minecraft runs after ASM:
And the code of the resources class:
PS I am just replacing the instructions of the method in the jar with the instructions of this one, and it works, but when I call something it didn't import.
My problem was I was loading a .obj model and it couldn't be found. However, when I try using this.object.doSomething() It crashes, and it says:
2013-07-09 16:56:19 [INFO] [STDERR] object cannot be resolved or is not a field
You're welcome!
I have this:
But its output is just a bunch of numbers.
-tlf
hmm, let me think about this one. I know for sure that you can have a base edit that calls your mod package. for example have an import to poersch.minecraft.bettergrassandleaves and have it call stuff from there directly.
but making a base inherit from you're mod? becomes a chicken or an egg first problem :/ i'll need to look into it further, in theory it should work.
my best guess is that it's just an obfuscation problem.
try to create a fresh forge development enviroment (unmodified minecraft src) and using a dummy jar that includes the your new classes. run it in the clean version and see if it patches and keeps on running normal.
i.e, run recompile.bat on your modified minecraft src and copy the changed class files directly from mcp/bin/ and not from mcp/reobf into your dummy jar. don't run reobfuscate.bat for this test.
It's from the ASM bytcode plugin for eclipse http://asm.ow2.org/eclipse/index.html
Thank you for showing me that. One more question, is there any way to tell if the current bytecode instruction matches a specific call? For example, can I tell when
is being called?
-tlf
did you try running everything in unobfuscated mode on a clean version of forge?
Trying that would help us narrow it down considerably.
I tried looking around forge to see if they tried to make a mod extend their class, unfortunatley i didn't find any, but found that they made some base classes implement their interfaces like the blockcactus class.
Have a look at this tutorial, it might give you a good alternatives to patching directly
http://www.minecraft.../topic/1812671-
LOL nevermind you already know about it
yeah those should stand out. you can also use the javap -c command to look at the bytecode directly.
-tlf
Well it gets a little bit more complicated then.
Always consult the ASM javadocs. You MUST go back to it to get the codes numbers.
I'll show you how it can be done for the Explosion example:
first add the imports:
The log looked like this:
Then you do string comparison on owner, name and desc.
You're welcome