MinecraftTransformer.java 3.52 KB
/*
 * This file is part of LiteLoader.
 * Copyright (C) 2012-16 Adam Mummery-Smith
 * All Rights Reserved.
 */
package com.mumfrey.liteloader.client.transformers;

import java.util.Iterator;

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.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TypeInsnNode;

import com.mumfrey.liteloader.core.runtime.Obf;
import com.mumfrey.liteloader.launch.LiteLoaderTweaker;
import com.mumfrey.liteloader.transformers.ClassTransformer;
import com.mumfrey.liteloader.util.log.LiteLoaderLogger;

public class MinecraftTransformer extends ClassTransformer
{
    private static final String TWEAKCLASS = LiteLoaderTweaker.class.getName().replace('.', '/');
    
    @Override
    public byte[] transform(String name, String transformedName, byte[] basicClass)
    {
        if ((Obf.Minecraft.name.equals(transformedName) || Obf.Minecraft.obf.equals(transformedName)))
        {
            ClassNode classNode = this.readClass(basicClass, true);
            for (MethodNode method : classNode.methods)
            {
                if (Obf.startGame.obf.equals(method.name) || Obf.startGame.srg.equals(method.name) || Obf.startGame.name.equals(method.name))
                {
                    this.transformStartGame(method);
                }
            }
            return this.writeClass(classNode);
        }
        return basicClass;
    }


    private void transformStartGame(MethodNode method)
    {
        InsnList insns = new InsnList(); 

        boolean loadingBarEnabled = LiteLoaderTweaker.loadingBarEnabled();
        boolean found = false;

        Iterator<AbstractInsnNode> iter = method.instructions.iterator();
        while (iter.hasNext())
        {
            AbstractInsnNode insn = iter.next();
            if (loadingBarEnabled && insn instanceof MethodInsnNode)
            {
                insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Obf.LoadingBar.ref, "incrementProgress", "()V", false));
            }
            
            insns.add(insn);

            if (insn instanceof TypeInsnNode && insn.getOpcode() == Opcodes.NEW && insns.getLast() != null)
            {
                TypeInsnNode typeNode = (TypeInsnNode)insn;
                if (!found && (Obf.EntityRenderer.obf.equals(typeNode.desc) || Obf.EntityRenderer.ref.equals(typeNode.desc)))
                {
                    LiteLoaderLogger.info("MinecraftTransformer found INIT injection point, this is good.");
                    found = true;

                    insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, MinecraftTransformer.TWEAKCLASS, Obf.init.name, "()V", false));
                    insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, MinecraftTransformer.TWEAKCLASS, Obf.postInit.name, "()V", false));
                }
            }

            if (loadingBarEnabled && insn instanceof LdcInsnNode)
            {
                LdcInsnNode ldcInsn = (LdcInsnNode)insn;
                if ("textures/blocks".equals(ldcInsn.cst))
                {
                    insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Obf.LoadingBar.ref, "initTextures", "()V", false));
                }
            }
        }

        method.instructions = insns;

        if (!found) LiteLoaderLogger.severe("MinecraftTransformer failed to find INIT injection point, the game will probably crash pretty soon.");
    }
}