pl.asie.foamfix.coremod.FoamFixTransformer.java Source code

Java tutorial

Introduction

Here is the source code for pl.asie.foamfix.coremod.FoamFixTransformer.java

Source

/**
 * This file is part of FoamFix.
 *
 * FoamFix is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * FoamFix is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with FoamFix.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Additional permission under GNU GPL version 3 section 7
 *
 * If you modify this Program, or any covered work, by linking or
 * combining it with the Minecraft game engine, the Mojang Launchwrapper,
 * the Mojang AuthLib and the Minecraft Realms library (and/or modified
 * versions of said software), containing parts covered by the terms of
 * their respective licenses, the licensors of this Program grant you
 * additional permission to convey the resulting work.
 */
package pl.asie.foamfix.coremod;

import java.io.IOException;
import java.util.Set;

import com.google.common.collect.Sets;
import org.objectweb.asm.commons.RemappingClassAdapter;
import org.objectweb.asm.commons.Remapper;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.ClassReader;
import com.google.common.io.ByteStreams;
import net.minecraft.launchwrapper.IClassTransformer;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import pl.asie.foamfix.shared.FoamFixShared;

public class FoamFixTransformer implements IClassTransformer {
    public byte[] spliceMethods(final byte[] data, final String className, final String targetClassName,
            final String... methods) {
        final Set<String> methodSet = Sets.newHashSet(methods);
        try {
            final byte[] dataSplice = ByteStreams.toByteArray(
                    this.getClass().getClassLoader().getResourceAsStream(className.replace('.', '/') + ".class"));
            final ClassReader readerData = new ClassReader(data);
            final ClassReader readerSplice = new ClassReader(dataSplice);
            final ClassWriter writer = new ClassWriter(8);
            final String className2 = className.replace('.', '/');
            final String targetClassName2 = targetClassName.replace('.', '/');
            final Remapper remapper = new Remapper() {
                public String map(final String name) {
                    return className2.equals(name) ? targetClassName2 : name;
                }
            };
            ClassNode nodeData = new ClassNode();
            ClassNode nodeSplice = new ClassNode();
            readerData.accept(nodeData, 8);
            readerSplice.accept(new RemappingClassAdapter(nodeSplice, remapper), 8);
            for (int i = 0; i < nodeSplice.methods.size(); i++) {
                if (methodSet.contains(nodeSplice.methods.get(i).name)) {
                    MethodNode mn = nodeSplice.methods.get(i);
                    boolean added = false;

                    for (int j = 0; j < nodeData.methods.size(); j++) {
                        if (nodeData.methods.get(j).name.equals(mn.name)
                                && nodeData.methods.get(j).desc.equals(mn.desc)) {
                            System.out.println("Spliced in: " + targetClassName + "." + mn.name);
                            nodeData.methods.set(j, mn);
                            added = true;
                            break;
                        }
                    }

                    if (!added) {
                        System.out.println("Added: " + targetClassName + "." + mn.name);
                        nodeData.methods.add(mn);
                        added = true;
                    }
                }
            }
            nodeData.accept(writer);
            return writer.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    public byte[] transform(final String name, final String transformedName, final byte[] dataOrig) {
        byte[] data = dataOrig;
        if (FoamFixShared.config.geBlockPosPatch) {
            if ("net.minecraft.util.math.Vec3i".equals(transformedName)) {
                data = BlockPosPatch.patchVec3i(data);
            } else {
                data = BlockPosPatch.patchOtherClass(data,
                        "net.minecraft.util.math.BlockPos$MutableBlockPos".equals(transformedName));
            }
        }

        if (FoamFixShared.enabledCoremodDeduplicator && FoamFixShared.config.clDeduplicate) {
            if ("net.minecraftforge.client.model.pipeline.UnpackedBakedQuad".equals(transformedName)) {
                data = spliceMethods(data, "pl.asie.foamfix.coremod.CachingUnpackedBakedQuad", transformedName,
                        "<init>");
            }
        }

        /* if ("net.minecraft.client.Minecraft".equals(transformedName)) {
        data = MinecraftPatch.patchMinecraft(data);
        } */
        return data;
    }
}