All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.minecraftforge.gradle.patcher.TaskReobfuscate Maven / Gradle / Ivy

/*
 * A Gradle plugin for the creation of Minecraft mods and MinecraftForge plugins.
 * Copyright (C) 2013-2019 Minecraft Forge
 * Copyright (C) 2020-2021 anatawa12 and other contributors
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
 * USA
 */
package net.minecraftforge.gradle.patcher;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URLClassLoader;
import java.nio.charset.Charset;
import java.util.LinkedList;
import java.util.List;

import net.md_5.specialsource.Jar;
import net.md_5.specialsource.JarMapping;
import net.md_5.specialsource.JarRemapper;
import net.md_5.specialsource.provider.ClassLoaderProvider;
import net.md_5.specialsource.provider.JarProvider;
import net.md_5.specialsource.provider.JointProvider;
import net.minecraftforge.gradle.common.Constants;
import net.minecraftforge.gradle.util.mcp.ReobfExceptor;

import org.gradle.api.DefaultTask;
import org.gradle.api.file.FileCollection;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;

import com.google.common.collect.Lists;
import com.google.common.io.Files;

class TaskReobfuscate extends DefaultTask
{
    //@formatter:off
    @InputFile  private Object inJar;
    @InputFile  private Object preFFJar;
    @InputFile  private Object srg;
    @InputFile  private Object exc;
    @InputFile  private Object methodsCsv;
    @InputFile  private Object fieldsCsv;
    @OutputFile private Object outJar;
    //@formatter: on
    
    @Input
    private LinkedList extraSrg = new LinkedList();
    
    @InputFiles
    private List libs = Lists.newArrayList();
    
    //@formatter:off
    public TaskReobfuscate() { super(); }
    //@formatter:on

    @TaskAction
    public void doTask() throws IOException
    {
        File inJar = getInJar();
        File srg = getSrg();

        {
            ReobfExceptor exceptor = new ReobfExceptor();
            exceptor.toReobfJar = inJar;
            exceptor.deobfJar = getPreFFJar();
            exceptor.excConfig = getExc();
            exceptor.fieldCSV = getFieldsCsv();
            exceptor.methodCSV = getMethodsCsv();
            
            File outSrg =  new File(this.getTemporaryDir(), "reobf_cls.srg");
            
            exceptor.doFirstThings();
            exceptor.buildSrg(srg, outSrg);
            
            srg = outSrg;
        }
        
        // append SRG
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(srg, true)))
        {
            for (String line : extraSrg)
            {
                writer.write(line);
                writer.newLine();
            }
        }

        obfuscate(inJar, getLibs(), srg);
    }

    private void obfuscate(File inJar, FileCollection classpath, File srg) throws FileNotFoundException, IOException
    {
        // load mapping
        JarMapping mapping = new JarMapping();
        mapping.loadMappings(Files.newReader(srg, Charset.defaultCharset()), null, null, false);

        // make remapper
        JarRemapper remapper = new JarRemapper(null, mapping);

        // load jar
        URLClassLoader classLoader = null;
        try (Jar input = Jar.init(inJar))
        {
            // ensure that inheritance provider is used
            JointProvider inheritanceProviders = new JointProvider();
            inheritanceProviders.add(new JarProvider(input));

            if (classpath != null && !classpath.isEmpty())
                inheritanceProviders.add(new ClassLoaderProvider(classLoader = new URLClassLoader(Constants.toUrls(classpath))));

            mapping.setFallbackInheritanceProvider(inheritanceProviders);

            File out = getOutJar();
            if (!out.getParentFile().exists()) //Needed because SS doesn't create it.
            {
                out.getParentFile().mkdirs();
            }

            // remap jar
            remapper.remapJar(input, getOutJar());
        }
        finally
        {
            if (classLoader != null)
                classLoader.close();
        }
    }
    
    public File getInJar()
    {
        return getProject().file(inJar);
    }

    public void setInJar(Object inJar)
    {
        this.inJar = inJar;
    }

    public File getOutJar()
    {
        return getProject().file(outJar);
    }

    public void setOutJar(Object outJar)
    {
        this.outJar = outJar;
    }
    
    public File getPreFFJar()
    {
        return getProject().file(preFFJar);
    }

    public void setPreFFJar(Object preFFJar)
    {
        this.preFFJar = preFFJar;
    }

    public File getSrg()
    {
        return getProject().file(srg);
    }

    public void setSrg(Object srg)
    {
        this.srg = srg;
    }

    public File getExc()
    {
        return getProject().file(exc);
    }

    public void setExc(Object exc)
    {
        this.exc = exc;
    }


    public File getMethodsCsv()
    {
        return getProject().file(methodsCsv);
    }

    public void setMethodsCsv(Object methodsCsv)
    {
        this.methodsCsv = methodsCsv;
    }

    public File getFieldsCsv()
    {
        return getProject().file(fieldsCsv);
    }

    public void setFieldsCsv(Object fieldsCsv)
    {
        this.fieldsCsv = fieldsCsv;
    }

    public LinkedList getExtraSrg()
    {
        return extraSrg;
    }

    public void setExtraSrg(LinkedList extraSrg)
    {
        this.extraSrg = extraSrg;
    }
    
    public FileCollection getLibs()
    {
        FileCollection collection = null;
        
        for (Object o : libs)
        {
            FileCollection col;
            if (o instanceof FileCollection)
            {
                col = (FileCollection) o;
            }
            else
            {
                col = getProject().files(o);
            }
            
            if (collection == null)
                collection = col;
            else
                collection = collection.plus(col);
        }
        
        return collection;
    }

    public void addLibs(Object libs)
    {
        this.libs.add(libs);
    }
}