From 458acc482d1bb79fcb9e79643c56bf6855c28cfa Mon Sep 17 00:00:00 2001 From: shedaniel Date: Wed, 14 Jul 2021 18:21:03 +0800 Subject: [PATCH] Split Minecraft and Forge jars (#34) Signed-off-by: shedaniel --- .../mixin/AnnotationProcessorInvoker.java | 4 + .../configuration/CompileConfiguration.java | 7 + .../configuration/MavenConfiguration.java | 5 + .../loom/configuration/mods/ModProcessor.java | 4 + .../providers/LaunchProvider.java | 4 + .../forge/MinecraftPatchedProvider.java | 138 +++++++++----- .../minecraft/MinecraftMappedProvider.java | 180 ++++++++++++++---- .../sources/ForgeSourcesRemapper.java | 3 +- .../loom/task/GenerateSourcesTask.java | 6 +- .../loom/task/MigrateMappingsTask.java | 13 +- .../net/fabricmc/loom/util/Constants.java | 1 + .../fabricmc/loom/util/SourceRemapper.java | 3 + .../fabricmc/loom/util/ThreadingUtils.java | 33 +++- .../loom/util/srg/SpecialSourceExecutor.java | 12 +- 14 files changed, 315 insertions(+), 98 deletions(-) diff --git a/src/main/java/net/fabricmc/loom/build/mixin/AnnotationProcessorInvoker.java b/src/main/java/net/fabricmc/loom/build/mixin/AnnotationProcessorInvoker.java index 6a0a2f65..676eac08 100644 --- a/src/main/java/net/fabricmc/loom/build/mixin/AnnotationProcessorInvoker.java +++ b/src/main/java/net/fabricmc/loom/build/mixin/AnnotationProcessorInvoker.java @@ -100,6 +100,10 @@ public abstract class AnnotationProcessorInvoker { configs.getByName(Constants.Configurations.MAPPINGS_FINAL) ); + if (extension.isForge()) { + processorConfig.extendsFrom(configs.getByName(Constants.Configurations.FORGE_NAMED)); + } + // Add Mixin and mixin extensions (fabric-mixin-compile-extensions pulls mixin itself too) project.getDependencies().add(processorConfig.getName(), Constants.Dependencies.MIXIN_COMPILE_EXTENSIONS + Constants.Dependencies.Versions.MIXIN_COMPILE_EXTENSIONS); diff --git a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java index f26ac192..610b5a93 100644 --- a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java +++ b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java @@ -95,10 +95,17 @@ public final class CompileConfiguration { forgeUniversalConfig.setTransitive(false); Configuration forgeDependencies = project.getConfigurations().maybeCreate(Constants.Configurations.FORGE_DEPENDENCIES); forgeDependencies.setTransitive(false); + Configuration forgeNamed = project.getConfigurations().maybeCreate(Constants.Configurations.FORGE_NAMED); + forgeNamed.setTransitive(false); Configuration mcpConfig = project.getConfigurations().maybeCreate(Constants.Configurations.MCP_CONFIG); mcpConfig.setTransitive(false); extendsFrom(Constants.Configurations.MINECRAFT_DEPENDENCIES, Constants.Configurations.FORGE_DEPENDENCIES, project); + + extendsFrom(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.FORGE_NAMED, project); + extendsFrom(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.FORGE_NAMED, project); + extendsFrom(JavaPlugin.TEST_COMPILE_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.FORGE_NAMED, project); + extendsFrom(JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME, Constants.Configurations.FORGE_NAMED, project); } if (project.getExtensions().getByType(LoomGradleExtension.class).supportsInclude()) { diff --git a/src/main/java/net/fabricmc/loom/configuration/MavenConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/MavenConfiguration.java index dc10e375..67a4e812 100644 --- a/src/main/java/net/fabricmc/loom/configuration/MavenConfiguration.java +++ b/src/main/java/net/fabricmc/loom/configuration/MavenConfiguration.java @@ -69,6 +69,11 @@ public class MavenConfiguration { }); }); + project.getRepositories().maven(repo -> { + repo.setName("Architectury"); + repo.setUrl("https://maven.architectury.dev/"); + }); + project.getRepositories().mavenCentral(); } } diff --git a/src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java b/src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java index 5b9f55b1..12681108 100644 --- a/src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java +++ b/src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java @@ -166,6 +166,10 @@ public class ModProcessor { remapper.readClassPathAsync(mc); remapper.readClassPathAsync(mcDeps); + if (extension.isForge()) { + remapper.readClassPathAsync(mappedProvider.getForgeSrgJar().toPath()); + } + final Map tagMap = new HashMap<>(); final Map outputConsumerMap = new HashMap<>(); final Map accessWidenerMap = new HashMap<>(); diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/LaunchProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/LaunchProvider.java index 75034a8d..03de5e66 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/LaunchProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/LaunchProvider.java @@ -177,6 +177,10 @@ public class LaunchProvider extends DependencyProvider { remapClasspath.add(getExtension().getMinecraftMappedProvider().getIntermediaryJar()); + if (getExtension().isForge()) { + remapClasspath.add(getExtension().getMinecraftMappedProvider().getForgeIntermediaryJar()); + } + String str = remapClasspath.stream() .map(File::getAbsolutePath) .collect(Collectors.joining(File.pathSeparator)); diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/forge/MinecraftPatchedProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/forge/MinecraftPatchedProvider.java index 2209e250..3dff6090 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/forge/MinecraftPatchedProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/forge/MinecraftPatchedProvider.java @@ -48,6 +48,7 @@ import java.util.List; import java.util.Locale; import java.util.Objects; import java.util.Set; +import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -58,11 +59,13 @@ import java.util.stream.Stream; import com.google.common.base.Preconditions; import com.google.common.base.Predicates; import com.google.common.base.Stopwatch; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.hash.Hashing; import com.google.common.io.ByteSource; import com.google.gson.JsonParser; import de.oceanlabs.mcp.mcinjector.adaptors.ParameterAnnotationFixer; +import dev.architectury.tinyremapper.InputTag; import dev.architectury.tinyremapper.OutputConsumerPath; import dev.architectury.tinyremapper.TinyRemapper; import net.minecraftforge.binarypatcher.ConsoleTool; @@ -86,7 +89,6 @@ import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMappedProvid import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.DependencyDownloader; import net.fabricmc.loom.util.FileSystemUtil; -import net.fabricmc.loom.util.JarUtil; import net.fabricmc.loom.util.ThreadingUtils; import net.fabricmc.loom.util.TinyRemapperMappingsHelper; import net.fabricmc.loom.util.function.FsPathConsumer; @@ -96,7 +98,7 @@ import net.fabricmc.mapping.tree.TinyTree; public class MinecraftPatchedProvider extends DependencyProvider { private static final String LOOM_PATCH_VERSION_KEY = "Loom-Patch-Version"; - private static final String CURRENT_LOOM_PATCH_VERSION = "3"; + private static final String CURRENT_LOOM_PATCH_VERSION = "4"; private static final String NAME_MAPPING_SERVICE_PATH = "/inject/META-INF/services/cpw.mods.modlauncher.api.INameMappingService"; // Step 1: Remap Minecraft to SRG (global) @@ -109,8 +111,9 @@ public class MinecraftPatchedProvider extends DependencyProvider { private File minecraftMergedPatchedSrgJar; // Step 4: Access Transform (global or project) private File minecraftMergedPatchedSrgAtJar; - // Step 5: Remap Patched AT to Official (global or project) + // Step 5: Remap Patched AT & Forge to Official (global or project) private File minecraftMergedPatchedJar; + private File forgeMergedJar; private File projectAtHash; private Set projectAts = new HashSet<>(); @@ -177,6 +180,7 @@ public class MinecraftPatchedProvider extends DependencyProvider { minecraftClientPatchedSrgJar = new File(globalDir, "client-srg-patched.jar"); minecraftServerPatchedSrgJar = new File(globalDir, "server-srg-patched.jar"); minecraftMergedPatchedSrgJar = new File(globalDir, "merged-srg-patched.jar"); + forgeMergedJar = new File(globalDir, "forge-official.jar"); minecraftMergedPatchedSrgAtJar = new File(projectDir, "merged-srg-at-patched.jar"); minecraftMergedPatchedJar = new File(projectDir, "merged-patched.jar"); @@ -214,6 +218,7 @@ public class MinecraftPatchedProvider extends DependencyProvider { minecraftClientPatchedSrgJar, minecraftServerPatchedSrgJar, minecraftMergedPatchedSrgJar, + forgeMergedJar, }; } @@ -251,7 +256,6 @@ public class MinecraftPatchedProvider extends DependencyProvider { if (!minecraftClientPatchedSrgJar.exists() || !minecraftServerPatchedSrgJar.exists()) { this.dirty = true; patchJars(getProject().getLogger()); - injectForgeClasses(getProject().getLogger()); } } @@ -265,14 +269,37 @@ public class MinecraftPatchedProvider extends DependencyProvider { accessTransformForge(getProject().getLogger()); } + if (!forgeMergedJar.exists()) { + this.dirty = true; + } + + Path input = minecraftMergedPatchedSrgAtJar.toPath(); if (dirty) { - remapPatchedJar(getProject().getLogger()); + remapPatchedJar(input, getProject().getLogger()); } this.filesDirty = dirty; this.dirty = false; } + private TinyRemapper buildRemapper(Path input) throws IOException { + Path[] libraries = MinecraftMappedProvider.getRemapClasspath(getProject()); + TinyTree mappingsWithSrg = getExtension().getMappingsProvider().getMappingsWithSrg(); + TinyRemapper remapper = TinyRemapper.newRemapper() + .logger(getProject().getLogger()::lifecycle) + .logUnknownInvokeDynamic(false) + .withMappings(TinyRemapperMappingsHelper.create(mappingsWithSrg, "srg", "official", true)) + .withMappings(InnerClassRemapper.of(input, mappingsWithSrg, "srg", "official")) + .renameInvalidLocals(true) + .rebuildSourceFilenames(true) + .fixPackageAccess(true) + .build(); + + remapper.readClassPath(libraries); + remapper.prepareClasses(); + return remapper; + } + private void writeAtHash() throws IOException { try (FileOutputStream out = new FileOutputStream(projectAtHash)) { out.write(getProjectAtsHash()); @@ -349,12 +376,12 @@ public class MinecraftPatchedProvider extends DependencyProvider { getProject().getLogger().info(":fixing parameter annotations for " + jarFile.getAbsolutePath() + " in " + stopwatch); } - private void injectForgeClasses(Logger logger) throws IOException { - logger.lifecycle(":injecting forge classes into minecraft"); - ThreadingUtils.run(Environment.values(), environment -> { - copyAll(getExtension().getForgeUniversalProvider().getForge(), environment.patchedSrgJar.apply(this)); - copyUserdevFiles(getExtension().getForgeUserdevProvider().getUserdevJar(), environment.patchedSrgJar.apply(this)); - }); + private File getForgeJar() { + return getExtension().getForgeUniversalProvider().getForge(); + } + + private File getForgeUserdevJar() { + return getExtension().getForgeUserdevProvider().getUserdevJar(); } private boolean isPatchedJarUpToDate(File jar) { @@ -380,6 +407,7 @@ public class MinecraftPatchedProvider extends DependencyProvider { } private void accessTransformForge(Logger logger) throws Exception { + List toDelete = new ArrayList<>(); String atDependency = Constants.Dependencies.ACCESS_TRANSFORMERS + Constants.Dependencies.Versions.ACCESS_TRANSFORMERS; FileCollection classpath = DependencyDownloader.download(getProject(), atDependency); @@ -388,17 +416,27 @@ public class MinecraftPatchedProvider extends DependencyProvider { File input = minecraftMergedPatchedSrgJar; File target = minecraftMergedPatchedSrgAtJar; Files.deleteIfExists(target.toPath()); - File at = File.createTempFile("at-conf", ".cfg"); - at.deleteOnExit(); - JarUtil.extractFile(input, "META-INF/accesstransformer.cfg", at); List args = new ArrayList<>(); args.add("--inJar"); args.add(input.getAbsolutePath()); args.add("--outJar"); args.add(target.getAbsolutePath()); - args.add("--atFile"); - args.add(at.getAbsolutePath()); + + for (File jar : ImmutableList.of(getForgeJar(), getForgeUserdevJar(), minecraftMergedPatchedSrgJar)) { + try (FileSystemUtil.FileSystemDelegate fs = FileSystemUtil.getJarFileSystem(jar, false)) { + Path atPath = fs.get().getPath("META-INF/accesstransformer.cfg"); + + if (Files.exists(atPath)) { + File tmpFile = File.createTempFile("at-conf", ".cfg"); + tmpFile.delete(); + toDelete.add(tmpFile); + Files.copy(atPath, tmpFile.toPath()); + args.add("--atFile"); + args.add(tmpFile.getAbsolutePath()); + } + } + } if (usesProjectCache()) { for (File projectAt : projectAts) { @@ -420,6 +458,10 @@ public class MinecraftPatchedProvider extends DependencyProvider { spec.setErrorOutput(NullOutputStream.NULL_OUTPUT_STREAM); } }).rethrowFailure().assertNormalExitValue(); + + for (File file : toDelete) { + file.delete(); + } } public enum Environment { @@ -444,35 +486,35 @@ public class MinecraftPatchedProvider extends DependencyProvider { } } - private void remapPatchedJar(Logger logger) throws Exception { - Path[] libraries = MinecraftMappedProvider.getRemapClasspath(getProject()); - logger.lifecycle(":remapping minecraft (TinyRemapper, srg -> official)"); - TinyTree mappingsWithSrg = getExtension().getMappingsProvider().getMappingsWithSrg(); + private void remapPatchedJar(Path input, Logger logger) throws Exception { + getProject().getLogger().lifecycle(":remapping minecraft (TinyRemapper, srg -> official)"); + Path mcOutput = minecraftMergedPatchedJar.toPath(); + Path forgeOutput = forgeMergedJar.toPath(); + Path forgeJar = getForgeJar().toPath(); + Path forgeUserdevJar = getForgeUserdevJar().toPath(); + Files.deleteIfExists(mcOutput); + Files.deleteIfExists(forgeOutput); + TinyRemapper remapper = buildRemapper(input); - Path input = minecraftMergedPatchedSrgAtJar.toPath(); - Path output = minecraftMergedPatchedJar.toPath(); - - Files.deleteIfExists(output); - - TinyRemapper remapper = TinyRemapper.newRemapper() - .logger(getProject().getLogger()::lifecycle) - .logUnknownInvokeDynamic(false) - .withMappings(TinyRemapperMappingsHelper.create(mappingsWithSrg, "srg", "official", true)) - .withMappings(InnerClassRemapper.of(input, mappingsWithSrg, "srg", "official")) - .renameInvalidLocals(true) - .rebuildSourceFilenames(true) - .fixPackageAccess(true) - .build(); - - try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(output).build()) { + try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(mcOutput).build(); + OutputConsumerPath outputConsumerForge = new OutputConsumerPath.Builder(forgeOutput).build()) { outputConsumer.addNonClassFiles(input); - remapper.readClassPath(libraries); - remapper.readInputs(input); - remapper.apply(outputConsumer); + InputTag mcTag = remapper.createInputTag(); + InputTag forgeTag = remapper.createInputTag(); + List> futures = new ArrayList<>(); + futures.add(remapper.readInputsAsync(mcTag, input)); + futures.add(remapper.readInputsAsync(forgeTag, forgeJar, forgeUserdevJar)); + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); + remapper.apply(outputConsumer, mcTag); + remapper.apply(outputConsumerForge, forgeTag); } finally { remapper.finish(); } + + applyLoomPatchVersion(mcOutput); + copyNonClassFiles(forgeJar.toFile(), forgeMergedJar); + copyUserdevFiles(forgeUserdevJar.toFile(), forgeMergedJar); } private void patchJars(Logger logger) throws IOException { @@ -574,7 +616,7 @@ public class MinecraftPatchedProvider extends DependencyProvider { private void copyNonClassFiles(File source, File target) throws IOException { Predicate filter = file -> { String s = file.toString(); - return !s.endsWith(".class") && !s.equalsIgnoreCase("/META-INF/MANIFEST.MF"); + return !s.endsWith(".class"); }; walkFileSystems(source, target, filter, this::copyReplacing); @@ -595,7 +637,7 @@ public class MinecraftPatchedProvider extends DependencyProvider { // If there are multiple name mapping services with the same "understanding" pair // (source -> target namespace pair), modlauncher throws a fit and will crash. // To use our YarnNamingService instead of MCPNamingService, we have to remove this file. - Predicate filter = file -> !file.toString().equals(NAME_MAPPING_SERVICE_PATH); + Predicate filter = file -> !file.toString().endsWith(".class") && !file.toString().equals(NAME_MAPPING_SERVICE_PATH); walkFileSystems(source, target, filter, fs -> Collections.singleton(fs.getPath("inject")), (sourceFs, targetFs, sourcePath, targetPath) -> { Path parent = targetPath.getParent(); @@ -606,16 +648,20 @@ public class MinecraftPatchedProvider extends DependencyProvider { Files.copy(sourcePath, targetPath); }); + } + public void applyLoomPatchVersion(Path target) throws IOException { try (FileSystemUtil.FileSystemDelegate delegate = FileSystemUtil.getJarFileSystem(target, false)) { Path manifestPath = delegate.get().getPath("META-INF/MANIFEST.MF"); Preconditions.checkArgument(Files.exists(manifestPath), "META-INF/MANIFEST.MF does not exist in patched srg jar!"); Manifest manifest = new Manifest(); - try (InputStream stream = Files.newInputStream(manifestPath)) { - manifest.read(stream); - manifest.getMainAttributes().putValue(LOOM_PATCH_VERSION_KEY, CURRENT_LOOM_PATCH_VERSION); + if (Files.exists(manifestPath)) { + try (InputStream stream = Files.newInputStream(manifestPath)) { + manifest.read(stream); + manifest.getMainAttributes().putValue(LOOM_PATCH_VERSION_KEY, CURRENT_LOOM_PATCH_VERSION); + } } try (OutputStream stream = Files.newOutputStream(manifestPath)) { @@ -628,6 +674,10 @@ public class MinecraftPatchedProvider extends DependencyProvider { return minecraftMergedPatchedJar; } + public File getForgeMergedJar() { + return forgeMergedJar; + } + public boolean usesProjectCache() { return !projectAts.isEmpty(); } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java index b6072275..52d90729 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java @@ -39,6 +39,7 @@ import java.util.function.Consumer; import com.google.common.base.Stopwatch; import com.google.common.collect.ImmutableMap; import dev.architectury.tinyremapper.IMappingProvider; +import dev.architectury.tinyremapper.InputTag; import dev.architectury.tinyremapper.NonClassCopyMode; import dev.architectury.tinyremapper.OutputConsumerPath; import dev.architectury.tinyremapper.TinyRemapper; @@ -69,9 +70,13 @@ public class MinecraftMappedProvider extends DependencyProvider { .build(); private File inputJar; + private File inputForgeJar; private File minecraftMappedJar; private File minecraftIntermediaryJar; private File minecraftSrgJar; + private File forgeMappedJar; + private File forgeIntermediaryJar; + private File forgeSrgJar; private MinecraftProvider minecraftProvider; @@ -90,8 +95,17 @@ public class MinecraftMappedProvider extends DependencyProvider { } boolean isForgeAtDirty = getExtension().isForge() && getExtension().getMappingsProvider().patchedProvider.isAtDirty(); + boolean needToRemap = false; if (!minecraftMappedJar.exists() || !getIntermediaryJar().exists() || (getExtension().isForge() && !getSrgJar().exists()) || isRefreshDeps() || isForgeAtDirty) { + needToRemap = true; + } + + if (getExtension().isForge() && (!getForgeMappedJar().exists() || !getForgeIntermediaryJar().exists() || !getForgeSrgJar().exists() || isRefreshDeps() || isForgeAtDirty)) { + needToRemap = true; + } + + if (needToRemap) { if (minecraftMappedJar.exists()) { minecraftMappedJar.delete(); } @@ -106,8 +120,20 @@ public class MinecraftMappedProvider extends DependencyProvider { minecraftSrgJar.delete(); } + if (getExtension().isForge()) { + if (getForgeMappedJar().exists()) { + getForgeMappedJar().delete(); + } + + getForgeMappedJar().getParentFile().mkdirs(); + getForgeIntermediaryJar().delete(); + getForgeSrgJar().delete(); + } + try { - mapMinecraftJar(); + TinyRemapper[] remapperArray = new TinyRemapper[] {null}; + mapMinecraftJar(remapperArray); + remapperArray[0].finish(); } catch (Throwable t) { // Cleanup some some things that may be in a bad state now DownloadUtil.delete(minecraftMappedJar); @@ -115,7 +141,10 @@ public class MinecraftMappedProvider extends DependencyProvider { getExtension().getMinecraftProvider().deleteFiles(); if (getExtension().isForge()) { - minecraftSrgJar.delete(); + DownloadUtil.delete(minecraftSrgJar); + DownloadUtil.delete(forgeMappedJar); + DownloadUtil.delete(forgeSrgJar); + DownloadUtil.delete(forgeIntermediaryJar); } getExtension().getMappingsProvider().cleanFiles(); @@ -129,36 +158,31 @@ public class MinecraftMappedProvider extends DependencyProvider { addDependencies(dependency, postPopulationScheduler); - getProject().afterEvaluate(project -> { - if (getExtension().isForge() && !OperatingSystem.isCIBuild()) { - try { - ForgeSourcesRemapper.addBaseForgeSources(project); - } catch (IOException e) { - e.printStackTrace(); + if (getExtension().isForge()) { + getProject().getDependencies().add(Constants.Configurations.FORGE_NAMED, + getProject().getDependencies().module("net.minecraftforge-loom:forge:" + getJarVersionString("mapped"))); + + getProject().afterEvaluate(project -> { + if (!OperatingSystem.isCIBuild()) { + try { + ForgeSourcesRemapper.addBaseForgeSources(project); + } catch (IOException e) { + e.printStackTrace(); + } } - } - }); + }); + } } - private void mapMinecraftJar() throws Exception { - String fromM = "official"; - - MappingsProvider mappingsProvider = getExtension().getMappingsProvider(); - - Path input = inputJar.toPath(); - Path outputMapped = minecraftMappedJar.toPath(); - Path outputIntermediary = minecraftIntermediaryJar.toPath(); - Path outputSrg = minecraftSrgJar == null ? null : minecraftSrgJar.toPath(); - + private TinyRemapper buildRemapper() throws IOException { Path[] libraries = getRemapClasspath(getProject()); TinyRemapper remapper = getTinyRemapper(); remapper.readClassPath(libraries); remapper.prepareClasses(); + return remapper; + } - Path tmpAssets = Files.createTempFile("tmpAssets", null); - Files.deleteIfExists(tmpAssets); - tmpAssets.toFile().deleteOnExit(); - + private byte[][] inputBytes(Path input) throws IOException { List inputByteList = new ArrayList<>(); try (FileSystemUtil.FileSystemDelegate inputFs = FileSystemUtil.getJarFileSystem(input, false)) { @@ -181,38 +205,102 @@ public class MinecraftMappedProvider extends DependencyProvider { taskCompleter.complete(); } - try (OutputConsumerPath tmpAssetsPath = new OutputConsumerPath.Builder(tmpAssets).assumeArchive(true).build()) { - if (getExtension().isForge()) { - tmpAssetsPath.addNonClassFiles(input, NonClassCopyMode.FIX_META_INF, null); - } else { - tmpAssetsPath.addNonClassFiles(input); + return inputByteList.toArray(new byte[0][0]); + } + + private void assetsOut(Path input, @Nullable Path assetsOut) throws IOException { + if (assetsOut != null) { + try (OutputConsumerPath tmpAssetsPath = new OutputConsumerPath.Builder(assetsOut).assumeArchive(true).build()) { + if (getExtension().isForge()) { + tmpAssetsPath.addNonClassFiles(input, NonClassCopyMode.FIX_META_INF, null); + } else { + tmpAssetsPath.addNonClassFiles(input); + } } } + } - byte[][] inputBytes = inputByteList.toArray(new byte[0][0]); + private void mapMinecraftJar(TinyRemapper[] remapperArray) throws Exception { + Path input = inputJar.toPath(); + Path inputForge = inputForgeJar == null ? null : inputForgeJar.toPath(); + Path outputMapped = minecraftMappedJar.toPath(); + Path outputIntermediary = minecraftIntermediaryJar.toPath(); + Path outputSrg = minecraftSrgJar == null ? null : minecraftSrgJar.toPath(); + Path forgeOutputMapped = forgeMappedJar == null ? null : forgeMappedJar.toPath(); + Path forgeOutputIntermediary = forgeIntermediaryJar == null ? null : forgeIntermediaryJar.toPath(); + Path forgeOutputSrg = forgeSrgJar == null ? null : forgeSrgJar.toPath(); + + Path vanillaAssets = Files.createTempFile("assets", null); + Files.deleteIfExists(vanillaAssets); + vanillaAssets.toFile().deleteOnExit(); + Path forgeAssets = Files.createTempFile("assets", null); + Files.deleteIfExists(forgeAssets); + forgeAssets.toFile().deleteOnExit(); + + Info vanilla = new Info(vanillaAssets, input, outputMapped, outputIntermediary, outputSrg); + Info forge = getExtension().isForge() ? new Info(forgeAssets, inputForge, forgeOutputMapped, forgeOutputIntermediary, forgeOutputSrg) : null; + + TinyRemapper remapper = remapperArray[0] = buildRemapper(); + + assetsOut(input, vanillaAssets); + + if ( getExtension().isForge()) { + assetsOut(inputForge, forgeAssets); + } + + remap(remapper, vanilla, forge, "official"); + } + + public static class Info { + Path assets; + Path input; + Path outputMapped; + Path outputIntermediary; + Path outputSrg; + + public Info(Path assets, Path input, Path outputMapped, Path outputIntermediary, Path outputSrg) { + this.assets = assets; + this.input = input; + this.outputMapped = outputMapped; + this.outputIntermediary = outputIntermediary; + this.outputSrg = outputSrg; + } + } + + public void remap(TinyRemapper remapper, Info vanilla, @Nullable Info forge, String fromM) throws IOException { for (String toM : getExtension().isForge() ? Arrays.asList("intermediary", "srg", "named") : Arrays.asList("intermediary", "named")) { - Path output = "named".equals(toM) ? outputMapped : "srg".equals(toM) ? outputSrg : outputIntermediary; + Path output = "named".equals(toM) ? vanilla.outputMapped : "srg".equals(toM) ? vanilla.outputSrg : vanilla.outputIntermediary; + Path outputForge = forge == null ? null : "named".equals(toM) ? forge.outputMapped : "srg".equals(toM) ? forge.outputSrg : forge.outputIntermediary; + InputTag vanillaTag = remapper.createInputTag(); + InputTag forgeTag = remapper.createInputTag(); Stopwatch stopwatch = Stopwatch.createStarted(); getProject().getLogger().lifecycle(":remapping minecraft (TinyRemapper, " + fromM + " -> " + toM + ")"); - remapper.readInputs(inputBytes); - remapper.replaceMappings(getMappings(input, fromM, toM)); - OutputRemappingHandler.remap(remapper, tmpAssets, output); + remapper.readInputs(vanillaTag, vanilla.input); + + if (forge != null) { + remapper.readInputs(forgeTag, forge.input); + } + + remapper.replaceMappings(getMappings(vanilla.input, fromM, toM)); + OutputRemappingHandler.remap(remapper, vanilla.assets, output, null, vanillaTag); + + if (forge != null) { + OutputRemappingHandler.remap(remapper, forge.assets, outputForge, null, forgeTag); + } getProject().getLogger().lifecycle(":remapped minecraft (TinyRemapper, " + fromM + " -> " + toM + ") in " + stopwatch); remapper.removeInput(); if (getExtension().isForge() && !"srg".equals(toM)) { - getProject().getLogger().info(":running forge finalising tasks"); + getProject().getLogger().info(":running minecraft finalising tasks"); TinyTree yarnWithSrg = getExtension().getMappingsProvider().getMappingsWithSrg(); AtRemapper.remap(getProject().getLogger(), output, yarnWithSrg); CoreModClassRemapper.remapJar(output, yarnWithSrg, getProject().getLogger()); } } - - remapper.finish(); } public TinyRemapper getTinyRemapper() throws IOException { @@ -268,6 +356,12 @@ public class MinecraftMappedProvider extends DependencyProvider { minecraftSrgJar = !getExtension().isForge() ? null : new File(getExtension().getUserCache(), "minecraft-" + getJarVersionString("srg") + ".jar"); minecraftMappedJar = new File(getJarDirectory(getExtension().getUserCache(), "mapped"), "minecraft-" + getJarVersionString("mapped") + ".jar"); inputJar = getExtension().isForge() ? mappingsProvider.patchedProvider.getMergedJar() : minecraftProvider.getMergedJar(); + if (getExtension().isForge()) { + inputForgeJar = mappingsProvider.patchedProvider.getForgeMergedJar(); + forgeIntermediaryJar = new File(getExtension().getUserCache(), "forge-" + getJarVersionString("intermediary") + ".jar"); + forgeSrgJar = new File(getExtension().getUserCache(), "forge-" + getJarVersionString("srg") + ".jar"); + forgeMappedJar = new File(getJarDirectory(getExtension().getUserCache(), "mapped"), "forge-" + getJarVersionString("mapped") + ".jar"); + } } protected File getJarDirectory(File parentDirectory, String type) { @@ -290,6 +384,18 @@ public class MinecraftMappedProvider extends DependencyProvider { return minecraftMappedJar; } + public File getForgeIntermediaryJar() { + return forgeIntermediaryJar; + } + + public File getForgeSrgJar() { + return forgeSrgJar; + } + + public File getForgeMappedJar() { + return forgeMappedJar; + } + public File getUnpickedJar() { return new File(getJarDirectory(getExtension().getUserCache(), "mapped"), "minecraft-" + getJarVersionString("unpicked") + ".jar"); } diff --git a/src/main/java/net/fabricmc/loom/configuration/sources/ForgeSourcesRemapper.java b/src/main/java/net/fabricmc/loom/configuration/sources/ForgeSourcesRemapper.java index 653ac32d..a80e091d 100644 --- a/src/main/java/net/fabricmc/loom/configuration/sources/ForgeSourcesRemapper.java +++ b/src/main/java/net/fabricmc/loom/configuration/sources/ForgeSourcesRemapper.java @@ -59,7 +59,7 @@ import net.fabricmc.lorenztiny.TinyMappingsReader; public class ForgeSourcesRemapper { public static void addBaseForgeSources(Project project) throws IOException { - Path sourcesJar = GenerateSourcesTask.getMappedJarFileWithSuffix(project, "-sources.jar").toPath(); + Path sourcesJar = GenerateSourcesTask.getMappedJarFileWithSuffix(project, "-sources.jar", true).toPath(); if (!Files.exists(sourcesJar)) { addForgeSources(project, sourcesJar); @@ -185,6 +185,7 @@ public class ForgeSourcesRemapper { // Distinct and add the srg jar at the top, so it gets prioritized mercury.getClassPath().add(0, extension.getMinecraftMappedProvider().getSrgJar().toPath()); + mercury.getClassPath().add(0, extension.getMinecraftMappedProvider().getForgeSrgJar().toPath()); List newClassPath = mercury.getClassPath().stream() .distinct() .filter(Files::isRegularFile) diff --git a/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java b/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java index 87706073..303fc598 100644 --- a/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java +++ b/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java @@ -110,9 +110,13 @@ public class GenerateSourcesTask extends AbstractLoomTask { } public static File getMappedJarFileWithSuffix(Project project, String suffix) { + return getMappedJarFileWithSuffix(project, suffix, false); + } + + public static File getMappedJarFileWithSuffix(Project project, String suffix, boolean forgeJar) { LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); MappingsProvider mappingsProvider = extension.getMappingsProvider(); - File mappedJar = mappingsProvider.mappedProvider.getMappedJar(); + File mappedJar = forgeJar ? mappingsProvider.mappedProvider.getForgeMappedJar() : mappingsProvider.mappedProvider.getMappedJar(); String path = mappedJar.getAbsolutePath(); if (!path.toLowerCase(Locale.ROOT).endsWith(".jar")) { diff --git a/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java b/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java index 97217fcb..f033b0f3 100644 --- a/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java +++ b/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java @@ -101,7 +101,7 @@ public class MigrateMappingsTask extends AbstractLoomTask { try { TinyTree currentMappings = mappingsProvider.getMappings(); TinyTree targetMappings = getMappings(mappings); - migrateMappings(project, extension.getMinecraftMappedProvider(), inputDir, outputDir, currentMappings, targetMappings); + migrateMappings(project, extension, extension.getMinecraftMappedProvider(), inputDir, outputDir, currentMappings, targetMappings); project.getLogger().lifecycle(":remapped project written to " + outputDir.toAbsolutePath()); } catch (IOException e) { throw new IllegalArgumentException("Error while loading mappings", e); @@ -158,8 +158,8 @@ public class MigrateMappingsTask extends AbstractLoomTask { } } - private static void migrateMappings(Project project, MinecraftMappedProvider minecraftMappedProvider, - Path inputDir, Path outputDir, TinyTree currentMappings, TinyTree targetMappings + private static void migrateMappings(Project project, LoomGradleExtension extension, MinecraftMappedProvider minecraftMappedProvider, + Path inputDir, Path outputDir, TinyTree currentMappings, TinyTree targetMappings ) throws IOException { project.getLogger().info(":joining mappings"); @@ -183,6 +183,13 @@ public class MigrateMappingsTask extends AbstractLoomTask { mercury.getClassPath().add(minecraftMappedProvider.getMappedJar().toPath()); mercury.getClassPath().add(minecraftMappedProvider.getIntermediaryJar().toPath()); + if (extension.isForge()) { + mercury.getClassPath().add(minecraftMappedProvider.getSrgJar().toPath()); + mercury.getClassPath().add(minecraftMappedProvider.getForgeMappedJar().toPath()); + mercury.getClassPath().add(minecraftMappedProvider.getForgeIntermediaryJar().toPath()); + mercury.getClassPath().add(minecraftMappedProvider.getForgeSrgJar().toPath()); + } + mercury.getProcessors().add(MercuryRemapper.create(mappingSet)); try { diff --git a/src/main/java/net/fabricmc/loom/util/Constants.java b/src/main/java/net/fabricmc/loom/util/Constants.java index bb913371..3defb513 100644 --- a/src/main/java/net/fabricmc/loom/util/Constants.java +++ b/src/main/java/net/fabricmc/loom/util/Constants.java @@ -86,6 +86,7 @@ public class Constants { public static final String FORGE_INSTALLER = "forgeInstaller"; public static final String FORGE_UNIVERSAL = "forgeUniversal"; public static final String FORGE_DEPENDENCIES = "forgeDependencies"; + public static final String FORGE_NAMED = "forgeNamed"; @Deprecated // Not to be used in gradle 7+ public static final String COMPILE = "compile"; public static final String MAPPING_CONSTANTS = "mappingsConstants"; diff --git a/src/main/java/net/fabricmc/loom/util/SourceRemapper.java b/src/main/java/net/fabricmc/loom/util/SourceRemapper.java index a6e9abbb..4aec12bc 100644 --- a/src/main/java/net/fabricmc/loom/util/SourceRemapper.java +++ b/src/main/java/net/fabricmc/loom/util/SourceRemapper.java @@ -209,6 +209,9 @@ public class SourceRemapper { if (extension.isForge()) { m.getClassPath().add(extension.getMinecraftMappedProvider().getSrgJar().toPath()); + m.getClassPath().add(extension.getMinecraftMappedProvider().getForgeMappedJar().toPath()); + m.getClassPath().add(extension.getMinecraftMappedProvider().getForgeIntermediaryJar().toPath()); + m.getClassPath().add(extension.getMinecraftMappedProvider().getForgeSrgJar().toPath()); } Set files = project.getConfigurations() diff --git a/src/main/java/net/fabricmc/loom/util/ThreadingUtils.java b/src/main/java/net/fabricmc/loom/util/ThreadingUtils.java index 0645f319..33617ff2 100644 --- a/src/main/java/net/fabricmc/loom/util/ThreadingUtils.java +++ b/src/main/java/net/fabricmc/loom/util/ThreadingUtils.java @@ -34,9 +34,11 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.Function; import java.util.stream.Collectors; +import com.google.common.base.Preconditions; import com.google.common.base.Stopwatch; public class ThreadingUtils { @@ -136,25 +138,34 @@ public class ThreadingUtils { } public static class TaskCompleter implements Function { + private final ReentrantLock lock = new ReentrantLock(); + private boolean canAdd = true; Stopwatch stopwatch = Stopwatch.createUnstarted(); List> tasks = new ArrayList<>(); ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); List> completionListener = new ArrayList<>(); public TaskCompleter add(UnsafeRunnable job) { - if (!stopwatch.isRunning()) { - stopwatch.start(); - } + Preconditions.checkArgument(canAdd); + lock.lock(); - tasks.add(CompletableFuture.runAsync(() -> { - try { - job.run(); - } catch (Throwable throwable) { - throw new RuntimeException(throwable); + try { + if (!stopwatch.isRunning()) { + stopwatch.start(); } - }, service).exceptionally(this)); - return this; + tasks.add(CompletableFuture.runAsync(() -> { + try { + job.run(); + } catch (Throwable throwable) { + throw new RuntimeException(throwable); + } + }, service).exceptionally(this)); + + return this; + } finally { + lock.unlock(); + } } public TaskCompleter onComplete(UnsafeConsumer consumer) { @@ -163,6 +174,8 @@ public class ThreadingUtils { } public void complete() { + canAdd = false; + try { CompletableFuture.allOf(tasks.toArray(new CompletableFuture[0])).exceptionally(this).get(); service.shutdownNow(); diff --git a/src/main/java/net/fabricmc/loom/util/srg/SpecialSourceExecutor.java b/src/main/java/net/fabricmc/loom/util/srg/SpecialSourceExecutor.java index bfdf9332..11adb3e5 100644 --- a/src/main/java/net/fabricmc/loom/util/srg/SpecialSourceExecutor.java +++ b/src/main/java/net/fabricmc/loom/util/srg/SpecialSourceExecutor.java @@ -35,8 +35,10 @@ import java.util.stream.Collectors; import java.util.zip.ZipEntry; import org.apache.commons.io.IOUtils; +import org.apache.commons.io.output.NullOutputStream; import org.gradle.api.Project; import org.gradle.api.file.FileCollection; +import org.gradle.api.logging.LogLevel; import org.zeroturnaround.zip.ZipUtil; import net.fabricmc.loom.LoomGradleExtension; @@ -83,8 +85,14 @@ public class SpecialSourceExecutor { spec.setClasspath(specialSourceCp); spec.workingDir(workingDir.toFile()); spec.setMain("net.md_5.specialsource.SpecialSource"); - spec.setStandardOutput(System.out); - spec.setErrorOutput(System.out); + + // if running with INFO or DEBUG logging + if (project.getGradle().getStartParameter().getLogLevel().compareTo(LogLevel.LIFECYCLE) < 0) { + spec.setStandardOutput(System.out); + } else { + spec.setStandardOutput(NullOutputStream.NULL_OUTPUT_STREAM); + spec.setErrorOutput(NullOutputStream.NULL_OUTPUT_STREAM); + } }).rethrowFailure().assertNormalExitValue(); Files.deleteIfExists(stripped);