Support using TinyV2 mappings (#132)
This commit is contained in:
		
							parent
							
								
									baf976d3f3
								
							
						
					
					
						commit
						8e916f8fb0
					
				
					 16 changed files with 451 additions and 214 deletions
				
			
		
							
								
								
									
										13
									
								
								build.gradle
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								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' | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -114,6 +114,7 @@ public class AbstractPlugin implements Plugin<Project> { | |||
| 		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<Project> { | |||
| 		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> { | |||
| 						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> { | |||
| 				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) { | ||||
|  |  | |||
|  | @ -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<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(); | ||||
| 
 | ||||
| 		if (StaticPathWatcher.INSTANCE.hasFileChanged(mappingsPath)) { | ||||
| 			mappingsCache.remove(mappingsPath); | ||||
| 		} | ||||
| 
 | ||||
| 		SoftReference<Mappings> ref = mappingsCache.get(mappingsPath); | ||||
| 		SoftReference<TinyTree> 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); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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<Runnable> 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<File> getMapperPaths() { | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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<String, ClassEntry> targetClasses = new HashMap<>(); | ||||
| 			Map<EntryTriple, FieldEntry> targetFields = new HashMap<>(); | ||||
| 			Map<EntryTriple, MethodEntry> targetMethods = new HashMap<>(); | ||||
| 		public MappingSet read(MappingSet mappings) { | ||||
| 			Map<String, ClassDef> targetClasses = new HashMap<>(); | ||||
| 			Map<String, FieldDef> targetFields = new HashMap<>(); | ||||
| 			Map<String, MethodDef> 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 <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 | ||||
| 		public void close() throws IOException { } | ||||
| 		public void close() { | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -76,16 +76,16 @@ public class RemapJarTask extends Jar { | |||
| 		String toM = "intermediary"; | ||||
| 
 | ||||
| 		Set<File> 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)); | ||||
|  |  | |||
|  | @ -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"; | ||||
| } | ||||
|  |  | |||
|  | @ -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(); | ||||
| 			} | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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() { } | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -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)); | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		}; | ||||
| 	} | ||||
|  |  | |||
|  | @ -16,6 +16,7 @@ archivesBaseName = project.archives_base_name | |||
| version = project.mod_version | ||||
| group = project.maven_group | ||||
| 
 | ||||
| 
 | ||||
| minecraft { | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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() | ||||
|  |  | |||
|  | @ -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' | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue