Posted August 12, 201411 yr Hey everyone, I'm having a bit of a problem patching classes with ASM. I'm attempting to patch two functions, one in BiomeGenBase and one in ChunkProviderGenerate. The patching works fine for BiomeGenBase, however, the class cannot be found by the JVM once I've patched it. Here is my class transformer: public class ClassTransformer implements IClassTransformer{ @Override public byte[] transform(String name, String transformedName, byte[] bytes) { FMLRelaunchLog.warning("%s", name); if(find(name, class_biomeGenBase) != -1){ ClassNode cNode = new ClassNode(); ClassReader reader = new ClassReader(bytes); reader.accept(cNode, 0); MethodNode mNode = null; //FMLRelaunchLog.warning("%s", Arrays.toString(cNode.methods.toArray())); for(MethodNode node:cNode.methods){ FMLRelaunchLog.warning("%s:%s", node.name, node.desc); if(find(node.name, method_genBiomeTerrain) != -1 && find(node.desc, desc_genBiomeTerrain) != -1){ mNode = node; break; } } if(mNode == null){ LogHelper.error("Failed to replace water!"); return bytes; } boolean fixed = false; for(AbstractInsnNode node:mNode.instructions.toArray()){ if(node instanceof FieldInsnNode){ FieldInsnNode vNode = (FieldInsnNode) node; LogHelper.info(vNode.name); if(find(vNode.name, field_blockWater) != -1){ node = vNode.getNext(); if(node instanceof VarInsnNode && ((VarInsnNode)node).var == 10){ vNode.owner = "me/superckl/betteroceans/common/reference/ModBlocks"; vNode.name = "saltWater"; vNode.desc = "Lme/superckl/betteroceans/common/fluid/block/BlockFluidSaltWater;"; LogHelper.info("Patched "+name+"."+mNode.name); fixed = true; break; } } } } LogHelper.info("Writing class with fixed: "+fixed); ClassWriter cWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); cNode.accept(cWriter); return cWriter.toByteArray(); }else if(find(name, class_chunkProviderGenerate) != -1){ ClassNode cNode = new ClassNode(); ClassReader reader = new ClassReader(bytes); reader.accept(cNode, 0); MethodNode mNode = null; //FMLRelaunchLog.warning("%s", Arrays.toString(cNode.methods.toArray())); for(MethodNode node:cNode.methods){ FMLRelaunchLog.warning("%s:%s", node.name, node.desc); if(find(node.name, method_func_147424_a) != -1 && find(node.desc, desc_func_147424_a) != -1){ mNode = node; break; } } if(mNode == null){ LogHelper.error("Failed to replace water!"); return bytes; } for(AbstractInsnNode node:mNode.instructions.toArray()){ if(node instanceof FieldInsnNode){ FieldInsnNode vNode = (FieldInsnNode) node; if(find(vNode.name, field_blockWater) != -1){ vNode.owner = "me/superckl/betteroceans/common/reference/ModBlocks"; vNode.name = "saltWater"; vNode.desc = "Lme/superckl/betteroceans/common/fluid/block/BlockFluidSaltWater;"; LogHelper.info("Patched "+name+"."+mNode.name); } } } ClassWriter cWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); cNode.accept(cWriter); return cWriter.toByteArray(); } return bytes; } public static <T> int find(final T toFind, final T[] in){ for(int i = 0; i < in.length; i++) if(in[i] == toFind || in[i].equals(toFind)) return i; return -1; } public static final String[] field_ocean = {"ocean", "field_76771_b"}; public static final String[] field_deepOcean = {"deepOcean", "field_150575_M"}; public static final String[] field_blockWater = {"water", "field_150355_j", "j"}; public static final String[] method_genBiomeTerrain = {"genBiomeTerrain", "func_150560_b", "b"}; public static final String[] method_func_147424_a = {"func_147424_a", "a"}; public static final String[] desc_genBiomeTerrain = {"(Lnet/minecraft/world/World;Ljava/util/Random;[Lnet/minecraft/block/Block;[bIID)V", "(Lahb;Ljava/util/Random;[Laji;[bIID)V"}; public static final String[] desc_func_147424_a = {"(II[Lnet/minecraft/block/Block;)V", "(II[Laji;)V"}; public static final String[] class_biomeGenBase = {"net.minecraft.world.biome.BiomeGenBase", "ahu"}; public static final String[] class_chunkProviderGenerate = {"net.minecraft.world.gen.ChunkProviderGenerate", "aqz"}; } And the error I get: java.lang.NoClassDefFoundError: me/superckl/betteroceans/common/gen/BiomeGenBetterOcean at me.superckl.betteroceans.common.utility.BiomeHelper.replaceOceanBiomes(BiomeHelper.java:22) ~[biomeHelper.class:?] at me.superckl.betteroceans.BetterOceans.init(BetterOceans.java:59) ~[betterOceans.class:?] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_05] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_05] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_05] at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_05] at cpw.mods.fml.common.FMLModContainer.handleModStateEvent(FMLModContainer.java:513) ~[forge-1.7.10-10.13.0.1183.jar:?] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_05] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_05] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_05] at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_05] at com.google.common.eventbus.EventSubscriber.handleEvent(EventSubscriber.java:74) ~[guava-16.0.jar:?] at com.google.common.eventbus.SynchronizedEventSubscriber.handleEvent(SynchronizedEventSubscriber.java:47) ~[guava-16.0.jar:?] at com.google.common.eventbus.EventBus.dispatch(EventBus.java:322) ~[guava-16.0.jar:?] at com.google.common.eventbus.EventBus.dispatchQueuedEvents(EventBus.java:304) ~[guava-16.0.jar:?] at com.google.common.eventbus.EventBus.post(EventBus.java:275) ~[guava-16.0.jar:?] at cpw.mods.fml.common.LoadController.sendEventToModContainer(LoadController.java:208) ~[forge-1.7.10-10.13.0.1183.jar:?] at cpw.mods.fml.common.LoadController.propogateStateMessage(LoadController.java:187) ~[forge-1.7.10-10.13.0.1183.jar:?] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_05] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_05] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_05] at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_05] at com.google.common.eventbus.EventSubscriber.handleEvent(EventSubscriber.java:74) ~[guava-16.0.jar:?] at com.google.common.eventbus.SynchronizedEventSubscriber.handleEvent(SynchronizedEventSubscriber.java:47) ~[guava-16.0.jar:?] at com.google.common.eventbus.EventBus.dispatch(EventBus.java:322) ~[guava-16.0.jar:?] at com.google.common.eventbus.EventBus.dispatchQueuedEvents(EventBus.java:304) ~[guava-16.0.jar:?] at com.google.common.eventbus.EventBus.post(EventBus.java:275) ~[guava-16.0.jar:?] at cpw.mods.fml.common.LoadController.distributeStateMessage(LoadController.java:118) [LoadController.class:?] at cpw.mods.fml.common.Loader.initializeMods(Loader.java:691) [Loader.class:?] at cpw.mods.fml.client.FMLClientHandler.finishMinecraftLoading(FMLClientHandler.java:288) [FMLClientHandler.class:?] at net.minecraft.client.Minecraft.func_71384_a(Minecraft.java:541) [bao.class:?] at net.minecraft.client.Minecraft.func_99999_d(Minecraft.java:867) [bao.class:?] at net.minecraft.client.main.Main.main(SourceFile:148) [Main.class:?] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_05] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_05] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_05] at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_05] at net.minecraft.launchwrapper.Launch.launch(Launch.java:134) [launchwrapper-1.9.jar:?] at net.minecraft.launchwrapper.Launch.main(Launch.java:28) [launchwrapper-1.9.jar:?] Caused by: java.lang.ClassNotFoundException: me.superckl.betteroceans.common.gen.BiomeGenBetterOcean at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:188) ~[launchwrapper-1.9.jar:?] at java.lang.ClassLoader.loadClass(Unknown Source) ~[?:1.8.0_05] at java.lang.ClassLoader.loadClass(Unknown Source) ~[?:1.8.0_05] ... 39 more Caused by: java.lang.NoClassDefFoundError: net/minecraft/world/biome/BiomeGenBase at java.lang.ClassLoader.defineClass1(Native Method) ~[?:1.8.0_05] at java.lang.ClassLoader.defineClass(Unknown Source) ~[?:1.8.0_05] at java.security.SecureClassLoader.defineClass(Unknown Source) ~[?:1.8.0_05] at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:180) ~[launchwrapper-1.9.jar:?] at java.lang.ClassLoader.loadClass(Unknown Source) ~[?:1.8.0_05] at java.lang.ClassLoader.loadClass(Unknown Source) ~[?:1.8.0_05] ... 39 more Caused by: java.lang.ClassNotFoundException: net.minecraft.world.biome.BiomeGenBase at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:99) ~[launchwrapper-1.9.jar:?] at java.lang.ClassLoader.loadClass(Unknown Source) ~[?:1.8.0_05] at java.lang.ClassLoader.loadClass(Unknown Source) ~[?:1.8.0_05] at java.lang.ClassLoader.defineClass1(Native Method) ~[?:1.8.0_05] at java.lang.ClassLoader.defineClass(Unknown Source) ~[?:1.8.0_05] at java.security.SecureClassLoader.defineClass(Unknown Source) ~[?:1.8.0_05] at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:180) ~[launchwrapper-1.9.jar:?] at java.lang.ClassLoader.loadClass(Unknown Source) ~[?:1.8.0_05] at java.lang.ClassLoader.loadClass(Unknown Source) ~[?:1.8.0_05] ... 39 more The error is thrown on this line of code: final BiomeGenBetterOcean boO = new BiomeGenBetterOcean(BiomeGenBase.ocean.biomeID); If I remove the class transformer, everything works fine. I'm not entirely sure what is going on here... Maybe I'm doing something completely wrong her - It's my first time working with ASM. Thanks for any help you can offer. EDIT: I forgot to mention that it works fine in my eclipse development environment. The patch works and does what it's supposed to. It seems like the obfuscation is messing it up in some way. EDIT 2: Fixed! I just applied a sorting index of > 1000 to get above the FML deobfuscater and it all worked! http://i.imgur.com/nVI9Y.png[/img]
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.