diff --git a/build.gradle b/build.gradle index 12ed83a0f4..7a07eec2a6 100644 --- a/build.gradle +++ b/build.gradle @@ -126,6 +126,7 @@ project(':forge') { mavenLocal() mavenCentral() } + ext { SPEC_VERSION = '24.0' // This is overwritten by git tag, but here so dev time doesnt explode // The new versioning sceme is -.. @@ -133,11 +134,30 @@ project(':forge') { // Essentially, the same as the old, except dropping the first number, and the builds are no longer unique. MCP_ARTIFACT = project(':mcp').mcp.config } + + def getVersion = { + //TAG-offset-hash + def raw = grgit.describe(longDescr: true) + def desc = (raw == null ? '0.0-0-unknown' : grgit.describe(longDescr: true)).split('-') as List + def hash = desc.remove(desc.size() - 1) + def offset = desc.remove(desc.size() - 1) + def tag = desc.join('-') + def branch = grgit.branch.current().name + if (branch in ['master', 'HEAD', MC_VERSION, MC_VERSION + '.0']) + branch = null + if (branch != null && branch.endsWith('.x') && MC_VERSION.startsWith(branch.substring(0, branch.length() - 2))) //1.13.x + branch = null + SPEC_VERSION = tag + return "${MC_VERSION}-${tag}.${offset}${t -> if (branch != null) t << '-' + branch}".toString() //Bake the response instead of making it dynamic + } + + version = getVersion() + patcher { parent = project(':clean') patches = file("$rootDir/patches/minecraft") patchedSrc = file('src/main/java') - accessTransformer = file("$rootDir/src/main/resources/forge_at.cfg") + accessTransformer = file("$rootDir/src/main/resources/META-INF/accesstransformer.cfg") exc = file("$rootDir/src/main/resources/forge.exc") srgPatches = true clientRun { @@ -153,9 +173,10 @@ project(':forge') { 'org.lwjgl.system.SharedLibraryExtractDirectory': 'lwjgl_dll', 'mc.version': MC_VERSION, 'mcp.version': MCP_VERSION, - 'forge.version': "${project.version.substring(MC_VERSION.length() + 1)}".toString(), + 'forge.version': project.version.substring(MC_VERSION.length() + 1), 'forge.spec': SPEC_VERSION, - 'forge.group': project.group + 'forge.group': project.group, + 'fmllauncher.version': SPEC_VERSION ] } serverRun { @@ -173,24 +194,6 @@ project(':forge') { } } - def getVersion = { - //TAG-offset-hash - def raw = grgit.describe(longDescr: true) - def desc = (raw == null ? '0.0-0-unknown' : grgit.describe(longDescr: true)).split('-') as List - def hash = desc.remove(desc.size() - 1) - def offset = desc.remove(desc.size() - 1) - def tag = desc.join('-') - def branch = grgit.branch.current().name - if (branch in ['master', 'HEAD', MC_VERSION, MC_VERSION + '.0']) - branch = null - if (branch != null && branch.endsWith('.x') && MC_VERSION.startsWith(branch.substring(0, branch.length() - 2))) //1.13.x - branch = null - SPEC_VERSION = tag - return "${MC_VERSION}-${tag}.${offset}${t -> if (branch != null) t << '-' + branch}".toString() //Bake the response instead of making it dynamic - } - - version = getVersion() - ext { MANIFESTS = [ '/': [ @@ -251,7 +254,7 @@ project(':forge') { installer 'org.ow2.asm:asm:6.2' installer 'org.ow2.asm:asm-commons:6.2' installer 'org.ow2.asm:asm-tree:6.2' - installer 'cpw.mods:modlauncher:0.2.0' + installer 'cpw.mods:modlauncher:0.3.0' installer 'net.minecraftforge:accesstransformers:0.10+:shadowed' installer 'net.minecraftforge:eventbus:0.1+:service' installer 'net.minecraftforge:forgespi:0.1+' diff --git a/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLClientLaunchProvider.java b/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLClientLaunchProvider.java index 4bc3d0444d..5b8355fe70 100644 --- a/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLClientLaunchProvider.java +++ b/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLClientLaunchProvider.java @@ -71,7 +71,7 @@ public class FMLClientLaunchProvider extends FMLCommonLaunchHandler implements I final String forgeVersion = (String) arguments.get("forgeVersion"); final String mcVersion = (String) arguments.get("mcVersion"); final String forgeGroup = (String) arguments.get("forgeGroup"); - mods.add(forgeGroup+":forge::universal:"+mcVersion+"-"+forgeVersion); + mods.add(forgeGroup+":forge:universal:"+mcVersion+"-"+forgeVersion); // generics are gross yea? ((Map)arguments).put("mavenRoots", mavenRoots); ((Map)arguments).put("mods", mods); diff --git a/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLDevClientLaunchProvider.java b/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLDevClientLaunchProvider.java index c227d8d951..350bd12b73 100644 --- a/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLDevClientLaunchProvider.java +++ b/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLDevClientLaunchProvider.java @@ -30,6 +30,7 @@ import org.apache.logging.log4j.Logger; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; @@ -87,8 +88,8 @@ public class FMLDevClientLaunchProvider extends FMLCommonLaunchHandler implement { // we're injecting forge into the exploded dir finder final Path forgemodstoml = LibraryFinder.findJarPathFor("META-INF/mods.toml", "forgemodstoml"); - ((Map>>) arguments).computeIfAbsent("explodedTargets", a->new ArrayList<>()). - add(Pair.of(compiledClasses, forgemodstoml)); + ((Map>>>) arguments).computeIfAbsent("explodedTargets", a->new ArrayList<>()). + add(Pair.of(forgemodstoml, Collections.singletonList(compiledClasses))); } @Override diff --git a/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLDevServerLaunchProvider.java b/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLDevServerLaunchProvider.java index d93ab0d682..c8080780a6 100644 --- a/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLDevServerLaunchProvider.java +++ b/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLDevServerLaunchProvider.java @@ -29,9 +29,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.Callable; import static net.minecraftforge.fml.loading.LogMarkers.CORE; @@ -86,8 +84,8 @@ public class FMLDevServerLaunchProvider extends FMLCommonLaunchHandler implement { // we're injecting forge into the exploded dir finder final Path forgemodstoml = LibraryFinder.findJarPathFor("META-INF/mods.toml", "forgemodstoml"); - ((Map>>) arguments).computeIfAbsent("explodedTargets", a->new ArrayList<>()). - add(Pair.of(compiledClasses, forgemodstoml)); + ((Map>>>) arguments).computeIfAbsent("explodedTargets", a->new ArrayList<>()). + add(Pair.of(forgemodstoml, Collections.singletonList(compiledClasses))); } @Override diff --git a/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLLoader.java b/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLLoader.java index 4ee097cb54..3b9afa5ec5 100644 --- a/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLLoader.java +++ b/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLLoader.java @@ -19,6 +19,7 @@ package net.minecraftforge.fml.loading; +import cpw.mods.modlauncher.TransformingClassLoader; import cpw.mods.modlauncher.api.IEnvironment; import cpw.mods.modlauncher.api.ILaunchHandlerService; import cpw.mods.modlauncher.api.ITransformationService; @@ -56,7 +57,7 @@ public class FMLLoader private static LanguageLoadingProvider languageLoadingProvider; private static Dist dist; private static LoadingModList loadingModList; - private static ClassLoader launchClassLoader; + private static TransformingClassLoader launchClassLoader; private static RuntimeDistCleaner runtimeDistCleaner; private static Path gamePath; private static Path forgePath; @@ -207,7 +208,7 @@ public class FMLLoader public static void beforeStart(ITransformingClassLoader launchClassLoader) { - FMLLoader.launchClassLoader = launchClassLoader.getInstance(); + FMLLoader.launchClassLoader = (TransformingClassLoader) launchClassLoader.getInstance(); } @@ -217,7 +218,7 @@ public class FMLLoader } - public static ClassLoader getLaunchClassLoader() + public static TransformingClassLoader getLaunchClassLoader() { return launchClassLoader; } diff --git a/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLServerLaunchProvider.java b/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLServerLaunchProvider.java index ca5e9800e8..329187b50b 100644 --- a/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLServerLaunchProvider.java +++ b/src/fmllauncher/java/net/minecraftforge/fml/loading/FMLServerLaunchProvider.java @@ -69,7 +69,7 @@ public class FMLServerLaunchProvider extends FMLCommonLaunchHandler implements I final String forgeVersion = (String) arguments.get("forgeVersion"); final String mcVersion = (String) arguments.get("mcVersion"); final String forgeGroup = (String) arguments.get("forgeGroup"); - mods.add(forgeGroup+":forge::universal:"+mcVersion+"-"+forgeVersion); + mods.add(forgeGroup+":forge:universal:"+mcVersion+"-"+forgeVersion); // generics are gross yea? ((Map)arguments).put("mavenRoots", mavenRoots); ((Map)arguments).put("mods", mods); diff --git a/src/fmllauncher/java/net/minecraftforge/fml/loading/LibraryFinder.java b/src/fmllauncher/java/net/minecraftforge/fml/loading/LibraryFinder.java index 635a72cc63..083b7515d4 100644 --- a/src/fmllauncher/java/net/minecraftforge/fml/loading/LibraryFinder.java +++ b/src/fmllauncher/java/net/minecraftforge/fml/loading/LibraryFinder.java @@ -49,22 +49,27 @@ public class LibraryFinder { static Path findJarPathFor(final String className, final String jarName) { final URL resource = LibraryFinder.class.getClassLoader().getResource(className); + return findJarPathFor(className, jarName, resource); + } + + public static Path findJarPathFor(final String resourceName, final String jarName, final URL resource) { try { Path path; final URI uri = resource.toURI(); if (uri.getRawSchemeSpecificPart().contains("!")) { path = Paths.get(new URI(uri.getRawSchemeSpecificPart().split("!")[0])); } else { - path = Paths.get(new URI("file://"+uri.getRawSchemeSpecificPart().substring(0, uri.getRawSchemeSpecificPart().length()-className.length()))); + path = Paths.get(new URI("file://"+uri.getRawSchemeSpecificPart().substring(0, uri.getRawSchemeSpecificPart().length()-resourceName.length()))); } LOGGER.debug(CORE, "Found JAR {} at path {}", jarName, path.toString()); return path; } catch (NullPointerException | URISyntaxException e) { - LOGGER.error(CORE, "Failed to find JAR for class {} - {}", className, jarName); - throw new RuntimeException("Unable to locate "+className+" - "+jarName, e); + LOGGER.error(CORE, "Failed to find JAR for class {} - {}", resourceName, jarName); + throw new RuntimeException("Unable to locate "+resourceName+" - "+jarName, e); } } - static Path[] commonLibPaths(Path[] extras) { + + public static Path[] commonLibPaths(Path[] extras) { final Path realms = findJarPathFor("com/mojang/realmsclient/RealmsVersion.class", "realms"); return ObjectArrays.concat(extras, realms); } diff --git a/src/fmllauncher/java/net/minecraftforge/fml/loading/LoadingModList.java b/src/fmllauncher/java/net/minecraftforge/fml/loading/LoadingModList.java index 80be27a930..7e65c7d9b7 100644 --- a/src/fmllauncher/java/net/minecraftforge/fml/loading/LoadingModList.java +++ b/src/fmllauncher/java/net/minecraftforge/fml/loading/LoadingModList.java @@ -25,6 +25,8 @@ import net.minecraftforge.fml.loading.moddiscovery.ModFile; import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo; import net.minecraftforge.fml.loading.moddiscovery.ModInfo; +import java.net.MalformedURLException; +import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -102,6 +104,20 @@ public class LoadingModList return null; } + public URL findURLForResource(final String resourceName) { + for (ModFileInfo mf : modFiles) { + final Path resource = mf.getFile().findResource(resourceName); + if (Files.exists(resource)) { + try { + return new URL("modjar://"+mf.getMods().get(0).getModId()+"/"+resourceName); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } + } + return null; + } + public ModFileInfo getModFileById(String modid) { return this.fileById.get(modid); diff --git a/src/fmllauncher/java/net/minecraftforge/fml/loading/MavenCoordinateResolver.java b/src/fmllauncher/java/net/minecraftforge/fml/loading/MavenCoordinateResolver.java index 3db254545f..c76d2d743e 100644 --- a/src/fmllauncher/java/net/minecraftforge/fml/loading/MavenCoordinateResolver.java +++ b/src/fmllauncher/java/net/minecraftforge/fml/loading/MavenCoordinateResolver.java @@ -25,7 +25,8 @@ import java.nio.file.Paths; /** * Convert a maven coordinate into a Path. * - * {@code :[:[:]]:}, must not be {@code null}. + * This is gradle standard not maven standard coordinate formatting + * {@code :[:]:[@extension]}, must not be {@code null}. */ public class MavenCoordinateResolver { @@ -33,9 +34,10 @@ public class MavenCoordinateResolver { final String[] parts = coordinate.split(":"); final String groupId = parts[0]; final String artifactId = parts[1]; - final String extension = parts.length > 3 ? parts[2] : ""; - final String classifier = parts.length > 4 ? parts[3] : ""; - final String version = parts[parts.length-1]; + final String classifier = parts.length > 3 ? parts[2] : ""; + final String[] versext = parts[parts.length-1].split("@"); + final String version = versext[0]; + final String extension = versext.length > 1 ? versext[1] : ""; return get(groupId, artifactId, extension, classifier, version); } diff --git a/src/fmllauncher/java/net/minecraftforge/fml/loading/ModJarURLHandler.java b/src/fmllauncher/java/net/minecraftforge/fml/loading/ModJarURLHandler.java index f77a322a69..5288747050 100644 --- a/src/fmllauncher/java/net/minecraftforge/fml/loading/ModJarURLHandler.java +++ b/src/fmllauncher/java/net/minecraftforge/fml/loading/ModJarURLHandler.java @@ -25,29 +25,43 @@ import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; import java.nio.file.Files; +import java.nio.file.Path; public class ModJarURLHandler extends URLStreamHandler { - // modjar:///modid!path/to/file + // modjar://modid/path/to/file @Override - protected URLConnection openConnection(URL url) throws IOException { + protected URLConnection openConnection(URL url) { return new URLConnection(url) { + private Path resource; private String modpath; private String modid; @Override - public void connect() throws IOException + public void connect() { - final String path = url.getPath(); - final String[] parts = path.split("!"); - if (parts.length!=2) throw new IOException("Illegal URL format "+path); - modid = parts[0]; - modpath = parts[1]; + if (resource == null) { + modid = url.getHost(); + // trim first char + modpath = url.getPath().substring(1); + resource = FMLLoader.getLoadingModList().getModFileById(modid).getFile().findResource(modpath); + } } @Override public InputStream getInputStream() throws IOException { - return Files.newInputStream(FMLLoader.getLoadingModList().getModFileById(modid).getFile().findResource(modpath)); + connect(); + return Files.newInputStream(resource); + } + + @Override + public long getContentLengthLong() { + try { + connect(); + return Files.size(resource); + } catch (IOException e) { + return -1L; + } } }; } diff --git a/src/fmllauncher/java/net/minecraftforge/fml/loading/moddiscovery/ExplodedDirectoryLocator.java b/src/fmllauncher/java/net/minecraftforge/fml/loading/moddiscovery/ExplodedDirectoryLocator.java index c7d81c4b95..075ead4b14 100644 --- a/src/fmllauncher/java/net/minecraftforge/fml/loading/moddiscovery/ExplodedDirectoryLocator.java +++ b/src/fmllauncher/java/net/minecraftforge/fml/loading/moddiscovery/ExplodedDirectoryLocator.java @@ -36,8 +36,8 @@ import static net.minecraftforge.fml.loading.LogMarkers.SCAN; public class ExplodedDirectoryLocator implements IModLocator { private static final Logger LOGGER = LogManager.getLogger(); - private final List> rootDirs; - private final Map> mods; + private final List>> rootDirs; + private final Map>> mods; public ExplodedDirectoryLocator() { this.rootDirs = new ArrayList<>(); @@ -49,7 +49,7 @@ public class ExplodedDirectoryLocator implements IModLocator { final Path modstoml = Paths.get("META-INF", "mods.toml"); // Collect all the mods.toml files found rootDirs.forEach(pathPathPair -> { - Path resources = pathPathPair.getRight(); + Path resources = pathPathPair.getLeft(); Path modtoml = resources.resolve(modstoml); if (Files.exists(modtoml)) { ModFile mf = new ModFile(pathPathPair.getLeft(), this); @@ -73,25 +73,29 @@ public class ExplodedDirectoryLocator implements IModLocator { } final Path target = Paths.get(path[0], Arrays.copyOfRange(path, 1, path.length)); // try right path first (resources) - Path found = mods.get(modFile).getRight().resolve(target); + Path found = mods.get(modFile).getLeft().resolve(target); if (Files.exists(found)) return found; // then try left path (classes) - return mods.get(modFile).getLeft().resolve(target); + return mods.get(modFile).getRight().stream().map(p->p.resolve(target)).findFirst().orElse(found.resolve(target)); } @Override public void scanFile(final ModFile modFile, final Consumer pathConsumer) { - LOGGER.debug(SCAN,"Scanning directory {}", modFile.getFilePath().toString()); - final Pair pathPathPair = mods.get(modFile); - // classes are in the left branch of the pair - try (Stream files = Files.find(pathPathPair.getLeft(), Integer.MAX_VALUE, (p, a) -> p.getNameCount() > 0 && p.getFileName().toString().endsWith(".class"))) { - files.forEach(pathConsumer); - } catch (IOException e) { - e.printStackTrace(); - } - LOGGER.debug(SCAN,"Directory scan complete {}", pathPathPair.getLeft()); + LOGGER.debug(SCAN,"Scanning exploded directory {}", modFile.getFilePath().toString()); + final Pair> pathPathPair = mods.get(modFile); + // classes are in the right branch of the pair + pathPathPair.getRight().forEach(path->scanIndividualPath(path, pathConsumer)); + LOGGER.debug(SCAN,"Exploded directory scan complete {}", pathPathPair.getLeft().toString()); } + private void scanIndividualPath(final Path path, Consumer pathConsumer) { + LOGGER.debug(SCAN, "Scanning exploded target {}", path.toString()); + try (Stream files = Files.find(path, Integer.MAX_VALUE, (p, a) -> p.getNameCount() > 0 && p.getFileName().toString().endsWith(".class"))) { + files.forEach(pathConsumer); + } catch (IOException e) { + LOGGER.info("Exception scanning {}", path, e); + } + } @Override public String toString() { @@ -107,7 +111,7 @@ public class ExplodedDirectoryLocator implements IModLocator { @SuppressWarnings("unchecked") @Override public void initArguments(final Map arguments) { - final List> explodedTargets = ((Map>>) arguments).get("explodedTargets"); + final List>> explodedTargets = ((Map>>>) arguments).get("explodedTargets"); if (explodedTargets != null && !explodedTargets.isEmpty()) { rootDirs.addAll(explodedTargets); } diff --git a/src/main/java/net/minecraftforge/fml/LaunchTesting.java b/src/main/java/net/minecraftforge/fml/LaunchTesting.java index 58f0ea578e..c2ce7d210b 100644 --- a/src/main/java/net/minecraftforge/fml/LaunchTesting.java +++ b/src/main/java/net/minecraftforge/fml/LaunchTesting.java @@ -49,12 +49,18 @@ public class LaunchTesting logcontext.getConfiguration().addFilter(eventbusFilter); logcontext.getConfiguration().addFilter(distxformFilter); logcontext.updateLoggers(); - File invsorter = new File("/home/cpw/projects/minecraft/inventorysorter/classes"); - if (invsorter.exists()) { - System.setProperty("fml.explodedDir", "/home/cpw/projects/minecraft/inventorysorter/classes"); //TODO: Move this to a example included in our tests, not a random location... - } + String assets = System.getenv().getOrDefault("assetDirectory", "assets"); String target = System.getenv().get("target"); + String[] launchArgs = new String[]{ + "--gameDir", ".", + "--launchTarget", target, + "--fml.forgeVersion", System.getProperty("forge.version"), + "--fml.mcpVersion", System.getProperty("mcp.version"), + "--fml.mcVersion", System.getProperty("mc.version"), + "--fml.forgeGroup", System.getProperty("forge.group") + }; + if (target == null) { throw new IllegalArgumentException("Environment variable target must be set."); @@ -62,23 +68,15 @@ public class LaunchTesting if (Objects.equals(target,"fmldevclient")) { hackNatives(); - Launcher.main("--launchTarget", target, - "--gameDir", ".", - "--accessToken", "blah", - "--version", "FMLDev", - "--assetIndex", "1.13", - "--assetsDir", assets, - "--userProperties", "{}", - "--fml.forgeVersion", "24.0.0", - "--fml.mcpVersion", "2018.11.30", - "--fml.mcVersion", "1.13"); - } else if (Objects.equals(target, "fmldevserver")) { - String[] launchargs = ObjectArrays.concat(new String[] {"--launchTarget", target, - "--gameDir", ".", "--fml.forgeVersion", "24.0.0", - "--fml.mcpVersion", "2018.11.30", - "--fml.mcVersion", "1.13"}, args, String.class); - Launcher.main(launchargs); + launchArgs = ObjectArrays.concat(launchArgs, new String[] { + "--accessToken", "blah", + "--version", "FMLDev", + "--assetIndex", "1.13", + "--assetsDir", assets, + "--userProperties", "{}" + }, String.class); } + Launcher.main(launchArgs); Thread.sleep(10000); } diff --git a/src/main/java/net/minecraftforge/fml/ModLoader.java b/src/main/java/net/minecraftforge/fml/ModLoader.java index be8acc8537..559f09028d 100644 --- a/src/main/java/net/minecraftforge/fml/ModLoader.java +++ b/src/main/java/net/minecraftforge/fml/ModLoader.java @@ -19,6 +19,7 @@ package net.minecraftforge.fml; +import cpw.mods.modlauncher.TransformingClassLoader; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.common.MinecraftForge; @@ -40,12 +41,13 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import static net.minecraftforge.fml.Logging.CORE; +import static net.minecraftforge.fml.Logging.LOADING; public class ModLoader { private static final Logger LOGGER = LogManager.getLogger(); private static ModLoader INSTANCE; - private final ClassLoader launchClassLoader; + private final TransformingClassLoader launchClassLoader; private final LoadingModList loadingModList; private final ModLoadingClassLoader modClassLoader; @@ -112,6 +114,7 @@ public class ModLoader { final Map modInfoMap = modFile.getModFileInfo().getMods().stream().collect(Collectors.toMap(IModInfo::getModId, Function.identity())); + LOGGER.debug(LOADING, "ModContainer is {}", ModContainer.class.getClassLoader()); return modFile.getScanResult().getTargets().entrySet().stream(). map(e-> { try { diff --git a/src/main/java/net/minecraftforge/fml/ModLoadingClassLoader.java b/src/main/java/net/minecraftforge/fml/ModLoadingClassLoader.java index 6215dfa8c8..81150f9e7c 100644 --- a/src/main/java/net/minecraftforge/fml/ModLoadingClassLoader.java +++ b/src/main/java/net/minecraftforge/fml/ModLoadingClassLoader.java @@ -19,20 +19,18 @@ package net.minecraftforge.fml; +import cpw.mods.modlauncher.TransformingClassLoader; import net.minecraftforge.fml.loading.FMLLoader; +import net.minecraftforge.fml.loading.ModJarURLHandler; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.io.IOException; import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.security.SecureClassLoader; import java.util.function.Predicate; import static net.minecraftforge.fml.Logging.LOADING; -public class ModLoadingClassLoader extends SecureClassLoader +public class ModLoadingClassLoader extends TransformingClassLoader { private static final Logger LOGGER = LogManager.getLogger(); @@ -41,62 +39,44 @@ public class ModLoadingClassLoader extends SecureClassLoader } private final Predicate classLoadingPredicate; + private final TransformingClassLoader tcl; - protected ModLoadingClassLoader(final ClassLoader parent) { - super(parent); + protected ModLoadingClassLoader(final TransformingClassLoader parent) { + super(parent, path->FMLLoader.getLoadingModList().findURLForResource(path)); + this.tcl = parent; this.classLoadingPredicate = FMLLoader.getClassLoaderExclusions(); } + @Override + protected URL locateResource(final String path) { + return FMLLoader.getLoadingModList().findURLForResource(path); + } + @Override public URL getResource(String name) { - return super.getResource(name); + return locateResource(name); } -/* @Override protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + synchronized (getClassLoadingLock(name)) { + Class existingClass = tcl.getLoadedClass(name); + if (existingClass != null) return existingClass; - final String className = name.replace('.', '/').concat(".class"); - final Path classResource = FMLLoader.getLoadingModList().findResource(className); - if (classResource != null) - { - return findClass(name); - } - - return super.loadClass(name, resolve); - } -*/ - - @Override - protected Class findClass(String name) throws ClassNotFoundException - { - if (!classLoadingPredicate.test(name)) { - LOGGER.debug(LOADING, "Delegating to parent {}", name); - return getParent().loadClass(name); - } - LOGGER.debug(LOADING, "Loading class {}", name); - final String className = name.replace('.','/').concat(".class"); - final Path classResource = FMLLoader.getLoadingModList().findResource(className); - if (classResource != null) { - try { - final byte[] bytes = Files.readAllBytes(classResource); - return defineClass(name, bytes, 0, bytes.length); + LOGGER.debug(LOADING, "Loading class {}", name); + if (!classLoadingPredicate.test(name)) { + LOGGER.debug(LOADING, "Delegating to parent {}", name); + return tcl.loadClass(name); } - catch (IOException e) - { - throw new ClassNotFoundException("Failed to load class file " + classResource + " for "+ className, e); - } - } else if(getParent() != null) { - getParent().loadClass(name); + return tcl.loadClass(name, this::locateResource); } - throw new ClassNotFoundException("Failed to find class file "+ className); } @Override protected URL findResource(String name) { - return super.findResource(name); + return locateResource(name); } } diff --git a/src/main/java/net/minecraftforge/fml/javafmlmod/FMLJavaModLanguageProvider.java b/src/main/java/net/minecraftforge/fml/javafmlmod/FMLJavaModLanguageProvider.java index 91df8665f1..151b40e2b5 100644 --- a/src/main/java/net/minecraftforge/fml/javafmlmod/FMLJavaModLanguageProvider.java +++ b/src/main/java/net/minecraftforge/fml/javafmlmod/FMLJavaModLanguageProvider.java @@ -35,8 +35,7 @@ import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; -import static net.minecraftforge.fml.Logging.LOADING; -import static net.minecraftforge.fml.Logging.SCAN; +import static net.minecraftforge.fml.Logging.*; public class FMLJavaModLanguageProvider implements IModLanguageProvider { @@ -68,13 +67,14 @@ public class FMLJavaModLanguageProvider implements IModLanguageProvider // in the classloader of the game - the context classloader is appropriate here. try { - final Constructor constructor = Class.forName("net.minecraftforge.fml.javafmlmod.FMLModContainer", true, Thread.currentThread().getContextClassLoader()). - getConstructor(IModInfo.class, String.class, ClassLoader.class, ModFileScanData.class); + final Class fmlContainer = Class.forName("net.minecraftforge.fml.javafmlmod.FMLModContainer", true, Thread.currentThread().getContextClassLoader()); + LOGGER.debug(LOADING, "Loading FMLModContainer from classloader {} - got {}", Thread.currentThread().getContextClassLoader(), fmlContainer.getClassLoader()); + final Constructor constructor = fmlContainer.getConstructor(IModInfo.class, String.class, ClassLoader.class, ModFileScanData.class); return (T)constructor.newInstance(info, className, modClassLoader, modFileScanResults); } catch (NoSuchMethodException | ClassNotFoundException | InstantiationException | IllegalAccessException | InvocationTargetException e) { - LOGGER.error(LOADING,"Unable to load FMLModContainer, wut?", e); + LOGGER.fatal(LOADING,"Unable to load FMLModContainer, wut?", e); throw new RuntimeException(e); } } diff --git a/src/userdev/java/net/minecraftforge/userdev/FMLUserdevClientLaunchProvider.java b/src/userdev/java/net/minecraftforge/userdev/FMLUserdevClientLaunchProvider.java new file mode 100644 index 0000000000..a61e4fef07 --- /dev/null +++ b/src/userdev/java/net/minecraftforge/userdev/FMLUserdevClientLaunchProvider.java @@ -0,0 +1,37 @@ +package net.minecraftforge.userdev; + +import cpw.mods.modlauncher.api.ILaunchHandlerService; +import cpw.mods.modlauncher.api.ITransformingClassLoader; +import net.minecraftforge.api.distmarker.Dist; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.concurrent.Callable; + +import static net.minecraftforge.fml.loading.LogMarkers.CORE; + +public class FMLUserdevClientLaunchProvider extends FMLUserdevLaunchProvider implements ILaunchHandlerService { + private static final Logger LOGGER = LogManager.getLogger(); + + @Override + public Dist getDist() { + return Dist.CLIENT; + } + + @Override + public String name() { + return "fmluserdevclient"; + } + + @Override + public Callable launchService(String[] arguments, ITransformingClassLoader launchClassLoader) + { + return () -> { + LOGGER.debug(CORE, "Launching minecraft in {} with arguments {}", launchClassLoader, arguments); + super.beforeStart(launchClassLoader); + launchClassLoader.addTargetPackageFilter(getPackagePredicate()); + Class.forName("net.minecraft.client.main.Main", true, launchClassLoader.getInstance()).getMethod("main", String[].class).invoke(null, (Object)arguments); + return null; + }; + } +} diff --git a/src/userdev/java/net/minecraftforge/userdev/FMLUserdevLaunchProvider.java b/src/userdev/java/net/minecraftforge/userdev/FMLUserdevLaunchProvider.java new file mode 100644 index 0000000000..5bd3fa1b6d --- /dev/null +++ b/src/userdev/java/net/minecraftforge/userdev/FMLUserdevLaunchProvider.java @@ -0,0 +1,106 @@ +package net.minecraftforge.userdev; + +import com.google.common.collect.ObjectArrays; +import com.google.common.collect.Streams; +import cpw.mods.modlauncher.api.IEnvironment; +import net.minecraftforge.fml.loading.FMLCommonLaunchHandler; +import net.minecraftforge.fml.loading.FMLLoader; +import net.minecraftforge.fml.loading.LibraryFinder; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; +import java.util.stream.Collectors; + +import static net.minecraftforge.fml.loading.LogMarkers.CORE; + +public abstract class FMLUserdevLaunchProvider extends FMLCommonLaunchHandler { + private static final Logger LOGGER = LogManager.getLogger(); + private Path forgeJar; + private Path mcJars; + + @Override + public Path getForgePath(final String mcVersion, final String forgeVersion, final String forgeGroup) { + final URL forgePath = getClass().getClassLoader().getResource("net/minecraftforge/versions/forge/ForgeVersion.class"); + if (forgePath == null) { + LOGGER.fatal(CORE, "Unable to locate forge on the classpath"); + throw new RuntimeException("Unable to locate forge on the classpath"); + } + forgeJar = LibraryFinder.findJarPathFor("ForgeVersion.class","forge", forgePath); + return forgeJar; + } + + @SuppressWarnings("unchecked") + @Override + public void setup(final IEnvironment environment, final Map arguments) { + final List mavenRoots = new ArrayList<>((List) arguments.get("mavenRoots")); + final List mods = new ArrayList<>((List) arguments.get("mods")); + final String forgeVersion = (String) arguments.get("forgeVersion"); + final String mcVersion = (String) arguments.get("mcVersion"); + final String mcpVersion = (String) arguments.get("mcpVersion"); + final String forgeGroup = (String) arguments.get("forgeGroup"); + final String userdevVersion = mcVersion+"-"+forgeVersion+"_mapped_snapshot_"+mcpVersion; + int dirs = forgeGroup.split("\\.").length + 2; + Path fjroot = forgeJar; + do { + fjroot = fjroot.getParent(); + } while (dirs-- > 0); + final String fjpath = fjroot.toString(); + LOGGER.info(CORE, "Injecting forge as mod {} from maven path {}", userdevVersion, fjpath); + mavenRoots.add(fjpath); + mods.add(forgeGroup+":userdev:"+userdevVersion); + + try { + final Enumeration resources = ClassLoader.getSystemClassLoader().getResources("META-INF/mods.toml"); + final ArrayList modstoml = Collections.list(resources); + modstoml.stream().filter(u-> !u.getPath().contains("!")); + + } catch (IOException e) { + LOGGER.fatal("Error trying to find resources", e); + throw new RuntimeException("wha?", e); + } + + LOGGER.fatal(CORE, "Got mod coordinates {} from env", System.getenv("MOD_CLASSES")); + + final List modClasses = Arrays.stream(System.getenv("MOD_CLASSES").split(File.pathSeparator)). + map(Paths::get).collect(Collectors.toList()); + + LOGGER.fatal(CORE, "Processed mod coordinates [{}]", modClasses.stream().map(Object::toString).collect(Collectors.joining(","))); + + ((Map>>>) arguments).computeIfAbsent("explodedTargets", a->new ArrayList<>()). + add(Pair.of(modClasses.get(0), modClasses.subList(1, modClasses.size()))); + + + // generics are gross yea? + ((Map)arguments).put("mavenRoots", mavenRoots); + ((Map)arguments).put("mods", mods); + } + + @Override + protected void validatePaths(final Path forgePath, final Path[] mcPaths, final String forgeVersion, final String mcVersion, final String mcpVersion) { + + } + + @Override + public Path[] getMCPaths(final String mcVersion, final String mcpVersion, final String forgeVersion, final String forgeGroup) { + final URL mcDataPath = getClass().getClassLoader().getResource("assets/minecraft/lang/en_us.json"); + if (mcDataPath == null) { + LOGGER.fatal(CORE, "Unable to locate minecraft data on the classpath"); + throw new RuntimeException("Unable to locate minecraft data on the classpath"); + } + mcJars = LibraryFinder.findJarPathFor("en_us.json","mcdata", mcDataPath); + return new Path[] {mcJars}; + } + + public Path[] identifyTransformationTargets() + { + return LibraryFinder.commonLibPaths(ObjectArrays.concat(FMLLoader.getForgePath(), FMLLoader.getMCPaths())); + } + +} diff --git a/src/userdev/java/net/minecraftforge/userdev/FMLUserdevServerLaunchProvider.java b/src/userdev/java/net/minecraftforge/userdev/FMLUserdevServerLaunchProvider.java new file mode 100644 index 0000000000..1e48f37c0b --- /dev/null +++ b/src/userdev/java/net/minecraftforge/userdev/FMLUserdevServerLaunchProvider.java @@ -0,0 +1,39 @@ +package net.minecraftforge.userdev; + +import cpw.mods.modlauncher.api.ILaunchHandlerService; +import cpw.mods.modlauncher.api.ITransformingClassLoader; +import net.minecraftforge.api.distmarker.Dist; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.concurrent.Callable; + +import static net.minecraftforge.fml.loading.LogMarkers.CORE; + +public class FMLUserdevServerLaunchProvider extends FMLUserdevLaunchProvider implements ILaunchHandlerService { + private static final Logger LOGGER = LogManager.getLogger(); + + @Override + public Dist getDist() { + return Dist.DEDICATED_SERVER; + } + + + @Override + public String name() { + return "fmluserdevserver"; + } + + @Override + public Callable launchService(String[] arguments, ITransformingClassLoader launchClassLoader) + { + return () -> { + LOGGER.debug(CORE, "Launching minecraft in {} with arguments {}", launchClassLoader, arguments); + super.beforeStart(launchClassLoader); + launchClassLoader.addTargetPackageFilter(getPackagePredicate()); + Thread.currentThread().setContextClassLoader(launchClassLoader.getInstance()); + Class.forName("net.minecraft.server.MinecraftServer", true, launchClassLoader.getInstance()).getMethod("main", String[].class).invoke(null, (Object)arguments); + return null; + }; + } +} diff --git a/src/userdev/java/net/minecraftforge/userdev/UserdevLauncher.java b/src/userdev/java/net/minecraftforge/userdev/UserdevLauncher.java index 53061facff..fe4b3578b3 100644 --- a/src/userdev/java/net/minecraftforge/userdev/UserdevLauncher.java +++ b/src/userdev/java/net/minecraftforge/userdev/UserdevLauncher.java @@ -57,25 +57,33 @@ public class UserdevLauncher 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'."); + throw new IllegalArgumentException("Environment variable 'target' must be set to 'fmluserdevclient' or 'fmluserdevserver'."); } - if (Objects.equals(target,"fmldevclient")) { + String[] launchArgs = new String[]{ + "--gameDir", ".", + "--launchTarget", target, + "--fml.forgeVersion", System.getenv("FORGE_VERSION"), + "--fml.mcpVersion", System.getenv("MCP_VERSION"), + "--fml.mcVersion", System.getenv("MC_VERSION"), + "--fml.forgeGroup", System.getenv("FORGE_GROUP") + }; + + if (Objects.equals(target,"fmluserdevclient")) { hackNatives(); - Launcher.main("--launchTarget", target, - "--gameDir", ".", + launchArgs = ObjectArrays.concat(launchArgs, new String[] { "--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); + "--userProperties", "{}" + }, String.class); + } else if (Objects.equals(target, "fmluserdevserver")) { + // we're good } else { throw new IllegalArgumentException("Unknown value for 'target' property: " + target); } + Launcher.main(launchArgs); Thread.sleep(10000); } diff --git a/src/userdev/resources/META-INF/services/cpw.mods.modlauncher.api.ILaunchHandlerService b/src/userdev/resources/META-INF/services/cpw.mods.modlauncher.api.ILaunchHandlerService new file mode 100644 index 0000000000..3c70f3f7ee --- /dev/null +++ b/src/userdev/resources/META-INF/services/cpw.mods.modlauncher.api.ILaunchHandlerService @@ -0,0 +1,2 @@ +net.minecraftforge.userdev.FMLUserdevClientLaunchProvider +net.minecraftforge.userdev.FMLUserdevServerLaunchProvider \ No newline at end of file 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 deleted file mode 100644 index fc6e5d3cce..0000000000 --- a/src/userdev/resources/META-INF/services/net.minecraftforge.fml.loading.moddiscovery.IModLocator +++ /dev/null @@ -1 +0,0 @@ -net.minecraftforge.userdev.ClasspathLocator \ No newline at end of file