diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8030d689b..a35845722 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ jackson = "2.15.2" guava = "32.1.2-jre" stitch = "0.6.2" -tiny-remapper = "1.9.22" +tiny-remapper = "1.10.23" access-widener = "2.1.0" mapping-io = "0.4.2" lorenz-tiny = "4.0.2" diff --git a/src/main/java/dev/architectury/loom/neoforge/MojangMappingsMerger.java b/src/main/java/dev/architectury/loom/neoforge/MojangMappingsMerger.java deleted file mode 100644 index 9a312ec61..000000000 --- a/src/main/java/dev/architectury/loom/neoforge/MojangMappingsMerger.java +++ /dev/null @@ -1,81 +0,0 @@ -package dev.architectury.loom.neoforge; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Path; -import java.util.List; -import java.util.Map; -import java.util.function.UnaryOperator; - -import net.fabricmc.loom.api.mappings.layered.MappingContext; -import net.fabricmc.loom.api.mappings.layered.MappingLayer; -import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; -import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsProcessor; -import net.fabricmc.loom.configuration.providers.mappings.mojmap.MojangMappingsSpec; -import net.fabricmc.loom.util.ExceptionUtil; -import net.fabricmc.mappingio.MappingReader; -import net.fabricmc.mappingio.MappingVisitor; -import net.fabricmc.mappingio.MappingWriter; -import net.fabricmc.mappingio.adapter.MappingNsCompleter; -import net.fabricmc.mappingio.adapter.MappingNsRenamer; -import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch; -import net.fabricmc.mappingio.format.MappingFormat; -import net.fabricmc.mappingio.tree.MemoryMappingTree; - -public final class MojangMappingsMerger { - public static void mergeMojangMappings(MappingContext context, Path raw, Path merged) { - try (MappingWriter writer = MappingWriter.create(merged, MappingFormat.TINY_2)) { - final MemoryMappingTree mappingTree = mergeMojangMappings(context, raw); - mappingTree.accept(writer); - } catch (IOException e) { - throw ExceptionUtil.createDescriptiveWrapper(UncheckedIOException::new, "Could not write Mojang-merged mappings", e); - } - } - - public static MemoryMappingTree mergeMojangMappings(MappingContext context, Path raw) { - try { - var processor = new LayeredMappingsProcessor(null); - var inputLayer = new FileLayer(raw, MappingsNamespace.NAMED); - var mojangLayer = new MojangMappingsSpec(() -> true, true).createLayer(context); - var renamedMojangLayer = new WrappedLayer(mojangLayer, next -> { - Map renames = Map.of(MappingsNamespace.NAMED.toString(), MappingsNamespace.MOJANG.toString()); - return new MappingNsRenamer(next, renames); - }); - MemoryMappingTree incomplete = processor.getMappings(List.of(inputLayer, renamedMojangLayer)); - MemoryMappingTree result = new MemoryMappingTree(); - MappingVisitor visitor = new MappingSourceNsSwitch(result, MappingsNamespace.OFFICIAL.toString()); - // Run via intermediary first to drop any missing names. - visitor = new MappingSourceNsSwitch(visitor, MappingsNamespace.INTERMEDIARY.toString(), true); - Map toComplete = Map.of(MappingsNamespace.MOJANG.toString(), MappingsNamespace.OFFICIAL.toString()); - visitor = new MappingNsCompleter(visitor, toComplete); - incomplete.accept(visitor); - return result; - } catch (IOException e) { - throw ExceptionUtil.createDescriptiveWrapper(UncheckedIOException::new, "Could not merge Mojang mappings", e); - } - } - - private record FileLayer(Path input, MappingsNamespace mergeNamespace) implements MappingLayer { - @Override - public void visit(MappingVisitor mappingVisitor) throws IOException { - MappingReader.read(input, mappingVisitor); - } - - @Override - public MappingsNamespace getSourceNamespace() { - return mergeNamespace; - } - } - - private record WrappedLayer(MappingLayer layer, UnaryOperator visitorWrapper) implements MappingLayer { - @Override - public void visit(MappingVisitor mappingVisitor) throws IOException { - layer.visit(visitorWrapper.apply(mappingVisitor)); - } - - @Override - public MappingsNamespace getSourceNamespace() { - return layer.getSourceNamespace(); - } - } -} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/forge/ForgeLibrariesProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/forge/ForgeLibrariesProvider.java index e90a73b41..6b56d81e7 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/forge/ForgeLibrariesProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/forge/ForgeLibrariesProvider.java @@ -32,7 +32,6 @@ import java.util.List; import com.google.common.hash.Hashing; -import dev.architectury.loom.neoforge.MojangMappingsMerger; import org.gradle.api.Project; import org.gradle.api.artifacts.Dependency; import org.gradle.api.artifacts.ModuleDependency; @@ -52,7 +51,7 @@ import net.fabricmc.loom.util.FileSystemUtil; import net.fabricmc.loom.util.PropertyUtil; import net.fabricmc.loom.util.srg.RemapObjectHolderVisitor; -import net.fabricmc.loom.util.srg.SrgMerger; +import net.fabricmc.loom.util.srg.ForgeMappingsMerger; import net.fabricmc.mappingio.tree.MemoryMappingTree; public class ForgeLibrariesProvider { @@ -70,7 +69,8 @@ public static void provide(MappingConfiguration mappingConfiguration, Project pr String dep = null; if (lib.startsWith("org.spongepowered:mixin:")) { - if (PropertyUtil.getAndFinalize(extension.getForge().getUseCustomMixin())) { + // Don't apply custom mixin on NeoForge. + if (extension.isForge() && PropertyUtil.getAndFinalize(extension.getForge().getUseCustomMixin())) { if (lib.contains("0.8.2")) { dep = "net.fabricmc:sponge-mixin:0.8.2+build.24"; } else { @@ -193,8 +193,8 @@ private static void remapObjectHolder(Project project, Path outputJar, MappingCo // Merge SRG mappings. The real SRG mapping file hasn't been created yet since the usual SRG merging // process occurs after all Forge libraries have been provided. // Forge libs are needed for MC, which is needed for the mappings. - final SrgMerger.ExtraMappings extraMappings = SrgMerger.ExtraMappings.ofMojmapTsrg(MappingConfiguration.getMojmapSrgFileIfPossible(project)); - final MemoryMappingTree mappings = SrgMerger.mergeSrg(MappingConfiguration.getRawSrgFile(project), mappingConfiguration.tinyMappings, extraMappings, true); + final ForgeMappingsMerger.ExtraMappings extraMappings = ForgeMappingsMerger.ExtraMappings.ofMojmapTsrg(MappingConfiguration.getMojmapSrgFileIfPossible(project)); + final MemoryMappingTree mappings = ForgeMappingsMerger.mergeSrg(MappingConfiguration.getRawSrgFile(project), mappingConfiguration.tinyMappings, extraMappings, true); // Remap the object holders. RemapObjectHolderVisitor.remapObjectHolder( @@ -212,7 +212,7 @@ private static void remapNeoForgeObjectHolder(Project project, Path outputJar, M // process occurs after all Forge libraries have been provided. // Forge libs are needed for MC, which is needed for the mappings. final MappingContext context = new GradleMappingContext(project, "tmp-neoforge-libs"); - final MemoryMappingTree mappings = MojangMappingsMerger.mergeMojangMappings(context, mappingConfiguration.tinyMappings); + final MemoryMappingTree mappings = ForgeMappingsMerger.mergeMojang(context, mappingConfiguration.tinyMappings, null, true); // Remap the object holders. RemapObjectHolderVisitor.remapObjectHolder( diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/forge/SrgProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/forge/SrgProvider.java index f5e5dca29..a6a25738d 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/forge/SrgProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/forge/SrgProvider.java @@ -45,6 +45,7 @@ import org.gradle.api.logging.LogLevel; import net.fabricmc.loom.LoomGradleExtension; +import net.fabricmc.loom.api.mappings.layered.MappingContext; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; import net.fabricmc.loom.configuration.DependencyInfo; import net.fabricmc.loom.configuration.providers.mappings.GradleMappingContext; @@ -216,7 +217,8 @@ public static Path getMojmapTsrg(Project project, LoomGradleExtension extension) if (Files.notExists(mojmapTsrg) || extension.refreshDeps()) { try (BufferedWriter writer = Files.newBufferedWriter(mojmapTsrg, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { - Tsrg2Utils.writeTsrg(visitor -> visitMojmap(visitor, project), + GradleMappingContext context = new GradleMappingContext(project, "tmp-mojmap"); + Tsrg2Utils.writeTsrg(visitor -> visitMojangMappings(visitor, context), MappingsNamespace.NAMED.toString(), false, writer); } } @@ -233,8 +235,9 @@ public static Path getMojmapTsrg2(Project project, LoomGradleExtension extension if (Files.notExists(mojmapTsrg2) || extension.refreshDeps()) { try (BufferedWriter writer = Files.newBufferedWriter(mojmapTsrg2, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { + GradleMappingContext context = new GradleMappingContext(project, "tmp-mojmap"); MemoryMappingTree tree = new MemoryMappingTree(); - visitMojmap(tree, project); + visitMojangMappings(tree, context); writer.write(Tsrg2Writer.serialize(tree)); } } @@ -243,21 +246,12 @@ public static Path getMojmapTsrg2(Project project, LoomGradleExtension extension return mojmapTsrg2; } - private static void visitMojmap(MappingVisitor visitor, Project project) { - GradleMappingContext context = new GradleMappingContext(project, "tmp-mojmap"); - + public static void visitMojangMappings(MappingVisitor visitor, MappingContext context) { try { - FileUtils.deleteDirectory(context.workingDirectory("/").toFile()); MojangMappingLayer layer = new MojangMappingsSpec(() -> true, true).createLayer(context); layer.visit(visitor); } catch (IOException e) { throw new UncheckedIOException(e); - } finally { - try { - FileUtils.deleteDirectory(context.workingDirectory("/").toFile()); - } catch (IOException e) { - e.printStackTrace(); - } } } 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 7af4eb6c9..2e58c8391 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 @@ -44,7 +44,6 @@ import com.google.common.base.Stopwatch; import com.google.gson.JsonObject; -import dev.architectury.loom.neoforge.MojangMappingsMerger; import dev.architectury.loom.util.MappingOption; import org.apache.tools.ant.util.StringUtils; import org.gradle.api.Project; @@ -70,10 +69,11 @@ import net.fabricmc.loom.util.service.ScopedSharedServiceManager; import net.fabricmc.loom.util.service.SharedServiceManager; import net.fabricmc.loom.util.srg.MCPReader; -import net.fabricmc.loom.util.srg.SrgMerger; +import net.fabricmc.loom.util.srg.ForgeMappingsMerger; import net.fabricmc.loom.util.srg.SrgNamedWriter; import net.fabricmc.mappingio.MappingReader; import net.fabricmc.mappingio.format.MappingFormat; +import net.fabricmc.mappingio.format.Tiny2Writer; import net.fabricmc.stitch.Command; import net.fabricmc.stitch.commands.CommandProposeFieldNames; import net.fabricmc.stitch.commands.tinyv2.TinyFile; @@ -213,7 +213,11 @@ public void setupPost(Project project) throws IOException { if (Files.notExists(tinyMappingsWithMojang) || extension.refreshDeps()) { final Stopwatch stopwatch = Stopwatch.createStarted(); final MappingContext context = new GradleMappingContext(project, "tmp-neoforge"); - MojangMappingsMerger.mergeMojangMappings(context, tinyMappings, tinyMappingsWithMojang); + + try (Tiny2Writer writer = new Tiny2Writer(Files.newBufferedWriter(tinyMappingsWithMojang), false)) { + ForgeMappingsMerger.mergeMojang(context, tinyMappings, null, true).accept(writer); + } + project.getLogger().info(":merged mojang mappings in {}", stopwatch.stop()); } } @@ -222,8 +226,12 @@ public void setupPost(Project project) throws IOException { if (Files.notExists(tinyMappingsWithSrg) || extension.refreshDeps()) { // Merge tiny mappings with srg Stopwatch stopwatch = Stopwatch.createStarted(); - SrgMerger.ExtraMappings extraMappings = SrgMerger.ExtraMappings.ofMojmapTsrg(getMojmapSrgFileIfPossible(project)); - SrgMerger.mergeSrg(getRawSrgFile(project), tinyMappings, tinyMappingsWithSrg, extraMappings, true); + ForgeMappingsMerger.ExtraMappings extraMappings = ForgeMappingsMerger.ExtraMappings.ofMojmapTsrg(getMojmapSrgFileIfPossible(project)); + + try (Tiny2Writer writer = new Tiny2Writer(Files.newBufferedWriter(tinyMappingsWithSrg), false)) { + ForgeMappingsMerger.mergeSrg(getRawSrgFile(project), tinyMappings, extraMappings, true).accept(writer); + } + project.getLogger().info(":merged srg mappings in " + stopwatch.stop()); } } diff --git a/src/main/java/net/fabricmc/loom/extension/ForgeExtensionImpl.java b/src/main/java/net/fabricmc/loom/extension/ForgeExtensionImpl.java index 953b47825..af190850a 100644 --- a/src/main/java/net/fabricmc/loom/extension/ForgeExtensionImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/ForgeExtensionImpl.java @@ -104,10 +104,6 @@ public Property getUseForgeLoggerConfig() { @Override public List getDataGenMods() { - if (extension.isNeoForge()) { - throw new UnsupportedOperationException("getDataGenMods is not available on NeoForge."); - } - // unmod list prevents uncontrolled additions (we want to create the run config too) return Collections.unmodifiableList(dataGenMods); } @@ -115,10 +111,6 @@ public List getDataGenMods() { @SuppressWarnings("Convert2Lambda") @Override public void dataGen(Action action) { - if (extension.isNeoForge()) { - throw new UnsupportedOperationException("dataGen is not available on NeoForge."); - } - action.execute(new DataGenConsumer() { @Override public void mod(String... modIds) { diff --git a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java index 59a0d858e..fc6e9e421 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java @@ -98,7 +98,7 @@ public LoomGradleExtensionImpl(Project project, LoomFiles files) { this.loomFiles = files; this.unmappedMods = project.files(); this.forgeExtension = Suppliers.memoize(() -> isForge() ? project.getObjects().newInstance(ForgeExtensionImpl.class, project, this) : null); - this.neoForgeExtension = Suppliers.memoize(() -> isNeoForge() ? project.getObjects().newInstance(NeoForgeExtensionImpl.class, project, this) : null); + this.neoForgeExtension = Suppliers.memoize(() -> isNeoForge() ? project.getObjects().newInstance(NeoForgeExtensionImpl.class, project) : null); // Setup the default intermediate mappings provider. setIntermediateMappingsProvider(IntermediaryMappingsProvider.class, provider -> { diff --git a/src/main/java/net/fabricmc/loom/task/launch/GenerateDLIConfigTask.java b/src/main/java/net/fabricmc/loom/task/launch/GenerateDLIConfigTask.java index e88448198..5076220ed 100644 --- a/src/main/java/net/fabricmc/loom/task/launch/GenerateDLIConfigTask.java +++ b/src/main/java/net/fabricmc/loom/task/launch/GenerateDLIConfigTask.java @@ -141,14 +141,14 @@ public void run() throws IOException { } else { launchConfig.property("net.minecraftforge.gradle.GradleStart.srg.srg-mcp", getExtension().getMappingConfiguration().srgToNamedSrg.toAbsolutePath().toString()); } - } - Set mixinConfigs = PropertyUtil.getAndFinalize(getExtension().getForge().getMixinConfigs()); + Set mixinConfigs = PropertyUtil.getAndFinalize(getExtension().getForge().getMixinConfigs()); - if (!mixinConfigs.isEmpty()) { - for (String config : mixinConfigs) { - launchConfig.argument("-mixin.config"); - launchConfig.argument(config); + if (!mixinConfigs.isEmpty()) { + for (String config : mixinConfigs) { + launchConfig.argument("-mixin.config"); + launchConfig.argument(config); + } } } diff --git a/src/main/java/net/fabricmc/loom/util/srg/SrgMerger.java b/src/main/java/net/fabricmc/loom/util/srg/ForgeMappingsMerger.java similarity index 60% rename from src/main/java/net/fabricmc/loom/util/srg/SrgMerger.java rename to src/main/java/net/fabricmc/loom/util/srg/ForgeMappingsMerger.java index 378b0fa33..dd57907dc 100644 --- a/src/main/java/net/fabricmc/loom/util/srg/SrgMerger.java +++ b/src/main/java/net/fabricmc/loom/util/srg/ForgeMappingsMerger.java @@ -34,56 +34,57 @@ import java.util.Map; import java.util.Set; import java.util.function.Consumer; -import java.util.stream.Collectors; -import java.util.stream.Stream; +import com.google.common.base.Preconditions; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; import org.jetbrains.annotations.Nullable; +import net.fabricmc.loom.api.mappings.layered.MappingContext; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; +import net.fabricmc.loom.configuration.providers.forge.SrgProvider; import net.fabricmc.loom.util.MappingException; import net.fabricmc.loom.util.function.CollectionUtil; import net.fabricmc.mappingio.FlatMappingVisitor; import net.fabricmc.mappingio.MappingReader; import net.fabricmc.mappingio.MappingVisitor; +import net.fabricmc.mappingio.adapter.ForwardingMappingVisitor; import net.fabricmc.mappingio.adapter.MappingNsRenamer; import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch; import net.fabricmc.mappingio.adapter.RegularAsFlatMappingVisitor; import net.fabricmc.mappingio.format.MappingFormat; -import net.fabricmc.mappingio.format.Tiny2Writer; import net.fabricmc.mappingio.format.TsrgReader; import net.fabricmc.mappingio.tree.MappingTree; import net.fabricmc.mappingio.tree.MappingTreeView; import net.fabricmc.mappingio.tree.MemoryMappingTree; /** - * Merges a Tiny file with an SRG file. + * Merges a Tiny file with a new namespace. * * @author Juuz */ -public final class SrgMerger { +public final class ForgeMappingsMerger { private static final List INPUT_NAMESPACES = List.of("official", "intermediary", "named"); - private final MemoryMappingTree srg; + private final MemoryMappingTree newNs; private final MemoryMappingTree src; private final MemoryMappingTree output; private final FlatMappingVisitor flatOutput; private final boolean lenient; private final @Nullable MemoryMappingTree extra; - private final ListMultimap methodsBySrgName; + private final ListMultimap methodsByNewNs; - private SrgMerger(Path srg, Path tiny, @Nullable ExtraMappings extraMappings, boolean lenient) throws IOException { - this.srg = readSrg(srg); - this.src = new MemoryMappingTree(); + private ForgeMappingsMerger(MemoryMappingTree newNs, MemoryMappingTree src, @Nullable ExtraMappings extraMappings, boolean lenient) throws IOException { + this.newNs = newNs; + Preconditions.checkArgument(this.newNs.getDstNamespaces().size() == 1, "New namespace must have exactly one destination namespace"); + this.src = src; this.output = new MemoryMappingTree(); this.flatOutput = new RegularAsFlatMappingVisitor(output); this.lenient = lenient; - this.methodsBySrgName = ArrayListMultimap.create(); + this.methodsByNewNs = ArrayListMultimap.create(); if (extraMappings != null) { this.extra = new MemoryMappingTree(); - MappingSourceNsSwitch nsSwitch = new MappingSourceNsSwitch(extra, "official"); - MappingVisitor visitor = nsSwitch; + MappingVisitor visitor = new MappingSourceNsSwitch(this.extra, MappingsNamespace.OFFICIAL.toString()); if (!extraMappings.hasCorrectNamespaces()) { Map namespaces = Map.of( @@ -98,33 +99,37 @@ private SrgMerger(Path srg, Path tiny, @Nullable ExtraMappings extraMappings, bo this.extra = null; } - MappingReader.read(tiny, this.src); - checkInputNamespaces(tiny); - - this.output.visitNamespaces(this.src.getSrcNamespace(), Stream.concat(Stream.of("srg"), this.src.getDstNamespaces().stream()).collect(Collectors.toList())); + var newDstNamespaces = new ArrayList(); + newDstNamespaces.add(this.newNs.getDstNamespaces().get(0)); + newDstNamespaces.addAll(this.src.getDstNamespaces()); + this.output.visitNamespaces(this.src.getSrcNamespace(), newDstNamespaces); } - private void checkInputNamespaces(Path tiny) { - List inputNamespaces = new ArrayList<>(this.src.getDstNamespaces()); - inputNamespaces.add(0, this.src.getSrcNamespace()); + private static MemoryMappingTree readInput(Path tiny) throws IOException { + MemoryMappingTree src = new MemoryMappingTree(); + MappingReader.read(tiny, src); + List inputNamespaces = new ArrayList<>(src.getDstNamespaces()); + inputNamespaces.add(0, src.getSrcNamespace()); if (!inputNamespaces.equals(INPUT_NAMESPACES)) { throw new MappingException("Mapping file " + tiny + " does not have 'official, intermediary, named' as its namespaces! Found: " + inputNamespaces); } + + return src; } /** * Creates a destination name array where the first element - * will be the srg name of the mapping element. + * will be the new namespace name of the mapping element. */ - private String[] createDstNameArray(MappingTree.ElementMappingView srg) { + private String[] createDstNameArray(MappingTree.ElementMappingView newNs) { String[] dstNames = new String[output.getDstNamespaces().size()]; - dstNames[0] = srg.getDstName(0); + dstNames[0] = newNs.getDstName(0); return dstNames; } /** - * Copies all the non-srg destination names from an element. + * Copies all the original destination names from an element. */ private void copyDstNames(String[] dstNames, MappingTreeView.ElementMappingView from) { for (int i = 1; i < dstNames.length; i++) { @@ -135,37 +140,37 @@ private void copyDstNames(String[] dstNames, MappingTreeView.ElementMappingView /** * Fills in an array of destination names with the element's source name. */ - private void fillMappings(String[] names, MappingTree.ElementMappingView srg) { + private void fillMappings(String[] names, MappingTree.ElementMappingView newNs) { for (int i = 1; i < names.length; i++) { - names[i] = srg.getSrcName(); + names[i] = newNs.getSrcName(); } } public MemoryMappingTree merge() throws IOException { - for (MappingTree.ClassMapping srgClass : srg.getClasses()) { - String[] dstNames = createDstNameArray(srgClass); - MappingTree.ClassMapping tinyClass = src.getClass(srgClass.getSrcName()); + for (MappingTree.ClassMapping newNsClass : newNs.getClasses()) { + String[] dstNames = createDstNameArray(newNsClass); + MappingTree.ClassMapping tinyClass = src.getClass(newNsClass.getSrcName()); String comment = null; if (tinyClass != null) { copyDstNames(dstNames, tinyClass); comment = tinyClass.getComment(); } else if (lenient) { - // Tiny class not found, we'll just use srg names - fillMappings(dstNames, srgClass); + // Tiny class not found, we'll just use new namespace names + fillMappings(dstNames, newNsClass); } else { - throw new MappingException("Could not find class " + srgClass.getSrcName() + "|" + srgClass.getDstName(0)); + throw new MappingException("Could not find class " + newNsClass.getSrcName() + "|" + newNsClass.getDstName(0)); } - flatOutput.visitClass(srgClass.getSrcName(), dstNames); - if (comment != null) flatOutput.visitClassComment(srgClass.getSrcName(), comment); + flatOutput.visitClass(newNsClass.getSrcName(), dstNames); + if (comment != null) flatOutput.visitClassComment(newNsClass.getSrcName(), comment); - for (MappingTree.FieldMapping field : srgClass.getFields()) { - mergeField(srgClass, field, tinyClass); + for (MappingTree.FieldMapping field : newNsClass.getFields()) { + mergeField(newNsClass, field, tinyClass); } - for (MappingTree.MethodMapping method : srgClass.getMethods()) { - mergeMethod(srgClass, method, tinyClass); + for (MappingTree.MethodMapping method : newNsClass.getMethods()) { + mergeMethod(newNsClass, method, tinyClass); } } @@ -174,20 +179,20 @@ public MemoryMappingTree merge() throws IOException { return output; } - private void mergeField(MappingTree.ClassMapping srgClass, MappingTree.FieldMapping srgField, @Nullable MappingTree.ClassMapping tinyClass) throws IOException { - String[] dstNames = createDstNameArray(srgField); + private void mergeField(MappingTree.ClassMapping newNsClass, MappingTree.FieldMapping newNsField, @Nullable MappingTree.ClassMapping tinyClass) throws IOException { + String[] dstNames = createDstNameArray(newNsField); MappingTree.FieldMapping tinyField = null; - String srcDesc = srgField.getSrcDesc(); + String srcDesc = newNsField.getSrcDesc(); String comment = null; if (tinyClass != null) { if (srcDesc != null) { - tinyField = tinyClass.getField(srgField.getSrcName(), srgField.getSrcDesc()); + tinyField = tinyClass.getField(newNsField.getSrcName(), newNsField.getSrcDesc()); } else { - tinyField = CollectionUtil.find(tinyClass.getFields(), field -> field.getSrcName().equals(srgField.getSrcName())).orElse(null); + tinyField = CollectionUtil.find(tinyClass.getFields(), field -> field.getSrcName().equals(newNsField.getSrcName())).orElse(null); } } else if (!lenient) { - throw new MappingException("Could not find field " + srgClass.getDstName(0) + '.' + srgField.getDstName(0) + ' ' + srgField.getDstDesc(0)); + throw new MappingException("Could not find field " + newNsClass.getDstName(0) + '.' + newNsField.getDstName(0) + ' ' + newNsField.getDstDesc(0)); } if (tinyField != null) { @@ -195,27 +200,27 @@ private void mergeField(MappingTree.ClassMapping srgClass, MappingTree.FieldMapp srcDesc = tinyField.getSrcDesc(); comment = tinyField.getComment(); } else { - fillMappings(dstNames, srgField); + fillMappings(dstNames, newNsField); } if (srcDesc != null) { - flatOutput.visitField(srgClass.getSrcName(), srgField.getSrcName(), srcDesc, dstNames); - if (comment != null) flatOutput.visitFieldComment(srgClass.getSrcName(), srgField.getSrcName(), srcDesc, comment); + flatOutput.visitField(newNsClass.getSrcName(), newNsField.getSrcName(), srcDesc, dstNames); + if (comment != null) flatOutput.visitFieldComment(newNsClass.getSrcName(), newNsField.getSrcName(), srcDesc, comment); } else if (!lenient) { - throw new MappingException("Could not find descriptor for field " + srgClass.getDstName(0) + '.' + srgField.getDstName(0)); + throw new MappingException("Could not find descriptor for field " + newNsClass.getDstName(0) + '.' + newNsField.getDstName(0)); } } - private void mergeMethod(MappingTree.ClassMapping srgClass, MappingTree.MethodMapping srgMethod, @Nullable MappingTree.ClassMapping tinyClass) throws IOException { - String[] dstNames = createDstNameArray(srgMethod); + private void mergeMethod(MappingTree.ClassMapping newNsClass, MappingTree.MethodMapping newNsMethod, @Nullable MappingTree.ClassMapping tinyClass) throws IOException { + String[] dstNames = createDstNameArray(newNsMethod); MappingTree.MethodMapping tinyMethod = null; String intermediaryName, namedName; String comment = null; if (tinyClass != null) { - tinyMethod = tinyClass.getMethod(srgMethod.getSrcName(), srgMethod.getSrcDesc()); + tinyMethod = tinyClass.getMethod(newNsMethod.getSrcName(), newNsMethod.getSrcDesc()); } else if (!lenient) { - throw new MappingException("Could not find method " + srgClass.getDstName(0) + '.' + srgMethod.getDstName(0) + ' ' + srgMethod.getDstDesc(0)); + throw new MappingException("Could not find method " + newNsClass.getDstName(0) + '.' + newNsMethod.getDstName(0) + ' ' + newNsMethod.getDstDesc(0)); } if (tinyMethod != null) { @@ -224,7 +229,7 @@ private void mergeMethod(MappingTree.ClassMapping srgClass, MappingTree.MethodMa namedName = tinyMethod.getName("named"); comment = tinyMethod.getComment(); } else { - if (srgMethod.getSrcName().equals(srgMethod.getDstName(0))) { + if (newNsMethod.getSrcName().equals(newNsMethod.getDstName(0))) { // These are only methods like or toString which have the same name in every NS. // We can safely ignore those. return; @@ -233,7 +238,7 @@ private void mergeMethod(MappingTree.ClassMapping srgClass, MappingTree.MethodMa @Nullable MappingTree.MethodMapping fillMethod = null; if (extra != null) { - MappingTree.MethodMapping extraMethod = extra.getMethod(srgClass.getSrcName(), srgMethod.getSrcName(), srgMethod.getSrcDesc()); + MappingTree.MethodMapping extraMethod = extra.getMethod(newNsClass.getSrcName(), newNsMethod.getSrcName(), newNsMethod.getSrcDesc()); if (extraMethod != null && extraMethod.getSrcName().equals(extraMethod.getDstName(0))) { fillMethod = extraMethod; @@ -246,33 +251,33 @@ private void mergeMethod(MappingTree.ClassMapping srgClass, MappingTree.MethodMa } else { // Do not allow missing methods as these are typically subclass methods and cause issues where // class B extends A, and overrides a method from the superclass. Then the subclass method - // DOES get a srg name but not a yarn/intermediary name. + // DOES get a new namespace name but not a yarn/intermediary name. return; } } - if (!srgMethod.getSrcName().equals(dstNames[0])) { // ignore and the likes - methodsBySrgName.put( - new SrgMethodKey(dstNames[0], srgMethod.getSrcDesc()), - new MethodData(srgClass.getSrcName(), srgMethod.getSrcName(), srgMethod.getSrcDesc(), tinyMethod != null, intermediaryName, namedName) + if (!newNsMethod.getSrcName().equals(dstNames[0])) { // ignore and the likes + methodsByNewNs.put( + new MethodKey(dstNames[0], newNsMethod.getSrcDesc()), + new MethodData(newNsClass.getSrcName(), newNsMethod.getSrcName(), newNsMethod.getSrcDesc(), tinyMethod != null, intermediaryName, namedName) ); } - flatOutput.visitMethod(srgClass.getSrcName(), srgMethod.getSrcName(), srgMethod.getSrcDesc(), dstNames); - if (comment != null) flatOutput.visitMethodComment(srgClass.getSrcName(), srgMethod.getSrcName(), srgMethod.getSrcDesc(), comment); + flatOutput.visitMethod(newNsClass.getSrcName(), newNsMethod.getSrcName(), newNsMethod.getSrcDesc(), dstNames); + if (comment != null) flatOutput.visitMethodComment(newNsClass.getSrcName(), newNsMethod.getSrcName(), newNsMethod.getSrcDesc(), comment); if (tinyMethod != null) { for (MappingTree.MethodArgMapping arg : tinyMethod.getArgs()) { String[] argDstNames = new String[output.getDstNamespaces().size()]; copyDstNames(argDstNames, arg); flatOutput.visitMethodArg( - srgClass.getSrcName(), srgMethod.getSrcName(), srgMethod.getSrcDesc(), + newNsClass.getSrcName(), newNsMethod.getSrcName(), newNsMethod.getSrcDesc(), arg.getArgPosition(), arg.getLvIndex(), arg.getSrcName(), argDstNames ); if (arg.getComment() != null) { flatOutput.visitMethodArgComment( - srgClass.getSrcName(), srgMethod.getSrcName(), srgMethod.getSrcDesc(), + newNsClass.getSrcName(), newNsMethod.getSrcName(), newNsMethod.getSrcDesc(), arg.getArgPosition(), arg.getLvIndex(), arg.getSrcName(), arg.getComment() ); @@ -282,14 +287,14 @@ private void mergeMethod(MappingTree.ClassMapping srgClass, MappingTree.MethodMa } /** - * Resolves conflicts where multiple methods map to an SRG method. + * Resolves conflicts where multiple methods map to a method in the new namespace. * We will prefer the ones with the Tiny mappings. */ private void resolveConflicts() { List conflicts = new ArrayList<>(); - for (SrgMethodKey srg : methodsBySrgName.keySet()) { - List methods = methodsBySrgName.get(srg); + for (MethodKey methodKey : methodsByNewNs.keySet()) { + List methods = methodsByNewNs.get(methodKey); if (methods.size() == 1) continue; // Determine whether the names conflict @@ -326,8 +331,8 @@ private void resolveConflicts() { List hasTiny = CollectionUtil.filter(methods, MethodData::hasTiny); // Record conflicts if needed - if (hasTiny.size() > 1) { // Multiple methods map to this SRG name - // Sometimes unrelated methods share an SRG name. Probably overrides from a past version? + if (hasTiny.size() > 1) { // Multiple methods map to this new name + // Sometimes unrelated methods share a SRG name. Probably overrides from a past version? Set intermediaryNames = new HashSet<>(); for (MethodData method : methods) { @@ -337,7 +342,7 @@ private void resolveConflicts() { // Only record a conflict if we map one intermediary name with multiple named names if (intermediaryNames.size() == 1) { StringBuilder message = new StringBuilder(); - message.append("- multiple preferred methods for ").append(srg).append(':'); + message.append("- multiple preferred methods for ").append(newNs).append(':'); for (MethodData preferred : hasTiny) { message.append("\n\t> ").append(preferred); @@ -347,50 +352,14 @@ private void resolveConflicts() { } return null; - } else if (hasTiny.isEmpty()) { // No methods map to this SRG name - conflictReporter.accept("- no preferred methods found for " + srg + ", available: " + methods); + } else if (hasTiny.isEmpty()) { // No methods map to this new name + conflictReporter.accept("- no preferred methods found for " + newNs + ", available: " + methods); return null; } return hasTiny.get(0); } - /** - * Merges SRG mappings with a tiny mappings tree through the obf names. - * This overload writes the mappings into a file. - * - *

The namespaces in the tiny file should be {@code official, intermediary, named}. - * The SRG names will add a new namespace called {@code srg} so that the final namespaces - * are {@code official, srg, intermediary, named}. - * - *

This method does not include local variables in the output. - * It can, however, be used for remapping the game jar since it has all - * classes, methods, fields, parameters and javadoc comments. - * - *

If {@code lenient} is true, the merger will not error when encountering names not present - * in the tiny mappings. Instead, the names will be filled from the {@code official} namespace. - * - * @param srg the SRG file in .tsrg format - * @param tiny the tiny file - * @param out the output file, will be in tiny v2 - * @param extraMappings an extra mappings file that will be used to determine - * whether an unobfuscated name is needed in the result file - * @param lenient whether lenient mode is enabled - * @throws IOException if an IO error occurs while reading or writing the mappings - * @throws MappingException if the input tiny mappings' namespaces are incorrect - * or if an element mentioned in the SRG file does not have tiny mappings in non-lenient mode - */ - public static void mergeSrg(Path srg, Path tiny, Path out, @Nullable ExtraMappings extraMappings, boolean lenient) - throws IOException, MappingException { - MemoryMappingTree tree = mergeSrg(srg, tiny, extraMappings, lenient); - - try (Tiny2Writer writer = new Tiny2Writer(Files.newBufferedWriter(out), false)) { - tree.accept(writer); - } catch (IOException e) { - e.printStackTrace(); - } - } - /** * Merges SRG mappings with a tiny mappings tree through the obf names. * This overload returns a {@link MemoryMappingTree} of the merged mappings. @@ -418,20 +387,29 @@ public static void mergeSrg(Path srg, Path tiny, Path out, @Nullable ExtraMappin */ public static MemoryMappingTree mergeSrg(Path srg, Path tiny, @Nullable ExtraMappings extraMappings, boolean lenient) throws IOException, MappingException { - return new SrgMerger(srg, tiny, extraMappings, lenient).merge(); + return new ForgeMappingsMerger(readSrg(srg), readInput(tiny), extraMappings, lenient).merge(); + } + + public static MemoryMappingTree mergeMojang(MappingContext context, Path tiny, @Nullable ExtraMappings extraMappings, boolean lenient) + throws IOException, MappingException { + MemoryMappingTree mojang = new MemoryMappingTree(); + SrgProvider.visitMojangMappings(new MappingNsRenamer(mojang, Map.of(MappingsNamespace.NAMED.toString(), MappingsNamespace.MOJANG.toString())), context); + return new ForgeMappingsMerger(mojang, readInput(tiny), extraMappings, lenient).merge(); } - private MemoryMappingTree readSrg(Path srg) throws IOException { + private static MemoryMappingTree readSrg(Path srg) throws IOException { try (BufferedReader reader = Files.newBufferedReader(srg)) { - MemoryMappingTree tsrg = new MemoryMappingTree(); - MemoryMappingTree temp = new MemoryMappingTree(); - TsrgReader.read(reader, temp); - Map namespaces = Map.of( - temp.getSrcNamespace(), MappingsNamespace.OFFICIAL.toString(), - temp.getDstNamespaces().get(0), MappingsNamespace.SRG.toString() - ); - temp.accept(new MappingNsRenamer(tsrg, namespaces)); - return tsrg; + MemoryMappingTree output = new MemoryMappingTree(); + TsrgReader.read(reader, new ForwardingMappingVisitor(output) { + // Override the namespaces to be official -> srg + @Override + public void visitNamespaces(String srcNamespace, List dstNamespaces) throws IOException { + List newDstNamespaces = new ArrayList<>(dstNamespaces); + newDstNamespaces.set(0, MappingsNamespace.SRG.toString()); + super.visitNamespaces(MappingsNamespace.OFFICIAL.toString(), newDstNamespaces); + } + }); + return output; } } @@ -445,7 +423,7 @@ public static ExtraMappings ofMojmapTsrg(Path path) { } } - private record SrgMethodKey(String name, String desc) { + private record MethodKey(String name, String desc) { @Override public String toString() { return name + desc; diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/forge/SrgMergerTest.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/forge/SrgMergerTest.groovy index d3dd0e1ab..76fc06dff 100644 --- a/src/test/groovy/net/fabricmc/loom/test/unit/forge/SrgMergerTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/unit/forge/SrgMergerTest.groovy @@ -30,9 +30,10 @@ import java.nio.file.Path import spock.lang.Specification import spock.lang.TempDir -import net.fabricmc.loom.util.srg.SrgMerger +import net.fabricmc.loom.util.srg.ForgeMappingsMerger import net.fabricmc.mappingio.MappingUtil import net.fabricmc.mappingio.format.MappingFormat +import net.fabricmc.mappingio.format.Tiny2Writer class SrgMergerTest extends Specification { @TempDir @@ -42,7 +43,7 @@ class SrgMergerTest extends Specification { def output = mappingsDir.resolve("output.tiny") def expected = readTestData("expectedOutput.tiny") def proguardInput = extractTempFile("proguard.txt") - def extraMappings = new SrgMerger.ExtraMappings(proguardInput, MappingFormat.PROGUARD, MappingUtil.NS_TARGET_FALLBACK, MappingUtil.NS_SOURCE_FALLBACK) + def extraMappings = new ForgeMappingsMerger.ExtraMappings(proguardInput, MappingFormat.PROGUARD, MappingUtil.NS_TARGET_FALLBACK, MappingUtil.NS_SOURCE_FALLBACK) when: merge(extraMappings, output) @@ -55,7 +56,7 @@ class SrgMergerTest extends Specification { def output = mappingsDir.resolve("output.tiny") def expected = readTestData("expectedOutput.tiny") def extraInput = extractTempFile("extraInput.tsrg") - def extraMappings = SrgMerger.ExtraMappings.ofMojmapTsrg(extraInput) + def extraMappings = ForgeMappingsMerger.ExtraMappings.ofMojmapTsrg(extraInput) when: merge(extraMappings, output) @@ -64,10 +65,13 @@ class SrgMergerTest extends Specification { Files.readAllLines(output) == expected } - private def merge(SrgMerger.ExtraMappings extraMappings, Path output) { + private def merge(ForgeMappingsMerger.ExtraMappings extraMappings, Path output) { def srgInput = extractTempFile("srgInput.tsrg") def tinyInput = extractTempFile("tinyInput.tiny") - SrgMerger.mergeSrg(srgInput, tinyInput, output, extraMappings, true) + + new Tiny2Writer(Files.newBufferedWriter(output), false).withCloseable { writer -> + ForgeMappingsMerger.mergeSrg(srgInput, tinyInput, extraMappings, true).accept(writer) + } } private InputStream openTestDataStream(String path) {