Support using TinyV2 mappings (#132)

dev/0.11
Fudge 2019-11-09 21:00:36 +02:00 committed by Player
parent baf976d3f3
commit 8e916f8fb0
16 changed files with 451 additions and 214 deletions

View File

@ -39,15 +39,17 @@ dependencies {
implementation ('com.google.guava:guava:28.0-jre') implementation ('com.google.guava:guava:28.0-jre')
// game handling utils // game handling utils
implementation ('net.fabricmc:stitch:0.2.1.60') { implementation ('net.fabricmc:stitch:0.3.0.66') {
exclude module: 'enigma' exclude module: 'enigma'
} }
// tinyfile management // tinyfile management
implementation ('net.fabricmc:tiny-remapper:0.1.0.38') { implementation ('net.fabricmc:tiny-remapper:0.2.0.52') {
transitive = false 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 // decompilers
implementation ('net.fabricmc:procyon-fabric-compilertools:0.5.35.+') 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'
}
}

View File

@ -114,6 +114,7 @@ public class AbstractPlugin implements Plugin<Project> {
includeConfig.setTransitive(false); // Dont get transitive deps includeConfig.setTransitive(false); // Dont get transitive deps
project.getConfigurations().maybeCreate(Constants.MAPPINGS); project.getConfigurations().maybeCreate(Constants.MAPPINGS);
project.getConfigurations().maybeCreate(Constants.MAPPINGS_FINAL);
for (RemappedConfigurationEntry entry : Constants.MOD_COMPILE_ENTRIES) { for (RemappedConfigurationEntry entry : Constants.MOD_COMPILE_ENTRIES) {
Configuration compileModsConfig = project.getConfigurations().maybeCreate(entry.getSourceConfiguration()); Configuration compileModsConfig = project.getConfigurations().maybeCreate(entry.getSourceConfiguration());
@ -136,8 +137,8 @@ public class AbstractPlugin implements Plugin<Project> {
extendsFrom(Constants.MINECRAFT_NAMED, Constants.MINECRAFT_DEPENDENCIES); extendsFrom(Constants.MINECRAFT_NAMED, Constants.MINECRAFT_DEPENDENCIES);
extendsFrom(Constants.MINECRAFT_INTERMEDIARY, Constants.MINECRAFT_DEPENDENCIES); extendsFrom(Constants.MINECRAFT_INTERMEDIARY, Constants.MINECRAFT_DEPENDENCIES);
extendsFrom("compile", Constants.MAPPINGS); extendsFrom("compile", Constants.MAPPINGS_FINAL);
extendsFrom("annotationProcessor", Constants.MAPPINGS); extendsFrom("annotationProcessor", Constants.MAPPINGS_FINAL);
configureIDEs(); configureIDEs();
configureCompile(); configureCompile();
@ -156,8 +157,8 @@ public class AbstractPlugin implements Plugin<Project> {
project.getLogger().lifecycle(":setting java compiler args"); project.getLogger().lifecycle(":setting java compiler args");
try { try {
javaCompileTask.getOptions().getCompilerArgs().add("-AinMapFileNamedIntermediary=" + extension.getMappingsProvider().MAPPINGS_TINY.getCanonicalPath()); javaCompileTask.getOptions().getCompilerArgs().add("-AinMapFileNamedIntermediary=" + extension.getMappingsProvider().tinyMappings.getCanonicalPath());
javaCompileTask.getOptions().getCompilerArgs().add("-AoutMapFileNamedIntermediary=" + extension.getMappingsProvider().MAPPINGS_MIXIN_EXPORT.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("-AoutRefMapFile=" + new File(javaCompileTask.getDestinationDir(), extension.getRefmapName()).getCanonicalPath());
javaCompileTask.getOptions().getCompilerArgs().add("-AdefaultObfuscationEnv=named:intermediary"); javaCompileTask.getOptions().getCompilerArgs().add("-AdefaultObfuscationEnv=named:intermediary");
} catch (IOException e) { } catch (IOException e) {
@ -183,8 +184,8 @@ public class AbstractPlugin implements Plugin<Project> {
project.getLogger().warn(":configuring scala compilation processing"); project.getLogger().warn(":configuring scala compilation processing");
try { try {
task.getOptions().getCompilerArgs().add("-AinMapFileNamedIntermediary=" + extension.getMappingsProvider().MAPPINGS_TINY.getCanonicalPath()); task.getOptions().getCompilerArgs().add("-AinMapFileNamedIntermediary=" + extension.getMappingsProvider().tinyMappings.getCanonicalPath());
task.getOptions().getCompilerArgs().add("-AoutMapFileNamedIntermediary=" + extension.getMappingsProvider().MAPPINGS_MIXIN_EXPORT.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("-AoutRefMapFile=" + new File(task.getDestinationDir(), extension.getRefmapName()).getCanonicalPath());
task.getOptions().getCompilerArgs().add("-AdefaultObfuscationEnv=named:intermediary"); task.getOptions().getCompilerArgs().add("-AdefaultObfuscationEnv=named:intermediary");
} catch (IOException e) { } catch (IOException e) {

View File

@ -24,8 +24,8 @@
package net.fabricmc.loom.providers; package net.fabricmc.loom.providers;
import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference; import java.lang.ref.SoftReference;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@ -33,32 +33,32 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import net.fabricmc.loom.util.StaticPathWatcher; 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 final class MappingsCache {
public static final MappingsCache INSTANCE = new MappingsCache(); public static final MappingsCache INSTANCE = new MappingsCache();
private final Map<Path, SoftReference<Mappings>> mappingsCache = new HashMap<>(); private final Map<Path, SoftReference<TinyTree>> 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(); mappingsPath = mappingsPath.toAbsolutePath();
if (StaticPathWatcher.INSTANCE.hasFileChanged(mappingsPath)) { if (StaticPathWatcher.INSTANCE.hasFileChanged(mappingsPath)) {
mappingsCache.remove(mappingsPath); mappingsCache.remove(mappingsPath);
} }
SoftReference<Mappings> ref = mappingsCache.get(mappingsPath); SoftReference<TinyTree> ref = mappingsCache.get(mappingsPath);
if (ref != null && ref.get() != null) { if (ref != null && ref.get() != null) {
return ref.get(); return ref.get();
} else { } else {
try (InputStream stream = Files.newInputStream(mappingsPath)) { try (BufferedReader reader = Files.newBufferedReader(mappingsPath)) {
Mappings mappings = net.fabricmc.mappings.MappingsProvider.readTinyMappings(stream, false); TinyTree mappings = TinyMappingFactory.loadWithDetection(reader);
ref = new SoftReference<>(mappings); ref = new SoftReference<>(mappings);
mappingsCache.put(mappingsPath, ref); mappingsCache.put(mappingsPath, ref);
return mappings; return mappings;
} catch (IOException e) {
throw new RuntimeException(e);
} }
} }
} }

View File

@ -24,25 +24,38 @@
package net.fabricmc.loom.providers; package net.fabricmc.loom.providers;
import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.URL;
import java.nio.file.FileSystem; import java.nio.file.FileSystem;
import java.nio.file.FileSystems; import java.nio.file.FileSystems;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.function.Consumer; 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.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.LoomGradleExtension;
import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.DependencyProvider; import net.fabricmc.loom.util.DependencyProvider;
import net.fabricmc.loom.util.DownloadUtil;
import net.fabricmc.loom.util.Version; 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.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 class MappingsProvider extends DependencyProvider {
public MinecraftMappedProvider mappedProvider; public MinecraftMappedProvider mappedProvider;
@ -50,13 +63,21 @@ public class MappingsProvider extends DependencyProvider {
public String minecraftVersion; public String minecraftVersion;
public String mappingsVersion; public String mappingsVersion;
public File MAPPINGS_DIR; private Path mappingsDir;
public File MAPPINGS_TINY_BASE; private Path mappingsStepsDir;
public File MAPPINGS_TINY; // The mappings that gradle gives us
public File MAPPINGS_MIXIN_EXPORT; private Path baseTinyMappings;
// The mappings we use in practice
public File tinyMappings;
public File tinyMappingsJar;
public File mappingsMixinExport;
public Mappings getMappings() throws IOException { public void clean() throws IOException {
return MappingsCache.INSTANCE.get(MAPPINGS_TINY.toPath()); FileUtils.deleteDirectory(mappingsDir.toFile());
}
public TinyTree getMappings() throws IOException {
return MappingsCache.INSTANCE.get(tinyMappings.toPath());
} }
@Override @Override
@ -66,50 +87,166 @@ public class MappingsProvider extends DependencyProvider {
project.getLogger().lifecycle(":setting up mappings (" + dependency.getDependency().getName() + " " + dependency.getResolvedVersion() + ")"); project.getLogger().lifecycle(":setting up mappings (" + dependency.getDependency().getName() + " " + dependency.getResolvedVersion() + ")");
String version = 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); Version mappingsVersion = new Version(version);
this.minecraftVersion = mappingsVersion.getMinecraftVersion(); this.minecraftVersion = mappingsVersion.getMinecraftVersion();
this.mappingsVersion = mappingsVersion.getMappingsVersion(); this.mappingsVersion = mappingsVersion.getMappingsVersion() + (isV2 ? "-v2" : "");
initFiles(project); initFiles(project);
if (!MAPPINGS_DIR.exists()) { Files.createDirectories(mappingsDir);
MAPPINGS_DIR.mkdir(); 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()) { tinyMappings = mappingsDir.resolve(StringUtils.removeSuffix(mappingsJar.getName(), ".jar") + ".tiny").toFile();
if (!MAPPINGS_TINY_BASE.exists()) { tinyMappingsJar = new File(extension.getUserCache(), mappingsJar.getName().replace(".jar", "-" + jarClassifier + ".jar"));
project.getLogger().lifecycle(":extracting " + mappingsJar.getName());
try (FileSystem fileSystem = FileSystems.newFileSystem(mappingsJar.toPath(), null)) { if (!tinyMappings.exists()) {
Path fileToExtract = fileSystem.getPath("mappings/mappings.tiny"); storeMappings(project, minecraftProvider, mappingsJar.toPath());
Files.copy(fileToExtract, MAPPINGS_TINY_BASE.toPath());
}
} }
if (MAPPINGS_TINY.exists()) { if (!tinyMappingsJar.exists()) {
MAPPINGS_TINY.delete(); ZipUtil.pack(new ZipEntrySource[] {new FileSource("mappings/mappings.tiny", tinyMappings)}, tinyMappingsJar);
} }
project.getLogger().lifecycle(":populating field names"); addDependency(tinyMappingsJar, project, Constants.MAPPINGS_FINAL);
new CommandProposeFieldNames().run(new String[]{minecraftProvider.MINECRAFT_MERGED_JAR.getAbsolutePath(), MAPPINGS_TINY_BASE.getAbsolutePath(), MAPPINGS_TINY.getAbsolutePath()});
}
mappedProvider = new MinecraftMappedProvider(); mappedProvider = new MinecraftMappedProvider();
mappedProvider.initFiles(project, minecraftProvider, this); mappedProvider.initFiles(project, minecraftProvider, this);
mappedProvider.provide(dependency, project, extension, postPopulationScheduler); mappedProvider.provide(dependency, project, extension, postPopulationScheduler);
} }
public void initFiles(Project project) { private void storeMappings(Project project, MinecraftProvider minecraftProvider, Path yarnJar) throws IOException {
LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); project.getLogger().lifecycle(":extracting " + yarnJar.getFileName());
MAPPINGS_DIR = new File(extension.getUserCache(), "mappings");
MAPPINGS_TINY_BASE = new File(MAPPINGS_DIR, mappingsName + "-tiny-" + minecraftVersion + "-" + mappingsVersion + "-base"); try (FileSystem fileSystem = FileSystems.newFileSystem(yarnJar, null)) {
MAPPINGS_TINY = new File(MAPPINGS_DIR, mappingsName + "-tiny-" + minecraftVersion + "-" + mappingsVersion); extractMappings(fileSystem, baseTinyMappings);
MAPPINGS_MIXIN_EXPORT = new File(extension.getProjectBuildCache(), "mixin-map-" + minecraftVersion + "-" + mappingsVersion + ".tiny"); }
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 @Override

View File

@ -39,11 +39,14 @@ public class MinecraftMappedProvider extends DependencyProvider {
public File MINECRAFT_MAPPED_JAR; public File MINECRAFT_MAPPED_JAR;
public File MINECRAFT_INTERMEDIARY_JAR; public File MINECRAFT_INTERMEDIARY_JAR;
public MinecraftMappedProvider() {
}
private MinecraftProvider minecraftProvider; private MinecraftProvider minecraftProvider;
@Override @Override
public void provide(DependencyInfo dependency, Project project, LoomGradleExtension extension, Consumer<Runnable> postPopulationScheduler) throws Exception { public void provide(DependencyInfo dependency, Project project, LoomGradleExtension extension, Consumer<Runnable> postPopulationScheduler) throws Exception {
if (!extension.getMappingsProvider().MAPPINGS_TINY.exists()) { if (!extension.getMappingsProvider().tinyMappings.exists()) {
throw new RuntimeException("mappings file not found"); throw new RuntimeException("mappings file not found");
} }
@ -67,17 +70,28 @@ public class MinecraftMappedProvider extends DependencyProvider {
throw new RuntimeException("mapped jar not found"); throw new RuntimeException("mapped jar not found");
} }
String version = minecraftProvider.minecraftVersion + "-mapped-" + extension.getMappingsProvider().mappingsName + "-" + extension.getMappingsProvider().mappingsVersion; MappingsProvider mappingsProvider = extension.getMappingsProvider();
project.getDependencies().add(Constants.MINECRAFT_NAMED, project.getDependencies().module("net.minecraft:minecraft:" + version)); project.getDependencies().add(Constants.MINECRAFT_NAMED,
version = minecraftProvider.minecraftVersion + "-intermediary-" + extension.getMappingsProvider().mappingsName; project.getDependencies().module("net.minecraft:minecraft:" + getNamedJarVersionString(mappingsProvider.mappingsName, mappingsProvider.mappingsVersion)));
project.getDependencies().add(Constants.MINECRAFT_INTERMEDIARY, project.getDependencies().module("net.minecraft:minecraft:" + version)); 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) { public void initFiles(Project project, MinecraftProvider minecraftProvider, MappingsProvider mappingsProvider) {
LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class);
this.minecraftProvider = minecraftProvider; this.minecraftProvider = minecraftProvider;
MINECRAFT_INTERMEDIARY_JAR = new File(extension.getUserCache(), "minecraft-" + minecraftProvider.minecraftVersion + "-intermediary-" + mappingsProvider.mappingsName + ".jar"); MINECRAFT_INTERMEDIARY_JAR = new File(extension.getUserCache(),
MINECRAFT_MAPPED_JAR = new File(extension.getUserCache(), "minecraft-" + minecraftProvider.minecraftVersion + "-mapped-" + mappingsProvider.mappingsName + "-" + mappingsProvider.mappingsVersion + ".jar"); "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<File> getMapperPaths() { public Collection<File> getMapperPaths() {

View File

@ -36,14 +36,12 @@ import net.fabricmc.loom.util.DeletingFileVisitor;
public class CleanLoomMappings extends AbstractLoomTask { public class CleanLoomMappings extends AbstractLoomTask {
@TaskAction @TaskAction
public void run() { public void run() {
try {
Project project = this.getProject(); Project project = this.getProject();
LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class);
extension.getMappingsProvider().MAPPINGS_TINY.delete(); extension.getMappingsProvider().clean();
extension.getMappingsProvider().MAPPINGS_TINY_BASE.delete();
extension.getMinecraftMappedProvider().getIntermediaryJar().delete(); extension.getMinecraftMappedProvider().getIntermediaryJar().delete();
extension.getMinecraftMappedProvider().getMappedJar().delete(); extension.getMinecraftMappedProvider().getMappedJar().delete();
try {
Files.walkFileTree(extension.getRootProjectBuildCache().toPath(), new DeletingFileVisitor()); Files.walkFileTree(extension.getRootProjectBuildCache().toPath(), new DeletingFileVisitor());
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);

View File

@ -24,27 +24,41 @@
package net.fabricmc.loom.task; package net.fabricmc.loom.task;
import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; 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.HashMap;
import java.util.Map; 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.MappingSet;
import org.cadixdev.lorenz.io.MappingsReader; 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.Mercury;
import org.cadixdev.mercury.remapper.MercuryRemapper; import org.cadixdev.mercury.remapper.MercuryRemapper;
import org.gradle.api.Project; import org.gradle.api.Project;
import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.TaskAction;
import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.providers.MappingsProvider;
import net.fabricmc.loom.util.Version; import net.fabricmc.loom.providers.MinecraftMappedProvider;
import net.fabricmc.mappings.ClassEntry; import net.fabricmc.loom.util.SourceRemapper;
import net.fabricmc.mappings.EntryTriple; import net.fabricmc.mapping.tree.ClassDef;
import net.fabricmc.mappings.FieldEntry; import net.fabricmc.mapping.tree.Descriptored;
import net.fabricmc.mappings.Mappings; import net.fabricmc.mapping.tree.FieldDef;
import net.fabricmc.mappings.MethodEntry; import net.fabricmc.mapping.tree.MethodDef;
import net.fabricmc.mapping.tree.TinyMappingFactory;
import net.fabricmc.mapping.tree.TinyTree;
public class MigrateMappingsTask extends AbstractLoomTask { public class MigrateMappingsTask extends AbstractLoomTask {
@TaskAction @TaskAction
@ -55,75 +69,95 @@ public class MigrateMappingsTask extends AbstractLoomTask {
project.getLogger().lifecycle(":loading mappings"); 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")) { if (officialMappingsVersion != null && localMappingsPath != null) {
mappingsFile = new File((String) properties.get("targetMappingsFile")); throw new IllegalArgumentException("targetMappings and targetLocalMappings are mutually exclusive;"
} else if (properties.containsKey("targetMappingsArtifact")) { + " you either specify an official yarn mappings version with targetMappings, "
String[] artifactName = ((String) properties.get("targetMappingsArtifact")).split(":"); + "or a local one with targetLocalMappings.");
if (artifactName.length != 3) {
throw new RuntimeException("Invalid artifact name: " + properties.get("targetMappingsArtifact"));
} }
String mappingsName = artifactName[0] + "." + artifactName[1]; if (officialMappingsVersion == null && localMappingsPath == null) {
throw new IllegalArgumentException("You must specify a new mappings version with -PtargetMappings (or local mappings with -PtargetLocalMappings).");
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 (mappingsFile == null || !mappingsFile.exists()) { boolean useLocalMappings = localMappingsPath != null;
throw new RuntimeException("Could not find mappings file: " + (mappingsFile != null ? mappingsFile : "null"));
if (useLocalMappings && !Files.exists(Paths.get(localMappingsPath))) {
throw new IllegalArgumentException("Can't find local mappings in specified location: " + localMappingsPath);
} }
if (!properties.containsKey("inputDir") || !properties.containsKey("outputDir")) { String targetMappingsName = useLocalMappings ? localMappingsPath : officialMappingsVersion;
throw new RuntimeException("Must specify input and output dir!");
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());
} }
File inputDir = new File((String) properties.get("inputDir")); Files.createDirectories(outputDirPath);
File outputDir = new File((String) properties.get("outputDir"));
if (!inputDir.exists() || !inputDir.isDirectory()) { MappingsProvider mappingsProvider = extension.getMappingsProvider();
throw new RuntimeException("Could not find input directory: " + inputDir);
}
if (!outputDir.exists()) { try {
if (!outputDir.mkdirs()) { TinyTree currentMappings = mappingsProvider.getMappings();
throw new RuntimeException("Could not create output directory:" + outputDir); 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);
} }
} }
Mappings sourceMappings = extension.getMappingsProvider().getMappings(); private TinyTree getMappings(Project project, String mappingsVersionOrPath, boolean useLocalMappings) throws IOException {
Mappings targetMappings; Path migrateMappingsDir = Files.createTempDirectory("migrate");
Path localMappingsOfVersion = migrateMappingsDir.resolve(mappingsVersionOrPath + ".tiny");
try (FileInputStream stream = new FileInputStream(mappingsFile)) { if (!Files.exists(localMappingsOfVersion)) {
targetMappings = net.fabricmc.mappings.MappingsProvider.readTinyMappings(stream, false); 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);
}
}
} }
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"); 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"); 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(minecraftMappedProvider.MINECRAFT_MAPPED_JAR.toPath());
mercury.getClassPath().add(file.toPath()); mercury.getClassPath().add(minecraftMappedProvider.MINECRAFT_INTERMEDIARY_JAR.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.getProcessors().add(MercuryRemapper.create(mappingSet)); mercury.getProcessors().add(MercuryRemapper.create(mappingSet));
try { try {
mercury.rewrite(inputDir.toPath(), outputDir.toPath()); mercury.rewrite(inputDir, outputDir);
} catch (Exception e) { } catch (Exception e) {
project.getLogger().warn("Could not remap fully!", e); project.getLogger().warn("Could not remap fully!", e);
} }
@ -133,10 +167,19 @@ public class MigrateMappingsTask extends AbstractLoomTask {
} }
public static class MappingsJoiner extends MappingsReader { public static class MappingsJoiner extends MappingsReader {
private final Mappings sourceMappings, targetMappings; private final TinyTree sourceMappings, targetMappings;
private final String fromNamespace, toNamespace; 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.sourceMappings = sourceMappings;
this.targetMappings = targetMappings; this.targetMappings = targetMappings;
this.fromNamespace = fromNamespace; this.fromNamespace = fromNamespace;
@ -144,40 +187,51 @@ public class MigrateMappingsTask extends AbstractLoomTask {
} }
@Override @Override
public MappingSet read(MappingSet mappings) throws IOException { public MappingSet read(MappingSet mappings) {
Map<String, ClassEntry> targetClasses = new HashMap<>(); Map<String, ClassDef> targetClasses = new HashMap<>();
Map<EntryTriple, FieldEntry> targetFields = new HashMap<>(); Map<String, FieldDef> targetFields = new HashMap<>();
Map<EntryTriple, MethodEntry> targetMethods = new HashMap<>(); Map<String, MethodDef> targetMethods = new HashMap<>();
targetMappings.getClassEntries().forEach((c) -> targetClasses.put(c.get(fromNamespace), c)); for (ClassDef newClass : targetMappings.getClasses()) {
targetMappings.getFieldEntries().forEach((c) -> targetFields.put(c.get(fromNamespace), c)); targetClasses.put(newClass.getName(fromNamespace), newClass);
targetMappings.getMethodEntries().forEach((c) -> targetMethods.put(c.get(fromNamespace), c));
for (ClassEntry entry : sourceMappings.getClassEntries()) { for (FieldDef field : newClass.getFields()) {
String from = entry.get(toNamespace); targetFields.put(field.getName(fromNamespace), field);
String to = targetClasses.getOrDefault(entry.get(fromNamespace), entry).get(toNamespace);
mappings.getOrCreateClassMapping(from).setDeobfuscatedName(to);
} }
for (FieldEntry entry : sourceMappings.getFieldEntries()) { for (MethodDef method : newClass.getMethods()) {
EntryTriple fromEntry = entry.get(toNamespace); targetMethods.put(method.getName(fromNamespace), method);
EntryTriple toEntry = targetFields.getOrDefault(entry.get(fromNamespace), entry).get(toNamespace); }
mappings.getOrCreateClassMapping(fromEntry.getOwner()).getOrCreateFieldMapping(fromEntry.getName(), fromEntry.getDesc()).setDeobfuscatedName(toEntry.getName());
} }
for (MethodEntry entry : sourceMappings.getMethodEntries()) { for (ClassDef oldClass : sourceMappings.getClasses()) {
EntryTriple fromEntry = entry.get(toNamespace); String namedMappingOfSourceMapping = oldClass.getName(toNamespace);
EntryTriple toEntry = targetMethods.getOrDefault(entry.get(fromNamespace), entry).get(toNamespace); String namedMappingOfTargetMapping = targetClasses.getOrDefault(oldClass.getName(fromNamespace), oldClass).getName(toNamespace);
mappings.getOrCreateClassMapping(fromEntry.getOwner()).getOrCreateMethodMapping(fromEntry.getName(), fromEntry.getDesc()).setDeobfuscatedName(toEntry.getName()); ClassMapping classMapping = mappings.getOrCreateClassMapping(namedMappingOfSourceMapping).setDeobfuscatedName(namedMappingOfTargetMapping);
mapMembers(oldClass.getFields(), targetFields, classMapping::getOrCreateFieldMapping);
mapMembers(oldClass.getMethods(), targetMethods, classMapping::getOrCreateMethodMapping);
} }
return mappings; return mappings;
} }
private <T extends Descriptored> void mapMembers(Collection<T> oldMembers, Map<String, T> newMembers,
BiFunction<String, String, Mapping> 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 @Override
public void close() throws IOException { } public void close() {
}
} }
} }

View File

@ -80,12 +80,12 @@ public class RemapJarTask extends Jar {
); );
Path[] classpath = classpathFiles.stream().map(File::toPath).filter((p) -> !input.equals(p) && Files.exists(p)).toArray(Path[]::new); 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(); Path mixinMapPath = mixinMapFile.toPath();
TinyRemapper.Builder remapperBuilder = TinyRemapper.newRemapper(); 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()) { if (mixinMapFile.exists()) {
remapperBuilder = remapperBuilder.withMappings(TinyUtils.createTinyMappingProvider(mixinMapPath, fromM, toM)); remapperBuilder = remapperBuilder.withMappings(TinyUtils.createTinyMappingProvider(mixinMapPath, fromM, toM));

View File

@ -50,4 +50,5 @@ public class Constants {
public static final String MINECRAFT_NAMED = "minecraftNamed"; public static final String MINECRAFT_NAMED = "minecraftNamed";
public static final String MINECRAFT_LINEMAPPED = "minecraftLinemapped"; public static final String MINECRAFT_LINEMAPPED = "minecraftLinemapped";
public static final String MAPPINGS = "mappings"; public static final String MAPPINGS = "mappings";
public static final String MAPPINGS_FINAL = "mappingsFinal";
} }

View File

@ -56,7 +56,11 @@ public class MapJarsTiny {
project.getLogger().lifecycle(":remapping minecraft (TinyRemapper, " + fromM + " -> " + toM + ")"); 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()) { try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(output).build()) {
outputConsumer.addNonClassFiles(input); outputConsumer.addNonClassFiles(input);
@ -64,7 +68,7 @@ public class MapJarsTiny {
remapper.readInputs(input); remapper.readInputs(input);
remapper.apply(outputConsumer); remapper.apply(outputConsumer);
} catch (Exception e) { } 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 { } finally {
remapper.finish(); remapper.finish();
} }

View File

@ -41,13 +41,12 @@ import com.google.gson.Gson;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import org.apache.commons.io.IOUtils; 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.ZipUtil;
import org.zeroturnaround.zip.commons.FileUtils; import org.zeroturnaround.zip.commons.FileUtils;
import org.zeroturnaround.zip.transform.StringZipEntryTransformer; import org.zeroturnaround.zip.transform.StringZipEntryTransformer;
import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry; 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.LoomGradleExtension;
import net.fabricmc.loom.providers.MappingsProvider; import net.fabricmc.loom.providers.MappingsProvider;
@ -110,7 +109,7 @@ public class ModProcessor {
JarEntry entry = parentJar.getJarEntry(fileName); JarEntry entry = parentJar.getJarEntry(fileName);
if (entry == null) { 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("/"))); File nestedFile = new File(extension.getNestedModCache(), fileName.substring(fileName.lastIndexOf("/")));
@ -133,7 +132,7 @@ public class ModProcessor {
private static void stripNestedJars(File file) { 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. //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 @Override
protected String transform(ZipEntry zipEntry, String input) throws IOException { protected String transform(ZipEntry zipEntry, String input) throws IOException {
JsonObject json = GSON.fromJson(input, JsonObject.class); JsonObject json = GSON.fromJson(input, JsonObject.class);
@ -151,8 +150,6 @@ public class ModProcessor {
MinecraftMappedProvider mappedProvider = extension.getMinecraftMappedProvider(); MinecraftMappedProvider mappedProvider = extension.getMinecraftMappedProvider();
MappingsProvider mappingsProvider = extension.getMappingsProvider(); MappingsProvider mappingsProvider = extension.getMappingsProvider();
File mappingsFile = mappingsProvider.MAPPINGS_TINY;
Path mappings = mappingsFile.toPath();
Path inputPath = input.getAbsoluteFile().toPath(); Path inputPath = input.getAbsoluteFile().toPath();
Path mc = mappedProvider.MINECRAFT_INTERMEDIARY_JAR.toPath(); Path mc = mappedProvider.MINECRAFT_INTERMEDIARY_JAR.toPath();
Path[] mcDeps = mappedProvider.getMapperPaths().stream().map(File::toPath).toArray(Path[]::new); 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 + ")"); 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()) { try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(Paths.get(output.getAbsolutePath())).build()) {
outputConsumer.addNonClassFiles(inputPath); outputConsumer.addNonClassFiles(inputPath);

View File

@ -31,18 +31,18 @@ import java.nio.file.Path;
import org.cadixdev.lorenz.MappingSet; import org.cadixdev.lorenz.MappingSet;
import org.cadixdev.lorenz.io.MappingsReader; import org.cadixdev.lorenz.io.MappingsReader;
import org.cadixdev.lorenz.model.ClassMapping;
import org.cadixdev.mercury.Mercury; import org.cadixdev.mercury.Mercury;
import org.cadixdev.mercury.remapper.MercuryRemapper; import org.cadixdev.mercury.remapper.MercuryRemapper;
import org.zeroturnaround.zip.ZipUtil;
import org.gradle.api.Project; import org.gradle.api.Project;
import org.zeroturnaround.zip.ZipUtil;
import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.providers.MappingsProvider; import net.fabricmc.loom.providers.MappingsProvider;
import net.fabricmc.mappings.ClassEntry; import net.fabricmc.mapping.tree.ClassDef;
import net.fabricmc.mappings.EntryTriple; import net.fabricmc.mapping.tree.FieldDef;
import net.fabricmc.mappings.FieldEntry; import net.fabricmc.mapping.tree.MethodDef;
import net.fabricmc.mappings.Mappings; import net.fabricmc.mapping.tree.TinyTree;
import net.fabricmc.mappings.MethodEntry;
import net.fabricmc.stitch.util.StitchUtil; import net.fabricmc.stitch.util.StitchUtil;
public class SourceRemapper { public class SourceRemapper {
@ -58,7 +58,7 @@ public class SourceRemapper {
MappingSet mappings = extension.getOrCreateSrcMappingCache(toNamed ? 1 : 0, () -> { MappingSet mappings = extension.getOrCreateSrcMappingCache(toNamed ? 1 : 0, () -> {
try { try {
Mappings m = mappingsProvider.getMappings(); TinyTree m = mappingsProvider.getMappings();
project.getLogger().lifecycle(":loading " + (toNamed ? "intermediary -> named" : "named -> intermediary") + " source mappings"); project.getLogger().lifecycle(":loading " + (toNamed ? "intermediary -> named" : "named -> intermediary") + " source mappings");
return new TinyReader(m, toNamed ? "intermediary" : "named", toNamed ? "named" : "intermediary").read(); return new TinyReader(m, toNamed ? "intermediary" : "named", toNamed ? "named" : "intermediary").read();
} catch (Exception e) { } catch (Exception e) {
@ -69,17 +69,7 @@ public class SourceRemapper {
project.getLogger().info(":remapping source jar"); project.getLogger().info(":remapping source jar");
Mercury mercury = extension.getOrCreateSrcMercuryCache(toNamed ? 1 : 0, () -> { Mercury mercury = extension.getOrCreateSrcMercuryCache(toNamed ? 1 : 0, () -> {
Mercury m = new Mercury(); Mercury m = createMercuryWithClassPath(project, toNamed);
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());
}
}
for (Path file : extension.getUnmappedMods()) { for (Path file : extension.getUnmappedMods()) {
if (Files.isRegularFile(file)) { 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) { private static boolean isJavaFile(Path path) {
String name = path.getFileName().toString(); String name = path.getFileName().toString();
// ".java" is not a valid java file // ".java" is not a valid java file
@ -166,39 +172,36 @@ public class SourceRemapper {
} }
public static class TinyReader extends MappingsReader { public static class TinyReader extends MappingsReader {
private final Mappings m; private final TinyTree mappings;
private final String from, to; private final String from, to;
public TinyReader(Mappings m, String from, String to) { public TinyReader(TinyTree m, String from, String to) {
this.m = m; this.mappings = m;
this.from = from; this.from = from;
this.to = to; this.to = to;
} }
@Override @Override
public MappingSet read(final MappingSet mappings) { public MappingSet read(final MappingSet mappings) {
for (ClassEntry entry : m.getClassEntries()) { for (ClassDef classDef : this.mappings.getClasses()) {
mappings.getOrCreateClassMapping(entry.get(from)).setDeobfuscatedName(entry.get(to)); ClassMapping classMapping = mappings.getOrCreateClassMapping(classDef.getName(from))
.setDeobfuscatedName(classDef.getName(to));
for (FieldDef field : classDef.getFields()) {
classMapping.getOrCreateFieldMapping(field.getName(from), field.getDescriptor(from))
.setDeobfuscatedName(field.getName(to));
} }
for (FieldEntry entry : m.getFieldEntries()) { for (MethodDef method : classDef.getMethods()) {
EntryTriple fromEntry = entry.get(from); classMapping.getOrCreateMethodMapping(method.getName(from), method.getDescriptor(from))
EntryTriple toEntry = entry.get(to); .setDeobfuscatedName(method.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());
} }
return mappings; return mappings;
} }
@Override @Override
public void close() throws IOException { } public void close() { }
} }
} }

View File

@ -24,31 +24,47 @@
package net.fabricmc.loom.util; package net.fabricmc.loom.util;
import net.fabricmc.mappings.ClassEntry; import net.fabricmc.mapping.tree.ClassDef;
import net.fabricmc.mappings.EntryTriple; import net.fabricmc.mapping.tree.FieldDef;
import net.fabricmc.mappings.FieldEntry; import net.fabricmc.mapping.tree.LocalVariableDef;
import net.fabricmc.mappings.Mappings; import net.fabricmc.mapping.tree.MethodDef;
import net.fabricmc.mappings.MethodEntry; import net.fabricmc.mapping.tree.ParameterDef;
import net.fabricmc.mapping.tree.TinyTree;
import net.fabricmc.tinyremapper.IMappingProvider; import net.fabricmc.tinyremapper.IMappingProvider;
import net.fabricmc.tinyremapper.MemberInstance;
public class TinyRemapperMappingsHelper { public class TinyRemapperMappingsHelper {
private TinyRemapperMappingsHelper() { } private TinyRemapperMappingsHelper() { }
public static IMappingProvider create(Mappings mappings, String from, String to) { private static IMappingProvider.Member memberOf(String className, String memberName, String descriptor) {
return (classMap, fieldMap, methodMap) -> { return new IMappingProvider.Member(className, memberName, descriptor);
for (ClassEntry entry : mappings.getClassEntries()) {
classMap.put(entry.get(from), entry.get(to));
} }
for (FieldEntry entry : mappings.getFieldEntries()) { public static IMappingProvider create(TinyTree mappings, String from, String to, boolean remapLocalVariables) {
EntryTriple fromTriple = entry.get(from); return (acceptor) -> {
fieldMap.put(fromTriple.getOwner() + "/" + MemberInstance.getFieldId(fromTriple.getName(), fromTriple.getDesc()), entry.get(to).getName()); for (ClassDef classDef : mappings.getClasses()) {
String className = classDef.getName(from);
acceptor.acceptClass(className, classDef.getName(to));
for (FieldDef field : classDef.getFields()) {
acceptor.acceptField(memberOf(className, field.getName(from), field.getDescriptor(from)), field.getName(to));
} }
for (MethodEntry entry : mappings.getMethodEntries()) { for (MethodDef method : classDef.getMethods()) {
EntryTriple fromTriple = entry.get(from); IMappingProvider.Member methodIdentifier = memberOf(className, method.getName(from), method.getDescriptor(from));
methodMap.put(fromTriple.getOwner() + "/" + MemberInstance.getMethodId(fromTriple.getName(), fromTriple.getDesc()), entry.get(to).getName()); 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));
}
}
}
} }
}; };
} }

View File

@ -16,6 +16,7 @@ archivesBaseName = project.archives_base_name
version = project.mod_version version = project.mod_version
group = project.maven_group group = project.maven_group
minecraft { minecraft {
} }

View File

@ -35,7 +35,7 @@ class EmptyBuildFunctionalTest extends Specification {
when: when:
def result = GradleRunner.create() def result = GradleRunner.create()
.withProjectDir(testProjectDir.root) .withProjectDir(testProjectDir.root)
.withArguments('build') .withArguments('build',"--stacktrace")
.withPluginClasspath() .withPluginClasspath()
.withGradleVersion("4.9") .withGradleVersion("4.9")
.build() .build()

View File

@ -45,9 +45,10 @@ class SimpleBuildFunctionalTest extends Specification {
when: when:
def result = GradleRunner.create() def result = GradleRunner.create()
.withProjectDir(testProjectDir.root) .withProjectDir(testProjectDir.root)
.withArguments('build') .withArguments('build',"--stacktrace")
.withPluginClasspath() .withPluginClasspath()
.withGradleVersion("4.9") .withGradleVersion("4.9")
.withDebug(true)
.build() .build()
then: then:
@ -55,6 +56,7 @@ class SimpleBuildFunctionalTest extends Specification {
where: where:
mcVersion | yarnVersion | loaderVersion | fabricVersion 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.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.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' '1.14.2' | '1.14.2+build.7' | '0.4.8+build.155' | '0.3.0+build.184'