Improve setup speed. (#208)
* Improve access widener remapper, now uses tiny remapper * First pass on using the new tiny remapper * Optimise source remapping
This commit is contained in:
		
							parent
							
								
									bf6fb4a95e
								
							
						
					
					
						commit
						3eff7d0fdb
					
				
					 13 changed files with 420 additions and 362 deletions
				
			
		|  | @ -47,7 +47,7 @@ dependencies { | |||
| 	} | ||||
| 
 | ||||
| 	// tinyfile management | ||||
| 	implementation ('net.fabricmc:tiny-remapper:0.2.2.66') { | ||||
| 	implementation ('net.fabricmc:tiny-remapper:0.3.0.70') { | ||||
| 		transitive = false | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -57,7 +57,6 @@ public class LoomGradleExtension { | |||
| 	public String loaderLaunchMethod; | ||||
| 	public boolean remapMod = true; | ||||
| 	public boolean autoGenIDERuns = true; | ||||
| 	public boolean extractJars = false; | ||||
| 	public String customManifest = null; | ||||
| 	public File accessWidener = null; | ||||
| 	public Function<String, Object> intermediaryUrl = mcVer -> "https://maven.fabricmc.net/net/fabricmc/intermediary/" + mcVer + "/intermediary-" + mcVer + "-v2.jar"; | ||||
|  |  | |||
|  | @ -0,0 +1,104 @@ | |||
| /* | ||||
|  * This file is part of fabric-loom, licensed under the MIT License (MIT). | ||||
|  * | ||||
|  * Copyright (c) 2016, 2017, 2018 FabricMC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in all | ||||
|  * copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| package net.fabricmc.loom.processors.dependency; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.InputStreamReader; | ||||
| import java.util.jar.JarEntry; | ||||
| import java.util.jar.JarFile; | ||||
| 
 | ||||
| import com.google.gson.JsonObject; | ||||
| 
 | ||||
| import net.fabricmc.loom.util.ModProcessor; | ||||
| 
 | ||||
| public class ModDependencyInfo { | ||||
| 	public final String group; | ||||
| 	public final String name; | ||||
| 	public final String version; | ||||
| 	public final String classifier; | ||||
| 	public final File inputFile; | ||||
| 
 | ||||
| 	public final RemapData remapData; | ||||
| 
 | ||||
| 	public ModDependencyInfo(String group, String name, String version, String classifier, File inputFile, RemapData remapData) { | ||||
| 		this.group = group; | ||||
| 		this.name = name; | ||||
| 		this.version = version; | ||||
| 		this.classifier = classifier; | ||||
| 		this.inputFile = inputFile; | ||||
| 		this.remapData = remapData; | ||||
| 	} | ||||
| 
 | ||||
| 	public String getRemappedNotation() { | ||||
| 		return String.format("%s:%s:%s@%s%s", group, name, version, remapData.mappingsSuffix, classifier); | ||||
| 	} | ||||
| 
 | ||||
| 	public String getRemappedFilename() { | ||||
| 		return String.format("%s-%s@%s", name, version, remapData.mappingsSuffix + classifier.replace(':', '-')); | ||||
| 	} | ||||
| 
 | ||||
| 	public File getRemappedOutput() { | ||||
| 		return new File(remapData.modStore, getRemappedFilename() + ".jar"); | ||||
| 	} | ||||
| 
 | ||||
| 	public File getInputFile() { | ||||
| 		return inputFile; | ||||
| 	} | ||||
| 
 | ||||
| 	public boolean requiresRemapping() { | ||||
| 		return !getRemappedOutput().exists() || inputFile.lastModified() <= 0 || inputFile.lastModified() > getRemappedOutput().lastModified(); | ||||
| 	} | ||||
| 
 | ||||
| 	public void finaliseRemapping() { | ||||
| 		getRemappedOutput().setLastModified(inputFile.lastModified()); | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public String toString() { | ||||
| 		return String.format("%s:%s:%s:%s", group, name, version, classifier); | ||||
| 	} | ||||
| 
 | ||||
| 	public String getAccessWidener() throws IOException { | ||||
| 		try (JarFile jarFile = new JarFile(getInputFile())) { | ||||
| 			JarEntry modJsonEntry = jarFile.getJarEntry("fabric.mod.json"); | ||||
| 
 | ||||
| 			if (modJsonEntry == null) { | ||||
| 				return null; | ||||
| 			} | ||||
| 
 | ||||
| 			try (InputStream inputStream = jarFile.getInputStream(modJsonEntry)) { | ||||
| 				JsonObject json = ModProcessor.GSON.fromJson(new InputStreamReader(inputStream), JsonObject.class); | ||||
| 
 | ||||
| 				if (!json.has("accessWidener")) { | ||||
| 					return null; | ||||
| 				} | ||||
| 
 | ||||
| 				return json.get("accessWidener").getAsString(); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,37 @@ | |||
| /* | ||||
|  * This file is part of fabric-loom, licensed under the MIT License (MIT). | ||||
|  * | ||||
|  * Copyright (c) 2016, 2017, 2018 FabricMC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in all | ||||
|  * copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| package net.fabricmc.loom.processors.dependency; | ||||
| 
 | ||||
| import java.io.File; | ||||
| 
 | ||||
| public class RemapData { | ||||
| 	public final String mappingsSuffix; | ||||
| 	public final File modStore; | ||||
| 
 | ||||
| 	public RemapData(String mappingsSuffix, File modStore) { | ||||
| 		this.mappingsSuffix = mappingsSuffix; | ||||
| 		this.modStore = modStore; | ||||
| 	} | ||||
| } | ||||
|  | @ -25,14 +25,19 @@ | |||
| package net.fabricmc.loom.providers; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.nio.file.Path; | ||||
| import java.util.Arrays; | ||||
| import java.util.Collection; | ||||
| import java.util.function.Consumer; | ||||
| 
 | ||||
| import org.gradle.api.Project; | ||||
| 
 | ||||
| import net.fabricmc.loom.util.TinyRemapperMappingsHelper; | ||||
| import net.fabricmc.tinyremapper.OutputConsumerPath; | ||||
| import net.fabricmc.tinyremapper.TinyRemapper; | ||||
| import net.fabricmc.loom.util.Constants; | ||||
| import net.fabricmc.loom.util.DependencyProvider; | ||||
| import net.fabricmc.loom.util.MapJarsTiny; | ||||
| 
 | ||||
| public class MinecraftMappedProvider extends DependencyProvider { | ||||
| 	private File minecraftMappedJar; | ||||
|  | @ -66,7 +71,7 @@ public class MinecraftMappedProvider extends DependencyProvider { | |||
| 			} | ||||
| 
 | ||||
| 			try { | ||||
| 				new MapJarsTiny().mapJars(minecraftProvider, this, this.minecraftMappedJar, this.minecraftIntermediaryJar, getProject()); | ||||
| 				mapMinecraftJar(); | ||||
| 			} catch (Throwable t) { | ||||
| 				//Cleanup some some things that may be in a bad state now | ||||
| 				minecraftMappedJar.delete(); | ||||
|  | @ -83,6 +88,47 @@ public class MinecraftMappedProvider extends DependencyProvider { | |||
| 		addDependencies(dependency, postPopulationScheduler); | ||||
| 	} | ||||
| 
 | ||||
| 	private void mapMinecraftJar() throws IOException { | ||||
| 		String fromM = "official"; | ||||
| 
 | ||||
| 		MappingsProvider mappingsProvider = getExtension().getMappingsProvider(); | ||||
| 
 | ||||
| 		Path input = minecraftProvider.getMergedJar().toPath(); | ||||
| 		Path outputMapped = minecraftMappedJar.toPath(); | ||||
| 		Path outputIntermediary = minecraftIntermediaryJar.toPath(); | ||||
| 
 | ||||
| 		for (String toM : Arrays.asList("named", "intermediary")) { | ||||
| 			Path output = "named".equals(toM) ? outputMapped : outputIntermediary; | ||||
| 
 | ||||
| 			getProject().getLogger().lifecycle(":remapping minecraft (TinyRemapper, " + fromM + " -> " + toM + ")"); | ||||
| 
 | ||||
| 			TinyRemapper remapper = getTinyRemapper(fromM, toM); | ||||
| 
 | ||||
| 			try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(output).build()) { | ||||
| 				outputConsumer.addNonClassFiles(input); | ||||
| 				remapper.readClassPath(getRemapClasspath()); | ||||
| 				remapper.readInputs(input); | ||||
| 				remapper.apply(outputConsumer); | ||||
| 			} catch (Exception e) { | ||||
| 				throw new RuntimeException("Failed to remap JAR " + input + " with mappings from " + mappingsProvider.tinyMappings, e); | ||||
| 			} finally { | ||||
| 				remapper.finish(); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public TinyRemapper getTinyRemapper(String fromM, String toM) throws IOException { | ||||
| 		return TinyRemapper.newRemapper() | ||||
| 				.withMappings(TinyRemapperMappingsHelper.create(getExtension().getMappingsProvider().getMappings(), fromM, toM, true)) | ||||
| 				.renameInvalidLocals(true) | ||||
| 				.rebuildSourceFilenames(true) | ||||
| 				.build(); | ||||
| 	} | ||||
| 
 | ||||
| 	public Path[] getRemapClasspath() { | ||||
| 		return getMapperPaths().stream().map(File::toPath).toArray(Path[]::new); | ||||
| 	} | ||||
| 
 | ||||
| 	protected void addDependencies(DependencyInfo dependency, Consumer<Runnable> postPopulationScheduler) { | ||||
| 		getProject().getRepositories().flatDir(repository -> repository.dir(getJarDirectory(getExtension().getUserCache(), "mapped"))); | ||||
| 
 | ||||
|  |  | |||
|  | @ -110,11 +110,16 @@ public class RemapJarTask extends Jar { | |||
| 			remapper.readInputs(input); | ||||
| 			remapper.apply(outputConsumer); | ||||
| 		} catch (Exception e) { | ||||
| 			throw new RuntimeException("Failed to remap " + input + " to " + output, e); | ||||
| 		} finally { | ||||
| 			remapper.finish(); | ||||
| 			throw new RuntimeException("Failed to remap " + input + " to " + output, e); | ||||
| 		} | ||||
| 
 | ||||
| 		if (extension.accessWidener != null) { | ||||
| 			extension.getJarProcessorManager().getByType(AccessWidenerJarProcessor.class).remapAccessWidener(output, remapper.getRemapper()); | ||||
| 		} | ||||
| 
 | ||||
| 		remapper.finish(); | ||||
| 
 | ||||
| 		if (!Files.exists(output)) { | ||||
| 			throw new RuntimeException("Failed to remap " + input + " to " + output + " - file missing!"); | ||||
| 		} | ||||
|  | @ -129,10 +134,6 @@ public class RemapJarTask extends Jar { | |||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (extension.accessWidener != null) { | ||||
| 			extension.getJarProcessorManager().getByType(AccessWidenerJarProcessor.class).remapAccessWidener(output); | ||||
| 		} | ||||
| 
 | ||||
| 		/*try { | ||||
| 			if (modJar.exists()) { | ||||
| 				Files.move(modJar, modJarUnmappedCopy); | ||||
|  |  | |||
|  | @ -116,11 +116,13 @@ public class LoomDependencyManager { | |||
| 			}); | ||||
| 		} | ||||
| 
 | ||||
| 		SourceRemapper sourceRemapper = new SourceRemapper(project, true); | ||||
| 
 | ||||
| 		{ | ||||
| 			String mappingsKey = mappingsProvider.mappingsName + "." + mappingsProvider.minecraftVersion.replace(' ', '_').replace('.', '_').replace('-', '_') + "." + mappingsProvider.mappingsVersion; | ||||
| 
 | ||||
| 			for (RemappedConfigurationEntry entry : Constants.MOD_COMPILE_ENTRIES) { | ||||
| 				ModCompileRemapper.remapDependencies(project, mappingsKey, extension, project.getConfigurations().getByName(entry.getSourceConfiguration()), project.getConfigurations().getByName(entry.getRemappedConfiguration()), project.getConfigurations().getByName(entry.getTargetConfiguration(project.getConfigurations())), afterTasks::add); | ||||
| 				ModCompileRemapper.remapDependencies(project, mappingsKey, extension, project.getConfigurations().getByName(entry.getSourceConfiguration()), project.getConfigurations().getByName(entry.getRemappedConfiguration()), project.getConfigurations().getByName(entry.getTargetConfiguration(project.getConfigurations())), sourceRemapper); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
|  | @ -150,6 +152,8 @@ public class LoomDependencyManager { | |||
| 			project.getLogger().warn("fabric-installer.json not found in classpath!"); | ||||
| 		} | ||||
| 
 | ||||
| 		sourceRemapper.remapAll(); | ||||
| 
 | ||||
| 		for (Runnable runnable : afterTasks) { | ||||
| 			runnable.run(); | ||||
| 		} | ||||
|  |  | |||
|  | @ -1,77 +0,0 @@ | |||
| /* | ||||
|  * This file is part of fabric-loom, licensed under the MIT License (MIT). | ||||
|  * | ||||
|  * Copyright (c) 2016, 2017, 2018 FabricMC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in all | ||||
|  * copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| package net.fabricmc.loom.util; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.nio.file.Path; | ||||
| import java.util.Arrays; | ||||
| 
 | ||||
| import org.gradle.api.Project; | ||||
| 
 | ||||
| import net.fabricmc.loom.LoomGradleExtension; | ||||
| import net.fabricmc.loom.providers.MappingsProvider; | ||||
| import net.fabricmc.loom.providers.MinecraftMappedProvider; | ||||
| import net.fabricmc.loom.providers.MinecraftProvider; | ||||
| import net.fabricmc.tinyremapper.OutputConsumerPath; | ||||
| import net.fabricmc.tinyremapper.TinyRemapper; | ||||
| 
 | ||||
| public class MapJarsTiny { | ||||
| 	public void mapJars(MinecraftProvider jarProvider, MinecraftMappedProvider mapProvider, File mappedJar, File intermediaryJar, Project project) throws IOException { | ||||
| 		String fromM = "official"; | ||||
| 
 | ||||
| 		LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); | ||||
| 		MappingsProvider mappingsProvider = extension.getMappingsProvider(); | ||||
| 
 | ||||
| 		Path[] classpath = mapProvider.getMapperPaths().stream().map(File::toPath).toArray(Path[]::new); | ||||
| 
 | ||||
| 		Path input = jarProvider.getMergedJar().toPath(); | ||||
| 		Path outputMapped = mappedJar.toPath(); | ||||
| 		Path outputIntermediary = intermediaryJar.toPath(); | ||||
| 
 | ||||
| 		for (String toM : Arrays.asList("named", "intermediary")) { | ||||
| 			Path output = "named".equals(toM) ? outputMapped : outputIntermediary; | ||||
| 
 | ||||
| 			project.getLogger().lifecycle(":remapping minecraft (TinyRemapper, " + fromM + " -> " + toM + ")"); | ||||
| 
 | ||||
| 			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); | ||||
| 				remapper.readClassPath(classpath); | ||||
| 				remapper.readInputs(input); | ||||
| 				remapper.apply(outputConsumer); | ||||
| 			} catch (Exception e) { | ||||
| 				throw new RuntimeException("Failed to remap JAR " + input + " with mappings from " + mappingsProvider.tinyMappings, e); | ||||
| 			} finally { | ||||
| 				remapper.finish(); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -26,7 +26,9 @@ package net.fabricmc.loom.util; | |||
| 
 | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.util.function.Consumer; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.stream.Collectors; | ||||
| import java.util.zip.ZipFile; | ||||
| 
 | ||||
| import org.gradle.api.Project; | ||||
|  | @ -45,12 +47,19 @@ import org.gradle.jvm.JvmLibrary; | |||
| import org.gradle.language.base.artifact.SourcesArtifact; | ||||
| 
 | ||||
| import net.fabricmc.loom.LoomGradleExtension; | ||||
| import net.fabricmc.loom.processors.dependency.ModDependencyInfo; | ||||
| import net.fabricmc.loom.processors.dependency.RemapData; | ||||
| 
 | ||||
| public class ModCompileRemapper { | ||||
| 	public static void remapDependencies(Project project, String mappingsSuffix, LoomGradleExtension extension, Configuration modCompile, Configuration modCompileRemapped, Configuration regularCompile, Consumer<Runnable> postPopulationScheduler) { | ||||
| 	public static void remapDependencies(Project project, String mappingsSuffix, LoomGradleExtension extension, Configuration modCompile, Configuration modCompileRemapped, Configuration regularCompile, SourceRemapper sourceRemapper) { | ||||
| 		Logger logger = project.getLogger(); | ||||
| 		DependencyHandler dependencies = project.getDependencies(); | ||||
| 
 | ||||
| 		final File modStore = extension.getRemappedModCache(); | ||||
| 		final RemapData remapData = new RemapData(mappingsSuffix, modStore); | ||||
| 
 | ||||
| 		final List<ModDependencyInfo> modDependencies = new ArrayList<>(); | ||||
| 
 | ||||
| 		for (ResolvedArtifact artifact : modCompile.getResolvedConfiguration().getResolvedArtifacts()) { | ||||
| 			String group; | ||||
| 			String name; | ||||
|  | @ -76,21 +85,32 @@ public class ModCompileRemapper { | |||
| 
 | ||||
| 			File sources = findSources(dependencies, artifact); | ||||
| 
 | ||||
| 			ModDependencyInfo info = new ModDependencyInfo(group, name, version, classifierSuffix, artifact.getFile(), remapData); | ||||
| 			modDependencies.add(info); | ||||
| 
 | ||||
| 			String remappedLog = group + ":" + name + ":" + version + classifierSuffix + " (" + mappingsSuffix + ")"; | ||||
| 			String remappedNotation = String.format("%s:%s:%s@%s%s", group, name, version, mappingsSuffix, classifierSuffix); | ||||
| 			String remappedFilename = String.format("%s-%s@%s", name, version, mappingsSuffix + classifierSuffix.replace(':', '-')); | ||||
| 			project.getLogger().info(":providing " + remappedLog); | ||||
| 
 | ||||
| 			File modStore = extension.getRemappedModCache(); | ||||
| 
 | ||||
| 			remapArtifact(project, modCompileRemapped, artifact, remappedFilename, modStore); | ||||
| 
 | ||||
| 			project.getDependencies().add(modCompileRemapped.getName(), project.getDependencies().module(remappedNotation)); | ||||
| 
 | ||||
| 			if (sources != null) { | ||||
| 				scheduleSourcesRemapping(project, postPopulationScheduler, sources, remappedLog, remappedFilename, modStore); | ||||
| 				scheduleSourcesRemapping(project, sourceRemapper, sources, remappedLog, remappedFilename, modStore); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		List<ModDependencyInfo> processList = modDependencies.stream() | ||||
| 				.filter(ModDependencyInfo::requiresRemapping) | ||||
| 				.collect(Collectors.toList()); | ||||
| 
 | ||||
| 		try { | ||||
| 			ModProcessor.processMods(project, processList); | ||||
| 		} catch (IOException e) { | ||||
| 			throw new RuntimeException("Failed to remap mods", e); | ||||
| 		} | ||||
| 
 | ||||
| 		// Add all of the remapped mods onto the config | ||||
| 		for (ModDependencyInfo modDependency : modDependencies) { | ||||
| 			project.getDependencies().add(modCompileRemapped.getName(), project.getDependencies().module(modDependency.getRemappedNotation())); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
|  | @ -123,28 +143,6 @@ public class ModCompileRemapper { | |||
| 		dependencies.add(regularCompile.getName(), dep); | ||||
| 	} | ||||
| 
 | ||||
| 	private static void remapArtifact(Project project, Configuration config, ResolvedArtifact artifact, String remappedFilename, File modStore) { | ||||
| 		File input = artifact.getFile(); | ||||
| 		File output = new File(modStore, remappedFilename + ".jar"); | ||||
| 
 | ||||
| 		if (!output.exists() || input.lastModified() <= 0 || input.lastModified() > output.lastModified()) { | ||||
| 			//If the output doesn't exist, or appears to be outdated compared to the input we'll remap it | ||||
| 			try { | ||||
| 				ModProcessor.processMod(input, output, project, config, artifact); | ||||
| 			} catch (IOException e) { | ||||
| 				throw new RuntimeException("Failed to remap mod", e); | ||||
| 			} | ||||
| 
 | ||||
| 			if (!output.exists()) { | ||||
| 				throw new RuntimeException("Failed to remap mod"); | ||||
| 			} | ||||
| 
 | ||||
| 			output.setLastModified(input.lastModified()); | ||||
| 		} else { | ||||
| 			project.getLogger().info(output.getName() + " is up to date with " + input.getName()); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public static File findSources(DependencyHandler dependencies, ResolvedArtifact artifact) { | ||||
| 		@SuppressWarnings("unchecked") ArtifactResolutionQuery query = dependencies.createArtifactResolutionQuery()// | ||||
| 				.forComponents(artifact.getId().getComponentIdentifier())// | ||||
|  | @ -161,23 +159,21 @@ public class ModCompileRemapper { | |||
| 		return null; | ||||
| 	} | ||||
| 
 | ||||
| 	private static void scheduleSourcesRemapping(Project project, Consumer<Runnable> postPopulationScheduler, File sources, String remappedLog, String remappedFilename, File modStore) { | ||||
| 		postPopulationScheduler.accept(() -> { | ||||
| 			project.getLogger().info(":providing " + remappedLog + " sources"); | ||||
| 			File remappedSources = new File(modStore, remappedFilename + "-sources.jar"); | ||||
| 	private static void scheduleSourcesRemapping(Project project, SourceRemapper sourceRemapper, File sources, String remappedLog, String remappedFilename, File modStore) { | ||||
| 		project.getLogger().info(":providing " + remappedLog + " sources"); | ||||
| 		File remappedSources = new File(modStore, remappedFilename + "-sources.jar"); | ||||
| 
 | ||||
| 			if (!remappedSources.exists() || sources.lastModified() <= 0 || sources.lastModified() > remappedSources.lastModified()) { | ||||
| 				try { | ||||
| 					SourceRemapper.remapSources(project, sources, remappedSources, true); | ||||
| 		if (!remappedSources.exists() || sources.lastModified() <= 0 || sources.lastModified() > remappedSources.lastModified()) { | ||||
| 			try { | ||||
| 				sourceRemapper.scheduleRemapSources(sources, remappedSources); | ||||
| 
 | ||||
| 					//Set the remapped sources creation date to match the sources if we're likely succeeded in making it | ||||
| 					remappedSources.setLastModified(sources.lastModified()); | ||||
| 				} catch (Exception e) { | ||||
| 					e.printStackTrace(); | ||||
| 				} | ||||
| 			} else { | ||||
| 				project.getLogger().info(remappedSources.getName() + " is up to date with " + sources.getName()); | ||||
| 				//Set the remapped sources creation date to match the sources if we're likely succeeded in making it | ||||
| 				remappedSources.setLastModified(sources.lastModified()); | ||||
| 			} catch (Exception e) { | ||||
| 				e.printStackTrace(); | ||||
| 			} | ||||
| 		}); | ||||
| 		} else { | ||||
| 			project.getLogger().info(remappedSources.getName() + " is up to date with " + sources.getName()); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -25,31 +25,28 @@ | |||
| package net.fabricmc.loom.util; | ||||
| 
 | ||||
| import java.io.BufferedReader; | ||||
| import java.io.ByteArrayInputStream; | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.InputStreamReader; | ||||
| import java.io.StringReader; | ||||
| import java.io.StringWriter; | ||||
| import java.nio.charset.StandardCharsets; | ||||
| import java.nio.file.Path; | ||||
| import java.nio.file.Paths; | ||||
| import java.util.HashSet; | ||||
| import java.util.Set; | ||||
| import java.util.jar.JarEntry; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.function.BiConsumer; | ||||
| import java.util.jar.JarFile; | ||||
| import java.util.zip.ZipEntry; | ||||
| 
 | ||||
| import com.google.gson.Gson; | ||||
| import com.google.gson.GsonBuilder; | ||||
| 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.gradle.api.artifacts.ResolvedArtifact; | ||||
| import org.objectweb.asm.commons.Remapper; | ||||
| import org.zeroturnaround.zip.ZipUtil; | ||||
| import org.zeroturnaround.zip.commons.FileUtils; | ||||
| import org.zeroturnaround.zip.transform.StringZipEntryTransformer; | ||||
| import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry; | ||||
| 
 | ||||
|  | @ -58,82 +55,34 @@ import net.fabricmc.loom.providers.MappingsProvider; | |||
| import net.fabricmc.loom.providers.MinecraftMappedProvider; | ||||
| import net.fabricmc.loom.util.accesswidener.AccessWidener; | ||||
| import net.fabricmc.loom.util.accesswidener.AccessWidenerRemapper; | ||||
| import net.fabricmc.tinyremapper.OutputConsumerPath; | ||||
| import net.fabricmc.loom.processors.dependency.ModDependencyInfo; | ||||
| import net.fabricmc.tinyremapper.TinyRemapper; | ||||
| import net.fabricmc.tinyremapper.InputTag; | ||||
| import net.fabricmc.tinyremapper.OutputConsumerPath; | ||||
| 
 | ||||
| public class ModProcessor { | ||||
| 	private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); | ||||
| 	public static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); | ||||
| 
 | ||||
| 	public static void processMod(File input, File output, Project project, Configuration config, ResolvedArtifact artifact) throws IOException { | ||||
| 		if (output.exists()) { | ||||
| 			output.delete(); | ||||
| 	public static void processMods(Project project, List<ModDependencyInfo> processList) throws IOException { | ||||
| 		if (processList.isEmpty()) { | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		remapJar(input, output, project, artifact); | ||||
| 
 | ||||
| 		//Enable this if you want your nested jars to be extracted, this will extract **all** jars | ||||
| 		if (project.getExtensions().getByType(LoomGradleExtension.class).extractJars) { | ||||
| 			handleNestedJars(input, project, config, artifact); | ||||
| 		} | ||||
| 
 | ||||
| 		remapaccessWidener(output, project); | ||||
| 
 | ||||
| 		//Always strip the nested jars | ||||
| 		stripNestedJars(output); | ||||
| 	} | ||||
| 
 | ||||
| 	private static void handleNestedJars(File input, Project project, Configuration config, ResolvedArtifact artifact) throws IOException { | ||||
| 		try (JarFile jarFile = new JarFile(input)) { | ||||
| 			JarEntry modJsonEntry = jarFile.getJarEntry("fabric.mod.json"); | ||||
| 
 | ||||
| 			if (modJsonEntry == null) { | ||||
| 				return; | ||||
| 			} | ||||
| 
 | ||||
| 			try (InputStream inputStream = jarFile.getInputStream(modJsonEntry)) { | ||||
| 				JsonObject json = GSON.fromJson(new InputStreamReader(inputStream), JsonObject.class); | ||||
| 
 | ||||
| 				if (json == null || !json.has("jars")) { | ||||
| 					return; | ||||
| 				} | ||||
| 
 | ||||
| 				JsonArray jsonArray = json.getAsJsonArray("jars"); | ||||
| 
 | ||||
| 				for (int i = 0; i < jsonArray.size(); i++) { | ||||
| 					JsonObject jsonObject = jsonArray.get(i).getAsJsonObject(); | ||||
| 					String fileName = jsonObject.get("file").getAsString(); | ||||
| 					project.getLogger().lifecycle(String.format("Found %s nested in %s", fileName, input.getName())); | ||||
| 					processNestedJar(jarFile, fileName, project, config, artifact); | ||||
| 				} | ||||
| 		for (ModDependencyInfo info : processList) { | ||||
| 			if (info.getRemappedOutput().exists()) { | ||||
| 				info.getRemappedOutput().delete(); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	private static void processNestedJar(JarFile parentJar, String fileName, Project project, Configuration config, ResolvedArtifact artifact) throws IOException { | ||||
| 		LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); | ||||
| 		remapJars(project, processList); | ||||
| 
 | ||||
| 		JarEntry entry = parentJar.getJarEntry(fileName); | ||||
| 		for (ModDependencyInfo info : processList) { | ||||
| 			if (!info.getRemappedOutput().exists()) { | ||||
| 				throw new RuntimeException("Failed to remap mod" + info); | ||||
| 			} | ||||
| 
 | ||||
| 		if (entry == null) { | ||||
| 			throw new RuntimeException(String.format("%s was not found in %s", fileName, parentJar.getName())); | ||||
| 			stripNestedJars(info.getRemappedOutput()); | ||||
| 		} | ||||
| 
 | ||||
| 		File nestedFile = new File(extension.getNestedModCache(), fileName.substring(fileName.lastIndexOf("/"))); | ||||
| 
 | ||||
| 		try (InputStream jarStream = parentJar.getInputStream(entry)) { | ||||
| 			FileUtils.copy(jarStream, nestedFile); | ||||
| 		} | ||||
| 
 | ||||
| 		File remappedFile = new File(extension.getRemappedModCache(), fileName.substring(fileName.lastIndexOf("/"))); | ||||
| 
 | ||||
| 		processMod(nestedFile, remappedFile, project, config, artifact); | ||||
| 
 | ||||
| 		if (!remappedFile.exists()) { | ||||
| 			throw new RuntimeException("Failed to find processed nested jar"); | ||||
| 		} | ||||
| 
 | ||||
| 		//Add the project right onto the remapped mods, hopefully this works | ||||
| 		project.getDependencies().add(config.getName(), project.files(remappedFile)); | ||||
| 	} | ||||
| 
 | ||||
| 	private static void stripNestedJars(File file) { | ||||
|  | @ -148,57 +97,24 @@ public class ModProcessor { | |||
| 		}))}); | ||||
| 	} | ||||
| 
 | ||||
| 	private static void remapaccessWidener(File input, Project project) throws IOException { | ||||
| 		String accessWidenerPath; | ||||
| 
 | ||||
| 		try (JarFile jarFile = new JarFile(input)) { | ||||
| 			JarEntry modJsonEntry = jarFile.getJarEntry("fabric.mod.json"); | ||||
| 
 | ||||
| 			if (modJsonEntry == null) { | ||||
| 				return; | ||||
| 			} | ||||
| 
 | ||||
| 			try (InputStream inputStream = jarFile.getInputStream(modJsonEntry)) { | ||||
| 				JsonObject json = GSON.fromJson(new InputStreamReader(inputStream), JsonObject.class); | ||||
| 
 | ||||
| 				if (!json.has("accessWidener")) { | ||||
| 					return; | ||||
| 				} | ||||
| 
 | ||||
| 				accessWidenerPath = json.get("accessWidener").getAsString(); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (accessWidenerPath == null) { | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		ZipUtil.transformEntry(input, accessWidenerPath, new StringZipEntryTransformer() { | ||||
| 			@Override | ||||
| 			protected String transform(ZipEntry zipEntry, String input) throws IOException { | ||||
| 				return remapaccessWidener(input, project); | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	private static String remapaccessWidener(String input, Project project) { | ||||
| 		try (BufferedReader bufferedReader = new BufferedReader(new StringReader(input))) { | ||||
| 	private static byte[] remapaccessWidener(byte[] input, Remapper remapper) { | ||||
| 		try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(input), StandardCharsets.UTF_8))) { | ||||
| 			AccessWidener accessWidener = new AccessWidener(); | ||||
| 			accessWidener.read(bufferedReader); | ||||
| 
 | ||||
| 			AccessWidenerRemapper accessWidenerRemapper = new AccessWidenerRemapper(accessWidener, project.getExtensions().getByType(LoomGradleExtension.class).getMappingsProvider().getMappings(), "named"); | ||||
| 			AccessWidenerRemapper accessWidenerRemapper = new AccessWidenerRemapper(accessWidener, remapper, "named"); | ||||
| 			AccessWidener remapped = accessWidenerRemapper.remap(); | ||||
| 
 | ||||
| 			try (StringWriter writer = new StringWriter()) { | ||||
| 				remapped.write(writer); | ||||
| 				return writer.toString(); | ||||
| 				return writer.toString().getBytes(StandardCharsets.UTF_8); | ||||
| 			} | ||||
| 		} catch (IOException e) { | ||||
| 			throw new RuntimeException(e); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	private static void remapJar(File input, File output, Project project, ResolvedArtifact artifact) throws IOException { | ||||
| 	private static void remapJars(Project project, List<ModDependencyInfo> processList) throws IOException { | ||||
| 		LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); | ||||
| 		String fromM = "intermediary"; | ||||
| 		String toM = "named"; | ||||
|  | @ -206,47 +122,57 @@ public class ModProcessor { | |||
| 		MinecraftMappedProvider mappedProvider = extension.getMinecraftMappedProvider(); | ||||
| 		MappingsProvider mappingsProvider = extension.getMappingsProvider(); | ||||
| 
 | ||||
| 		Path inputPath = input.getAbsoluteFile().toPath(); | ||||
| 		Path mc = mappedProvider.getIntermediaryJar().toPath(); | ||||
| 		Path[] mcDeps = mappedProvider.getMapperPaths().stream().map(File::toPath).toArray(Path[]::new); | ||||
| 		Set<Path> modCompiles = new HashSet<>(); | ||||
| 
 | ||||
| 		for (RemappedConfigurationEntry entry : Constants.MOD_COMPILE_ENTRIES) { | ||||
| 			project.getConfigurations().getByName(entry.getSourceConfiguration()).getFiles().stream().filter((f) -> !f.equals(input)).map(p -> { | ||||
| 				if (p.equals(input)) { | ||||
| 					return inputPath; | ||||
| 				} else { | ||||
| 					return p.toPath(); | ||||
| 				} | ||||
| 			}).forEach(modCompiles::add); | ||||
| 		} | ||||
| 
 | ||||
| 		project.getLogger().lifecycle(":remapping " + input.getName() + " (TinyRemapper, " + fromM + " -> " + toM + ")"); | ||||
| 
 | ||||
| 		// If the sources don't exist, we want remapper to give nicer names to the missing variable names. | ||||
| 		// However, if the sources do exist, if remapper gives names to the parameters that prevents IDEs (at least IDEA) | ||||
| 		// from replacing the parameters with the actual names from the sources. | ||||
| 		boolean sourcesExist = ModCompileRemapper.findSources(project.getDependencies(), artifact) != null; | ||||
| 		project.getLogger().lifecycle(":remapping " + processList.size() + " mods (TinyRemapper, " + fromM + " -> " + toM + ")"); | ||||
| 
 | ||||
| 		TinyRemapper remapper = TinyRemapper.newRemapper() | ||||
| 						.withMappings(TinyRemapperMappingsHelper.create(mappingsProvider.getMappings(), fromM, toM, false)) | ||||
| 						.renameInvalidLocals(!sourcesExist) | ||||
| 						.renameInvalidLocals(false) | ||||
| 						.build(); | ||||
| 
 | ||||
| 		try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(Paths.get(output.getAbsolutePath())).build()) { | ||||
| 			outputConsumer.addNonClassFiles(inputPath); | ||||
| 			remapper.readClassPath(modCompiles.toArray(new Path[0])); | ||||
| 			remapper.readClassPath(mc); | ||||
| 			remapper.readClassPath(mcDeps); | ||||
| 			remapper.readInputs(inputPath); | ||||
| 			remapper.apply(outputConsumer); | ||||
| 		} finally { | ||||
| 			remapper.finish(); | ||||
| 		remapper.readClassPathAsync(mc); | ||||
| 		remapper.readClassPathAsync(mcDeps); | ||||
| 
 | ||||
| 		final Map<ModDependencyInfo, InputTag> tagMap = new HashMap<>(); | ||||
| 		final Map<ModDependencyInfo, OutputConsumerPath> outputConsumerMap = new HashMap<>(); | ||||
| 
 | ||||
| 		for (ModDependencyInfo info : processList) { | ||||
| 			InputTag tag = remapper.createInputTag(); | ||||
| 			remapper.readInputsAsync(tag, info.getInputFile().toPath()); | ||||
| 			tagMap.put(info, tag); | ||||
| 		} | ||||
| 
 | ||||
| 		if (!output.exists()) { | ||||
| 			throw new RuntimeException("Failed to remap JAR to " + toM + " file not found: " + output.getAbsolutePath()); | ||||
| 		// Apply this in a second loop as we need to ensure all the inputs are on the classpath before remapping. | ||||
| 		for (ModDependencyInfo info : processList) { | ||||
| 			OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(info.getRemappedOutput().toPath()).build(); | ||||
| 			outputConsumer.addNonClassFiles(info.getInputFile().toPath()); | ||||
| 			outputConsumerMap.put(info, outputConsumer); | ||||
| 			String accessWidener = info.getAccessWidener(); | ||||
| 
 | ||||
| 			if (accessWidener == null) { | ||||
| 				remapper.apply(outputConsumer, tagMap.get(info)); | ||||
| 			} else { | ||||
| 				remapper.apply(remapAccessWidener(remapper.getRemapper(), accessWidener, outputConsumer), tagMap.get(info)); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		remapper.finish(); | ||||
| 
 | ||||
| 		for (ModDependencyInfo info : processList) { | ||||
| 			outputConsumerMap.get(info).close(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	static BiConsumer<String, byte[]> remapAccessWidener(Remapper remapper, String accessWidener, BiConsumer<String, byte[]> output) { | ||||
| 		return (s, bytes) -> { | ||||
| 			if (s.equals(accessWidener)) { | ||||
| 				output.accept(s, remapaccessWidener(bytes, remapper)); | ||||
| 			} else { | ||||
| 				output.accept(s, bytes); | ||||
| 			} | ||||
| 		}; | ||||
| 	} | ||||
| 
 | ||||
| 	static JsonObject readInstallerJson(File file, Project project) { | ||||
|  |  | |||
|  | @ -28,6 +28,8 @@ import java.io.File; | |||
| import java.io.IOException; | ||||
| import java.nio.file.Files; | ||||
| import java.nio.file.Path; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| 
 | ||||
| import org.cadixdev.lorenz.MappingSet; | ||||
| import org.cadixdev.lorenz.io.MappingsReader; | ||||
|  | @ -46,44 +48,46 @@ import net.fabricmc.mapping.tree.TinyTree; | |||
| import net.fabricmc.stitch.util.StitchUtil; | ||||
| 
 | ||||
| public class SourceRemapper { | ||||
| 	public static void remapSources(Project project, File source, File destination, boolean toNamed) throws Exception { | ||||
| 		remapSourcesInner(project, source, destination, toNamed); | ||||
| 	private final Project project; | ||||
| 	private final boolean toNamed; | ||||
| 	private final List<Runnable> remapTasks = new ArrayList<>(); | ||||
| 
 | ||||
| 	private Mercury mercury; | ||||
| 
 | ||||
| 	public SourceRemapper(Project project, boolean toNamed) { | ||||
| 		this.project = project; | ||||
| 		this.toNamed = toNamed; | ||||
| 	} | ||||
| 
 | ||||
| 	public static void remapSources(Project project, File input, File output, boolean named) throws Exception { | ||||
| 		SourceRemapper sourceRemapper = new SourceRemapper(project, named); | ||||
| 		sourceRemapper.scheduleRemapSources(input, output); | ||||
| 		sourceRemapper.remapAll(); | ||||
| 	} | ||||
| 
 | ||||
| 	public void scheduleRemapSources(File source, File destination) throws Exception { | ||||
| 		remapTasks.add(() -> { | ||||
| 			try { | ||||
| 				remapSourcesInner(source, destination); | ||||
| 			} catch (Exception e) { | ||||
| 				throw new RuntimeException("Failed to remap sources for " + source, e); | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	public void remapAll() { | ||||
| 		if (!remapTasks.isEmpty()) { | ||||
| 			project.getLogger().lifecycle(":remapping sources"); | ||||
| 		} | ||||
| 
 | ||||
| 		remapTasks.forEach(Runnable::run); | ||||
| 		// TODO: FIXME - WORKAROUND https://github.com/FabricMC/fabric-loom/issues/45 | ||||
| 		System.gc(); | ||||
| 	} | ||||
| 
 | ||||
| 	private static void remapSourcesInner(Project project, File source, File destination, boolean toNamed) throws Exception { | ||||
| 		LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); | ||||
| 		MappingsProvider mappingsProvider = extension.getMappingsProvider(); | ||||
| 
 | ||||
| 		MappingSet mappings = extension.getOrCreateSrcMappingCache(toNamed ? 1 : 0, () -> { | ||||
| 			try { | ||||
| 				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) { | ||||
| 				throw new RuntimeException(e); | ||||
| 			} | ||||
| 		}); | ||||
| 
 | ||||
| 	private void remapSourcesInner(File source, File destination) throws Exception { | ||||
| 		project.getLogger().info(":remapping source jar"); | ||||
| 
 | ||||
| 		Mercury mercury = extension.getOrCreateSrcMercuryCache(toNamed ? 1 : 0, () -> { | ||||
| 			Mercury m = createMercuryWithClassPath(project, toNamed); | ||||
| 
 | ||||
| 			for (Path file : extension.getUnmappedMods()) { | ||||
| 				if (Files.isRegularFile(file)) { | ||||
| 					m.getClassPath().add(file); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			m.getClassPath().add(extension.getMinecraftMappedProvider().getMappedJar().toPath()); | ||||
| 			m.getClassPath().add(extension.getMinecraftMappedProvider().getIntermediaryJar().toPath()); | ||||
| 
 | ||||
| 			m.getProcessors().add(MercuryRemapper.create(mappings)); | ||||
| 
 | ||||
| 			return m; | ||||
| 		}); | ||||
| 		Mercury mercury = getMercuryInstance(); | ||||
| 
 | ||||
| 		if (source.equals(destination)) { | ||||
| 			if (source.isDirectory()) { | ||||
|  | @ -135,6 +139,45 @@ public class SourceRemapper { | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	private Mercury getMercuryInstance() { | ||||
| 		if (this.mercury != null) { | ||||
| 			return this.mercury; | ||||
| 		} | ||||
| 
 | ||||
| 		LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); | ||||
| 		MappingsProvider mappingsProvider = extension.getMappingsProvider(); | ||||
| 
 | ||||
| 		MappingSet mappings = extension.getOrCreateSrcMappingCache(toNamed ? 1 : 0, () -> { | ||||
| 			try { | ||||
| 				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) { | ||||
| 				throw new RuntimeException(e); | ||||
| 			} | ||||
| 		}); | ||||
| 
 | ||||
| 		Mercury mercury = extension.getOrCreateSrcMercuryCache(toNamed ? 1 : 0, () -> { | ||||
| 			Mercury m = createMercuryWithClassPath(project, toNamed); | ||||
| 
 | ||||
| 			for (Path file : extension.getUnmappedMods()) { | ||||
| 				if (Files.isRegularFile(file)) { | ||||
| 					m.getClassPath().add(file); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			m.getClassPath().add(extension.getMinecraftMappedProvider().getMappedJar().toPath()); | ||||
| 			m.getClassPath().add(extension.getMinecraftMappedProvider().getIntermediaryJar().toPath()); | ||||
| 
 | ||||
| 			m.getProcessors().add(MercuryRemapper.create(mappings)); | ||||
| 
 | ||||
| 			return m; | ||||
| 		}); | ||||
| 
 | ||||
| 		this.mercury = mercury; | ||||
| 		return mercury; | ||||
| 	} | ||||
| 
 | ||||
| 	private static void copyNonJavaFiles(Path from, Path to, Project project, File source) throws IOException { | ||||
| 		Files.walk(from).forEach(path -> { | ||||
| 			Path targetPath = to.resolve(from.relativize(path).toString()); | ||||
|  |  | |||
|  | @ -44,6 +44,7 @@ import org.objectweb.asm.ClassWriter; | |||
| import org.objectweb.asm.FieldVisitor; | ||||
| import org.objectweb.asm.MethodVisitor; | ||||
| import org.objectweb.asm.Opcodes; | ||||
| import org.objectweb.asm.commons.Remapper; | ||||
| import org.zeroturnaround.zip.ZipUtil; | ||||
| import org.zeroturnaround.zip.transform.ByteArrayZipEntryTransformer; | ||||
| import org.zeroturnaround.zip.transform.ZipEntryTransformer; | ||||
|  | @ -53,6 +54,7 @@ import net.fabricmc.mappings.EntryTriple; | |||
| import net.fabricmc.loom.LoomGradleExtension; | ||||
| import net.fabricmc.loom.util.Checksum; | ||||
| import net.fabricmc.loom.processors.JarProcessor; | ||||
| import net.fabricmc.tinyremapper.TinyRemapper; | ||||
| 
 | ||||
| public class AccessWidenerJarProcessor implements JarProcessor { | ||||
| 	private AccessWidener accessWidener = new AccessWidener(); | ||||
|  | @ -79,8 +81,13 @@ public class AccessWidenerJarProcessor implements JarProcessor { | |||
| 		//Remap accessWidener if its not named, allows for AE's to be written in intermediary | ||||
| 		if (!accessWidener.namespace.equals("named")) { | ||||
| 			try { | ||||
| 				AccessWidenerRemapper remapper = new AccessWidenerRemapper(accessWidener, loomGradleExtension.getMappingsProvider().getMappings(), "named"); | ||||
| 				TinyRemapper tinyRemapper = loomGradleExtension.getMinecraftMappedProvider().getTinyRemapper("official", "named"); | ||||
| 				tinyRemapper.readClassPath(loomGradleExtension.getMinecraftMappedProvider().getRemapClasspath()); | ||||
| 
 | ||||
| 				AccessWidenerRemapper remapper = new AccessWidenerRemapper(accessWidener, tinyRemapper.getRemapper(), "named"); | ||||
| 				accessWidener = remapper.remap(); | ||||
| 
 | ||||
| 				tinyRemapper.finish(); | ||||
| 			} catch (IOException e) { | ||||
| 				throw new RuntimeException("Failed to remap access widener", e); | ||||
| 			} | ||||
|  | @ -116,9 +123,8 @@ public class AccessWidenerJarProcessor implements JarProcessor { | |||
| 	} | ||||
| 
 | ||||
| 	//Called when remapping the mod | ||||
| 	public void remapAccessWidener(Path modJarPath) throws IOException { | ||||
| 		LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); | ||||
| 		AccessWidenerRemapper remapper = new AccessWidenerRemapper(accessWidener, extension.getMappingsProvider().getMappings(), "intermediary"); | ||||
| 	public void remapAccessWidener(Path modJarPath, Remapper asmRemapper) throws IOException { | ||||
| 		AccessWidenerRemapper remapper = new AccessWidenerRemapper(accessWidener, asmRemapper, "intermediary"); | ||||
| 		AccessWidener remapped = remapper.remap(); | ||||
| 
 | ||||
| 		StringWriter writer = new StringWriter(); | ||||
|  |  | |||
|  | @ -24,54 +24,21 @@ | |||
| 
 | ||||
| package net.fabricmc.loom.util.accesswidener; | ||||
| 
 | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| 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 org.objectweb.asm.commons.Remapper; | ||||
| 
 | ||||
| import net.fabricmc.mappings.EntryTriple; | ||||
| 
 | ||||
| public class AccessWidenerRemapper { | ||||
| 	private final AccessWidener input; | ||||
| 	private final String from, to; | ||||
| 	private final String to; | ||||
| 	private final Remapper remapper; | ||||
| 
 | ||||
| 	private Map<String, String> classNames = new HashMap<>(); | ||||
| 	private Map<EntryTriple, EntryTriple> fieldNames = new HashMap<>(); | ||||
| 	private Map<EntryTriple, EntryTriple> methodNames = new HashMap<>(); | ||||
| 
 | ||||
| 	public AccessWidenerRemapper(AccessWidener input, TinyTree tinyTree, String to) { | ||||
| 	public AccessWidenerRemapper(AccessWidener input, Remapper remapper, String to) { | ||||
| 		this.input = input; | ||||
| 		this.from = input.namespace; | ||||
| 		this.to = to; | ||||
| 		populateMappings(tinyTree); | ||||
| 	} | ||||
| 
 | ||||
| 	private void populateMappings(TinyTree tinyTree) { | ||||
| 		if (!tinyTree.getMetadata().getNamespaces().contains(from)) { | ||||
| 			throw new UnsupportedOperationException("Unknown namespace: " + from); | ||||
| 		} | ||||
| 
 | ||||
| 		if (!tinyTree.getMetadata().getNamespaces().contains(to)) { | ||||
| 			throw new UnsupportedOperationException("Unknown namespace: " + to); | ||||
| 		} | ||||
| 
 | ||||
| 		for (ClassDef classDef : tinyTree.getClasses()) { | ||||
| 			classNames.put(classDef.getName(from), classDef.getName(to)); | ||||
| 
 | ||||
| 			for (FieldDef fieldDef : classDef.getFields()) { | ||||
| 				EntryTriple fromEntry = new EntryTriple(classDef.getName(from), fieldDef.getName(from), fieldDef.getDescriptor(from)); | ||||
| 				EntryTriple toEntry = new EntryTriple(classDef.getName(to), fieldDef.getName(to), fieldDef.getDescriptor(to)); | ||||
| 				fieldNames.put(fromEntry, toEntry); | ||||
| 			} | ||||
| 
 | ||||
| 			for (MethodDef methodDef : classDef.getMethods()) { | ||||
| 				EntryTriple fromEntry = new EntryTriple(classDef.getName(from), methodDef.getName(from), methodDef.getDescriptor(from)); | ||||
| 				EntryTriple toEntry = new EntryTriple(classDef.getName(to), methodDef.getName(to), methodDef.getDescriptor(to)); | ||||
| 				methodNames.put(fromEntry, toEntry); | ||||
| 			} | ||||
| 		} | ||||
| 		this.remapper = remapper; | ||||
| 	} | ||||
| 
 | ||||
| 	public AccessWidener remap() { | ||||
|  | @ -84,27 +51,33 @@ public class AccessWidenerRemapper { | |||
| 		remapped.namespace = to; | ||||
| 
 | ||||
| 		for (Map.Entry<String, AccessWidener.Access> entry : input.classAccess.entrySet()) { | ||||
| 			remapped.classAccess.put(findMapping(classNames, entry.getKey()), entry.getValue()); | ||||
| 			remapped.classAccess.put(remapper.map(entry.getKey()), entry.getValue()); | ||||
| 		} | ||||
| 
 | ||||
| 		for (Map.Entry<EntryTriple, AccessWidener.Access> entry : input.methodAccess.entrySet()) { | ||||
| 			remapped.addOrMerge(remapped.methodAccess, findMapping(methodNames, entry.getKey()), entry.getValue()); | ||||
| 			remapped.addOrMerge(remapped.methodAccess, remapMethod(entry.getKey()), entry.getValue()); | ||||
| 		} | ||||
| 
 | ||||
| 		for (Map.Entry<EntryTriple, AccessWidener.Access> entry : input.fieldAccess.entrySet()) { | ||||
| 			remapped.addOrMerge(remapped.fieldAccess, findMapping(fieldNames, entry.getKey()), entry.getValue()); | ||||
| 			remapped.addOrMerge(remapped.fieldAccess, remapField(entry.getKey()), entry.getValue()); | ||||
| 		} | ||||
| 
 | ||||
| 		return remapped; | ||||
| 	} | ||||
| 
 | ||||
| 	private static <K, V> V findMapping(Map<K, V> map, K key) { | ||||
| 		V value = map.get(key); | ||||
| 	private EntryTriple remapMethod(EntryTriple entryTriple) { | ||||
| 		return new EntryTriple( | ||||
| 					remapper.map(entryTriple.getName()), | ||||
| 					remapper.mapMethodName(entryTriple.getOwner(), entryTriple.getName(), entryTriple.getDesc()), | ||||
| 					remapper.mapDesc(entryTriple.getDesc()) | ||||
| 				); | ||||
| 	} | ||||
| 
 | ||||
| 		if (value == null) { | ||||
| 			throw new RuntimeException("Failed to find mapping for " + key.toString()); | ||||
| 		} | ||||
| 
 | ||||
| 		return value; | ||||
| 	private EntryTriple remapField(EntryTriple entryTriple) { | ||||
| 		return new EntryTriple( | ||||
| 				remapper.map(entryTriple.getName()), | ||||
| 				remapper.mapFieldName(entryTriple.getOwner(), entryTriple.getName(), entryTriple.getDesc()), | ||||
| 				remapper.mapDesc(entryTriple.getDesc()) | ||||
| 		); | ||||
| 	} | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue