From 3670ccb9594c92d5858f2f3810fa93dd00798a66 Mon Sep 17 00:00:00 2001 From: Space Walker <48224626+SpaceWalkerRS@users.noreply.github.com> Date: Tue, 19 Mar 2024 18:25:57 +0100 Subject: [PATCH] Support merging pre 1.3 Minecraft versions. (#1026) Co-authored-by: modmuss50 --- .../fabricmc/loom/LoomGradleExtension.java | 2 +- .../loom/api/LoomGradleExtensionAPI.java | 1 + .../IntermediateMappingsProvider.java | 8 ++ .../mappings/layered/MappingsNamespace.java | 20 ++++- .../configuration/CompileConfiguration.java | 8 +- .../mappings/IntermediateMappingsService.java | 16 +++- .../mappings/MappingConfiguration.java | 2 +- .../NoOpIntermediateMappingsProvider.java | 5 +- .../mappings/tiny/MappingsMerger.java | 34 ++++++- .../LegacyMergedMinecraftProvider.java | 83 ++++++++++++++++++ .../minecraft/MergedMinecraftProvider.java | 32 +++++-- .../minecraft/MinecraftClassMerger.java | 16 ++++ .../minecraft/MinecraftJarConfiguration.java | 11 +++ .../minecraft/MinecraftJarMerger.java | 2 + .../minecraft/MinecraftProvider.java | 11 +++ .../minecraft/SingleJarMinecraftProvider.java | 34 +++++-- .../minecraft/SplitMinecraftProvider.java | 6 ++ .../AbstractMappedMinecraftProvider.java | 6 +- .../mapped/IntermediaryMinecraftProvider.java | 50 +++++++++-- .../mapped/NamedMinecraftProvider.java | 59 ++++++++++++- .../ProcessedNamedMinecraftProvider.java | 12 +++ .../extension/LoomGradleExtensionImpl.java | 9 ++ .../net/fabricmc/loom/util/Constants.java | 1 + .../loom/util/TinyRemapperHelper.java | 2 +- .../test/integration/LegacyProjectTest.groovy | 29 ++++++ .../TestPlugin.groovy | 63 +++++++++++++ .../IntermediaryMappingLayerTest.groovy | 1 + .../LayeredMappingsTestConstants.groovy | 4 +- .../mappings/1.2.5-intermediary.tiny.zip | Bin 0 -> 85026 bytes src/test/resources/mappings/ATTRIBUTIONS.md | 2 + 30 files changed, 490 insertions(+), 39 deletions(-) create mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/minecraft/LegacyMergedMinecraftProvider.java create mode 100644 src/test/groovy/net/fabricmc/loom/test/integration/buildSrc/legacyMergedIntermediary/TestPlugin.groovy create mode 100644 src/test/resources/mappings/1.2.5-intermediary.tiny.zip create mode 100644 src/test/resources/mappings/ATTRIBUTIONS.md diff --git a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java index 15bb0cd4..e78939ac 100644 --- a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java +++ b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java @@ -89,7 +89,7 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI { return switch (mappingsNamespace) { case NAMED -> getNamedMinecraftProvider().getMinecraftJarPaths(); case INTERMEDIARY -> getIntermediaryMinecraftProvider().getMinecraftJarPaths(); - case OFFICIAL -> getMinecraftProvider().getMinecraftJars(); + case OFFICIAL, CLIENT_OFFICIAL, SERVER_OFFICIAL -> getMinecraftProvider().getMinecraftJars(); }; } diff --git a/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java b/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java index 3dc9325f..1eef6031 100644 --- a/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java +++ b/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java @@ -204,6 +204,7 @@ public interface LoomGradleExtensionAPI { */ Property getIntermediaryUrl(); + @ApiStatus.Experimental Property> getMinecraftJarConfiguration(); default void serverOnlyMinecraftJar() { diff --git a/src/main/java/net/fabricmc/loom/api/mappings/intermediate/IntermediateMappingsProvider.java b/src/main/java/net/fabricmc/loom/api/mappings/intermediate/IntermediateMappingsProvider.java index 594a74b8..d4987b08 100644 --- a/src/main/java/net/fabricmc/loom/api/mappings/intermediate/IntermediateMappingsProvider.java +++ b/src/main/java/net/fabricmc/loom/api/mappings/intermediate/IntermediateMappingsProvider.java @@ -44,6 +44,14 @@ public abstract class IntermediateMappingsProvider implements Named { public abstract Property> getDownloader(); + /** + * Set to true if the minecraft version is pre 1.3. + * When true the expected src namespace is intermediary, and the expected dst namespaces are clientOfficial and/or serverOfficial + * When false the expected src namespace is named and the expected dst namespace is intermediary + */ + @ApiStatus.Experimental + public abstract Property getIsLegacyMinecraft(); + /** * Generate or download a tinyv2 mapping file with intermediary and named namespaces. * @throws IOException diff --git a/src/main/java/net/fabricmc/loom/api/mappings/layered/MappingsNamespace.java b/src/main/java/net/fabricmc/loom/api/mappings/layered/MappingsNamespace.java index 4e3a628a..c264274a 100644 --- a/src/main/java/net/fabricmc/loom/api/mappings/layered/MappingsNamespace.java +++ b/src/main/java/net/fabricmc/loom/api/mappings/layered/MappingsNamespace.java @@ -37,6 +37,18 @@ public enum MappingsNamespace { */ OFFICIAL, + /** + * Official names for the Minecraft client jar, usually obfuscated. + * This namespace is used for versions <1.3, where the client and server jars are obfuscated differently. + */ + CLIENT_OFFICIAL, + + /** + * Official names for the Minecraft server jar, usually obfuscated. + * This namespace is used for versions <1.3, where the client and server jars are obfuscated differently. + */ + SERVER_OFFICIAL, + /** * Intermediary mappings have been generated to provide a stable set of names across minecraft versions. * @@ -60,6 +72,8 @@ public enum MappingsNamespace { public static @Nullable MappingsNamespace of(String namespace) { return switch (namespace) { case "official" -> OFFICIAL; + case "clientOfficial" -> CLIENT_OFFICIAL; + case "serverOfficial" -> SERVER_OFFICIAL; case "intermediary" -> INTERMEDIARY; case "named" -> NAMED; default -> null; @@ -68,6 +82,10 @@ public enum MappingsNamespace { @Override public String toString() { - return name().toLowerCase(Locale.ROOT); + return switch (this) { + case CLIENT_OFFICIAL -> "clientOfficial"; + case SERVER_OFFICIAL -> "serverOfficial"; + default -> name().toLowerCase(Locale.ROOT); + }; } } diff --git a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java index 1e59e9fc..fff381f6 100644 --- a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java +++ b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java @@ -60,6 +60,7 @@ import net.fabricmc.loom.configuration.processors.MinecraftJarProcessorManager; import net.fabricmc.loom.configuration.processors.ModJavadocProcessor; import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsFactory; import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration; +import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMetadataProvider; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets; @@ -68,6 +69,7 @@ import net.fabricmc.loom.configuration.providers.minecraft.mapped.IntermediaryMi import net.fabricmc.loom.configuration.providers.minecraft.mapped.NamedMinecraftProvider; import net.fabricmc.loom.extension.MixinExtension; import net.fabricmc.loom.util.Checksum; +import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.ExceptionUtil; import net.fabricmc.loom.util.ProcessUtil; import net.fabricmc.loom.util.gradle.GradleUtils; @@ -154,7 +156,11 @@ public abstract class CompileConfiguration implements Runnable { final MinecraftMetadataProvider metadataProvider = MinecraftMetadataProvider.create(configContext); - final var jarConfiguration = extension.getMinecraftJarConfiguration().get(); + var jarConfiguration = extension.getMinecraftJarConfiguration().get(); + + if (jarConfiguration == MinecraftJarConfiguration.MERGED && !metadataProvider.getVersionMeta().isVersionOrNewer(Constants.RELEASE_TIME_1_3)) { + jarConfiguration = MinecraftJarConfiguration.LEGACY_MERGED; + } // Provide the vanilla mc jars final MinecraftProvider minecraftProvider = jarConfiguration.createMinecraftProvider(metadataProvider, configContext); diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/IntermediateMappingsService.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/IntermediateMappingsService.java index 75af308c..a0568de9 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/IntermediateMappingsService.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/IntermediateMappingsService.java @@ -50,10 +50,12 @@ import net.fabricmc.mappingio.tree.MemoryMappingTree; public final class IntermediateMappingsService implements SharedService { private final Path intermediaryTiny; + private final String expectedSrcNs; private final Supplier memoryMappingTree = Suppliers.memoize(this::createMemoryMappingTree); - private IntermediateMappingsService(Path intermediaryTiny) { + private IntermediateMappingsService(Path intermediaryTiny, String expectedSrcNs) { this.intermediaryTiny = intermediaryTiny; + this.expectedSrcNs = expectedSrcNs; } public static synchronized IntermediateMappingsService getInstance(SharedServiceManager sharedServiceManager, Project project, MinecraftProvider minecraftProvider) { @@ -84,7 +86,13 @@ public final class IntermediateMappingsService implements SharedService { throw new UncheckedIOException("Failed to provide intermediate mappings", e); } - return new IntermediateMappingsService(intermediaryTiny); + // When merging legacy versions there will be multiple named namespaces, so use intermediary as the common src ns + // Newer versions will use intermediary as the src ns + final String expectedSrcNs = minecraftProvider.isLegacyVersion() + ? MappingsNamespace.INTERMEDIARY.toString() // <1.3 + : MappingsNamespace.OFFICIAL.toString(); // >=1.3 + + return new IntermediateMappingsService(intermediaryTiny, expectedSrcNs); } private MemoryMappingTree createMemoryMappingTree() { @@ -100,6 +108,10 @@ public final class IntermediateMappingsService implements SharedService { throw new UncheckedIOException("Failed to read intermediary mappings", e); } + if (!expectedSrcNs.equals(tree.getSrcNamespace())) { + throw new RuntimeException("Invalid intermediate mappings: expected source namespace '" + expectedSrcNs + "' but found '" + tree.getSrcNamespace() + "\'"); + } + return tree; } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingConfiguration.java index bce9d5d0..e57cb9d4 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingConfiguration.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingConfiguration.java @@ -176,7 +176,7 @@ public class MappingConfiguration { // These are unmerged v2 mappings IntermediateMappingsService intermediateMappingsService = IntermediateMappingsService.getInstance(serviceManager, project, minecraftProvider); - MappingsMerger.mergeAndSaveMappings(baseTinyMappings, tinyMappings, intermediateMappingsService); + MappingsMerger.mergeAndSaveMappings(baseTinyMappings, tinyMappings, minecraftProvider, intermediateMappingsService); } else { final List minecraftJars = minecraftProvider.getMinecraftJars(); diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/NoOpIntermediateMappingsProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/NoOpIntermediateMappingsProvider.java index 28ddfc63..d198baf9 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/NoOpIntermediateMappingsProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/NoOpIntermediateMappingsProvider.java @@ -37,11 +37,12 @@ import net.fabricmc.loom.api.mappings.intermediate.IntermediateMappingsProvider; * A bit of a hack, creates an empty intermediary mapping file to be used for mc versions without any intermediate mappings. */ public abstract class NoOpIntermediateMappingsProvider extends IntermediateMappingsProvider { - private static final String HEADER = "tiny\t2\t0\tofficial\tintermediary"; + private static final String HEADER_OFFICIAL_MERGED = "tiny\t2\t0\tofficial\tintermediary"; + private static final String HEADER_OFFICIAL_LEGACY_MERGED = "tiny\t2\t0\tintermediary\tclientOfficial\tserverOfficial\t"; @Override public void provide(Path tinyMappings) throws IOException { - Files.writeString(tinyMappings, HEADER, StandardCharsets.UTF_8); + Files.writeString(tinyMappings, getIsLegacyMinecraft().get() ? HEADER_OFFICIAL_LEGACY_MERGED : HEADER_OFFICIAL_MERGED, StandardCharsets.UTF_8); } @Override diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/tiny/MappingsMerger.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/tiny/MappingsMerger.java index db845663..e2f6ba67 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/tiny/MappingsMerger.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/tiny/MappingsMerger.java @@ -39,6 +39,7 @@ import org.slf4j.LoggerFactory; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; import net.fabricmc.loom.configuration.providers.mappings.IntermediateMappingsService; +import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider; import net.fabricmc.mappingio.adapter.MappingNsCompleter; import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch; import net.fabricmc.mappingio.format.tiny.Tiny2FileReader; @@ -49,10 +50,20 @@ import net.fabricmc.mappingio.tree.MemoryMappingTree; public final class MappingsMerger { private static final Logger LOGGER = LoggerFactory.getLogger(MappingsMerger.class); - public static void mergeAndSaveMappings(Path from, Path out, IntermediateMappingsService intermediateMappingsService) throws IOException { + public static void mergeAndSaveMappings(Path from, Path out, MinecraftProvider minecraftProvider, IntermediateMappingsService intermediateMappingsService) throws IOException { Stopwatch stopwatch = Stopwatch.createStarted(); LOGGER.info(":merging mappings"); + if (minecraftProvider.isLegacyVersion()) { + legacyMergeAndSaveMappings(from, out, intermediateMappingsService); + } else { + mergeAndSaveMappings(from, out, intermediateMappingsService); + } + + LOGGER.info(":merged mappings in " + stopwatch.stop()); + } + + private static void mergeAndSaveMappings(Path from, Path out, IntermediateMappingsService intermediateMappingsService) throws IOException { MemoryMappingTree intermediaryTree = new MemoryMappingTree(); intermediateMappingsService.getMemoryMappingTree().accept(new MappingSourceNsSwitch(intermediaryTree, MappingsNamespace.INTERMEDIARY.toString())); @@ -70,8 +81,27 @@ public final class MappingsMerger { try (var writer = new Tiny2FileWriter(Files.newBufferedWriter(out, StandardCharsets.UTF_8), false)) { officialTree.accept(writer); } + } - LOGGER.info(":merged mappings in " + stopwatch.stop()); + private static void legacyMergeAndSaveMappings(Path from, Path out, IntermediateMappingsService intermediateMappingsService) throws IOException { + MemoryMappingTree intermediaryTree = new MemoryMappingTree(); + intermediateMappingsService.getMemoryMappingTree().accept(intermediaryTree); + + try (BufferedReader reader = Files.newBufferedReader(from, StandardCharsets.UTF_8)) { + Tiny2FileReader.read(reader, intermediaryTree); + } + + MemoryMappingTree officialTree = new MemoryMappingTree(); + MappingNsCompleter nsCompleter = new MappingNsCompleter(officialTree, Map.of(MappingsNamespace.CLIENT_OFFICIAL.toString(), MappingsNamespace.INTERMEDIARY.toString(), MappingsNamespace.SERVER_OFFICIAL.toString(), MappingsNamespace.INTERMEDIARY.toString())); + intermediaryTree.accept(nsCompleter); + + // versions this old strip inner class attributes + // from the obfuscated jars anyway + //inheritMappedNamesOfEnclosingClasses(officialTree); + + try (var writer = new Tiny2FileWriter(Files.newBufferedWriter(out, StandardCharsets.UTF_8), false)) { + officialTree.accept(writer); + } } /** diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/LegacyMergedMinecraftProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/LegacyMergedMinecraftProvider.java new file mode 100644 index 00000000..28284f1d --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/LegacyMergedMinecraftProvider.java @@ -0,0 +1,83 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2024 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.configuration.providers.minecraft; + +import java.nio.file.Path; +import java.util.List; + +import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; +import net.fabricmc.loom.configuration.ConfigContext; + +/** + * Minecraft versions prior to 1.3 obfuscate the server and client jars differently. + * The obfuscated jars must be provided separately, and can be merged after remapping. + */ +public final class LegacyMergedMinecraftProvider extends MinecraftProvider { + private final SingleJarMinecraftProvider.Server serverMinecraftProvider; + private final SingleJarMinecraftProvider.Client clientMinecraftProvider; + + public LegacyMergedMinecraftProvider(MinecraftMetadataProvider metadataProvider, ConfigContext configContext) { + super(metadataProvider, configContext); + serverMinecraftProvider = SingleJarMinecraftProvider.server(metadataProvider, configContext); + clientMinecraftProvider = SingleJarMinecraftProvider.client(metadataProvider, configContext); + + if (!isLegacyVersion()) { + throw new RuntimeException("something has gone wrong - legacy-merged jar configuration selected but Minecraft " + metadataProvider.getMinecraftVersion() + " allows merging the obfuscated jars - the merged jar configuration should have been selected!"); + } + } + + public SingleJarMinecraftProvider.Server getServerMinecraftProvider() { + return serverMinecraftProvider; + } + + public SingleJarMinecraftProvider.Client getClientMinecraftProvider() { + return clientMinecraftProvider; + } + + @Override + public void provide() throws Exception { + if (!serverMinecraftProvider.provideServer() || !clientMinecraftProvider.provideClient()) { + throw new UnsupportedOperationException("This version does not provide both the client and server jars - please select the client-only or server-only jar configuration!"); + } + + serverMinecraftProvider.provide(); + clientMinecraftProvider.provide(); + } + + @Override + public List getMinecraftJars() { + return List.of( + serverMinecraftProvider.getMinecraftEnvOnlyJar(), + clientMinecraftProvider.getMinecraftEnvOnlyJar() + ); + } + + @Override + @Deprecated + public MappingsNamespace getOfficialNamespace() { + // Legacy merged providers do not have a single namespace as they delegate to the single jar providers + throw new UnsupportedOperationException("Cannot query the official namespace for legacy-merged minecraft providers"); + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MergedMinecraftProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MergedMinecraftProvider.java index b0ff9d65..3f2d4437 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MergedMinecraftProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MergedMinecraftProvider.java @@ -34,6 +34,7 @@ import java.util.Objects; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; import net.fabricmc.loom.configuration.ConfigContext; public final class MergedMinecraftProvider extends MinecraftProvider { @@ -43,6 +44,10 @@ public final class MergedMinecraftProvider extends MinecraftProvider { public MergedMinecraftProvider(MinecraftMetadataProvider metadataProvider, ConfigContext configContext) { super(metadataProvider, configContext); + + if (isLegacyVersion()) { + throw new RuntimeException("something has gone wrong - merged jar configuration selected but Minecraft " + metadataProvider.getMinecraftVersion() + " does not allow merging the obfuscated jars - the legacy-merged jar configuration should have been selected!"); + } } @Override @@ -56,12 +61,17 @@ public final class MergedMinecraftProvider extends MinecraftProvider { return List.of(minecraftMergedJar); } + @Override + public MappingsNamespace getOfficialNamespace() { + return MappingsNamespace.OFFICIAL; + } + @Override public void provide() throws Exception { super.provide(); - if (!getVersionInfo().isVersionOrNewer("2012-07-25T22:00:00+00:00" /* 1.3 release date */)) { - throw new UnsupportedOperationException("Minecraft versions 1.2.5 and older cannot be merged. Please use `loom { server/clientOnlyMinecraftJar() }`"); + if (!provideServer() || !provideClient()) { + throw new UnsupportedOperationException("This version does not provide both the client and server jars - please select the client-only or server-only jar configuration!"); } if (!Files.exists(minecraftMergedJar) || getExtension().refreshDeps()) { @@ -79,18 +89,24 @@ public final class MergedMinecraftProvider extends MinecraftProvider { } private void mergeJars() throws IOException { - LOGGER.info(":merging jars"); - - File jarToMerge = getMinecraftServerJar(); + File minecraftClientJar = getMinecraftClientJar(); + File minecraftServerJar = getMinecraftServerJar(); if (getServerBundleMetadata() != null) { extractBundledServerJar(); - jarToMerge = getMinecraftExtractedServerJar(); + minecraftServerJar = getMinecraftExtractedServerJar(); } - Objects.requireNonNull(jarToMerge, "Cannot merge null input jar?"); + mergeJars(minecraftClientJar, minecraftServerJar, minecraftMergedJar.toFile()); + } - try (var jarMerger = new MinecraftJarMerger(getMinecraftClientJar(), jarToMerge, minecraftMergedJar.toFile())) { + public static void mergeJars(File clientJar, File serverJar, File mergedJar) throws IOException { + LOGGER.info(":merging jars"); + + Objects.requireNonNull(clientJar, "Cannot merge null client jar?"); + Objects.requireNonNull(serverJar, "Cannot merge null server jar?"); + + try (var jarMerger = new MinecraftJarMerger(clientJar, serverJar, mergedJar)) { jarMerger.enableSyntheticParamsOffset(); jarMerger.merge(); } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftClassMerger.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftClassMerger.java index 7d38da2e..b60cb417 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftClassMerger.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftClassMerger.java @@ -257,6 +257,8 @@ public class MinecraftClassMerger { int j = 0; while (i < first.size() || j < second.size()) { + int saved = i + j; + while (i < first.size() && j < second.size() && first.get(i).equals(second.get(j))) { out.add(first.get(i)); @@ -273,6 +275,20 @@ public class MinecraftClassMerger { out.add(second.get(j)); j++; } + + // if the order is scrambled, it's not possible to merge + // the lists while preserving the order from both sides + if (i + j == saved) { + for (; i < first.size(); i++) { + out.add(first.get(i)); + } + + for (; j < second.size(); j++) { + if (!first.contains(second.get(j))) { + out.add(second.get(j)); + } + } + } } return out; diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftJarConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftJarConfiguration.java index 927cbe72..ca851331 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftJarConfiguration.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftJarConfiguration.java @@ -60,6 +60,17 @@ public record MinecraftJarConfiguration< SingleJarDecompileConfiguration::new, List.of("client", "server") ); + public static final MinecraftJarConfiguration< + LegacyMergedMinecraftProvider, + NamedMinecraftProvider.LegacyMergedImpl, + MappedMinecraftProvider> LEGACY_MERGED = new MinecraftJarConfiguration<>( + LegacyMergedMinecraftProvider::new, + IntermediaryMinecraftProvider.LegacyMergedImpl::new, + NamedMinecraftProvider.LegacyMergedImpl::new, + ProcessedNamedMinecraftProvider.LegacyMergedImpl::new, + SingleJarDecompileConfiguration::new, + List.of("client", "server") + ); public static final MinecraftJarConfiguration< SingleJarMinecraftProvider, NamedMinecraftProvider.SingleJarImpl, diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftJarMerger.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftJarMerger.java index 5b0f9d9c..450010f0 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftJarMerger.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftJarMerger.java @@ -82,6 +82,8 @@ public class MinecraftJarMerger implements AutoCloseable { } } + Files.createDirectories(output.toPath().getParent()); + this.inputClient = (inputClientFs = FileSystemUtil.getJarFileSystem(inputClient, false)).get().getPath("/"); this.inputServer = (inputServerFs = FileSystemUtil.getJarFileSystem(inputServer, false)).get().getPath("/"); this.outputFs = FileSystemUtil.getJarFileSystem(output, true); diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftProvider.java index 0e6a0682..b789a3b0 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftProvider.java @@ -38,8 +38,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.fabricmc.loom.LoomGradleExtension; +import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; import net.fabricmc.loom.configuration.ConfigContext; import net.fabricmc.loom.configuration.providers.BundleMetadata; +import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.download.DownloadExecutor; import net.fabricmc.loom.util.download.GradleDownloadProgressListener; import net.fabricmc.loom.util.gradle.ProgressGroup; @@ -185,6 +187,13 @@ public abstract class MinecraftProvider { return Objects.requireNonNull(metadataProvider, "Metadata provider not setup").getVersionMeta(); } + /** + * @return true if the minecraft version is older than 1.3. + */ + public boolean isLegacyVersion() { + return !getVersionInfo().isVersionOrNewer(Constants.RELEASE_TIME_1_3); + } + @Nullable public BundleMetadata getServerBundleMetadata() { return serverBundleMetadata; @@ -192,6 +201,8 @@ public abstract class MinecraftProvider { public abstract List getMinecraftJars(); + public abstract MappingsNamespace getOfficialNamespace(); + protected Project getProject() { return configContext.project(); } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/SingleJarMinecraftProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/SingleJarMinecraftProvider.java index 389873c6..76b06564 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/SingleJarMinecraftProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/SingleJarMinecraftProvider.java @@ -28,25 +28,38 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.List; +import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; import net.fabricmc.loom.configuration.ConfigContext; import net.fabricmc.loom.configuration.providers.BundleMetadata; +import net.fabricmc.loom.util.Constants; import net.fabricmc.tinyremapper.NonClassCopyMode; import net.fabricmc.tinyremapper.OutputConsumerPath; import net.fabricmc.tinyremapper.TinyRemapper; public abstract sealed class SingleJarMinecraftProvider extends MinecraftProvider permits SingleJarMinecraftProvider.Server, SingleJarMinecraftProvider.Client { + private final MappingsNamespace officialNamespace; private Path minecraftEnvOnlyJar; - private SingleJarMinecraftProvider(MinecraftMetadataProvider metadataProvider, ConfigContext configContext) { + private SingleJarMinecraftProvider(MinecraftMetadataProvider metadataProvider, ConfigContext configContext, MappingsNamespace officialNamespace) { super(metadataProvider, configContext); + this.officialNamespace = officialNamespace; } public static SingleJarMinecraftProvider.Server server(MinecraftMetadataProvider metadataProvider, ConfigContext configContext) { - return new SingleJarMinecraftProvider.Server(metadataProvider, configContext); + return new SingleJarMinecraftProvider.Server(metadataProvider, configContext, getOfficialNamespace(metadataProvider, true)); } public static SingleJarMinecraftProvider.Client client(MinecraftMetadataProvider metadataProvider, ConfigContext configContext) { - return new SingleJarMinecraftProvider.Client(metadataProvider, configContext); + return new SingleJarMinecraftProvider.Client(metadataProvider, configContext, getOfficialNamespace(metadataProvider, false)); + } + + private static MappingsNamespace getOfficialNamespace(MinecraftMetadataProvider metadataProvider, boolean server) { + // Versions before 1.3 don't have a common namespace, so use side specific namespaces. + if (!metadataProvider.getVersionMeta().isVersionOrNewer(Constants.RELEASE_TIME_1_3)) { + return server ? MappingsNamespace.SERVER_OFFICIAL : MappingsNamespace.CLIENT_OFFICIAL; + } + + return MappingsNamespace.OFFICIAL; } @Override @@ -66,7 +79,7 @@ public abstract sealed class SingleJarMinecraftProvider extends MinecraftProvide super.provide(); // Server only JARs are supported on any version, client only JARs are pretty much useless after 1.3. - if (provideClient() && getVersionInfo().isVersionOrNewer("2012-07-25T22:00:00+00:00" /* 1.3 release date */)) { + if (provideClient() && !isLegacyVersion()) { getProject().getLogger().warn("Using `clientOnlyMinecraftJar()` is not recommended for Minecraft versions 1.3 or newer."); } @@ -105,13 +118,18 @@ public abstract sealed class SingleJarMinecraftProvider extends MinecraftProvide return minecraftEnvOnlyJar; } + @Override + public MappingsNamespace getOfficialNamespace() { + return officialNamespace; + } + abstract SingleJarEnvType type(); abstract Path getInputJar(SingleJarMinecraftProvider provider) throws Exception; public static final class Server extends SingleJarMinecraftProvider { - private Server(MinecraftMetadataProvider metadataProvider, ConfigContext configContext) { - super(metadataProvider, configContext); + private Server(MinecraftMetadataProvider metadataProvider, ConfigContext configContext, MappingsNamespace officialNamespace) { + super(metadataProvider, configContext, officialNamespace); } @Override @@ -143,8 +161,8 @@ public abstract sealed class SingleJarMinecraftProvider extends MinecraftProvide } public static final class Client extends SingleJarMinecraftProvider { - private Client(MinecraftMetadataProvider metadataProvider, ConfigContext configContext) { - super(metadataProvider, configContext); + private Client(MinecraftMetadataProvider metadataProvider, ConfigContext configContext, MappingsNamespace officialNamespace) { + super(metadataProvider, configContext, officialNamespace); } @Override diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/SplitMinecraftProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/SplitMinecraftProvider.java index 69f0be26..d2190142 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/SplitMinecraftProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/SplitMinecraftProvider.java @@ -28,6 +28,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.List; +import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; import net.fabricmc.loom.configuration.ConfigContext; import net.fabricmc.loom.configuration.providers.BundleMetadata; @@ -52,6 +53,11 @@ public final class SplitMinecraftProvider extends MinecraftProvider { return List.of(minecraftClientOnlyJar, minecraftCommonJar); } + @Override + public MappingsNamespace getOfficialNamespace() { + return MappingsNamespace.OFFICIAL; + } + @Override public void provide() throws Exception { super.provide(); diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/AbstractMappedMinecraftProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/AbstractMappedMinecraftProvider.java index c81e3084..fa66f429 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/AbstractMappedMinecraftProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/AbstractMappedMinecraftProvider.java @@ -46,6 +46,7 @@ import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJar; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets; +import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta; import net.fabricmc.loom.configuration.providers.minecraft.SignatureFixerApplyVisitor; import net.fabricmc.loom.extension.LoomFiles; import net.fabricmc.loom.util.SidedClassVisitor; @@ -190,7 +191,10 @@ public abstract class AbstractMappedMinecraftProvider remappedSignatures = SignatureFixerApplyVisitor.getRemappedSignatures(getTargetNamespace() == MappingsNamespace.INTERMEDIARY, mappingConfiguration, getProject(), configContext.serviceManager(), toM); - TinyRemapper remapper = TinyRemapperHelper.getTinyRemapper(getProject(), configContext.serviceManager(), fromM, toM, true, (builder) -> { + final MinecraftVersionMeta.JavaVersion javaVersion = minecraftProvider.getVersionInfo().javaVersion(); + final boolean fixRecords = javaVersion != null && javaVersion.majorVersion() >= 16; + + TinyRemapper remapper = TinyRemapperHelper.getTinyRemapper(getProject(), configContext.serviceManager(), fromM, toM, fixRecords, (builder) -> { builder.extraPostApplyVisitor(new SignatureFixerApplyVisitor(remappedSignatures)); configureRemapper(remappedJars, builder); }); diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/IntermediaryMinecraftProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/IntermediaryMinecraftProvider.java index aefed08b..70a1424e 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/IntermediaryMinecraftProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/IntermediaryMinecraftProvider.java @@ -29,14 +29,16 @@ import java.util.List; import org.gradle.api.Project; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; +import net.fabricmc.loom.configuration.providers.minecraft.LegacyMergedMinecraftProvider; import net.fabricmc.loom.configuration.providers.minecraft.MergedMinecraftProvider; +import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJar; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider; import net.fabricmc.loom.configuration.providers.minecraft.SingleJarEnvType; import net.fabricmc.loom.configuration.providers.minecraft.SingleJarMinecraftProvider; import net.fabricmc.loom.configuration.providers.minecraft.SplitMinecraftProvider; import net.fabricmc.tinyremapper.TinyRemapper; -public abstract sealed class IntermediaryMinecraftProvider extends AbstractMappedMinecraftProvider permits IntermediaryMinecraftProvider.MergedImpl, IntermediaryMinecraftProvider.SingleJarImpl, IntermediaryMinecraftProvider.SplitImpl { +public abstract sealed class IntermediaryMinecraftProvider extends AbstractMappedMinecraftProvider permits IntermediaryMinecraftProvider.MergedImpl, IntermediaryMinecraftProvider.LegacyMergedImpl, IntermediaryMinecraftProvider.SingleJarImpl, IntermediaryMinecraftProvider.SplitImpl { public IntermediaryMinecraftProvider(Project project, M minecraftProvider) { super(project, minecraftProvider); } @@ -59,11 +61,49 @@ public abstract sealed class IntermediaryMinecraftProvider getRemappedJars() { return List.of( - new RemappedJars(minecraftProvider.getMergedJar(), getMergedJar(), MappingsNamespace.OFFICIAL) + new RemappedJars(minecraftProvider.getMergedJar(), getMergedJar(), minecraftProvider.getOfficialNamespace()) ); } } + public static final class LegacyMergedImpl extends IntermediaryMinecraftProvider implements Merged { + private final SingleJarImpl server; + private final SingleJarImpl client; + + public LegacyMergedImpl(Project project, LegacyMergedMinecraftProvider minecraftProvider) { + super(project, minecraftProvider); + server = new SingleJarImpl(project, minecraftProvider.getServerMinecraftProvider(), SingleJarEnvType.SERVER); + client = new SingleJarImpl(project, minecraftProvider.getClientMinecraftProvider(), SingleJarEnvType.CLIENT); + } + + @Override + public List provide(ProvideContext context) throws Exception { + // Map the client and server jars separately + server.provide(context); + client.provide(context); + + // then merge them + MergedMinecraftProvider.mergeJars( + client.getEnvOnlyJar().toFile(), + server.getEnvOnlyJar().toFile(), + getMergedJar().toFile() + ); + + return List.of(getMergedJar()); + } + + @Override + public List getRemappedJars() { + // The delegate providers will handle the remapping + throw new UnsupportedOperationException("LegacyMergedImpl does not support getRemappedJars"); + } + + @Override + public List getDependencyTypes() { + return List.of(MinecraftJar.Type.MERGED); + } + } + public static final class SplitImpl extends IntermediaryMinecraftProvider implements Split { public SplitImpl(Project project, SplitMinecraftProvider minecraftProvider) { super(project, minecraftProvider); @@ -72,8 +112,8 @@ public abstract sealed class IntermediaryMinecraftProvider getRemappedJars() { return List.of( - new RemappedJars(minecraftProvider.getMinecraftCommonJar(), getCommonJar(), MappingsNamespace.OFFICIAL), - new RemappedJars(minecraftProvider.getMinecraftClientOnlyJar(), getClientOnlyJar(), MappingsNamespace.OFFICIAL, minecraftProvider.getMinecraftCommonJar()) + new RemappedJars(minecraftProvider.getMinecraftCommonJar(), getCommonJar(), minecraftProvider.getOfficialNamespace()), + new RemappedJars(minecraftProvider.getMinecraftClientOnlyJar(), getClientOnlyJar(), minecraftProvider.getOfficialNamespace(), minecraftProvider.getMinecraftCommonJar()) ); } @@ -102,7 +142,7 @@ public abstract sealed class IntermediaryMinecraftProvider getRemappedJars() { return List.of( - new RemappedJars(minecraftProvider.getMinecraftEnvOnlyJar(), getEnvOnlyJar(), MappingsNamespace.OFFICIAL) + new RemappedJars(minecraftProvider.getMinecraftEnvOnlyJar(), getEnvOnlyJar(), minecraftProvider.getOfficialNamespace()) ); } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/NamedMinecraftProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/NamedMinecraftProvider.java index 1bfdbe72..f2753609 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/NamedMinecraftProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/NamedMinecraftProvider.java @@ -29,9 +29,11 @@ import java.util.List; import org.gradle.api.Project; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; +import net.fabricmc.loom.configuration.providers.minecraft.LegacyMergedMinecraftProvider; import net.fabricmc.loom.configuration.providers.minecraft.MergedMinecraftProvider; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJar; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider; +import net.fabricmc.loom.configuration.providers.minecraft.MinecraftSourceSets; import net.fabricmc.loom.configuration.providers.minecraft.SingleJarEnvType; import net.fabricmc.loom.configuration.providers.minecraft.SingleJarMinecraftProvider; import net.fabricmc.loom.configuration.providers.minecraft.SplitMinecraftProvider; @@ -60,7 +62,7 @@ public abstract class NamedMinecraftProvider extend @Override public List getRemappedJars() { return List.of( - new RemappedJars(minecraftProvider.getMergedJar(), getMergedJar(), MappingsNamespace.OFFICIAL) + new RemappedJars(minecraftProvider.getMergedJar(), getMergedJar(), minecraftProvider.getOfficialNamespace()) ); } @@ -70,6 +72,55 @@ public abstract class NamedMinecraftProvider extend } } + public static final class LegacyMergedImpl extends NamedMinecraftProvider implements Merged { + private final SingleJarImpl server; + private final SingleJarImpl client; + + public LegacyMergedImpl(Project project, LegacyMergedMinecraftProvider minecraftProvider) { + super(project, minecraftProvider); + server = new SingleJarImpl(project, minecraftProvider.getServerMinecraftProvider(), SingleJarEnvType.SERVER); + client = new SingleJarImpl(project, minecraftProvider.getClientMinecraftProvider(), SingleJarEnvType.CLIENT); + } + + @Override + public List provide(ProvideContext context) throws Exception { + final ProvideContext childContext = context.withApplyDependencies(false); + + // Map the client and server jars separately + server.provide(childContext); + client.provide(childContext); + + // then merge them + MergedMinecraftProvider.mergeJars( + client.getEnvOnlyJar().toFile(), + server.getEnvOnlyJar().toFile(), + getMergedJar().toFile() + ); + + getMavenHelper(MinecraftJar.Type.MERGED).savePom(); + + if (context.applyDependencies()) { + MinecraftSourceSets.get(getProject()).applyDependencies( + (configuration, type) -> getProject().getDependencies().add(configuration, getDependencyNotation(type)), + getDependencyTypes() + ); + } + + return List.of(getMergedJar()); + } + + @Override + public List getRemappedJars() { + // The delegate providers will handle the remapping + throw new UnsupportedOperationException("LegacyMergedImpl does not support getRemappedJars"); + } + + @Override + public List getDependencyTypes() { + return List.of(MinecraftJar.Type.MERGED); + } + } + public static final class SplitImpl extends NamedMinecraftProvider implements Split { public SplitImpl(Project project, SplitMinecraftProvider minecraftProvider) { super(project, minecraftProvider); @@ -78,8 +129,8 @@ public abstract class NamedMinecraftProvider extend @Override public List getRemappedJars() { return List.of( - new RemappedJars(minecraftProvider.getMinecraftCommonJar(), getCommonJar(), MappingsNamespace.OFFICIAL), - new RemappedJars(minecraftProvider.getMinecraftClientOnlyJar(), getClientOnlyJar(), MappingsNamespace.OFFICIAL, minecraftProvider.getMinecraftCommonJar()) + new RemappedJars(minecraftProvider.getMinecraftCommonJar(), getCommonJar(), minecraftProvider.getOfficialNamespace()), + new RemappedJars(minecraftProvider.getMinecraftClientOnlyJar(), getClientOnlyJar(), minecraftProvider.getOfficialNamespace(), minecraftProvider.getMinecraftCommonJar()) ); } @@ -113,7 +164,7 @@ public abstract class NamedMinecraftProvider extend @Override public List getRemappedJars() { return List.of( - new RemappedJars(minecraftProvider.getMinecraftEnvOnlyJar(), getEnvOnlyJar(), MappingsNamespace.OFFICIAL) + new RemappedJars(minecraftProvider.getMinecraftEnvOnlyJar(), getEnvOnlyJar(), minecraftProvider.getOfficialNamespace()) ); } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/ProcessedNamedMinecraftProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/ProcessedNamedMinecraftProvider.java index 5d28071e..d8f14e3c 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/ProcessedNamedMinecraftProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/mapped/ProcessedNamedMinecraftProvider.java @@ -37,6 +37,7 @@ import net.fabricmc.loom.configuration.ConfigContext; import net.fabricmc.loom.configuration.mods.dependency.LocalMavenHelper; import net.fabricmc.loom.configuration.processors.MinecraftJarProcessorManager; import net.fabricmc.loom.configuration.processors.ProcessorContextImpl; +import net.fabricmc.loom.configuration.providers.minecraft.LegacyMergedMinecraftProvider; import net.fabricmc.loom.configuration.providers.minecraft.MergedMinecraftProvider; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJar; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider; @@ -177,6 +178,17 @@ public abstract class ProcessedNamedMinecraftProvider implements Merged { + public LegacyMergedImpl(NamedMinecraftProvider.LegacyMergedImpl parentMinecraftProvider, MinecraftJarProcessorManager jarProcessorManager) { + super(parentMinecraftProvider, jarProcessorManager); + } + + @Override + public MinecraftJar getMergedJar() { + return getProcessedJar(getParentMinecraftProvider().getMergedJar()); + } + } + public static final class SplitImpl extends ProcessedNamedMinecraftProvider implements Split { public SplitImpl(NamedMinecraftProvider.SplitImpl parentMinecraftProvide, MinecraftJarProcessorManager jarProcessorManager) { super(parentMinecraftProvide, jarProcessorManager); diff --git a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java index 382fbc14..851832df 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java @@ -47,6 +47,7 @@ import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile; import net.fabricmc.loom.configuration.providers.mappings.IntermediaryMappingsProvider; import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsFactory; import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration; +import net.fabricmc.loom.configuration.providers.mappings.NoOpIntermediateMappingsProvider; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftProvider; import net.fabricmc.loom.configuration.providers.minecraft.library.LibraryProcessorManager; import net.fabricmc.loom.configuration.providers.minecraft.mapped.IntermediaryMinecraftProvider; @@ -165,6 +166,11 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen this.intermediaryMinecraftProvider = intermediaryMinecraftProvider; } + @Override + public void noIntermediateMappings() { + setIntermediateMappingsProvider(NoOpIntermediateMappingsProvider.class, p -> { }); + } + @Override public FileCollection getMinecraftJarsCollection(MappingsNamespace mappingsNamespace) { return getProject().files( @@ -271,6 +277,9 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen provider.getDownloader().set(this::download); provider.getDownloader().disallowChanges(); + + provider.getIsLegacyMinecraft().set(getProject().provider(() -> getMinecraftProvider().isLegacyVersion())); + provider.getIsLegacyMinecraft().disallowChanges(); } @Override diff --git a/src/main/java/net/fabricmc/loom/util/Constants.java b/src/main/java/net/fabricmc/loom/util/Constants.java index 10083571..c148ccb4 100644 --- a/src/main/java/net/fabricmc/loom/util/Constants.java +++ b/src/main/java/net/fabricmc/loom/util/Constants.java @@ -34,6 +34,7 @@ public class Constants { public static final String FABRIC_REPOSITORY = "https://maven.fabricmc.net/"; public static final int ASM_VERSION = Opcodes.ASM9; + public static final String RELEASE_TIME_1_3 = "2012-07-25T22:00:00+00:00"; private Constants() { } diff --git a/src/main/java/net/fabricmc/loom/util/TinyRemapperHelper.java b/src/main/java/net/fabricmc/loom/util/TinyRemapperHelper.java index 202e4646..d67eb4d9 100644 --- a/src/main/java/net/fabricmc/loom/util/TinyRemapperHelper.java +++ b/src/main/java/net/fabricmc/loom/util/TinyRemapperHelper.java @@ -69,7 +69,7 @@ public final class TinyRemapperHelper { MemoryMappingTree mappingTree = extension.getMappingConfiguration().getMappingsService(serviceManager).getMappingTree(); if (fixRecords && !mappingTree.getSrcNamespace().equals(fromM)) { - throw new IllegalStateException("Mappings src namespace must match remap src namespace"); + throw new IllegalStateException("Mappings src namespace must match remap src namespace, expected " + fromM + " but got " + mappingTree.getSrcNamespace()); } int intermediaryNsId = mappingTree.getNamespaceId(MappingsNamespace.INTERMEDIARY.toString()); diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/LegacyProjectTest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/LegacyProjectTest.groovy index 907de8f1..1cb8e760 100644 --- a/src/test/groovy/net/fabricmc/loom/test/integration/LegacyProjectTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/integration/LegacyProjectTest.groovy @@ -24,6 +24,8 @@ package net.fabricmc.loom.test.integration +import java.nio.file.Path + import spock.lang.Specification import spock.lang.Unroll @@ -118,4 +120,31 @@ class LegacyProjectTest extends Specification implements GradleProjectTestTrait 'b1.8.1' | _ 'a1.2.5' | _ } + + @Unroll + def "Legacy merged"() { + setup: + def mappings = Path.of("src/test/resources/mappings/1.2.5-intermediary.tiny.zip").toAbsolutePath() + def gradle = gradleProject(project: "minimalBase", version: PRE_RELEASE_GRADLE) + + gradle.buildGradle << """ + dependencies { + minecraft "com.mojang:minecraft:1.2.5" + mappings loom.layered() { + // No names + } + + modImplementation "net.fabricmc:fabric-loader:0.15.7" + } + """ + gradle.buildSrc("legacyMergedIntermediary") + + when: + def result = gradle.run(task: "build", args: [ + "-Ploom.test.legacyMergedIntermediary.mappingPath=${mappings}" + ]) + + then: + result.task(":build").outcome == SUCCESS + } } diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/buildSrc/legacyMergedIntermediary/TestPlugin.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/buildSrc/legacyMergedIntermediary/TestPlugin.groovy new file mode 100644 index 00000000..137f629f --- /dev/null +++ b/src/test/groovy/net/fabricmc/loom/test/integration/buildSrc/legacyMergedIntermediary/TestPlugin.groovy @@ -0,0 +1,63 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2022 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.test.integration.buildSrc.legacyMergedIntermediary + +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.Paths + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.provider.Property + +import net.fabricmc.loom.api.LoomGradleExtensionAPI +import net.fabricmc.loom.api.mappings.intermediate.IntermediateMappingsProvider +import net.fabricmc.loom.util.ZipUtils + +class TestPlugin implements Plugin { + @Override + void apply(Project project) { + LoomGradleExtensionAPI extension = project.getExtensions().getByName("loom") + extension.setIntermediateMappingsProvider(LegacyIntermediaryProvider.class) { + mappingPath.set(project.property("loom.test.legacyMergedIntermediary.mappingPath")) + } + } + + abstract static class LegacyIntermediaryProvider extends IntermediateMappingsProvider { + final String name = "legacyMerged" + + abstract Property getMappingPath(); + + @Override + void provide(Path tinyMappings) throws IOException { + if (getMinecraftVersion().get() != "1.2.5") { + throw new IllegalStateException("This plugin only supports Minecraft 1.2.5") + } + + byte[] data = ZipUtils.unpack(Paths.get(getMappingPath().get()), "1.2.5-intermediary.tiny") + Files.write(tinyMappings, data) + } + } +} diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/IntermediaryMappingLayerTest.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/IntermediaryMappingLayerTest.groovy index d99f352f..5afbf436 100644 --- a/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/IntermediaryMappingLayerTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/IntermediaryMappingLayerTest.groovy @@ -30,6 +30,7 @@ class IntermediaryMappingLayerTest extends LayeredMappingsSpecification { def "Read intermediary mappings" () { setup: intermediaryUrl = INTERMEDIARY_1_17_URL + mockMinecraftProvider.getVersionInfo() >> VERSION_META_1_17 when: def mappings = getSingleMapping(new IntermediaryMappingsSpec()) def tiny = getTiny(mappings) diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingsTestConstants.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingsTestConstants.groovy index a5bc09ab..c69e665e 100644 --- a/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingsTestConstants.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingsTestConstants.groovy @@ -34,13 +34,13 @@ interface LayeredMappingsTestConstants { client_mappings: new MinecraftVersionMeta.Download(null, "227d16f520848747a59bef6f490ae19dc290a804", 6431705, "https://launcher.mojang.com/v1/objects/227d16f520848747a59bef6f490ae19dc290a804/client.txt"), server_mappings: new MinecraftVersionMeta.Download(null, "84d80036e14bc5c7894a4fad9dd9f367d3000334", 4948536, "https://launcher.mojang.com/v1/objects/84d80036e14bc5c7894a4fad9dd9f367d3000334/server.txt") ] - public static final MinecraftVersionMeta VERSION_META_1_17 = new MinecraftVersionMeta(null, null, null, 0, DOWNLOADS_1_17, null, null, null, null, 0, null, null, null, null) + public static final MinecraftVersionMeta VERSION_META_1_17 = new MinecraftVersionMeta(null, null, null, 0, DOWNLOADS_1_17, null, null, null, null, 0, "2021-06-08T11:00:40+00:00", null, null, null) public static final Map DOWNLOADS_1_16_5 = [ client_mappings: new MinecraftVersionMeta.Download(null, "e3dfb0001e1079a1af72ee21517330edf52e6192", 5746047, "https://launcher.mojang.com/v1/objects/e3dfb0001e1079a1af72ee21517330edf52e6192/client.txt"), server_mappings: new MinecraftVersionMeta.Download(null, "81d5c793695d8cde63afddb40dde88e3a88132ac", 4400926, "https://launcher.mojang.com/v1/objects/81d5c793695d8cde63afddb40dde88e3a88132ac/server.txt") ] - public static final MinecraftVersionMeta VERSION_META_1_16_5 = new MinecraftVersionMeta(null, null, null, 0, DOWNLOADS_1_16_5, null, null, null, null, 0, null, null, null, null) + public static final MinecraftVersionMeta VERSION_META_1_16_5 = new MinecraftVersionMeta(null, null, null, 0, DOWNLOADS_1_16_5, null, null, null, null, 0, "2021-01-14T16:05:32+00:00", null, null, null) public static final String PARCHMENT_NOTATION = "org.parchmentmc.data:parchment-1.16.5:20210608-SNAPSHOT@zip" public static final String PARCHMENT_URL = "https://maven.parchmentmc.net/org/parchmentmc/data/parchment-1.16.5/20210608-SNAPSHOT/parchment-1.16.5-20210608-SNAPSHOT.zip" diff --git a/src/test/resources/mappings/1.2.5-intermediary.tiny.zip b/src/test/resources/mappings/1.2.5-intermediary.tiny.zip new file mode 100644 index 0000000000000000000000000000000000000000..0086053b72103372c1b704fb6815ab4edcc6eaf4 GIT binary patch literal 85026 zcmV)8K*qmNO9KQH00;mG0J@-ZSO5S3000000KYf|02crt05L8yE;TJ_ZggdGZDnL> zVRCscbZKsRRa6ZC2ce$$Wt^t?Wuczu8bItW| zcKt|=5S&iphruryudT6xLxQtT8z+7o3`x=Y81fLQq)(XKi@^|Oe6-qg zNHQwwV8!pskn`Qg-FIg<-@QD$JkIl0&ikOm%lzk`U*nR+>j!1T@8?S{g&?C5f5?|! z@v+iM6(#--ESI!MddR<0d7Wj2C~*L*DR*RFD?4{ZlvF%iZ<6?|yo? zKf8X%K`|y}ofLm=zbst{1{3~Eo1IlMc%Q^y+k;JVSd%3F)<)S7eeg#7z1<^y)J{wB zk9H;ayNwld9y`4LP~Kp z3oNId(pFrzD=K;~lM*+hxtZv6$R|iiCnXO2?P!xgTH5IH>B0Up*nW50hhVvRSj7GC za7AxTk#|N1$O!R%Fa#pNB`?c1!yz_WjC8q;+IpXVC1FjYmEyzbR~#gy%h6 z$DtmlP}N0DK|f=WKg|jNVpT^aK98pA5_Fd-Z|8&bT6`IuhzNOI#G}DxFxabKG2}}8 zzrXpnxWY9lA?&jCGF?+pEfAa8G~u;9Tl5MWP+|%;8za*|4_PLm*&Z{GMfk3{p;TbrCS(mg%oRef^M#>l5{TRu3Cu_me*{bGHRm5!w-dPg%LQQ-;0ZX!{&I>nNxM z84=o}o>&s;y|K_OPu}&!I2fZe*QRm5*5jnNjxdb9Znj&sBBC; zc@wr*OqkjA+D#Vc4Vx*O98cZ^lL zDsVW~*-&VU;8j-Z58bsu?S&)tq5nwA!8i+9m#Oqi9Y;Bah-0C33Lsrl*WXsBCzrs`_FZoHtldZ~&XnFn`Q{p57nt zj;bAkQ|K25%3pz(aWZ_MY zAART_FL&?r-ht$^2{y@zI9Y$$Y^jTz;&kMP>j>qgCNbBHI&4L+wOp8cRaU|!h6ei9 z4%D>n)du5kayIr@Wz&zqe`0)R_h?p08f~HL5BB_cf*g)xbvpj>q_u%X#YYX+5}qo-Rei?d3(k4CLx@$eD6lz5QiGO;nTbB*nfC9yZr7?XYaFI zQ1}e-If4YLoZiRc^yAf_F51U@Sr!>C7z~i%k;H4@ad+q9^XI{hIO|s2Ty2*M!DA0N zHJn1gS@YuJM%;dSv`jyh5HCKTj8Sel!ofLsl-aL`n`5!|^$4#7d2Pgubq(wp2Gr^q zUoojPq>9XAQnpmnBm`DO5~K%Awk(nqe7X2YN-Xw;&)%@iLSkz)NatOyu_@oR=$m7p zSHcK79UQf3<*LPoLzO?=?m5F?WhQvYWyxo6)CQW=p`9RH-tYx6&N{7hS*5l8qa?+! zIREl=7zn2j$IR?MX8YqL0U92r`7p}YB`_drE$p5e<;ziQ7)P#}z9-`6l^?b)D5pyr z1g9ZU8Lq!IM28OI{V38w%UFdPSB0so!*~_uA+Wx^gM~R-g>Fa=m_{c?;pT1#+`%(2+nu1<7jCę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ð%N}|yg2KV)(TY{aKAh3<%2HWue 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 literal 0 HcmV?d00001 diff --git a/src/test/resources/mappings/ATTRIBUTIONS.md b/src/test/resources/mappings/ATTRIBUTIONS.md new file mode 100644 index 00000000..52005c30 --- /dev/null +++ b/src/test/resources/mappings/ATTRIBUTIONS.md @@ -0,0 +1,2 @@ +The file `1.2.5-intermediary.tiny` was taken from OrnitheMC's "[Calamus](https://github.com/OrnitheMC/calamus/blob/gen2/mappings/1.2.5.tiny)" intermediaries under the CC0 license. +The file was rewritten in Tiny V2 format, but the mappings are otherwise unmodified.