diff --git a/build.gradle b/build.gradle index 90fe3c3..7992cd8 100644 --- a/build.gradle +++ b/build.gradle @@ -39,15 +39,17 @@ dependencies { implementation ('com.google.guava:guava:28.0-jre') // game handling utils - implementation ('net.fabricmc:stitch:0.2.1.60') { + implementation ('net.fabricmc:stitch:0.3.0.66') { exclude module: 'enigma' } // tinyfile management - implementation ('net.fabricmc:tiny-remapper:0.1.0.38') { + implementation ('net.fabricmc:tiny-remapper:0.2.0.52') { transitive = false } - implementation ('net.fabricmc:fabric-mixin-compile-extensions:0.1.0.+') + implementation ('net.fabricmc:fabric-mixin-compile-extensions:0.2.0.3'){ + exclude group :"net.fabricmc" + } // decompilers implementation ('net.fabricmc:procyon-fabric-compilertools:0.5.35.+') @@ -132,3 +134,8 @@ publishing { } } } +configurations.all { + resolutionStrategy { + force 'org.codehaus.groovy:groovy-all:2.4.12' + } +} diff --git a/src/main/java/net/fabricmc/loom/AbstractPlugin.java b/src/main/java/net/fabricmc/loom/AbstractPlugin.java index ceb31bd..88e135a 100644 --- a/src/main/java/net/fabricmc/loom/AbstractPlugin.java +++ b/src/main/java/net/fabricmc/loom/AbstractPlugin.java @@ -114,6 +114,7 @@ public class AbstractPlugin implements Plugin { includeConfig.setTransitive(false); // Dont get transitive deps project.getConfigurations().maybeCreate(Constants.MAPPINGS); + project.getConfigurations().maybeCreate(Constants.MAPPINGS_FINAL); for (RemappedConfigurationEntry entry : Constants.MOD_COMPILE_ENTRIES) { Configuration compileModsConfig = project.getConfigurations().maybeCreate(entry.getSourceConfiguration()); @@ -136,8 +137,8 @@ public class AbstractPlugin implements Plugin { extendsFrom(Constants.MINECRAFT_NAMED, Constants.MINECRAFT_DEPENDENCIES); extendsFrom(Constants.MINECRAFT_INTERMEDIARY, Constants.MINECRAFT_DEPENDENCIES); - extendsFrom("compile", Constants.MAPPINGS); - extendsFrom("annotationProcessor", Constants.MAPPINGS); + extendsFrom("compile", Constants.MAPPINGS_FINAL); + extendsFrom("annotationProcessor", Constants.MAPPINGS_FINAL); configureIDEs(); configureCompile(); @@ -156,8 +157,8 @@ public class AbstractPlugin implements Plugin { project.getLogger().lifecycle(":setting java compiler args"); try { - javaCompileTask.getOptions().getCompilerArgs().add("-AinMapFileNamedIntermediary=" + extension.getMappingsProvider().MAPPINGS_TINY.getCanonicalPath()); - javaCompileTask.getOptions().getCompilerArgs().add("-AoutMapFileNamedIntermediary=" + extension.getMappingsProvider().MAPPINGS_MIXIN_EXPORT.getCanonicalPath()); + javaCompileTask.getOptions().getCompilerArgs().add("-AinMapFileNamedIntermediary=" + extension.getMappingsProvider().tinyMappings.getCanonicalPath()); + javaCompileTask.getOptions().getCompilerArgs().add("-AoutMapFileNamedIntermediary=" + extension.getMappingsProvider().mappingsMixinExport.getCanonicalPath()); javaCompileTask.getOptions().getCompilerArgs().add("-AoutRefMapFile=" + new File(javaCompileTask.getDestinationDir(), extension.getRefmapName()).getCanonicalPath()); javaCompileTask.getOptions().getCompilerArgs().add("-AdefaultObfuscationEnv=named:intermediary"); } catch (IOException e) { @@ -183,8 +184,8 @@ public class AbstractPlugin implements Plugin { project.getLogger().warn(":configuring scala compilation processing"); try { - task.getOptions().getCompilerArgs().add("-AinMapFileNamedIntermediary=" + extension.getMappingsProvider().MAPPINGS_TINY.getCanonicalPath()); - task.getOptions().getCompilerArgs().add("-AoutMapFileNamedIntermediary=" + extension.getMappingsProvider().MAPPINGS_MIXIN_EXPORT.getCanonicalPath()); + task.getOptions().getCompilerArgs().add("-AinMapFileNamedIntermediary=" + extension.getMappingsProvider().tinyMappings.getCanonicalPath()); + task.getOptions().getCompilerArgs().add("-AoutMapFileNamedIntermediary=" + extension.getMappingsProvider().mappingsMixinExport.getCanonicalPath()); task.getOptions().getCompilerArgs().add("-AoutRefMapFile=" + new File(task.getDestinationDir(), extension.getRefmapName()).getCanonicalPath()); task.getOptions().getCompilerArgs().add("-AdefaultObfuscationEnv=named:intermediary"); } catch (IOException e) { diff --git a/src/main/java/net/fabricmc/loom/providers/MappingsCache.java b/src/main/java/net/fabricmc/loom/providers/MappingsCache.java index 953f694..fbcec82 100644 --- a/src/main/java/net/fabricmc/loom/providers/MappingsCache.java +++ b/src/main/java/net/fabricmc/loom/providers/MappingsCache.java @@ -24,8 +24,8 @@ package net.fabricmc.loom.providers; +import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStream; import java.lang.ref.SoftReference; import java.nio.file.Files; import java.nio.file.Path; @@ -33,32 +33,32 @@ import java.util.HashMap; import java.util.Map; import net.fabricmc.loom.util.StaticPathWatcher; -import net.fabricmc.mappings.Mappings; +import net.fabricmc.mapping.tree.TinyMappingFactory; +import net.fabricmc.mapping.tree.TinyTree; public final class MappingsCache { public static final MappingsCache INSTANCE = new MappingsCache(); - private final Map> mappingsCache = new HashMap<>(); + private final Map> mappingsCache = new HashMap<>(); - public Mappings get(Path mappingsPath) { + //TODO: loom doesn't actually use new mappings when the mappings change until the gradle daemons are stopped + public TinyTree get(Path mappingsPath) throws IOException { mappingsPath = mappingsPath.toAbsolutePath(); if (StaticPathWatcher.INSTANCE.hasFileChanged(mappingsPath)) { mappingsCache.remove(mappingsPath); } - SoftReference ref = mappingsCache.get(mappingsPath); + SoftReference ref = mappingsCache.get(mappingsPath); if (ref != null && ref.get() != null) { return ref.get(); } else { - try (InputStream stream = Files.newInputStream(mappingsPath)) { - Mappings mappings = net.fabricmc.mappings.MappingsProvider.readTinyMappings(stream, false); + try (BufferedReader reader = Files.newBufferedReader(mappingsPath)) { + TinyTree mappings = TinyMappingFactory.loadWithDetection(reader); ref = new SoftReference<>(mappings); mappingsCache.put(mappingsPath, ref); return mappings; - } catch (IOException e) { - throw new RuntimeException(e); } } } diff --git a/src/main/java/net/fabricmc/loom/providers/MappingsProvider.java b/src/main/java/net/fabricmc/loom/providers/MappingsProvider.java index 3eddfc5..77f8d15 100644 --- a/src/main/java/net/fabricmc/loom/providers/MappingsProvider.java +++ b/src/main/java/net/fabricmc/loom/providers/MappingsProvider.java @@ -24,25 +24,38 @@ package net.fabricmc.loom.providers; +import java.io.BufferedReader; import java.io.File; import java.io.IOException; +import java.net.URL; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; import java.util.function.Consumer; +import com.google.common.net.UrlEscapers; +import org.apache.commons.io.FileUtils; +import org.apache.tools.ant.util.StringUtils; import org.gradle.api.Project; +import org.zeroturnaround.zip.FileSource; +import org.zeroturnaround.zip.ZipEntrySource; +import org.zeroturnaround.zip.ZipUtil; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.DependencyProvider; +import net.fabricmc.loom.util.DownloadUtil; import net.fabricmc.loom.util.Version; -import net.fabricmc.mappings.Mappings; +import net.fabricmc.mapping.reader.v2.TinyV2Factory; +import net.fabricmc.mapping.tree.TinyTree; +import net.fabricmc.stitch.Command; import net.fabricmc.stitch.commands.CommandProposeFieldNames; +import net.fabricmc.stitch.commands.tinyv2.CommandMergeTinyV2; +import net.fabricmc.stitch.commands.tinyv2.CommandReorderTinyV2; -//TODO fix local mappings -//TODO possibly use maven for mappings, can fix above at the same time public class MappingsProvider extends DependencyProvider { public MinecraftMappedProvider mappedProvider; @@ -50,13 +63,21 @@ public class MappingsProvider extends DependencyProvider { public String minecraftVersion; public String mappingsVersion; - public File MAPPINGS_DIR; - public File MAPPINGS_TINY_BASE; - public File MAPPINGS_TINY; - public File MAPPINGS_MIXIN_EXPORT; + private Path mappingsDir; + private Path mappingsStepsDir; + // The mappings that gradle gives us + private Path baseTinyMappings; + // The mappings we use in practice + public File tinyMappings; + public File tinyMappingsJar; + public File mappingsMixinExport; - public Mappings getMappings() throws IOException { - return MappingsCache.INSTANCE.get(MAPPINGS_TINY.toPath()); + public void clean() throws IOException { + FileUtils.deleteDirectory(mappingsDir.toFile()); + } + + public TinyTree getMappings() throws IOException { + return MappingsCache.INSTANCE.get(tinyMappings.toPath()); } @Override @@ -66,50 +87,166 @@ public class MappingsProvider extends DependencyProvider { project.getLogger().lifecycle(":setting up mappings (" + dependency.getDependency().getName() + " " + dependency.getResolvedVersion() + ")"); String version = dependency.getResolvedVersion(); - File mappingsJar = dependency.resolveFile().orElseThrow(() -> new RuntimeException("Could not find dependency " + dependency)); + File mappingsJar = dependency.resolveFile().orElseThrow(() -> new RuntimeException("Could not find yarn mappings: " + dependency)); - this.mappingsName = dependency.getDependency().getGroup() + "." + dependency.getDependency().getName(); + this.mappingsName = StringUtils.removeSuffix(dependency.getDependency().getGroup() + "." + dependency.getDependency().getName(), "-unmerged"); + + boolean isV2 = doesJarContainV2Mappings(mappingsJar.toPath()); Version mappingsVersion = new Version(version); this.minecraftVersion = mappingsVersion.getMinecraftVersion(); - this.mappingsVersion = mappingsVersion.getMappingsVersion(); + this.mappingsVersion = mappingsVersion.getMappingsVersion() + (isV2 ? "-v2" : ""); initFiles(project); - if (!MAPPINGS_DIR.exists()) { - MAPPINGS_DIR.mkdir(); + Files.createDirectories(mappingsDir); + Files.createDirectories(mappingsStepsDir); + + String[] depStringSplit = dependency.getDepString().split(":"); + String jarClassifier = "final"; + + if (depStringSplit.length >= 4) { + jarClassifier = jarClassifier + depStringSplit[3]; } - if (!MAPPINGS_TINY_BASE.exists() || !MAPPINGS_TINY.exists()) { - if (!MAPPINGS_TINY_BASE.exists()) { - project.getLogger().lifecycle(":extracting " + mappingsJar.getName()); + tinyMappings = mappingsDir.resolve(StringUtils.removeSuffix(mappingsJar.getName(), ".jar") + ".tiny").toFile(); + tinyMappingsJar = new File(extension.getUserCache(), mappingsJar.getName().replace(".jar", "-" + jarClassifier + ".jar")); - try (FileSystem fileSystem = FileSystems.newFileSystem(mappingsJar.toPath(), null)) { - Path fileToExtract = fileSystem.getPath("mappings/mappings.tiny"); - Files.copy(fileToExtract, MAPPINGS_TINY_BASE.toPath()); - } - } - - if (MAPPINGS_TINY.exists()) { - MAPPINGS_TINY.delete(); - } - - project.getLogger().lifecycle(":populating field names"); - new CommandProposeFieldNames().run(new String[]{minecraftProvider.MINECRAFT_MERGED_JAR.getAbsolutePath(), MAPPINGS_TINY_BASE.getAbsolutePath(), MAPPINGS_TINY.getAbsolutePath()}); + if (!tinyMappings.exists()) { + storeMappings(project, minecraftProvider, mappingsJar.toPath()); } + if (!tinyMappingsJar.exists()) { + ZipUtil.pack(new ZipEntrySource[] {new FileSource("mappings/mappings.tiny", tinyMappings)}, tinyMappingsJar); + } + + addDependency(tinyMappingsJar, project, Constants.MAPPINGS_FINAL); + mappedProvider = new MinecraftMappedProvider(); mappedProvider.initFiles(project, minecraftProvider, this); mappedProvider.provide(dependency, project, extension, postPopulationScheduler); } - public void initFiles(Project project) { - LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); - MAPPINGS_DIR = new File(extension.getUserCache(), "mappings"); + private void storeMappings(Project project, MinecraftProvider minecraftProvider, Path yarnJar) throws IOException { + project.getLogger().lifecycle(":extracting " + yarnJar.getFileName()); - MAPPINGS_TINY_BASE = new File(MAPPINGS_DIR, mappingsName + "-tiny-" + minecraftVersion + "-" + mappingsVersion + "-base"); - MAPPINGS_TINY = new File(MAPPINGS_DIR, mappingsName + "-tiny-" + minecraftVersion + "-" + mappingsVersion); - MAPPINGS_MIXIN_EXPORT = new File(extension.getProjectBuildCache(), "mixin-map-" + minecraftVersion + "-" + mappingsVersion + ".tiny"); + try (FileSystem fileSystem = FileSystems.newFileSystem(yarnJar, null)) { + extractMappings(fileSystem, baseTinyMappings); + } + + if (baseMappingsAreV2()) { + // These are unmerged v2 mappings + + // Download and extract intermediary + String encodedMinecraftVersion = UrlEscapers.urlFragmentEscaper().escape(minecraftVersion); + String intermediaryArtifactUrl = "https://maven.fabricmc.net/net/fabricmc/intermediary/" + encodedMinecraftVersion + "/intermediary-" + encodedMinecraftVersion + "-v2.jar"; + Path intermediaryJar = mappingsStepsDir.resolve("v2-intermediary-" + minecraftVersion + ".jar"); + DownloadUtil.downloadIfChanged(new URL(intermediaryArtifactUrl), intermediaryJar.toFile(), project.getLogger()); + + mergeAndSaveMappings(project, intermediaryJar, yarnJar); + } else { + // These are merged v1 mappings + if (tinyMappings.exists()) { + tinyMappings.delete(); + } + + project.getLogger().lifecycle(":populating field names"); + suggestFieldNames(minecraftProvider, baseTinyMappings, tinyMappings.toPath()); + } + } + + private boolean baseMappingsAreV2() throws IOException { + try (BufferedReader reader = Files.newBufferedReader(baseTinyMappings)) { + TinyV2Factory.readMetadata(reader); + return true; + } catch (IllegalArgumentException e) { + // TODO: just check the mappings version when Parser supports V1 in readMetadata() + return false; + } + } + + private boolean doesJarContainV2Mappings(Path path) throws IOException { + try (FileSystem fs = FileSystems.newFileSystem(path, null)) { + try (BufferedReader reader = Files.newBufferedReader(fs.getPath("mappings", "mappings.tiny"))) { + TinyV2Factory.readMetadata(reader); + return true; + } catch (IllegalArgumentException e) { + return false; + } + } + } + + public static void extractMappings(FileSystem jar, Path extractTo) throws IOException { + Files.copy(jar.getPath("mappings/mappings.tiny"), extractTo, StandardCopyOption.REPLACE_EXISTING); + } + + private void mergeAndSaveMappings(Project project, Path unmergedIntermediaryJar, Path unmergedYarnJar) throws IOException { + Path unmergedIntermediary = Paths.get(mappingsStepsDir.toString(), "unmerged-intermediary.tiny"); + project.getLogger().info(":extracting " + unmergedIntermediaryJar.getFileName()); + + try (FileSystem unmergedIntermediaryFs = FileSystems.newFileSystem(unmergedIntermediaryJar, null)) { + extractMappings(unmergedIntermediaryFs, unmergedIntermediary); + } + + Path unmergedYarn = Paths.get(mappingsStepsDir.toString(), "unmerged-yarn.tiny"); + project.getLogger().info(":extracting " + unmergedYarnJar.getFileName()); + + try (FileSystem unmergedYarnJarFs = FileSystems.newFileSystem(unmergedYarnJar, null)) { + extractMappings(unmergedYarnJarFs, unmergedYarn); + } + + Path invertedIntermediary = Paths.get(mappingsStepsDir.toString(), "inverted-intermediary.tiny"); + reorderMappings(unmergedIntermediary, invertedIntermediary, "intermediary", "official"); + Path unorderedMergedMappings = Paths.get(mappingsStepsDir.toString(), "unordered-merged.tiny"); + project.getLogger().info(":merging"); + mergeMappings(invertedIntermediary, unmergedYarn, unorderedMergedMappings); + reorderMappings(unorderedMergedMappings, tinyMappings.toPath(), "official", "intermediary", "named"); + } + + private void reorderMappings(Path oldMappings, Path newMappings, String... newOrder) { + Command command = new CommandReorderTinyV2(); + String[] args = new String[2 + newOrder.length]; + args[0] = oldMappings.toAbsolutePath().toString(); + args[1] = newMappings.toAbsolutePath().toString(); + System.arraycopy(newOrder, 0, args, 2, newOrder.length); + runCommand(command, args); + } + + private void mergeMappings(Path intermediaryMappings, Path yarnMappings, Path newMergedMappings) { + try { + Command command = new CommandMergeTinyV2(); + runCommand(command, intermediaryMappings.toAbsolutePath().toString(), + yarnMappings.toAbsolutePath().toString(), + newMergedMappings.toAbsolutePath().toString(), + "intermediary", "official"); + } catch (Exception e) { + throw new RuntimeException("Could not merge mappings from " + intermediaryMappings.toString() + + " with mappings from " + yarnMappings, e); + } + } + + private void suggestFieldNames(MinecraftProvider minecraftProvider, Path oldMappings, Path newMappings) { + Command command = new CommandProposeFieldNames(); + runCommand(command, minecraftProvider.MINECRAFT_MERGED_JAR.getAbsolutePath(), + oldMappings.toAbsolutePath().toString(), + newMappings.toAbsolutePath().toString()); + } + + private void runCommand(Command command, String... args) { + try { + command.run(args); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private void initFiles(Project project) { + LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); + mappingsDir = extension.getUserCache().toPath().resolve("mappings"); + mappingsStepsDir = mappingsDir.resolve("steps"); + + baseTinyMappings = mappingsDir.resolve(mappingsName + "-tiny-" + minecraftVersion + "-" + mappingsVersion + "-base"); + mappingsMixinExport = new File(extension.getProjectBuildCache(), "mixin-map-" + minecraftVersion + "-" + mappingsVersion + ".tiny"); } @Override diff --git a/src/main/java/net/fabricmc/loom/providers/MinecraftMappedProvider.java b/src/main/java/net/fabricmc/loom/providers/MinecraftMappedProvider.java index 9d44c0d..3a398a8 100644 --- a/src/main/java/net/fabricmc/loom/providers/MinecraftMappedProvider.java +++ b/src/main/java/net/fabricmc/loom/providers/MinecraftMappedProvider.java @@ -39,11 +39,14 @@ public class MinecraftMappedProvider extends DependencyProvider { public File MINECRAFT_MAPPED_JAR; public File MINECRAFT_INTERMEDIARY_JAR; + public MinecraftMappedProvider() { + } + private MinecraftProvider minecraftProvider; @Override public void provide(DependencyInfo dependency, Project project, LoomGradleExtension extension, Consumer postPopulationScheduler) throws Exception { - if (!extension.getMappingsProvider().MAPPINGS_TINY.exists()) { + if (!extension.getMappingsProvider().tinyMappings.exists()) { throw new RuntimeException("mappings file not found"); } @@ -67,17 +70,28 @@ public class MinecraftMappedProvider extends DependencyProvider { throw new RuntimeException("mapped jar not found"); } - String version = minecraftProvider.minecraftVersion + "-mapped-" + extension.getMappingsProvider().mappingsName + "-" + extension.getMappingsProvider().mappingsVersion; - project.getDependencies().add(Constants.MINECRAFT_NAMED, project.getDependencies().module("net.minecraft:minecraft:" + version)); - version = minecraftProvider.minecraftVersion + "-intermediary-" + extension.getMappingsProvider().mappingsName; - project.getDependencies().add(Constants.MINECRAFT_INTERMEDIARY, project.getDependencies().module("net.minecraft:minecraft:" + version)); + MappingsProvider mappingsProvider = extension.getMappingsProvider(); + project.getDependencies().add(Constants.MINECRAFT_NAMED, + project.getDependencies().module("net.minecraft:minecraft:" + getNamedJarVersionString(mappingsProvider.mappingsName, mappingsProvider.mappingsVersion))); + project.getDependencies().add(Constants.MINECRAFT_INTERMEDIARY, + project.getDependencies().module("net.minecraft:minecraft:" + getIntermediaryJarVersionString(mappingsProvider.mappingsName, mappingsProvider.mappingsVersion))); } public void initFiles(Project project, MinecraftProvider minecraftProvider, MappingsProvider mappingsProvider) { LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); this.minecraftProvider = minecraftProvider; - MINECRAFT_INTERMEDIARY_JAR = new File(extension.getUserCache(), "minecraft-" + minecraftProvider.minecraftVersion + "-intermediary-" + mappingsProvider.mappingsName + ".jar"); - MINECRAFT_MAPPED_JAR = new File(extension.getUserCache(), "minecraft-" + minecraftProvider.minecraftVersion + "-mapped-" + mappingsProvider.mappingsName + "-" + mappingsProvider.mappingsVersion + ".jar"); + MINECRAFT_INTERMEDIARY_JAR = new File(extension.getUserCache(), + "minecraft-" + getIntermediaryJarVersionString(mappingsProvider.mappingsName, mappingsProvider.mappingsVersion) + ".jar"); + MINECRAFT_MAPPED_JAR = new File(extension.getUserCache(), + "minecraft-" + getNamedJarVersionString(mappingsProvider.mappingsName, mappingsProvider.mappingsVersion) + ".jar"); + } + + private String getNamedJarVersionString(String mappingsName, String mappingsVersion) { + return minecraftProvider.minecraftVersion + "-mapped-" + mappingsName + "-" + mappingsVersion; + } + + private String getIntermediaryJarVersionString(String mappingsName, String mappingsVersion) { + return minecraftProvider.minecraftVersion + "-intermediary-" + mappingsName + "-" + mappingsVersion; } public Collection getMapperPaths() { diff --git a/src/main/java/net/fabricmc/loom/task/CleanLoomMappings.java b/src/main/java/net/fabricmc/loom/task/CleanLoomMappings.java index f2121b6..2310a8a 100644 --- a/src/main/java/net/fabricmc/loom/task/CleanLoomMappings.java +++ b/src/main/java/net/fabricmc/loom/task/CleanLoomMappings.java @@ -36,14 +36,12 @@ import net.fabricmc.loom.util.DeletingFileVisitor; public class CleanLoomMappings extends AbstractLoomTask { @TaskAction public void run() { - Project project = this.getProject(); - LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); - extension.getMappingsProvider().MAPPINGS_TINY.delete(); - extension.getMappingsProvider().MAPPINGS_TINY_BASE.delete(); - extension.getMinecraftMappedProvider().getIntermediaryJar().delete(); - extension.getMinecraftMappedProvider().getMappedJar().delete(); - try { + Project project = this.getProject(); + LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); + extension.getMappingsProvider().clean(); + extension.getMinecraftMappedProvider().getIntermediaryJar().delete(); + extension.getMinecraftMappedProvider().getMappedJar().delete(); Files.walkFileTree(extension.getRootProjectBuildCache().toPath(), new DeletingFileVisitor()); } catch (IOException e) { throw new RuntimeException(e); diff --git a/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java b/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java index 35ef071..b965770 100644 --- a/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java +++ b/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java @@ -24,27 +24,41 @@ package net.fabricmc.loom.task; +import java.io.BufferedReader; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; +import java.net.URL; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.function.BiFunction; +import com.google.common.net.UrlEscapers; +import org.apache.commons.io.FileUtils; import org.cadixdev.lorenz.MappingSet; import org.cadixdev.lorenz.io.MappingsReader; +import org.cadixdev.lorenz.model.ClassMapping; +import org.cadixdev.lorenz.model.Mapping; import org.cadixdev.mercury.Mercury; import org.cadixdev.mercury.remapper.MercuryRemapper; import org.gradle.api.Project; import org.gradle.api.tasks.TaskAction; import net.fabricmc.loom.LoomGradleExtension; -import net.fabricmc.loom.util.Constants; -import net.fabricmc.loom.util.Version; -import net.fabricmc.mappings.ClassEntry; -import net.fabricmc.mappings.EntryTriple; -import net.fabricmc.mappings.FieldEntry; -import net.fabricmc.mappings.Mappings; -import net.fabricmc.mappings.MethodEntry; +import net.fabricmc.loom.providers.MappingsProvider; +import net.fabricmc.loom.providers.MinecraftMappedProvider; +import net.fabricmc.loom.util.SourceRemapper; +import net.fabricmc.mapping.tree.ClassDef; +import net.fabricmc.mapping.tree.Descriptored; +import net.fabricmc.mapping.tree.FieldDef; +import net.fabricmc.mapping.tree.MethodDef; +import net.fabricmc.mapping.tree.TinyMappingFactory; +import net.fabricmc.mapping.tree.TinyTree; public class MigrateMappingsTask extends AbstractLoomTask { @TaskAction @@ -55,75 +69,95 @@ public class MigrateMappingsTask extends AbstractLoomTask { project.getLogger().lifecycle(":loading mappings"); - File mappingsFile = null; + String inputDir = (String) properties.get("inputDir"); + if (inputDir == null) inputDir = "src/main/java"; + String outputDir = (String) properties.get("outputDir"); + if (outputDir == null) outputDir = "remappedSrc"; + String officialMappingsVersion = (String) properties.get("targetMappings"); + String localMappingsPath = (String) properties.get("targetLocalMappings"); - if (properties.containsKey("targetMappingsFile")) { - mappingsFile = new File((String) properties.get("targetMappingsFile")); - } else if (properties.containsKey("targetMappingsArtifact")) { - String[] artifactName = ((String) properties.get("targetMappingsArtifact")).split(":"); - - if (artifactName.length != 3) { - throw new RuntimeException("Invalid artifact name: " + properties.get("targetMappingsArtifact")); - } - - String mappingsName = artifactName[0] + "." + artifactName[1]; - - Version v = new Version(artifactName[2]); - String minecraftVersion = v.getMinecraftVersion(); - String mappingsVersion = v.getMappingsVersion(); - - mappingsFile = new File(extension.getMappingsProvider().MAPPINGS_DIR, mappingsName + "-tiny-" + minecraftVersion + "-" + mappingsVersion); + if (officialMappingsVersion != null && localMappingsPath != null) { + throw new IllegalArgumentException("targetMappings and targetLocalMappings are mutually exclusive;" + + " you either specify an official yarn mappings version with targetMappings, " + + "or a local one with targetLocalMappings."); } - if (mappingsFile == null || !mappingsFile.exists()) { - throw new RuntimeException("Could not find mappings file: " + (mappingsFile != null ? mappingsFile : "null")); + if (officialMappingsVersion == null && localMappingsPath == null) { + throw new IllegalArgumentException("You must specify a new mappings version with -PtargetMappings (or local mappings with -PtargetLocalMappings)."); } - if (!properties.containsKey("inputDir") || !properties.containsKey("outputDir")) { - throw new RuntimeException("Must specify input and output dir!"); + boolean useLocalMappings = localMappingsPath != null; + + if (useLocalMappings && !Files.exists(Paths.get(localMappingsPath))) { + throw new IllegalArgumentException("Can't find local mappings in specified location: " + localMappingsPath); } - File inputDir = new File((String) properties.get("inputDir")); - File outputDir = new File((String) properties.get("outputDir")); + String targetMappingsName = useLocalMappings ? localMappingsPath : officialMappingsVersion; - if (!inputDir.exists() || !inputDir.isDirectory()) { - throw new RuntimeException("Could not find input directory: " + inputDir); + Path inputDirPath = Paths.get(System.getProperty("user.dir"), inputDir); + Path outputDirPath = Paths.get(System.getProperty("user.dir"), outputDir); + + if (!Files.exists(inputDirPath) || !Files.isDirectory(inputDirPath)) { + throw new IllegalArgumentException("Could not find input directory: " + inputDirPath.toAbsolutePath()); } - if (!outputDir.exists()) { - if (!outputDir.mkdirs()) { - throw new RuntimeException("Could not create output directory:" + outputDir); + Files.createDirectories(outputDirPath); + + MappingsProvider mappingsProvider = extension.getMappingsProvider(); + + try { + TinyTree currentMappings = mappingsProvider.getMappings(); + TinyTree targetMappings = getMappings(project, targetMappingsName, useLocalMappings); + migrateMappings(project, extension.getMinecraftMappedProvider(), inputDirPath, outputDirPath, currentMappings, targetMappings, extension); + project.getLogger().lifecycle(":remapped project written to " + outputDirPath.toAbsolutePath()); + } catch (IOException e) { + throw new IllegalArgumentException("Could not find mappings for version " + officialMappingsVersion, e); + } + } + + private TinyTree getMappings(Project project, String mappingsVersionOrPath, boolean useLocalMappings) throws IOException { + Path migrateMappingsDir = Files.createTempDirectory("migrate"); + Path localMappingsOfVersion = migrateMappingsDir.resolve(mappingsVersionOrPath + ".tiny"); + + if (!Files.exists(localMappingsOfVersion)) { + if (useLocalMappings) { + Files.copy(Paths.get(mappingsVersionOrPath), localMappingsOfVersion); + } else { + String versionRelativePath = UrlEscapers.urlFragmentEscaper().escape(mappingsVersionOrPath); + String artifactUrl = "https://maven.fabricmc.net/net/fabricmc/yarn/" + versionRelativePath + "/yarn-" + versionRelativePath + ".jar"; + File mappingsJar = File.createTempFile("migrateMappingsJar", ".jar"); + project.getLogger().lifecycle(":downloading new mappings from " + artifactUrl); + FileUtils.copyURLToFile(new URL(artifactUrl), mappingsJar); + + try (FileSystem jar = FileSystems.newFileSystem(mappingsJar.toPath(), null)) { + if (!Files.exists(migrateMappingsDir)) Files.createDirectory(migrateMappingsDir); + MappingsProvider.extractMappings(jar, localMappingsOfVersion); + } } } - Mappings sourceMappings = extension.getMappingsProvider().getMappings(); - Mappings targetMappings; - - try (FileInputStream stream = new FileInputStream(mappingsFile)) { - targetMappings = net.fabricmc.mappings.MappingsProvider.readTinyMappings(stream, false); + try (BufferedReader reader = Files.newBufferedReader(localMappingsOfVersion)) { + return TinyMappingFactory.loadWithDetection(reader); } + } + private static void migrateMappings(Project project, MinecraftMappedProvider minecraftMappedProvider, + Path inputDir, Path outputDir, TinyTree currentMappings, TinyTree targetMappings, LoomGradleExtension extension + ) throws IOException { project.getLogger().lifecycle(":joining mappings"); - MappingSet mappingSet = new MappingsJoiner(sourceMappings, targetMappings, "intermediary", "named").read(); + MappingSet mappingSet = new MappingsJoiner(currentMappings, targetMappings, + "intermediary", "named").read(); project.getLogger().lifecycle(":remapping"); - Mercury mercury = new Mercury(); + Mercury mercury = SourceRemapper.createMercuryWithClassPath(project, false); - for (File file : project.getConfigurations().getByName(Constants.MINECRAFT_DEPENDENCIES).getFiles()) { - mercury.getClassPath().add(file.toPath()); - } - - for (File file : project.getConfigurations().getByName("compileClasspath").getFiles()) { - mercury.getClassPath().add(file.toPath()); - } - - mercury.getClassPath().add(extension.getMinecraftMappedProvider().MINECRAFT_MAPPED_JAR.toPath()); - mercury.getClassPath().add(extension.getMinecraftMappedProvider().MINECRAFT_INTERMEDIARY_JAR.toPath()); + mercury.getClassPath().add(minecraftMappedProvider.MINECRAFT_MAPPED_JAR.toPath()); + mercury.getClassPath().add(minecraftMappedProvider.MINECRAFT_INTERMEDIARY_JAR.toPath()); mercury.getProcessors().add(MercuryRemapper.create(mappingSet)); try { - mercury.rewrite(inputDir.toPath(), outputDir.toPath()); + mercury.rewrite(inputDir, outputDir); } catch (Exception e) { project.getLogger().warn("Could not remap fully!", e); } @@ -133,10 +167,19 @@ public class MigrateMappingsTask extends AbstractLoomTask { } public static class MappingsJoiner extends MappingsReader { - private final Mappings sourceMappings, targetMappings; + private final TinyTree sourceMappings, targetMappings; private final String fromNamespace, toNamespace; - public MappingsJoiner(Mappings sourceMappings, Mappings targetMappings, String fromNamespace, String toNamespace) { + /** + * Say A is the source mappings and B is the target mappings. + * It does not map from intermediary to named but rather maps from named-A to named-B, by matching intermediary names. + * It goes through all of the intermediary names of A, and for every such intermediary name, call it I, + * matches the named mapping of I in A, with the named mapping of I in B. + * As you might imagine, this requires intermediary mappings to be stable across all versions. + * Since we only use intermediary names (and not descriptors) to match, and intermediary names are unique, + * this will migrate methods that have had their signature changed too. + */ + public MappingsJoiner(TinyTree sourceMappings, TinyTree targetMappings, String fromNamespace, String toNamespace) { this.sourceMappings = sourceMappings; this.targetMappings = targetMappings; this.fromNamespace = fromNamespace; @@ -144,40 +187,51 @@ public class MigrateMappingsTask extends AbstractLoomTask { } @Override - public MappingSet read(MappingSet mappings) throws IOException { - Map targetClasses = new HashMap<>(); - Map targetFields = new HashMap<>(); - Map targetMethods = new HashMap<>(); + public MappingSet read(MappingSet mappings) { + Map targetClasses = new HashMap<>(); + Map targetFields = new HashMap<>(); + Map targetMethods = new HashMap<>(); - targetMappings.getClassEntries().forEach((c) -> targetClasses.put(c.get(fromNamespace), c)); - targetMappings.getFieldEntries().forEach((c) -> targetFields.put(c.get(fromNamespace), c)); - targetMappings.getMethodEntries().forEach((c) -> targetMethods.put(c.get(fromNamespace), c)); + for (ClassDef newClass : targetMappings.getClasses()) { + targetClasses.put(newClass.getName(fromNamespace), newClass); - for (ClassEntry entry : sourceMappings.getClassEntries()) { - String from = entry.get(toNamespace); - String to = targetClasses.getOrDefault(entry.get(fromNamespace), entry).get(toNamespace); + for (FieldDef field : newClass.getFields()) { + targetFields.put(field.getName(fromNamespace), field); + } - mappings.getOrCreateClassMapping(from).setDeobfuscatedName(to); + for (MethodDef method : newClass.getMethods()) { + targetMethods.put(method.getName(fromNamespace), method); + } } - for (FieldEntry entry : sourceMappings.getFieldEntries()) { - EntryTriple fromEntry = entry.get(toNamespace); - EntryTriple toEntry = targetFields.getOrDefault(entry.get(fromNamespace), entry).get(toNamespace); + for (ClassDef oldClass : sourceMappings.getClasses()) { + String namedMappingOfSourceMapping = oldClass.getName(toNamespace); + String namedMappingOfTargetMapping = targetClasses.getOrDefault(oldClass.getName(fromNamespace), oldClass).getName(toNamespace); - mappings.getOrCreateClassMapping(fromEntry.getOwner()).getOrCreateFieldMapping(fromEntry.getName(), fromEntry.getDesc()).setDeobfuscatedName(toEntry.getName()); - } + ClassMapping classMapping = mappings.getOrCreateClassMapping(namedMappingOfSourceMapping).setDeobfuscatedName(namedMappingOfTargetMapping); - for (MethodEntry entry : sourceMappings.getMethodEntries()) { - EntryTriple fromEntry = entry.get(toNamespace); - EntryTriple toEntry = targetMethods.getOrDefault(entry.get(fromNamespace), entry).get(toNamespace); - - mappings.getOrCreateClassMapping(fromEntry.getOwner()).getOrCreateMethodMapping(fromEntry.getName(), fromEntry.getDesc()).setDeobfuscatedName(toEntry.getName()); + mapMembers(oldClass.getFields(), targetFields, classMapping::getOrCreateFieldMapping); + mapMembers(oldClass.getMethods(), targetMethods, classMapping::getOrCreateMethodMapping); } return mappings; } + private void mapMembers(Collection oldMembers, Map newMembers, + BiFunction mapper) { + for (T oldMember : oldMembers) { + String oldName = oldMember.getName(toNamespace); + String oldDescriptor = oldMember.getDescriptor(toNamespace); + // We only use the intermediary name (and not the descriptor) because every method has a unique intermediary name + String newName = newMembers.getOrDefault(oldMember.getName(fromNamespace), oldMember).getName(toNamespace); + + mapper.apply(oldName, oldDescriptor).setDeobfuscatedName(newName); + } + } + @Override - public void close() throws IOException { } + public void close() { + } } } + diff --git a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java index 3936fc6..446702f 100644 --- a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java +++ b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java @@ -76,16 +76,16 @@ public class RemapJarTask extends Jar { String toM = "intermediary"; Set classpathFiles = new LinkedHashSet<>( - project.getConfigurations().getByName("compileClasspath").getFiles() + project.getConfigurations().getByName("compileClasspath").getFiles() ); Path[] classpath = classpathFiles.stream().map(File::toPath).filter((p) -> !input.equals(p) && Files.exists(p)).toArray(Path[]::new); - File mixinMapFile = mappingsProvider.MAPPINGS_MIXIN_EXPORT; + File mixinMapFile = mappingsProvider.mappingsMixinExport; Path mixinMapPath = mixinMapFile.toPath(); TinyRemapper.Builder remapperBuilder = TinyRemapper.newRemapper(); - remapperBuilder = remapperBuilder.withMappings(TinyRemapperMappingsHelper.create(mappingsProvider.getMappings(), fromM, toM)); + remapperBuilder = remapperBuilder.withMappings(TinyRemapperMappingsHelper.create(mappingsProvider.getMappings(), fromM, toM, false)); if (mixinMapFile.exists()) { remapperBuilder = remapperBuilder.withMappings(TinyUtils.createTinyMappingProvider(mixinMapPath, fromM, toM)); diff --git a/src/main/java/net/fabricmc/loom/util/Constants.java b/src/main/java/net/fabricmc/loom/util/Constants.java index c2f0eab..26aa4ff 100644 --- a/src/main/java/net/fabricmc/loom/util/Constants.java +++ b/src/main/java/net/fabricmc/loom/util/Constants.java @@ -50,4 +50,5 @@ public class Constants { public static final String MINECRAFT_NAMED = "minecraftNamed"; public static final String MINECRAFT_LINEMAPPED = "minecraftLinemapped"; public static final String MAPPINGS = "mappings"; + public static final String MAPPINGS_FINAL = "mappingsFinal"; } diff --git a/src/main/java/net/fabricmc/loom/util/MapJarsTiny.java b/src/main/java/net/fabricmc/loom/util/MapJarsTiny.java index 2f23e6f..3e67192 100644 --- a/src/main/java/net/fabricmc/loom/util/MapJarsTiny.java +++ b/src/main/java/net/fabricmc/loom/util/MapJarsTiny.java @@ -56,7 +56,11 @@ public class MapJarsTiny { project.getLogger().lifecycle(":remapping minecraft (TinyRemapper, " + fromM + " -> " + toM + ")"); - TinyRemapper remapper = TinyRemapper.newRemapper().withMappings(TinyRemapperMappingsHelper.create(mappingsProvider.getMappings(), fromM, toM)).renameInvalidLocals(true).rebuildSourceFilenames(true).build(); + TinyRemapper remapper = TinyRemapper.newRemapper() + .withMappings(TinyRemapperMappingsHelper.create(mappingsProvider.getMappings(), fromM, toM, true)) + .renameInvalidLocals(true) + .rebuildSourceFilenames(true) + .build(); try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(output).build()) { outputConsumer.addNonClassFiles(input); @@ -64,7 +68,7 @@ public class MapJarsTiny { remapper.readInputs(input); remapper.apply(outputConsumer); } catch (Exception e) { - throw new RuntimeException("Failed to remap JAR", e); + throw new RuntimeException("Failed to remap JAR " + input + " with mappings from " + mappingsProvider.tinyMappings, e); } finally { remapper.finish(); } diff --git a/src/main/java/net/fabricmc/loom/util/ModProcessor.java b/src/main/java/net/fabricmc/loom/util/ModProcessor.java index cccd2b4..09c746f 100644 --- a/src/main/java/net/fabricmc/loom/util/ModProcessor.java +++ b/src/main/java/net/fabricmc/loom/util/ModProcessor.java @@ -41,13 +41,12 @@ import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import org.apache.commons.io.IOUtils; +import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; import org.zeroturnaround.zip.ZipUtil; import org.zeroturnaround.zip.commons.FileUtils; import org.zeroturnaround.zip.transform.StringZipEntryTransformer; import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry; -import org.gradle.api.Project; -import org.gradle.api.artifacts.Configuration; -import org.gradle.internal.impldep.aQute.lib.strings.Strings; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.providers.MappingsProvider; @@ -110,7 +109,7 @@ public class ModProcessor { JarEntry entry = parentJar.getJarEntry(fileName); if (entry == null) { - throw new RuntimeException(Strings.format("%s was not found in %s", fileName, parentJar.getName())); + throw new RuntimeException(String.format("%s was not found in %s", fileName, parentJar.getName())); } File nestedFile = new File(extension.getNestedModCache(), fileName.substring(fileName.lastIndexOf("/"))); @@ -133,7 +132,7 @@ public class ModProcessor { private static void stripNestedJars(File file) { //Strip out all contained jar info as we dont want loader to try and load the jars contained in dev. - ZipUtil.transformEntries(file, new ZipEntryTransformerEntry[]{(new ZipEntryTransformerEntry("fabric.mod.json", new StringZipEntryTransformer() { + ZipUtil.transformEntries(file, new ZipEntryTransformerEntry[] {(new ZipEntryTransformerEntry("fabric.mod.json", new StringZipEntryTransformer() { @Override protected String transform(ZipEntry zipEntry, String input) throws IOException { JsonObject json = GSON.fromJson(input, JsonObject.class); @@ -151,8 +150,6 @@ public class ModProcessor { MinecraftMappedProvider mappedProvider = extension.getMinecraftMappedProvider(); MappingsProvider mappingsProvider = extension.getMappingsProvider(); - File mappingsFile = mappingsProvider.MAPPINGS_TINY; - Path mappings = mappingsFile.toPath(); Path inputPath = input.getAbsoluteFile().toPath(); Path mc = mappedProvider.MINECRAFT_INTERMEDIARY_JAR.toPath(); Path[] mcDeps = mappedProvider.getMapperPaths().stream().map(File::toPath).toArray(Path[]::new); @@ -170,7 +167,9 @@ public class ModProcessor { project.getLogger().lifecycle(":remapping " + input.getName() + " (TinyRemapper, " + fromM + " -> " + toM + ")"); - TinyRemapper remapper = TinyRemapper.newRemapper().withMappings(TinyRemapperMappingsHelper.create(mappingsProvider.getMappings(), fromM, toM)).build(); + TinyRemapper remapper = TinyRemapper.newRemapper() + .withMappings(TinyRemapperMappingsHelper.create(mappingsProvider.getMappings(), fromM, toM, false)) + .build(); try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(Paths.get(output.getAbsolutePath())).build()) { outputConsumer.addNonClassFiles(inputPath); diff --git a/src/main/java/net/fabricmc/loom/util/SourceRemapper.java b/src/main/java/net/fabricmc/loom/util/SourceRemapper.java index 258dc84..e2eff62 100644 --- a/src/main/java/net/fabricmc/loom/util/SourceRemapper.java +++ b/src/main/java/net/fabricmc/loom/util/SourceRemapper.java @@ -31,18 +31,18 @@ import java.nio.file.Path; import org.cadixdev.lorenz.MappingSet; import org.cadixdev.lorenz.io.MappingsReader; +import org.cadixdev.lorenz.model.ClassMapping; import org.cadixdev.mercury.Mercury; import org.cadixdev.mercury.remapper.MercuryRemapper; -import org.zeroturnaround.zip.ZipUtil; import org.gradle.api.Project; +import org.zeroturnaround.zip.ZipUtil; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.providers.MappingsProvider; -import net.fabricmc.mappings.ClassEntry; -import net.fabricmc.mappings.EntryTriple; -import net.fabricmc.mappings.FieldEntry; -import net.fabricmc.mappings.Mappings; -import net.fabricmc.mappings.MethodEntry; +import net.fabricmc.mapping.tree.ClassDef; +import net.fabricmc.mapping.tree.FieldDef; +import net.fabricmc.mapping.tree.MethodDef; +import net.fabricmc.mapping.tree.TinyTree; import net.fabricmc.stitch.util.StitchUtil; public class SourceRemapper { @@ -58,7 +58,7 @@ public class SourceRemapper { MappingSet mappings = extension.getOrCreateSrcMappingCache(toNamed ? 1 : 0, () -> { try { - Mappings m = mappingsProvider.getMappings(); + TinyTree m = mappingsProvider.getMappings(); project.getLogger().lifecycle(":loading " + (toNamed ? "intermediary -> named" : "named -> intermediary") + " source mappings"); return new TinyReader(m, toNamed ? "intermediary" : "named", toNamed ? "named" : "intermediary").read(); } catch (Exception e) { @@ -69,17 +69,7 @@ public class SourceRemapper { project.getLogger().info(":remapping source jar"); Mercury mercury = extension.getOrCreateSrcMercuryCache(toNamed ? 1 : 0, () -> { - Mercury m = new Mercury(); - - for (File file : project.getConfigurations().getByName(Constants.MINECRAFT_DEPENDENCIES).getFiles()) { - m.getClassPath().add(file.toPath()); - } - - if (!toNamed) { - for (File file : project.getConfigurations().getByName("compileClasspath").getFiles()) { - m.getClassPath().add(file.toPath()); - } - } + Mercury m = createMercuryWithClassPath(project, toNamed); for (Path file : extension.getUnmappedMods()) { if (Files.isRegularFile(file)) { @@ -159,6 +149,22 @@ public class SourceRemapper { }); } + public static Mercury createMercuryWithClassPath(Project project, boolean toNamed) { + Mercury m = new Mercury(); + + for (File file : project.getConfigurations().getByName(Constants.MINECRAFT_DEPENDENCIES).getFiles()) { + m.getClassPath().add(file.toPath()); + } + + if (!toNamed) { + for (File file : project.getConfigurations().getByName("compileClasspath").getFiles()) { + m.getClassPath().add(file.toPath()); + } + } + + return m; + } + private static boolean isJavaFile(Path path) { String name = path.getFileName().toString(); // ".java" is not a valid java file @@ -166,39 +172,36 @@ public class SourceRemapper { } public static class TinyReader extends MappingsReader { - private final Mappings m; + private final TinyTree mappings; private final String from, to; - public TinyReader(Mappings m, String from, String to) { - this.m = m; + public TinyReader(TinyTree m, String from, String to) { + this.mappings = m; this.from = from; this.to = to; } @Override public MappingSet read(final MappingSet mappings) { - for (ClassEntry entry : m.getClassEntries()) { - mappings.getOrCreateClassMapping(entry.get(from)).setDeobfuscatedName(entry.get(to)); - } + for (ClassDef classDef : this.mappings.getClasses()) { + ClassMapping classMapping = mappings.getOrCreateClassMapping(classDef.getName(from)) + .setDeobfuscatedName(classDef.getName(to)); - for (FieldEntry entry : m.getFieldEntries()) { - EntryTriple fromEntry = entry.get(from); - EntryTriple toEntry = entry.get(to); + for (FieldDef field : classDef.getFields()) { + classMapping.getOrCreateFieldMapping(field.getName(from), field.getDescriptor(from)) + .setDeobfuscatedName(field.getName(to)); + } - mappings.getOrCreateClassMapping(fromEntry.getOwner()).getOrCreateFieldMapping(fromEntry.getName(), fromEntry.getDesc()).setDeobfuscatedName(toEntry.getName()); - } - - for (MethodEntry entry : m.getMethodEntries()) { - EntryTriple fromEntry = entry.get(from); - EntryTriple toEntry = entry.get(to); - - mappings.getOrCreateClassMapping(fromEntry.getOwner()).getOrCreateMethodMapping(fromEntry.getName(), fromEntry.getDesc()).setDeobfuscatedName(toEntry.getName()); + for (MethodDef method : classDef.getMethods()) { + classMapping.getOrCreateMethodMapping(method.getName(from), method.getDescriptor(from)) + .setDeobfuscatedName(method.getName(to)); + } } return mappings; } @Override - public void close() throws IOException { } + public void close() { } } } diff --git a/src/main/java/net/fabricmc/loom/util/TinyRemapperMappingsHelper.java b/src/main/java/net/fabricmc/loom/util/TinyRemapperMappingsHelper.java index 0652e52..b996402 100644 --- a/src/main/java/net/fabricmc/loom/util/TinyRemapperMappingsHelper.java +++ b/src/main/java/net/fabricmc/loom/util/TinyRemapperMappingsHelper.java @@ -24,31 +24,47 @@ package net.fabricmc.loom.util; -import net.fabricmc.mappings.ClassEntry; -import net.fabricmc.mappings.EntryTriple; -import net.fabricmc.mappings.FieldEntry; -import net.fabricmc.mappings.Mappings; -import net.fabricmc.mappings.MethodEntry; +import net.fabricmc.mapping.tree.ClassDef; +import net.fabricmc.mapping.tree.FieldDef; +import net.fabricmc.mapping.tree.LocalVariableDef; +import net.fabricmc.mapping.tree.MethodDef; +import net.fabricmc.mapping.tree.ParameterDef; +import net.fabricmc.mapping.tree.TinyTree; import net.fabricmc.tinyremapper.IMappingProvider; -import net.fabricmc.tinyremapper.MemberInstance; public class TinyRemapperMappingsHelper { private TinyRemapperMappingsHelper() { } - public static IMappingProvider create(Mappings mappings, String from, String to) { - return (classMap, fieldMap, methodMap) -> { - for (ClassEntry entry : mappings.getClassEntries()) { - classMap.put(entry.get(from), entry.get(to)); - } + private static IMappingProvider.Member memberOf(String className, String memberName, String descriptor) { + return new IMappingProvider.Member(className, memberName, descriptor); + } - for (FieldEntry entry : mappings.getFieldEntries()) { - EntryTriple fromTriple = entry.get(from); - fieldMap.put(fromTriple.getOwner() + "/" + MemberInstance.getFieldId(fromTriple.getName(), fromTriple.getDesc()), entry.get(to).getName()); - } + public static IMappingProvider create(TinyTree mappings, String from, String to, boolean remapLocalVariables) { + return (acceptor) -> { + for (ClassDef classDef : mappings.getClasses()) { + String className = classDef.getName(from); + acceptor.acceptClass(className, classDef.getName(to)); - for (MethodEntry entry : mappings.getMethodEntries()) { - EntryTriple fromTriple = entry.get(from); - methodMap.put(fromTriple.getOwner() + "/" + MemberInstance.getMethodId(fromTriple.getName(), fromTriple.getDesc()), entry.get(to).getName()); + for (FieldDef field : classDef.getFields()) { + acceptor.acceptField(memberOf(className, field.getName(from), field.getDescriptor(from)), field.getName(to)); + } + + for (MethodDef method : classDef.getMethods()) { + IMappingProvider.Member methodIdentifier = memberOf(className, method.getName(from), method.getDescriptor(from)); + acceptor.acceptMethod(methodIdentifier, method.getName(to)); + + if (remapLocalVariables) { + for (ParameterDef parameter : method.getParameters()) { + acceptor.acceptMethodArg(methodIdentifier, parameter.getLocalVariableIndex(), parameter.getName(to)); + } + + for (LocalVariableDef localVariable : method.getLocalVariables()) { + acceptor.acceptMethodVar(methodIdentifier, localVariable.getLocalVariableIndex(), + localVariable.getLocalVariableStartOffset(), localVariable.getLocalVariableTableIndex(), + localVariable.getName(to)); + } + } + } } }; } diff --git a/src/test/groovy/net/fabricmc/loom/BuildUtils.groovy b/src/test/groovy/net/fabricmc/loom/BuildUtils.groovy index 8391fec..bb2ca78 100644 --- a/src/test/groovy/net/fabricmc/loom/BuildUtils.groovy +++ b/src/test/groovy/net/fabricmc/loom/BuildUtils.groovy @@ -16,6 +16,7 @@ archivesBaseName = project.archives_base_name version = project.mod_version group = project.maven_group + minecraft { } diff --git a/src/test/groovy/net/fabricmc/loom/EmptyBuildFunctionalTest.groovy b/src/test/groovy/net/fabricmc/loom/EmptyBuildFunctionalTest.groovy index b9d6301..e42ee12 100644 --- a/src/test/groovy/net/fabricmc/loom/EmptyBuildFunctionalTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/EmptyBuildFunctionalTest.groovy @@ -35,7 +35,7 @@ class EmptyBuildFunctionalTest extends Specification { when: def result = GradleRunner.create() .withProjectDir(testProjectDir.root) - .withArguments('build') + .withArguments('build',"--stacktrace") .withPluginClasspath() .withGradleVersion("4.9") .build() diff --git a/src/test/groovy/net/fabricmc/loom/SimpleBuildFunctionalTest.groovy b/src/test/groovy/net/fabricmc/loom/SimpleBuildFunctionalTest.groovy index 3db6cb5..9706e7e 100644 --- a/src/test/groovy/net/fabricmc/loom/SimpleBuildFunctionalTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/SimpleBuildFunctionalTest.groovy @@ -45,9 +45,10 @@ class SimpleBuildFunctionalTest extends Specification { when: def result = GradleRunner.create() .withProjectDir(testProjectDir.root) - .withArguments('build') + .withArguments('build',"--stacktrace") .withPluginClasspath() .withGradleVersion("4.9") + .withDebug(true) .build() then: @@ -55,6 +56,7 @@ class SimpleBuildFunctionalTest extends Specification { where: mcVersion | yarnVersion | loaderVersion | fabricVersion + '19w45a' | '19w45a+build.2:v2' | '0.6.2+build.166' | '0.4.9+build.258-1.15' '1.14' | '1.14+build.21' | '0.4.8+build.155' | '0.3.0+build.184' '1.14.1' | '1.14.1+build.10' | '0.4.8+build.155' | '0.3.0+build.184' '1.14.2' | '1.14.2+build.7' | '0.4.8+build.155' | '0.3.0+build.184'