Проблемы с ASM

167
3
23
Собстно, сам трансформер(прошу прощения за грязный код):

package ru.fewizz.trainfinger;

import java.util.ListIterator;
import java.util.Map;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.IntInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TypeInsnNode;
import org.objectweb.asm.tree.VarInsnNode;

import net.minecraft.launchwrapper.IClassTransformer;

public class TFTransformer implements IClassTransformer{

int i = 0;
int i1 = 0;

@Override
public byte[] transform(String name, String transformedName, byte[] basicClass) {

if("net.minecraft.client.multiplayer.PlayerControllerMP".equals(transformedName)){// || "bje".equals(name)) {
ClassNode cn = new ClassNode(Opcodes.ASM5);
ClassReader cr = new ClassReader(basicClass);
cr.accept(cn, 0);

System.out.println("Transforming: " + transformedName);

for(MethodNode method : cn.methods) {
if("onPlayerDamageBlock".equals(method.name) || "c".equals(method.name) && "(IIII)V".equals(method.desc)) {
InsnList code = method.instructions;

for(ListIterator<AbstractInsnNode> iterator = code.iterator(); iterator.hasNext(); ) {
AbstractInsnNode insn = iterator.next();

if(insn.getOpcode() == Opcodes.ALOAD && insn.getNext().getOpcode() == Opcodes.ICONST_5 && insn.getNext().getNext().getOpcode() == Opcodes.PUTFIELD) {
if(i == 0){
i++;
}
else{

InsnList toInsert = new InsnList();
toInsert.set(insn.getNext(), new InsnNode(Opcodes.ICONST_0));
method.instructions.insert(toInsert);
i++;
break;
}
}
}
}
}

ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
cn.accept(writer);
System.out.println("Patching PlayerControllerMP Complete!");
i = 0;
return writer.toByteArray();
}

if("net.minecraft.client.Minecraft".equals(transformedName)){// || "bao".equals(name)){
ClassNode cn = new ClassNode(Opcodes.ASM5);

ClassReader cr = new ClassReader(basicClass);
cr.accept(cn, 0);

System.out.println("Transforming: " + transformedName);

for(MethodNode method : cn.methods) {
if("func_147115_a".equals(method.name) || "a".equals(method.name) && "(Z)V".equals(method.desc)) {
InsnList code = method.instructions;

for(ListIterator<AbstractInsnNode> iterator = code.iterator(); iterator.hasNext(); ) {
AbstractInsnNode insn = iterator.next();

if(insn.getOpcode() == Opcodes.ILOAD) {
if(i == 0){
i++;

InsnList toInsert = new InsnList();

toInsert.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "ru/fewizz/trainfinger/Hooks", "LeftClickCounter", "(Z)Z", false));
method.instructions.insertBefore(insn.getNext(), toInsert);
}
}

if(insn.getOpcode() == Opcodes.ICONST_0){
if(i1 == 0){
i1++;

InsnList toInsert = new InsnList();

toInsert.add(new InsnNode(Opcodes.RETURN));
method.instructions.insert(insn.getNext(), toInsert);
}
}


try{
if(insn.getPrevious().getPrevious().getPrevious().getOpcode() == Opcodes.GOTO && insn.getNext().getOpcode() == Opcodes.ALOAD && insn.getNext().getNext().getOpcode() == Opcodes.GETFIELD && insn.getNext().getNext().getNext().getOpcode() == Opcodes.INVOKEVIRTUAL){

InsnList toInsert = new InsnList();

toInsert.set(insn.getNext().getNext().getNext(), new MethodInsnNode(Opcodes.INVOKESTATIC, "ru/fewizz/trainfinger/Hooks", "blockRemoving", "(Lnet/minecraft/client/multiplayer/PlayerControllerMP;)V", false));
method.instructions.insert(insn, toInsert);
}
}catch(Exception e){
}
}
}
}


ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
cn.accept(writer);
System.out.println("Patching Minecraft Complete!");
i = 0;
return writer.toByteArray();
}



return basicClass;
}
}




Если не компилировать, всё ок. Если скомпилировать, клиент кричит вот это:

[20:24:26] [main/INFO] [LaunchWrapper]: Calling tweak class cpw.mods.fml.common.launcher.FMLDeobfTweaker
[20:24:27] [main/INFO] [LaunchWrapper]: Loading tweak class name cpw.mods.fml.common.launcher.TerminalTweaker
[20:24:27] [main/INFO] [LaunchWrapper]: Calling tweak class cpw.mods.fml.common.launcher.TerminalTweaker
[20:24:27] [main/INFO] [LaunchWrapper]: Launching wrapped minecraft {net.minecraft.client.main.Main}
[20:24:27] [main/INFO] [STDOUT]: [ru.fewizz.trainfinger.TFTransformer:transform:75]: Transforming: net.minecraft.client.Minecraft
[20:24:27] [main/ERROR] [LaunchWrapper]: Unable to launch
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.7.0_79]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.7.0_79]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.7.0_79]
at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.7.0_79]
at net.minecraft.launchwrapper.Launch.launch(Launch.java:135) [launchwrapper-1.11.jar:?]
at net.minecraft.launchwrapper.Launch.main(Launch.java:28) [launchwrapper-1.11.jar:?]
Caused by: java.lang.NoClassDefFoundError: net/minecraft/client/Minecraft
at net.minecraft.client.main.Main.main(SourceFile:72) ~[Main.class:?]
... 6 more
Caused by: java.lang.ClassNotFoundException: net.minecraft.client.Minecraft
at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:191) ~[launchwrapper-1.11.jar:?]
at java.lang.ClassLoader.loadClass(Unknown Source) ~[?:1.7.0_79]
at java.lang.ClassLoader.loadClass(Unknown Source) ~[?:1.7.0_79]
at net.minecraft.client.main.Main.main(SourceFile:72) ~[Main.class:?]
... 6 more
Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: bdc
at org.objectweb.asm.ClassWriter.getCommonSuperClass(Unknown Source) ~[asm-all-5.0.3.jar:5.0.3]
at org.objectweb.asm.ClassWriter.a(Unknown Source) ~[asm-all-5.0.3.jar:5.0.3]
at org.objectweb.asm.Frame.a(Unknown Source) ~[asm-all-5.0.3.jar:5.0.3]
at org.objectweb.asm.Frame.a(Unknown Source) ~[asm-all-5.0.3.jar:5.0.3]
at org.objectweb.asm.MethodWriter.visitMaxs(Unknown Source) ~[asm-all-5.0.3.jar:5.0.3]
at org.objectweb.asm.tree.MethodNode.accept(Unknown Source) ~[asm-all-5.0.3.jar:5.0.3]
at org.objectweb.asm.tree.MethodNode.accept(Unknown Source) ~[asm-all-5.0.3.jar:5.0.3]
at org.objectweb.asm.tree.ClassNode.accept(Unknown Source) ~[asm-all-5.0.3.jar:5.0.3]
at ru.fewizz.trainfinger.TFTransformer.transform(TFTransformer.java:123) ~[TFTransformer.class:?]
at net.minecraft.launchwrapper.LaunchClassLoader.runTransformers(LaunchClassLoader.java:279) ~[launchwrapper-1.11.jar:?]
at net.minecraft.launchwrapper.LaunchClassLoader.findClass(LaunchClassLoader.java:176) ~[launchwrapper-1.11.jar:?]
at java.lang.ClassLoader.loadClass(Unknown Source) ~[?:1.7.0_79]
at java.lang.ClassLoader.loadClass(Unknown Source) ~[?:1.7.0_79]
at net.minecraft.client.main.Main.main(SourceFile:72) ~[Main.class:?]
... 6 more

Помогите тупому человеку пожалуйста!
 
Просмотрел по диагонали, появилось одно замечание: вместо "func_78759_c" пиши просто "c".
 
А что это за ужас вообще такой? Для чего он применяется?
Не пробовал ASM на Java, поэтому в шоке от увиденного
 
Блокировка. Теперь чтобы копать и добывать Придётся несколько раз кликать мышкой, а не зажимать как было раньше.
 
Ну ещё вот это описание будет некорректно в обфусцированном клиенте:
(Lnet/minecraft/client/multiplayer/PlayerControllerMP;)V

Я, чтобы не путаться с обфусцированными именами, придерживаюсь такого стиля оформления:
Код:
    @Override
    public byte[] transform(String className, String newName, byte[] bytecode) {
        try {
            if (className.equals("net.minecraft.client.renderer.EntityRenderer")){
                bytecode = transformEntityRenderer(bytecode, false);
            } else if (className.equals("bfe")){
                bytecode = transformEntityRenderer(bytecode, true);
            }
            //другие классы
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bytecode;
    }

    private byte[] transformEntityRenderer(byte[] bytecode, boolean obf) {
        EffectsMod.log("Transforming EntityRenderer");
        
        ClassNode classNode = new ClassNode();
        ClassReader classReader = new ClassReader(bytecode);
        classReader.accept(classNode, 0);
        
        //Все названия классов/полей/методов и описания методов сохраняем в отдельные переменные.
        //Так не запутаешься.
        //P.S: названий типа field_123456_a или method_654321_b тут быть не может, просто a или b.
        String rainSnowMethod = obf ? "d" : "renderRainSnow"; 
        String cameraTransformMethod = obf ? "a" : "setupCameraTransform"; 
        
        //трансформируем класс как надо
        insertCall(classNode, rainSnowMethod, "(F)V", HOOKS_CLASS,
                "shouldNotRenderRainSnow", "()Z", false, true, null, new int[] {}, new int[] {});
        
        //COMPUTE_FRAMES | COMPUTE_MAXS иногда имеет свойство не работать, поэтому при необходимости я пересчитываю их сам.
        //Впрочем, такая необходимость случается в одном случае из десяти.
        ClassWriter writer = new ClassWriter(0);
        classNode.accept(writer);
        return writer.toByteArray();
    }
 
GloomyFolken, спасиб за гайд :) . Думаю всем будет полезно.
 
Назад
Сверху