Improve setup speed. (#208)
* Improve access widener remapper, now uses tiny remapper * First pass on using the new tiny remapper * Optimise source remappingdev/0.11
parent
bf6fb4a95e
commit
3eff7d0fdb
|
@ -47,7 +47,7 @@ dependencies {
|
||||||
}
|
}
|
||||||
|
|
||||||
// tinyfile management
|
// tinyfile management
|
||||||
implementation ('net.fabricmc:tiny-remapper:0.2.2.66') {
|
implementation ('net.fabricmc:tiny-remapper:0.3.0.70') {
|
||||||
transitive = false
|
transitive = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,6 @@ public class LoomGradleExtension {
|
||||||
public String loaderLaunchMethod;
|
public String loaderLaunchMethod;
|
||||||
public boolean remapMod = true;
|
public boolean remapMod = true;
|
||||||
public boolean autoGenIDERuns = true;
|
public boolean autoGenIDERuns = true;
|
||||||
public boolean extractJars = false;
|
|
||||||
public String customManifest = null;
|
public String customManifest = null;
|
||||||
public File accessWidener = null;
|
public File accessWidener = null;
|
||||||
public Function<String, Object> intermediaryUrl = mcVer -> "https://maven.fabricmc.net/net/fabricmc/intermediary/" + mcVer + "/intermediary-" + mcVer + "-v2.jar";
|
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;
|
package net.fabricmc.loom.providers;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.gradle.api.Project;
|
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.Constants;
|
||||||
import net.fabricmc.loom.util.DependencyProvider;
|
import net.fabricmc.loom.util.DependencyProvider;
|
||||||
import net.fabricmc.loom.util.MapJarsTiny;
|
|
||||||
|
|
||||||
public class MinecraftMappedProvider extends DependencyProvider {
|
public class MinecraftMappedProvider extends DependencyProvider {
|
||||||
private File minecraftMappedJar;
|
private File minecraftMappedJar;
|
||||||
|
@ -66,7 +71,7 @@ public class MinecraftMappedProvider extends DependencyProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
new MapJarsTiny().mapJars(minecraftProvider, this, this.minecraftMappedJar, this.minecraftIntermediaryJar, getProject());
|
mapMinecraftJar();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
//Cleanup some some things that may be in a bad state now
|
//Cleanup some some things that may be in a bad state now
|
||||||
minecraftMappedJar.delete();
|
minecraftMappedJar.delete();
|
||||||
|
@ -83,6 +88,47 @@ public class MinecraftMappedProvider extends DependencyProvider {
|
||||||
addDependencies(dependency, postPopulationScheduler);
|
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) {
|
protected void addDependencies(DependencyInfo dependency, Consumer<Runnable> postPopulationScheduler) {
|
||||||
getProject().getRepositories().flatDir(repository -> repository.dir(getJarDirectory(getExtension().getUserCache(), "mapped")));
|
getProject().getRepositories().flatDir(repository -> repository.dir(getJarDirectory(getExtension().getUserCache(), "mapped")));
|
||||||
|
|
||||||
|
|
|
@ -110,11 +110,16 @@ public class RemapJarTask extends Jar {
|
||||||
remapper.readInputs(input);
|
remapper.readInputs(input);
|
||||||
remapper.apply(outputConsumer);
|
remapper.apply(outputConsumer);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException("Failed to remap " + input + " to " + output, e);
|
|
||||||
} finally {
|
|
||||||
remapper.finish();
|
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)) {
|
if (!Files.exists(output)) {
|
||||||
throw new RuntimeException("Failed to remap " + input + " to " + output + " - file missing!");
|
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 {
|
/*try {
|
||||||
if (modJar.exists()) {
|
if (modJar.exists()) {
|
||||||
Files.move(modJar, modJarUnmappedCopy);
|
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;
|
String mappingsKey = mappingsProvider.mappingsName + "." + mappingsProvider.minecraftVersion.replace(' ', '_').replace('.', '_').replace('-', '_') + "." + mappingsProvider.mappingsVersion;
|
||||||
|
|
||||||
for (RemappedConfigurationEntry entry : Constants.MOD_COMPILE_ENTRIES) {
|
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!");
|
project.getLogger().warn("fabric-installer.json not found in classpath!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sourceRemapper.remapAll();
|
||||||
|
|
||||||
for (Runnable runnable : afterTasks) {
|
for (Runnable runnable : afterTasks) {
|
||||||
runnable.run();
|
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.File;
|
||||||
import java.io.IOException;
|
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 java.util.zip.ZipFile;
|
||||||
|
|
||||||
import org.gradle.api.Project;
|
import org.gradle.api.Project;
|
||||||
|
@ -45,12 +47,19 @@ import org.gradle.jvm.JvmLibrary;
|
||||||
import org.gradle.language.base.artifact.SourcesArtifact;
|
import org.gradle.language.base.artifact.SourcesArtifact;
|
||||||
|
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
|
import net.fabricmc.loom.processors.dependency.ModDependencyInfo;
|
||||||
|
import net.fabricmc.loom.processors.dependency.RemapData;
|
||||||
|
|
||||||
public class ModCompileRemapper {
|
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();
|
Logger logger = project.getLogger();
|
||||||
DependencyHandler dependencies = project.getDependencies();
|
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()) {
|
for (ResolvedArtifact artifact : modCompile.getResolvedConfiguration().getResolvedArtifacts()) {
|
||||||
String group;
|
String group;
|
||||||
String name;
|
String name;
|
||||||
|
@ -76,21 +85,32 @@ public class ModCompileRemapper {
|
||||||
|
|
||||||
File sources = findSources(dependencies, artifact);
|
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 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(':', '-'));
|
String remappedFilename = String.format("%s-%s@%s", name, version, mappingsSuffix + classifierSuffix.replace(':', '-'));
|
||||||
project.getLogger().info(":providing " + remappedLog);
|
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) {
|
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);
|
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) {
|
public static File findSources(DependencyHandler dependencies, ResolvedArtifact artifact) {
|
||||||
@SuppressWarnings("unchecked") ArtifactResolutionQuery query = dependencies.createArtifactResolutionQuery()//
|
@SuppressWarnings("unchecked") ArtifactResolutionQuery query = dependencies.createArtifactResolutionQuery()//
|
||||||
.forComponents(artifact.getId().getComponentIdentifier())//
|
.forComponents(artifact.getId().getComponentIdentifier())//
|
||||||
|
@ -161,23 +159,21 @@ public class ModCompileRemapper {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void scheduleSourcesRemapping(Project project, Consumer<Runnable> postPopulationScheduler, File sources, String remappedLog, String remappedFilename, File modStore) {
|
private static void scheduleSourcesRemapping(Project project, SourceRemapper sourceRemapper, File sources, String remappedLog, String remappedFilename, File modStore) {
|
||||||
postPopulationScheduler.accept(() -> {
|
project.getLogger().info(":providing " + remappedLog + " sources");
|
||||||
project.getLogger().info(":providing " + remappedLog + " sources");
|
File remappedSources = new File(modStore, remappedFilename + "-sources.jar");
|
||||||
File remappedSources = new File(modStore, remappedFilename + "-sources.jar");
|
|
||||||
|
|
||||||
if (!remappedSources.exists() || sources.lastModified() <= 0 || sources.lastModified() > remappedSources.lastModified()) {
|
if (!remappedSources.exists() || sources.lastModified() <= 0 || sources.lastModified() > remappedSources.lastModified()) {
|
||||||
try {
|
try {
|
||||||
SourceRemapper.remapSources(project, sources, remappedSources, true);
|
sourceRemapper.scheduleRemapSources(sources, remappedSources);
|
||||||
|
|
||||||
//Set the remapped sources creation date to match the sources if we're likely succeeded in making it
|
//Set the remapped sources creation date to match the sources if we're likely succeeded in making it
|
||||||
remappedSources.setLastModified(sources.lastModified());
|
remappedSources.setLastModified(sources.lastModified());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
|
||||||
} else {
|
|
||||||
project.getLogger().info(remappedSources.getName() + " is up to date with " + sources.getName());
|
|
||||||
}
|
}
|
||||||
});
|
} else {
|
||||||
|
project.getLogger().info(remappedSources.getName() + " is up to date with " + sources.getName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,31 +25,28 @@
|
||||||
package net.fabricmc.loom.util;
|
package net.fabricmc.loom.util;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.StringReader;
|
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Map;
|
||||||
import java.util.jar.JarEntry;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.google.gson.JsonArray;
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.gradle.api.Project;
|
import org.gradle.api.Project;
|
||||||
import org.gradle.api.artifacts.Configuration;
|
import org.objectweb.asm.commons.Remapper;
|
||||||
import org.gradle.api.artifacts.ResolvedArtifact;
|
|
||||||
import org.zeroturnaround.zip.ZipUtil;
|
import org.zeroturnaround.zip.ZipUtil;
|
||||||
import org.zeroturnaround.zip.commons.FileUtils;
|
|
||||||
import org.zeroturnaround.zip.transform.StringZipEntryTransformer;
|
import org.zeroturnaround.zip.transform.StringZipEntryTransformer;
|
||||||
import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry;
|
import org.zeroturnaround.zip.transform.ZipEntryTransformerEntry;
|
||||||
|
|
||||||
|
@ -58,82 +55,34 @@ import net.fabricmc.loom.providers.MappingsProvider;
|
||||||
import net.fabricmc.loom.providers.MinecraftMappedProvider;
|
import net.fabricmc.loom.providers.MinecraftMappedProvider;
|
||||||
import net.fabricmc.loom.util.accesswidener.AccessWidener;
|
import net.fabricmc.loom.util.accesswidener.AccessWidener;
|
||||||
import net.fabricmc.loom.util.accesswidener.AccessWidenerRemapper;
|
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.TinyRemapper;
|
||||||
|
import net.fabricmc.tinyremapper.InputTag;
|
||||||
|
import net.fabricmc.tinyremapper.OutputConsumerPath;
|
||||||
|
|
||||||
public class ModProcessor {
|
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 {
|
public static void processMods(Project project, List<ModDependencyInfo> processList) throws IOException {
|
||||||
if (output.exists()) {
|
if (processList.isEmpty()) {
|
||||||
output.delete();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
remapJar(input, output, project, artifact);
|
for (ModDependencyInfo info : processList) {
|
||||||
|
if (info.getRemappedOutput().exists()) {
|
||||||
//Enable this if you want your nested jars to be extracted, this will extract **all** jars
|
info.getRemappedOutput().delete();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private static void processNestedJar(JarFile parentJar, String fileName, Project project, Configuration config, ResolvedArtifact artifact) throws IOException {
|
remapJars(project, processList);
|
||||||
LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class);
|
|
||||||
|
|
||||||
JarEntry entry = parentJar.getJarEntry(fileName);
|
for (ModDependencyInfo info : processList) {
|
||||||
|
if (!info.getRemappedOutput().exists()) {
|
||||||
|
throw new RuntimeException("Failed to remap mod" + info);
|
||||||
|
}
|
||||||
|
|
||||||
if (entry == null) {
|
stripNestedJars(info.getRemappedOutput());
|
||||||
throw new RuntimeException(String.format("%s was not found in %s", fileName, parentJar.getName()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
private static void stripNestedJars(File file) {
|
||||||
|
@ -148,57 +97,24 @@ public class ModProcessor {
|
||||||
}))});
|
}))});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void remapaccessWidener(File input, Project project) throws IOException {
|
private static byte[] remapaccessWidener(byte[] input, Remapper remapper) {
|
||||||
String accessWidenerPath;
|
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(input), StandardCharsets.UTF_8))) {
|
||||||
|
|
||||||
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))) {
|
|
||||||
AccessWidener accessWidener = new AccessWidener();
|
AccessWidener accessWidener = new AccessWidener();
|
||||||
accessWidener.read(bufferedReader);
|
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();
|
AccessWidener remapped = accessWidenerRemapper.remap();
|
||||||
|
|
||||||
try (StringWriter writer = new StringWriter()) {
|
try (StringWriter writer = new StringWriter()) {
|
||||||
remapped.write(writer);
|
remapped.write(writer);
|
||||||
return writer.toString();
|
return writer.toString().getBytes(StandardCharsets.UTF_8);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(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);
|
LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class);
|
||||||
String fromM = "intermediary";
|
String fromM = "intermediary";
|
||||||
String toM = "named";
|
String toM = "named";
|
||||||
|
@ -206,47 +122,57 @@ public class ModProcessor {
|
||||||
MinecraftMappedProvider mappedProvider = extension.getMinecraftMappedProvider();
|
MinecraftMappedProvider mappedProvider = extension.getMinecraftMappedProvider();
|
||||||
MappingsProvider mappingsProvider = extension.getMappingsProvider();
|
MappingsProvider mappingsProvider = extension.getMappingsProvider();
|
||||||
|
|
||||||
Path inputPath = input.getAbsoluteFile().toPath();
|
|
||||||
Path mc = mappedProvider.getIntermediaryJar().toPath();
|
Path mc = mappedProvider.getIntermediaryJar().toPath();
|
||||||
Path[] mcDeps = mappedProvider.getMapperPaths().stream().map(File::toPath).toArray(Path[]::new);
|
Path[] mcDeps = mappedProvider.getMapperPaths().stream().map(File::toPath).toArray(Path[]::new);
|
||||||
Set<Path> modCompiles = new HashSet<>();
|
|
||||||
|
|
||||||
for (RemappedConfigurationEntry entry : Constants.MOD_COMPILE_ENTRIES) {
|
project.getLogger().lifecycle(":remapping " + processList.size() + " mods (TinyRemapper, " + fromM + " -> " + toM + ")");
|
||||||
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;
|
|
||||||
|
|
||||||
TinyRemapper remapper = TinyRemapper.newRemapper()
|
TinyRemapper remapper = TinyRemapper.newRemapper()
|
||||||
.withMappings(TinyRemapperMappingsHelper.create(mappingsProvider.getMappings(), fromM, toM, false))
|
.withMappings(TinyRemapperMappingsHelper.create(mappingsProvider.getMappings(), fromM, toM, false))
|
||||||
.renameInvalidLocals(!sourcesExist)
|
.renameInvalidLocals(false)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(Paths.get(output.getAbsolutePath())).build()) {
|
remapper.readClassPathAsync(mc);
|
||||||
outputConsumer.addNonClassFiles(inputPath);
|
remapper.readClassPathAsync(mcDeps);
|
||||||
remapper.readClassPath(modCompiles.toArray(new Path[0]));
|
|
||||||
remapper.readClassPath(mc);
|
final Map<ModDependencyInfo, InputTag> tagMap = new HashMap<>();
|
||||||
remapper.readClassPath(mcDeps);
|
final Map<ModDependencyInfo, OutputConsumerPath> outputConsumerMap = new HashMap<>();
|
||||||
remapper.readInputs(inputPath);
|
|
||||||
remapper.apply(outputConsumer);
|
for (ModDependencyInfo info : processList) {
|
||||||
} finally {
|
InputTag tag = remapper.createInputTag();
|
||||||
remapper.finish();
|
remapper.readInputsAsync(tag, info.getInputFile().toPath());
|
||||||
|
tagMap.put(info, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!output.exists()) {
|
// Apply this in a second loop as we need to ensure all the inputs are on the classpath before remapping.
|
||||||
throw new RuntimeException("Failed to remap JAR to " + toM + " file not found: " + output.getAbsolutePath());
|
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) {
|
static JsonObject readInstallerJson(File file, Project project) {
|
||||||
|
|
|
@ -28,6 +28,8 @@ import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.cadixdev.lorenz.MappingSet;
|
import org.cadixdev.lorenz.MappingSet;
|
||||||
import org.cadixdev.lorenz.io.MappingsReader;
|
import org.cadixdev.lorenz.io.MappingsReader;
|
||||||
|
@ -46,44 +48,46 @@ import net.fabricmc.mapping.tree.TinyTree;
|
||||||
import net.fabricmc.stitch.util.StitchUtil;
|
import net.fabricmc.stitch.util.StitchUtil;
|
||||||
|
|
||||||
public class SourceRemapper {
|
public class SourceRemapper {
|
||||||
public static void remapSources(Project project, File source, File destination, boolean toNamed) throws Exception {
|
private final Project project;
|
||||||
remapSourcesInner(project, source, destination, toNamed);
|
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
|
// TODO: FIXME - WORKAROUND https://github.com/FabricMC/fabric-loom/issues/45
|
||||||
System.gc();
|
System.gc();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void remapSourcesInner(Project project, File source, File destination, boolean toNamed) throws Exception {
|
private void remapSourcesInner(File source, File destination) 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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
project.getLogger().info(":remapping source jar");
|
project.getLogger().info(":remapping source jar");
|
||||||
|
Mercury mercury = getMercuryInstance();
|
||||||
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;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (source.equals(destination)) {
|
if (source.equals(destination)) {
|
||||||
if (source.isDirectory()) {
|
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 {
|
private static void copyNonJavaFiles(Path from, Path to, Project project, File source) throws IOException {
|
||||||
Files.walk(from).forEach(path -> {
|
Files.walk(from).forEach(path -> {
|
||||||
Path targetPath = to.resolve(from.relativize(path).toString());
|
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.FieldVisitor;
|
||||||
import org.objectweb.asm.MethodVisitor;
|
import org.objectweb.asm.MethodVisitor;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
|
import org.objectweb.asm.commons.Remapper;
|
||||||
import org.zeroturnaround.zip.ZipUtil;
|
import org.zeroturnaround.zip.ZipUtil;
|
||||||
import org.zeroturnaround.zip.transform.ByteArrayZipEntryTransformer;
|
import org.zeroturnaround.zip.transform.ByteArrayZipEntryTransformer;
|
||||||
import org.zeroturnaround.zip.transform.ZipEntryTransformer;
|
import org.zeroturnaround.zip.transform.ZipEntryTransformer;
|
||||||
|
@ -53,6 +54,7 @@ import net.fabricmc.mappings.EntryTriple;
|
||||||
import net.fabricmc.loom.LoomGradleExtension;
|
import net.fabricmc.loom.LoomGradleExtension;
|
||||||
import net.fabricmc.loom.util.Checksum;
|
import net.fabricmc.loom.util.Checksum;
|
||||||
import net.fabricmc.loom.processors.JarProcessor;
|
import net.fabricmc.loom.processors.JarProcessor;
|
||||||
|
import net.fabricmc.tinyremapper.TinyRemapper;
|
||||||
|
|
||||||
public class AccessWidenerJarProcessor implements JarProcessor {
|
public class AccessWidenerJarProcessor implements JarProcessor {
|
||||||
private AccessWidener accessWidener = new AccessWidener();
|
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
|
//Remap accessWidener if its not named, allows for AE's to be written in intermediary
|
||||||
if (!accessWidener.namespace.equals("named")) {
|
if (!accessWidener.namespace.equals("named")) {
|
||||||
try {
|
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();
|
accessWidener = remapper.remap();
|
||||||
|
|
||||||
|
tinyRemapper.finish();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException("Failed to remap access widener", e);
|
throw new RuntimeException("Failed to remap access widener", e);
|
||||||
}
|
}
|
||||||
|
@ -116,9 +123,8 @@ public class AccessWidenerJarProcessor implements JarProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
//Called when remapping the mod
|
//Called when remapping the mod
|
||||||
public void remapAccessWidener(Path modJarPath) throws IOException {
|
public void remapAccessWidener(Path modJarPath, Remapper asmRemapper) throws IOException {
|
||||||
LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class);
|
AccessWidenerRemapper remapper = new AccessWidenerRemapper(accessWidener, asmRemapper, "intermediary");
|
||||||
AccessWidenerRemapper remapper = new AccessWidenerRemapper(accessWidener, extension.getMappingsProvider().getMappings(), "intermediary");
|
|
||||||
AccessWidener remapped = remapper.remap();
|
AccessWidener remapped = remapper.remap();
|
||||||
|
|
||||||
StringWriter writer = new StringWriter();
|
StringWriter writer = new StringWriter();
|
||||||
|
|
|
@ -24,54 +24,21 @@
|
||||||
|
|
||||||
package net.fabricmc.loom.util.accesswidener;
|
package net.fabricmc.loom.util.accesswidener;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import net.fabricmc.mapping.tree.ClassDef;
|
import org.objectweb.asm.commons.Remapper;
|
||||||
import net.fabricmc.mapping.tree.FieldDef;
|
|
||||||
import net.fabricmc.mapping.tree.MethodDef;
|
|
||||||
import net.fabricmc.mapping.tree.TinyTree;
|
|
||||||
import net.fabricmc.mappings.EntryTriple;
|
import net.fabricmc.mappings.EntryTriple;
|
||||||
|
|
||||||
public class AccessWidenerRemapper {
|
public class AccessWidenerRemapper {
|
||||||
private final AccessWidener input;
|
private final AccessWidener input;
|
||||||
private final String from, to;
|
private final String to;
|
||||||
|
private final Remapper remapper;
|
||||||
|
|
||||||
private Map<String, String> classNames = new HashMap<>();
|
public AccessWidenerRemapper(AccessWidener input, Remapper remapper, String to) {
|
||||||
private Map<EntryTriple, EntryTriple> fieldNames = new HashMap<>();
|
|
||||||
private Map<EntryTriple, EntryTriple> methodNames = new HashMap<>();
|
|
||||||
|
|
||||||
public AccessWidenerRemapper(AccessWidener input, TinyTree tinyTree, String to) {
|
|
||||||
this.input = input;
|
this.input = input;
|
||||||
this.from = input.namespace;
|
|
||||||
this.to = to;
|
this.to = to;
|
||||||
populateMappings(tinyTree);
|
this.remapper = remapper;
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public AccessWidener remap() {
|
public AccessWidener remap() {
|
||||||
|
@ -84,27 +51,33 @@ public class AccessWidenerRemapper {
|
||||||
remapped.namespace = to;
|
remapped.namespace = to;
|
||||||
|
|
||||||
for (Map.Entry<String, AccessWidener.Access> entry : input.classAccess.entrySet()) {
|
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()) {
|
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()) {
|
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;
|
return remapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <K, V> V findMapping(Map<K, V> map, K key) {
|
private EntryTriple remapMethod(EntryTriple entryTriple) {
|
||||||
V value = map.get(key);
|
return new EntryTriple(
|
||||||
|
remapper.map(entryTriple.getName()),
|
||||||
|
remapper.mapMethodName(entryTriple.getOwner(), entryTriple.getName(), entryTriple.getDesc()),
|
||||||
|
remapper.mapDesc(entryTriple.getDesc())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (value == null) {
|
private EntryTriple remapField(EntryTriple entryTriple) {
|
||||||
throw new RuntimeException("Failed to find mapping for " + key.toString());
|
return new EntryTriple(
|
||||||
}
|
remapper.map(entryTriple.getName()),
|
||||||
|
remapper.mapFieldName(entryTriple.getOwner(), entryTriple.getName(), entryTriple.getDesc()),
|
||||||
return value;
|
remapper.mapDesc(entryTriple.getDesc())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue