hellfirepvp.astralsorcery.core.transform.AstralPatchTransformer.java Source code

Java tutorial

Introduction

Here is the source code for hellfirepvp.astralsorcery.core.transform.AstralPatchTransformer.java

Source

/*******************************************************************************
 * HellFirePvP / Astral Sorcery 2017
 *
 * This project is licensed under GNU GENERAL PUBLIC LICENSE Version 3.
 * The source code is available on github: https://github.com/HellFirePvP/AstralSorcery
 * For further details, see the License file there.
 ******************************************************************************/

package hellfirepvp.astralsorcery.core.transform;

import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.ClassPath;
import hellfirepvp.astralsorcery.core.ASMTransformationException;
import hellfirepvp.astralsorcery.core.ClassPatch;
import hellfirepvp.astralsorcery.core.SubClassTransformer;
import net.minecraftforge.fml.common.FMLLog;
import org.objectweb.asm.tree.ClassNode;

import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * This class is part of the Astral Sorcery Mod
 * The complete source code for this mod can be found on github.
 * Class: AstralPatchTransformer
 * Created by HellFirePvP
 * Date: 05.12.2016 / 16:46
 */
public class AstralPatchTransformer implements SubClassTransformer {

    private static final String PATCH_PACKAGE = "hellfirepvp.astralsorcery.core.patch";

    private static ClassPatch currentPatch = null;

    private Map<String, List<ClassPatch>> availablePatches = new HashMap<>();

    public AstralPatchTransformer() throws IOException {
        FMLLog.info("[AstralTransformer] Loading patches...");
        int loaded = loadClassPatches();
        FMLLog.info("[AstralTransformer] Initialized! Loaded " + loaded + " class patches!");
    }

    private int loadClassPatches() throws IOException {
        ImmutableSet<ClassPath.ClassInfo> classes = ClassPath.from(Thread.currentThread().getContextClassLoader())
                .getTopLevelClassesRecursive(PATCH_PACKAGE);
        List<Class> patchClasses = new LinkedList<>();
        for (ClassPath.ClassInfo info : classes) {
            if (info.getName().startsWith(PATCH_PACKAGE)) {
                patchClasses.add(info.load());
            }
        }
        int load = 0;
        for (Class patchClass : patchClasses) {
            if (ClassPatch.class.isAssignableFrom(patchClass) && !Modifier.isAbstract(patchClass.getModifiers())) {
                try {
                    ClassPatch patch = (ClassPatch) patchClass.newInstance();
                    if (!availablePatches.containsKey(patch.getClassName())) {
                        availablePatches.put(patch.getClassName(), new LinkedList<>());
                    }
                    availablePatches.get(patch.getClassName()).add(patch);
                    load++;
                } catch (Exception exc) {
                    throw new IllegalStateException("Could not load ClassPatch: " + patchClass.getSimpleName(),
                            exc);
                }
            }
        }
        return load;
    }

    @Override
    public void transformClassNode(ClassNode cn, String transformedClassName, String obfName) {
        if (!availablePatches.isEmpty()) {
            List<ClassPatch> patches = availablePatches.get(transformedClassName);
            if (patches != null && !patches.isEmpty()) {
                FMLLog.info("[AstralTransformer] Transforming " + obfName + " : " + transformedClassName + " with "
                        + patches.size() + " patches!");
                try {
                    for (ClassPatch patch : patches) {
                        currentPatch = patch;
                        patch.transform(cn);
                        FMLLog.info("[AstralTransformer] Applied patch "
                                + patch.getClass().getSimpleName().toUpperCase());
                        currentPatch = null;
                    }
                } catch (Exception exc) {
                    throw new ASMTransformationException("Applying ClassPatches failed (ClassName: " + obfName
                            + " - " + transformedClassName + ") - Rethrowing exception!", exc);
                }
            }
            availablePatches.remove(transformedClassName);
        }
    }

    @Override
    public String getIdentifier() {
        return "Patch based transformer";
    }

    @Override
    public void addErrorInformation() {
        if (currentPatch != null) {
            FMLLog.warning("Patcher was in active patch: " + currentPatch.getClass().getSimpleName());
        }
    }

    @Override
    public boolean isTransformRequired(String transformedClassName) {
        return availablePatches.containsKey(transformedClassName);
    }

}