Package powercrystals.core.asm

Source Code of powercrystals.core.asm.PCCASMTransformer

package powercrystals.core.asm;

import cpw.mods.fml.relauncher.FMLRelauncher;
import cpw.mods.fml.relauncher.IClassTransformer;

import java.util.ArrayList;
import java.util.List;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;

import powercrystals.core.CoreLoader;
import powercrystals.core.asm.relauncher.Implementable;

public class PCCASMTransformer implements IClassTransformer
{
  private String desc;
  private ArrayList<String> workingPath = new ArrayList<String>();
  private boolean isClient = FMLRelauncher.side().equals("CLIENT");

  public PCCASMTransformer()
  {
    desc = Type.getDescriptor(Implementable.class);
  }

  @Override
  public byte[] transform(String name, String transformedName, byte[] bytes)
  {
    ClassReader cr = new ClassReader(bytes);
    ClassNode cn = new ClassNode();
    cr.accept(cn, 0);

    workingPath.add(transformedName);

    if (this.implement(cn))
    {
      System.out.println("Adding runtime interfaces to " + transformedName);
      ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
      cn.accept(cw);
      bytes = cw.toByteArray();
      cr = new ClassReader(bytes);
    }

    workingPath.remove(workingPath.size() - 1);

    if ("net.minecraft.world.WorldServer".equals(transformedName))
    {
      bytes = writeWorldServer(name, transformedName, bytes, cr);
    }
    else if (!isClient && "net.minecraft.world.World".equals(transformedName))
    {
      bytes = writeWorld(name, transformedName, bytes, cr);
    }

    return bytes;
  }

  private byte[] writeWorld(String name, String transformedName, byte[] bytes, ClassReader cr)
  {
    String[] names = null;
    if (CoreLoader.runtimeDeobfEnabled)
    {
      names = new String[]{"field_73019_z","field_72986_A","field_73011_w","field_72984_F","field_98181_L"};
    }
    else
    {
      names = new String[]{"saveHandler","worldInfo","provider","theProfiler","worldLogAgent"};
    }
    name = name.replace('.', '/');
    ClassNode cn = new ClassNode(Opcodes.ASM4);
    cr.accept(cn, ClassReader.EXPAND_FRAMES);
   
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
    cn.accept(cw);
    /* new World constructor
     * World(ISaveHandler saveHandler, String worldName,
            WorldProvider provider, WorldSettings worldSettings,
            Profiler theProfiler, ILogAgent worldLogAgent)
     **/
    String sig = "(Lnet/minecraft/world/storage/ISaveHandler;Ljava/lang/String;Lnet/minecraft/world/WorldProvider;Lnet/minecraft/world/WorldSettings;Lnet/minecraft/profiler/Profiler;Lnet/minecraft/logging/ILogAgent;)V";
    cw.newMethod(name, "<init>", sig, true);
    MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", sig, null, null);
    mv.visitCode();
    mv.visitVarInsn(Opcodes.ALOAD, 0);
    mv.visitInsn(Opcodes.DUP);
    mv.visitInsn(Opcodes.DUP);
    mv.visitInsn(Opcodes.DUP);
    mv.visitInsn(Opcodes.DUP);
    mv.visitInsn(Opcodes.DUP);
    mv.visitInsn(Opcodes.DUP);
    mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
    mv.visitVarInsn(Opcodes.ALOAD, 1);
    mv.visitFieldInsn(Opcodes.PUTFIELD, name, names[0], "Lnet/minecraft/world/storage/ISaveHandler;");
    mv.visitTypeInsn(Opcodes.NEW, "net/minecraft/world/storage/WorldInfo");
    mv.visitInsn(Opcodes.DUP);
    mv.visitVarInsn(Opcodes.ALOAD, 4);
    mv.visitVarInsn(Opcodes.ALOAD, 2);
    mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "net/minecraft/world/storage/WorldInfo", "<init>", "(Lnet/minecraft/world/WorldSettings;Ljava/lang/String;)V");
    mv.visitFieldInsn(Opcodes.PUTFIELD, name, names[1], "Lnet/minecraft/world/storage/WorldInfo;");
    mv.visitVarInsn(Opcodes.ALOAD, 3);
    mv.visitFieldInsn(Opcodes.PUTFIELD, name, names[2], "Lnet/minecraft/world/WorldProvider;");
    mv.visitVarInsn(Opcodes.ALOAD, 5);
    mv.visitFieldInsn(Opcodes.PUTFIELD, name, names[3], "Lnet/minecraft/profiler/Profiler;");
    mv.visitVarInsn(Opcodes.ALOAD, 6);
    mv.visitFieldInsn(Opcodes.PUTFIELD, name, names[4], "Lnet/minecraft/logging/ILogAgent;");
    mv.visitInsn(Opcodes.RETURN);
    mv.visitMaxs(11, 10);
    mv.visitEnd();
    cw.visitEnd();
    return cw.toByteArray();
  }

  private byte[] writeWorldServer(String name, String transformedName, byte[] bytes, ClassReader cr)
  {
    String[] names = null;
    if (CoreLoader.runtimeDeobfEnabled)
    {
      names = new String[]{"field_73061_a","field_73062_L","field_73063_M","field_85177_Q"};
    }
    else
    {
      names = new String[]{"mcServer","theEntityTracker","thePlayerManager","field_85177_Q"};
    }
    name = name.replace('.', '/');
    ClassNode cn = new ClassNode(Opcodes.ASM4);
    cr.accept(cn, ClassReader.EXPAND_FRAMES);

    for(MethodNode m : cn.methods)
    {
      if("<init>".equals(m.name) && "(Lnet/minecraft/server/MinecraftServer;Lnet/minecraft/world/storage/ISaveHandler;Ljava/lang/String;Lnet/minecraft/world/WorldProvider;Lnet/minecraft/world/WorldSettings;Lnet/minecraft/profiler/Profiler;Lnet/minecraft/logging/ILogAgent;)V".equals(m.desc))
      {
        return bytes;
      }
    }
   
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
    cn.accept(cw);
    /* new WorldServer constructor
     * WorldServer(MinecraftServer minecraftServer,
            ISaveHandler saveHandler, String worldName,
            WorldProvider provider, WorldSettings worldSettings,
            Profiler theProfiler, ILogAgent worldLogAgent)
     **/
    String sig = "(Lnet/minecraft/server/MinecraftServer;Lnet/minecraft/world/storage/ISaveHandler;Ljava/lang/String;Lnet/minecraft/world/WorldProvider;Lnet/minecraft/world/WorldSettings;Lnet/minecraft/profiler/Profiler;Lnet/minecraft/logging/ILogAgent;)V";
    cw.newMethod(name, "<init>", sig, true);
    MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", sig, null, null);
    mv.visitCode();
    mv.visitVarInsn(Opcodes.ALOAD, 0);
    mv.visitInsn(Opcodes.DUP);
    mv.visitInsn(Opcodes.DUP);
    mv.visitInsn(Opcodes.DUP);
    mv.visitInsn(Opcodes.DUP);
    mv.visitVarInsn(Opcodes.ALOAD, 2);
    mv.visitVarInsn(Opcodes.ALOAD, 3);
    mv.visitVarInsn(Opcodes.ALOAD, 4);
    mv.visitVarInsn(Opcodes.ALOAD, 5);
    mv.visitVarInsn(Opcodes.ALOAD, 6);
    mv.visitVarInsn(Opcodes.ALOAD, 7);
    // [World] super(saveHandler, par2String, provider, par4WorldSettings, theProfiler, worldLogAgent);
    mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "net/minecraft/world/World", "<init>", "(Lnet/minecraft/world/storage/ISaveHandler;Ljava/lang/String;Lnet/minecraft/world/WorldProvider;Lnet/minecraft/world/WorldSettings;Lnet/minecraft/profiler/Profiler;Lnet/minecraft/logging/ILogAgent;)V");
    mv.visitVarInsn(Opcodes.ALOAD, 1);
    mv.visitFieldInsn(Opcodes.PUTFIELD, name, names[0], "Lnet/minecraft/server/MinecraftServer;");
    mv.visitInsn(Opcodes.ACONST_NULL);
    mv.visitFieldInsn(Opcodes.PUTFIELD, name, names[1], "Lnet/minecraft/entity/EntityTracker;");
    mv.visitInsn(Opcodes.ACONST_NULL);
    mv.visitFieldInsn(Opcodes.PUTFIELD, name, names[2], "Lnet/minecraft/server/management/PlayerManager;");
    mv.visitInsn(Opcodes.ACONST_NULL);
    mv.visitFieldInsn(Opcodes.PUTFIELD, name, names[3], "Lnet/minecraft/world/Teleporter;");
    mv.visitInsn(Opcodes.RETURN);
    mv.visitMaxs(11, 10);
    mv.visitEnd();
    cw.visitEnd();
    return cw.toByteArray();
  }

  private boolean implement(ClassNode cn)
  {
    if (cn.visibleAnnotations == null)
    {
      return false;
    }
    boolean interfaces = false;
    for (AnnotationNode node : cn.visibleAnnotations)
    {
      if (node.desc.equals(desc))
      {
        if (node.values != null)
        {
          List<Object> values = node.values;
          for (int i = 0, e = values.size(); i < e; )
          {
            Object k = values.get(i++);
            Object v = values.get(i++);
            if (k instanceof String && k.equals("value") && v instanceof String)
            {
              String[] value = ((String)v).split(";");
              for (int j = 0, l = value.length; j < l; ++j)
              {
                String clazz = value[j].trim();
                String cz = clazz.replace('.', '/');
                if (!cn.interfaces.contains(cz))
                {
                  try {
                    if (!workingPath.contains(clazz))
                    {
                      Class.forName(clazz, false, this.getClass().getClassLoader());
                    }
                    cn.interfaces.add(cz);
                    interfaces = true;
                  } catch (Throwable _) {}
                }
              }
            }
          }
        }
      }
    }
    return interfaces;
  }

}
TOP

Related Classes of powercrystals.core.asm.PCCASMTransformer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.