From b7b5dd5beac9058dfe22b1a291aff64a0743d151 Mon Sep 17 00:00:00 2001 From: David Quintana Date: Wed, 12 Dec 2018 05:04:23 +0100 Subject: [PATCH] Create a userdev-specific main, and include it as an injected file in the userdev jar. (#5231) --- build.gradle | 40 ++++++ mdk/build.gradle | 24 +++- .../userdev/ClasspathLocator.java | 135 ++++++++++++++++++ .../userdev/UserdevLauncher.java | 106 ++++++++++++++ ...forge.fml.loading.moddiscovery.IModLocator | 1 + 5 files changed, 304 insertions(+), 2 deletions(-) create mode 100644 src/userdev/java/net/minecraftforge/userdev/ClasspathLocator.java create mode 100644 src/userdev/java/net/minecraftforge/userdev/UserdevLauncher.java create mode 100644 src/userdev/resources/META-INF/services/net.minecraftforge.fml.loading.moddiscovery.IModLocator diff --git a/build.gradle b/build.gradle index 7f1acda42..fd685e19f 100644 --- a/build.gradle +++ b/build.gradle @@ -22,6 +22,9 @@ import net.minecraftforge.gradle.common.task.SignJar import net.minecraftforge.gradle.patcher.task.ApplyBinPatches import org.apache.tools.ant.filters.ReplaceTokens import de.undercouch.gradle.tasks.download.Download +import net.minecraftforge.gradle.patcher.task.TaskReobfuscateJar + +import java.util.stream.Collectors plugins { id 'net.minecrell.licenser' version '0.4' @@ -98,6 +101,16 @@ project(':forge') { srcDir "$rootDir/src/main/resources" } } + userdev { + compileClasspath += sourceSets.main.runtimeClasspath + runtimeClasspath += sourceSets.main.runtimeClasspath + java { + srcDir "$rootDir/src/userdev/java" + } + resources { + srcDir "$rootDir/src/userdev/resources" + } + } } repositories { mavenLocal() @@ -755,6 +768,33 @@ project(':forge') { } } + task userdevExtras(type:Jar) { + dependsOn classes + from sourceSets.userdev.output + classifier 'userdev-temp' + } + + task userdevExtrasReobf(type:TaskReobfuscateJar) { + dependsOn userdevExtras, createMcp2Srg + input = tasks.userdevExtras.archivePath + classpath = project.configurations.getByName("compile") + srg = tasks.createMcp2Srg.output + } + + userdevJar { + dependsOn userdevExtrasReobf + from (zipTree(tasks.userdevExtrasReobf.output)) { + into '/inject/' + } + from (sourceSets.userdev.output.resourcesDir) { + into '/inject/' + } + } + + applyRangeMap { + setSources sourceSets.userdev.java.srcDirs.findAll({f -> (f != patcher.patchedSrc) }) + } + publishing { publications { mavenJava(MavenPublication) { diff --git a/mdk/build.gradle b/mdk/build.gradle index ee711d2a9..ce344c185 100644 --- a/mdk/build.gradle +++ b/mdk/build.gradle @@ -39,6 +39,26 @@ minecraft { // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable. //accessTransformer = file('my_at.cfg') + + // default run configurations. + // these can be tweaked, removed, or duplicated as needed. + runConfig { + name= "Minecraft Client" + main= "net.minecraftforge.userdev.UserdevLauncher" + ideaModuleName = "${project.name}_main" + workingDirectory = project.file("run").canonicalPath + environment "target", "fmldevclient" + environment "assetDirectory", downloadAssets.output.absolutePath + } + + runConfig { + name= "Minecraft Server" + main= "net.minecraftforge.userdev.UserdevLauncher" + ideaModuleName = "${project.name}_main" + workingDirectory = project.file("run").canonicalPath + environment "target", "fmldevserver" + environment "assetDirectory", downloadAssets.output.absolutePath + } } dependencies { @@ -76,7 +96,7 @@ processResources { // replace stuff in mcmod.info, nothing else from(sourceSets.main.resources.srcDirs) { - include 'mcmod.info' + include 'META_INF/mods.toml' // replace version and mcversion expand 'version':project.version, 'mcversion': '@MC_VERSION@' @@ -84,6 +104,6 @@ processResources { // copy everything else except the mcmod.info from(sourceSets.main.resources.srcDirs) { - exclude 'mcmod.info' + exclude 'META_INF/mods.toml' } } diff --git a/src/userdev/java/net/minecraftforge/userdev/ClasspathLocator.java b/src/userdev/java/net/minecraftforge/userdev/ClasspathLocator.java new file mode 100644 index 000000000..7f16338dd --- /dev/null +++ b/src/userdev/java/net/minecraftforge/userdev/ClasspathLocator.java @@ -0,0 +1,135 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2018. + * + * 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 version 2.1 + * of the License. + * + * 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.userdev; + +import com.google.common.collect.Sets; +import net.minecraftforge.fml.loading.moddiscovery.IModLocator; +import net.minecraftforge.fml.loading.moddiscovery.ModFile; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.function.Consumer; +import java.util.jar.Manifest; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static net.minecraftforge.fml.Logging.SCAN; + +public class ClasspathLocator implements IModLocator +{ + private static final Logger LOGGER = LogManager.getLogger(); + + public ClasspathLocator() { + } + + @Override + public List scanMods() { + Set modUrls = Sets.newHashSet(); + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + try + { + modUrls.addAll(Collections.list(ClassLoader.getSystemResources("META-INF/coremods.json"))); + modUrls.addAll(Collections.list(loader.getResources("META-INF/coremods.json"))); + modUrls.addAll(Collections.list(ClassLoader.getSystemResources("META-INF/mods.toml"))); + modUrls.addAll(Collections.list(loader.getResources("META-INF/mods.toml"))); + } + catch (IOException e) + { + e.printStackTrace(); + } + + return modUrls.stream().map((url) -> { + try + { + // We got URLs including "META-INF/ new ModFile(path, this)) + .collect(Collectors.toList()); + } + + @Override + public String name() { + return "classpath mods"; + } + + @Override + public Path findPath(final ModFile modFile, final String... path) { + if (path.length < 1) { + throw new IllegalArgumentException("Missing path"); + } + return modFile.getFilePath().resolve(modFile.getFilePath().getFileSystem().getPath(path[0], Arrays.copyOfRange(path, 1, path.length))); + } + + @Override + public void scanFile(final ModFile modFile, final Consumer pathConsumer) { + LOGGER.debug(SCAN,"Scanning classpath"); + + Path filePath = modFile.getFilePath(); + + Path scanPath = filePath; + + // Hack 1: When running from within intellij, we get + // "out/production/resources" + "out/production/classes" + if(filePath.getNameCount() >= 1 && filePath.getName(filePath.getNameCount()-1).toString().equals("resources")) + { + scanPath = filePath.getParent().resolve("classes"); + } + // Hack 2: When running from gradle, we get + // "build/resources/" + "build/classes//" + else if(filePath.getNameCount() >= 2 && filePath.getName(filePath.getNameCount()-2).toString().equals("resources")) + { + // We'll scan all the subdirectories for languages and sourcesets, hopefully that works... + scanPath = filePath.getParent().getParent().resolve("classes"); + } + + try (Stream files = Files.find(scanPath, Integer.MAX_VALUE, (p, a) -> p.getNameCount() > 0 && p.getFileName().toString().endsWith(".class"))) { + files.forEach(pathConsumer); + } catch (IOException e) { + e.printStackTrace(); + } + LOGGER.debug(SCAN,"Classpath scan complete"); + } + + @Override + public String toString() + { + return "{Classpath locator}"; + } + + @Override + public Optional findManifest(Path file) + { + return Optional.empty(); + } +} \ No newline at end of file diff --git a/src/userdev/java/net/minecraftforge/userdev/UserdevLauncher.java b/src/userdev/java/net/minecraftforge/userdev/UserdevLauncher.java new file mode 100644 index 000000000..53061facf --- /dev/null +++ b/src/userdev/java/net/minecraftforge/userdev/UserdevLauncher.java @@ -0,0 +1,106 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2018. + * + * 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 version 2.1 + * of the License. + * + * 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.userdev; + +import com.google.common.base.Strings; +import com.google.common.collect.ObjectArrays; +import cpw.mods.modlauncher.Launcher; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.Filter; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.Configurator; +import org.apache.logging.log4j.core.filter.MarkerFilter; + +import java.io.File; +import java.lang.reflect.Field; +import java.util.*; + +public class UserdevLauncher +{ + public static void main(String... args) throws InterruptedException + { + Configurator.setRootLevel(Level.DEBUG); + final MarkerFilter classloadingFilter = MarkerFilter.createFilter("CLASSLOADING", Filter.Result.DENY, Filter.Result.NEUTRAL); + final MarkerFilter launchpluginFilter = MarkerFilter.createFilter("LAUNCHPLUGIN", Filter.Result.DENY, Filter.Result.NEUTRAL); + final MarkerFilter axformFilter= MarkerFilter.createFilter("AXFORM", Filter.Result.DENY, Filter.Result.NEUTRAL); + final MarkerFilter eventbusFilter = MarkerFilter.createFilter("EVENTBUS", Filter.Result.DENY, Filter.Result.NEUTRAL); + final MarkerFilter distxformFilter = MarkerFilter.createFilter("DISTXFORM", Filter.Result.DENY, Filter.Result.NEUTRAL); + final LoggerContext logcontext = LoggerContext.getContext(false); + logcontext.getConfiguration().addFilter(classloadingFilter); + logcontext.getConfiguration().addFilter(launchpluginFilter); + logcontext.getConfiguration().addFilter(axformFilter); + logcontext.getConfiguration().addFilter(eventbusFilter); + logcontext.getConfiguration().addFilter(distxformFilter); + logcontext.updateLoggers(); + + String assets = System.getenv().getOrDefault("assetDirectory", "assets"); + String target = System.getenv().get("target"); + + if (assets == null ||!new File(assets).exists()) { + throw new IllegalArgumentException("Environment variable 'assets' must be set to a valid path."); + } + if (target == null) { + throw new IllegalArgumentException("Environment variable 'target' must be set to 'fmldevclient' or 'fmldevserver'."); + } + + if (Objects.equals(target,"fmldevclient")) { + hackNatives(); + Launcher.main("--launchTarget", target, + "--gameDir", ".", + "--accessToken", "blah", + "--version", "FMLDev", + "--assetIndex", "1.13", + "--assetsDir", assets, + "--userProperties", "{}"); + } else if (Objects.equals(target, "fmldevserver")) { + String[] launchargs = ObjectArrays.concat(new String[] {"--launchTarget", target, + "--gameDir", "."}, args, String.class); + Launcher.main(launchargs); + } else { + throw new IllegalArgumentException("Unknown value for 'target' property: " + target); + } + Thread.sleep(10000); + } + + private static void hackNatives() + { + String paths = System.getProperty("java.library.path"); + String nativesDir = System.getenv().get("nativesDirectory"); + + if (Strings.isNullOrEmpty(paths)) + paths = nativesDir; + else + paths += File.pathSeparator + nativesDir; + + System.setProperty("java.library.path", paths); + + // hack the classloader now. + try + { + final Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths"); + sysPathsField.setAccessible(true); + sysPathsField.set(null, null); + } + catch(Throwable t) {} + } + + + +} diff --git a/src/userdev/resources/META-INF/services/net.minecraftforge.fml.loading.moddiscovery.IModLocator b/src/userdev/resources/META-INF/services/net.minecraftforge.fml.loading.moddiscovery.IModLocator new file mode 100644 index 000000000..fc6e5d3cc --- /dev/null +++ b/src/userdev/resources/META-INF/services/net.minecraftforge.fml.loading.moddiscovery.IModLocator @@ -0,0 +1 @@ +net.minecraftforge.userdev.ClasspathLocator \ No newline at end of file