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

net.minecraftforge.gradle.mcp.util.MCPRuntime Maven / Gradle / Ivy

Go to download

Minecraft mod development framework used by Forge and FML for the gradle build system adapted for mohist api.

The newest version!
/*
 * ForgeGradle
 * Copyright (C) 2018 Forge Development LLC
 *
 * 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.mcp.util;

import net.minecraftforge.gradle.common.config.MCPConfigV1;
import net.minecraftforge.gradle.common.config.MCPConfigV2;
import net.minecraftforge.gradle.common.util.MavenArtifactDownloader;
import net.minecraftforge.gradle.mcp.function.MCPFunction;
import net.minecraftforge.gradle.mcp.function.MCPFunctionFactory;

import org.gradle.api.Project;
import org.gradle.api.logging.Logger;

import java.io.File;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.zip.ZipFile;

import javax.annotation.Nullable;

public class MCPRuntime {

    private static final Pattern OUTPUT_REPLACE_PATTERN = Pattern.compile("^\\{(\\w+)Output}$");

    final Project project;
    final MCPEnvironment environment;
    final File mcpDirectory;

    final File zipFile;

    final Map steps = new LinkedHashMap<>();
    Step currentStep;

    public MCPRuntime(Project project, File mcp_config, MCPConfigV2 config, String side,
            File mcpDirectory, Map extraPres) {
        this.project = project;
        this.environment = new MCPEnvironment(this, config.getVersion(), config.getJavaTarget(), side);
        this.mcpDirectory = mcpDirectory;

        this.zipFile = mcp_config;

        @SuppressWarnings("unchecked")
        Map data = config.getData().entrySet().stream().collect(Collectors.toMap(Entry::getKey,
            e -> e.getValue() instanceof Map ? ((Map)e.getValue()).get(side) : (String)e.getValue()
        ));

        List steps = config.getSteps(side);
        if (steps.isEmpty())
            throw new IllegalArgumentException("Unknown side: " + side + " For Config: " + mcp_config);

        for (MCPConfigV1.Step step : steps) {
            if (step.getName().equals("decompile")) { //TODO: Clearly define decomp vs bin, needs MCPConfig spec bump.
                if (!extraPres.isEmpty()) {
                    String input = step.getValues().get("input"); //Decompile's input
                    String lastName = null;
                    for (Entry entry : extraPres.entrySet()) {
                        String name = entry.getKey();
                        Map args = new HashMap<>();
                        args.put("input", input);
                        this.steps.put(name, new Step(name, entry.getValue(), args, new File(this.mcpDirectory, name), data));
                        input = "{" + name +"Output}";
                        lastName = name;
                    }
                    step.getValues().put("input", "{" + lastName + "Output}");
                }
            }

            @SuppressWarnings("deprecation")
            MCPFunction function = MCPFunctionFactory.createBuiltIn(step.getType(), config.spec);

            if (function == null) {
                MCPConfigV1.Function custom = config.getFunction(step.getType());
                if (custom == null)
                    throw new IllegalArgumentException("Invalid MCP Config, Unknown function step type: " + step.getType() + " File: " + mcp_config);

                File jar = MavenArtifactDownloader.manual(project, custom.getVersion(), false);
                if (jar == null || !jar.exists())
                    throw new IllegalArgumentException("Could not download MCP Config dependency: " + custom.getVersion());

                @SuppressWarnings("deprecation")
                MCPFunction tmp = MCPFunctionFactory.createExecute(jar, custom.getJvmArgs(), custom.getArgs());
                function = tmp;
            }

            File workingDir = new File(this.mcpDirectory, step.getName());
            this.steps.put(step.getName(), new Step(step.getName(), function, step.getValues(), workingDir, data));
        }
    }

    public File execute(Logger logger) throws Exception {
        return execute(logger, null);
    }

    public File executeUpTo(Logger logger, @Nullable String stop) throws Exception {
        String last = null;
        for(Step step : steps.values()) {
            if (step.name.equals(stop))
                break;
            last = step.name;
        }
        return execute(logger, last);
    }

    public File execute(Logger logger, @Nullable String stop) throws Exception {
        environment.logger = logger;

        logger.lifecycle("Setting up MCP environment");

        logger.lifecycle("Initializing steps");
        ZipFile zip = new ZipFile(zipFile);
        for (Step step : steps.values()) {
            logger.info(" > Initializing '" + step.name + "'");
            currentStep = step;
            step.initialize(zip);
        }
        zip.close();

        File ret = null;
        logger.lifecycle("Executing steps");
        for (Step step : steps.values()) {
            logger.lifecycle(" > Running '" + step.name + "'");
            currentStep = step;
            step.arguments.replaceAll((key, value) -> value instanceof String ? applyStepOutputSubstitutions((String)value) : value);
            ret = step.execute();

            if (stop != null && stop.equals(step.name)) {
                logger.lifecycle("Stopping at requested step: " + ret);
                return ret;
            }
        }

        logger.lifecycle("MCP environment setup is complete");
        return ret;
    }

    private Object applyStepOutputSubstitutions(String value) {
        Matcher matcher = OUTPUT_REPLACE_PATTERN.matcher(value);
        if (!matcher.find()) return value; // Not a replaceable string

        String stepName = matcher.group(1);
        if (stepName != null) {
            return environment.getStepOutput(stepName);
        }
        throw new IllegalStateException("The string '" + value + "' did not return a valid substitution match!");
    }

    class Step {

        private final String name;
        private final MCPFunction function;
        final Map arguments;
        final File workingDirectory;
        File output;

        private Step(String name, MCPFunction function, Map arguments, File workingDirectory, Map data) {
            this.name = name;
            this.function = function;
            this.arguments = new HashMap<>(arguments);
            this.workingDirectory = workingDirectory;
            function.loadData(data);
        }

        private void initialize(ZipFile zip) throws Exception {
            function.initialize(environment, zip);
        }

        private File execute() throws Exception {
            try {
                output = function.execute(environment);
            } finally {
                function.cleanup(environment);
            }
            return output;
        }

        boolean isOfType(Class type) {
            return type.isAssignableFrom(function.getClass());
        }

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy