From 1f9f48052b4ac4ac2658b62128911f6a36127f8c Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Mon, 14 Jun 2021 18:39:03 +0100 Subject: [PATCH] Basic layered mappings with @ParchmentMC support (#413) --- build.gradle | 4 +- .../fabricmc/loom/LoomGradleExtension.java | 30 +- .../configuration/CompileConfiguration.java | 8 +- .../configuration/LoomDependencyManager.java | 8 +- .../loom/configuration/mods/ModProcessor.java | 4 +- .../MinecraftProcessedProvider.java | 6 +- .../providers/LaunchProvider.java | 2 +- .../providers/MinecraftProvider.java | 220 +-------- .../providers/MinecraftProviderImpl.java | 249 +++++++++++ .../mappings/GradleMappingContext.java | 74 +++ .../mappings/LayeredMappingSpec.java | 34 ++ .../mappings/LayeredMappingSpecBuilder.java | 65 +++ .../mappings/LayeredMappingsDependency.java | 143 ++++++ .../mappings/LayeredMappingsProcessor.java | 89 ++++ .../providers/mappings/MappingContext.java | 50 +++ .../providers/mappings/MappingLayer.java | 43 ++ .../providers/mappings/MappingNamespace.java | 37 ++ .../providers/mappings/MappingsProvider.java | 385 +--------------- .../mappings/MappingsProviderImpl.java | 423 ++++++++++++++++++ .../providers/mappings/MappingsSpec.java | 29 ++ .../mappings/MojangMappingsDependency.java | 275 ------------ .../IntermediaryMappingLayer.java | 55 +++ .../IntermediaryMappingsSpec.java | 35 ++ .../mappings/mojmap/MojangMappingLayer.java | 102 +++++ .../mappings/mojmap/MojangMappingsSpec.java | 51 +++ .../parchment/ParchmentMappingLayer.java | 63 +++ .../parchment/ParchmentMappingsSpec.java | 35 ++ .../ParchmentMappingsSpecBuilder.java | 48 ++ ...ParchmentPrefixStripingMappingVisitor.java | 50 +++ .../mappings/parchment/ParchmentTreeV1.java | 165 +++++++ .../minecraft/MinecraftLibraryProvider.java | 6 +- .../minecraft/MinecraftMappedProvider.java | 12 +- .../assets/MinecraftAssetsProvider.java | 6 +- .../loom/task/GenerateSourcesTask.java | 4 +- .../net/fabricmc/loom/task/LoomTasks.java | 4 +- .../loom/task/MigrateMappingsTask.java | 14 +- .../net/fabricmc/loom/task/RemapJarTask.java | 4 +- .../fabricmc/loom/util/SourceRemapper.java | 4 +- ...DependencyResolutionManagementTest.groovy} | 0 .../test/integration/ParchmentTest.groovy | 52 +++ .../IntermediaryMappingLayerTest.groovy | 43 ++ .../LayeredMappingSpecBuilderTest.groovy | 118 +++++ .../LayeredMappingsSpecification.groovy | 121 +++++ .../LayeredMappingsTestConstants.groovy | 47 ++ .../MojangMappingLayerTest.groovy | 49 ++ .../ParchmentMappingLayerTest.groovy | 74 +++ .../resources/projects/parchment/build.gradle | 20 + 47 files changed, 2435 insertions(+), 925 deletions(-) create mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/MinecraftProviderImpl.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/mappings/GradleMappingContext.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingSpec.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingSpecBuilder.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingsDependency.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingsProcessor.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingContext.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingLayer.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingNamespace.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProviderImpl.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsSpec.java delete mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/mappings/MojangMappingsDependency.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/mappings/intermediary/IntermediaryMappingLayer.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/mappings/intermediary/IntermediaryMappingsSpec.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/mappings/mojmap/MojangMappingLayer.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/mappings/mojmap/MojangMappingsSpec.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/mappings/parchment/ParchmentMappingLayer.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/mappings/parchment/ParchmentMappingsSpec.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/mappings/parchment/ParchmentMappingsSpecBuilder.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/mappings/parchment/ParchmentPrefixStripingMappingVisitor.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/mappings/parchment/ParchmentTreeV1.java rename src/test/groovy/net/fabricmc/loom/test/integration/{dependencyResolutionManagement.groovy => DependencyResolutionManagementTest.groovy} (100%) create mode 100644 src/test/groovy/net/fabricmc/loom/test/integration/ParchmentTest.groovy create mode 100644 src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/IntermediaryMappingLayerTest.groovy create mode 100644 src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingSpecBuilderTest.groovy create mode 100644 src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingsSpecification.groovy create mode 100644 src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingsTestConstants.groovy create mode 100644 src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/MojangMappingLayerTest.groovy create mode 100644 src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/ParchmentMappingLayerTest.groovy create mode 100644 src/test/resources/projects/parchment/build.gradle diff --git a/build.gradle b/build.gradle index ef171a3..3e4cb36 100644 --- a/build.gradle +++ b/build.gradle @@ -45,6 +45,7 @@ configurations { } compileClasspath.extendsFrom bootstrap runtimeClasspath.extendsFrom bootstrap + testRuntimeClasspath.extendsFrom bootstrap } dependencies { @@ -74,6 +75,7 @@ dependencies { implementation ('net.fabricmc:tiny-mappings-parser:0.3.0+build.17') implementation 'net.fabricmc:access-widener:1.0.0' + implementation 'net.fabricmc:mapping-io:0.1.3' implementation ('net.fabricmc:lorenz-tiny:3.0.0') { transitive = false @@ -92,7 +94,7 @@ dependencies { // Testing testImplementation(gradleTestKit()) - testImplementation('org.spockframework:spock-core:2.0-M5-groovy-3.0') { + testImplementation('org.spockframework:spock-core:2.0-groovy-3.0') { exclude module: 'groovy-all' } testImplementation 'io.javalin:javalin:3.13.7' diff --git a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java index b451c8d..4f9f5e9 100644 --- a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java +++ b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java @@ -52,10 +52,13 @@ import net.fabricmc.loom.configuration.LoomProjectData; import net.fabricmc.loom.configuration.ide.RunConfigSettings; import net.fabricmc.loom.configuration.processors.JarProcessor; import net.fabricmc.loom.configuration.processors.JarProcessorManager; -import net.fabricmc.loom.configuration.providers.MinecraftProvider; -import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider; -import net.fabricmc.loom.configuration.providers.mappings.MojangMappingsDependency; +import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMappedProvider; +import net.fabricmc.loom.configuration.providers.mappings.GradleMappingContext; +import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpec; +import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuilder; +import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsDependency; +import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; public class LoomGradleExtension { public String refmapName; @@ -114,7 +117,14 @@ public class LoomGradleExtension { } public Dependency officialMojangMappings() { - return new MojangMappingsDependency(project, this); + return layered(LayeredMappingSpecBuilder::officalMojangMappings); + } + + public Dependency layered(Action action) { + LayeredMappingSpecBuilder builder = new LayeredMappingSpecBuilder(); + action.execute(builder); + LayeredMappingSpec builtSpec = builder.build(); + return new LayeredMappingsDependency(new GradleMappingContext(project, "layers_" + builtSpec.getVersion().replace("+", "_").replace(".", "_")), builtSpec, builtSpec.getVersion()); } public LoomGradleExtension(Project project) { @@ -246,7 +256,7 @@ public class LoomGradleExtension { return new File((String) project.property("fabric.loom.natives.dir")); } - File natives = new File(getUserCache(), "natives/" + getMinecraftProvider().getMinecraftVersion()); + File natives = new File(getUserCache(), "natives/" + getMinecraftProvider().minecraftVersion()); if (!natives.exists()) { natives.mkdirs(); @@ -271,16 +281,16 @@ public class LoomGradleExtension { return dependencyManager; } - public MinecraftProvider getMinecraftProvider() { - return getDependencyManager().getProvider(MinecraftProvider.class); + public MinecraftProviderImpl getMinecraftProvider() { + return getDependencyManager().getProvider(MinecraftProviderImpl.class); } public MinecraftMappedProvider getMinecraftMappedProvider() { return getMappingsProvider().mappedProvider; } - public MappingsProvider getMappingsProvider() { - return getDependencyManager().getProvider(MappingsProvider.class); + public MappingsProviderImpl getMappingsProvider() { + return getDependencyManager().getProvider(MappingsProviderImpl.class); } public void setDependencyManager(LoomDependencyManager dependencyManager) { @@ -342,7 +352,7 @@ public class LoomGradleExtension { // Creates a new file each time its called, this is then held onto later when remapping the output jar // Required as now when using parallel builds the old single file could be written by another sourceset compile task public synchronized File getNextMixinMappings() { - File mixinMapping = new File(getProjectBuildCache(), "mixin-map-" + getMinecraftProvider().getMinecraftVersion() + "-" + getMappingsProvider().mappingsVersion + "." + mixinMappings.size() + ".tiny"); + File mixinMapping = new File(getProjectBuildCache(), "mixin-map-" + getMinecraftProvider().minecraftVersion() + "-" + getMappingsProvider().mappingsVersion + "." + mixinMappings.size() + ".tiny"); mixinMappings.add(mixinMapping); return mixinMapping; } diff --git a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java index fb35b97..df32026 100644 --- a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java +++ b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java @@ -39,8 +39,8 @@ import net.fabricmc.loom.build.mixin.KaptApInvoker; import net.fabricmc.loom.build.mixin.ScalaApInvoker; import net.fabricmc.loom.configuration.ide.SetupIntelijRunConfigs; import net.fabricmc.loom.configuration.providers.LaunchProvider; -import net.fabricmc.loom.configuration.providers.MinecraftProvider; -import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider; +import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl; +import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; import net.fabricmc.loom.util.Constants; public final class CompileConfiguration { @@ -116,8 +116,8 @@ public final class CompileConfiguration { LoomDependencyManager dependencyManager = new LoomDependencyManager(); extension.setDependencyManager(dependencyManager); - dependencyManager.addProvider(new MinecraftProvider(project)); - dependencyManager.addProvider(new MappingsProvider(project)); + dependencyManager.addProvider(new MinecraftProviderImpl(project)); + dependencyManager.addProvider(new MappingsProviderImpl(project)); dependencyManager.addProvider(new LaunchProvider(project)); dependencyManager.handleDependencies(project); diff --git a/src/main/java/net/fabricmc/loom/configuration/LoomDependencyManager.java b/src/main/java/net/fabricmc/loom/configuration/LoomDependencyManager.java index 55c544c..31ec1b6 100644 --- a/src/main/java/net/fabricmc/loom/configuration/LoomDependencyManager.java +++ b/src/main/java/net/fabricmc/loom/configuration/LoomDependencyManager.java @@ -42,7 +42,7 @@ import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.build.ModCompileRemapper; import net.fabricmc.loom.configuration.DependencyProvider.DependencyInfo; import net.fabricmc.loom.configuration.mods.ModProcessor; -import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider; +import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.SourceRemapper; import net.fabricmc.loom.LoomRepositoryPlugin; @@ -86,7 +86,7 @@ public class LoomDependencyManager { public void handleDependencies(Project project) { List afterTasks = new ArrayList<>(); - MappingsProvider mappingsProvider = null; + MappingsProviderImpl mappingsProvider = null; project.getLogger().info(":setting up loom dependencies"); LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); @@ -100,8 +100,8 @@ public class LoomDependencyManager { return list; }).providers.add(provider); - if (provider instanceof MappingsProvider) { - mappingsProvider = (MappingsProvider) provider; + if (provider instanceof MappingsProviderImpl) { + mappingsProvider = (MappingsProviderImpl) provider; } } diff --git a/src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java b/src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java index 6eaa113..23d6138 100644 --- a/src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java +++ b/src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java @@ -56,7 +56,7 @@ import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.LoomGradlePlugin; import net.fabricmc.loom.configuration.RemappedConfigurationEntry; import net.fabricmc.loom.configuration.processors.dependency.ModDependencyInfo; -import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider; +import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMappedProvider; import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.TinyRemapperMappingsHelper; @@ -132,7 +132,7 @@ public class ModProcessor { String toM = "named"; MinecraftMappedProvider mappedProvider = extension.getMinecraftMappedProvider(); - MappingsProvider mappingsProvider = extension.getMappingsProvider(); + MappingsProviderImpl mappingsProvider = extension.getMappingsProvider(); Path mc = mappedProvider.getIntermediaryJar().toPath(); Path[] mcDeps = project.getConfigurations().getByName(Constants.Configurations.LOADER_DEPENDENCIES).getFiles() diff --git a/src/main/java/net/fabricmc/loom/configuration/processors/MinecraftProcessedProvider.java b/src/main/java/net/fabricmc/loom/configuration/processors/MinecraftProcessedProvider.java index 0a24a75..d0213eb 100644 --- a/src/main/java/net/fabricmc/loom/configuration/processors/MinecraftProcessedProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/processors/MinecraftProcessedProvider.java @@ -31,8 +31,8 @@ import java.util.function.Consumer; import org.apache.commons.io.FileUtils; import org.gradle.api.Project; -import net.fabricmc.loom.configuration.providers.MinecraftProvider; -import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider; +import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl; +import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMappedProvider; import net.fabricmc.loom.util.Constants; @@ -84,7 +84,7 @@ public class MinecraftProcessedProvider extends MinecraftMappedProvider { } @Override - public void initFiles(MinecraftProvider minecraftProvider, MappingsProvider mappingsProvider) { + public void initFiles(MinecraftProviderImpl minecraftProvider, MappingsProviderImpl mappingsProvider) { super.initFiles(minecraftProvider, mappingsProvider); projectMappedJar = new File(getJarDirectory(getExtension().getRootProjectPersistentCache(), projectMappedClassifier), "minecraft-" + getJarVersionString(projectMappedClassifier) + ".jar"); diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/LaunchProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/LaunchProvider.java index e7f961d..980cecf 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/LaunchProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/LaunchProvider.java @@ -65,7 +65,7 @@ public class LaunchProvider extends DependencyProvider { .property("client", "org.lwjgl.librarypath", getExtension().getNativesDirectory().getAbsolutePath()) .argument("client", "--assetIndex") - .argument("client", getExtension().getMinecraftProvider().getVersionInfo().assetIndex().fabricId(getExtension().getMinecraftProvider().getMinecraftVersion())) + .argument("client", getExtension().getMinecraftProvider().getVersionInfo().assetIndex().fabricId(getExtension().getMinecraftProvider().minecraftVersion())) .argument("client", "--assetsDir") .argument("client", new File(getExtension().getUserCache(), "assets").getAbsolutePath()); diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/MinecraftProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/MinecraftProvider.java index aed9c72..fed7f5f 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/MinecraftProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/MinecraftProvider.java @@ -24,224 +24,10 @@ package net.fabricmc.loom.configuration.providers; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.Optional; -import java.util.function.Consumer; - -import com.google.common.io.Files; -import org.gradle.api.GradleException; -import org.gradle.api.Project; -import org.gradle.api.logging.Logger; - -import net.fabricmc.loom.LoomGradlePlugin; -import net.fabricmc.loom.configuration.DependencyProvider; -import net.fabricmc.loom.configuration.providers.minecraft.ManifestVersion; -import net.fabricmc.loom.configuration.providers.minecraft.MinecraftLibraryProvider; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta; -import net.fabricmc.loom.util.Constants; -import net.fabricmc.loom.util.DownloadUtil; -import net.fabricmc.loom.util.HashedDownloadUtil; -import net.fabricmc.stitch.merge.JarMerger; -public class MinecraftProvider extends DependencyProvider { - private String minecraftVersion; +public interface MinecraftProvider { + String minecraftVersion(); - private MinecraftVersionMeta versionInfo; - private MinecraftLibraryProvider libraryProvider; - - private File minecraftJson; - private File minecraftClientJar; - private File minecraftServerJar; - private File minecraftMergedJar; - private File versionManifestJson; - - public MinecraftProvider(Project project) { - super(project); - } - - @Override - public void provide(DependencyInfo dependency, Consumer postPopulationScheduler) throws Exception { - minecraftVersion = dependency.getDependency().getVersion(); - - boolean offline = getProject().getGradle().getStartParameter().isOffline(); - - initFiles(); - - downloadMcJson(offline); - - try (FileReader reader = new FileReader(minecraftJson)) { - versionInfo = LoomGradlePlugin.OBJECT_MAPPER.readValue(reader, MinecraftVersionMeta.class); - } - - // Add Loom as an annotation processor - addDependency(getProject().files(this.getClass().getProtectionDomain().getCodeSource().getLocation()), "compileOnly"); - - if (offline) { - if (minecraftClientJar.exists() && minecraftServerJar.exists()) { - getProject().getLogger().debug("Found client and server jars, presuming up-to-date"); - } else if (minecraftMergedJar.exists()) { - //Strictly we don't need the split jars if the merged one exists, let's try go on - getProject().getLogger().warn("Missing game jar but merged jar present, things might end badly"); - } else { - throw new GradleException("Missing jar(s); Client: " + minecraftClientJar.exists() + ", Server: " + minecraftServerJar.exists()); - } - } else { - downloadJars(getProject().getLogger()); - } - - libraryProvider = new MinecraftLibraryProvider(); - libraryProvider.provide(this, getProject()); - - if (!minecraftMergedJar.exists() || isRefreshDeps()) { - try { - mergeJars(getProject().getLogger()); - } catch (Throwable e) { - HashedDownloadUtil.delete(minecraftClientJar); - HashedDownloadUtil.delete(minecraftServerJar); - minecraftMergedJar.delete(); - - getProject().getLogger().error("Could not merge JARs! Deleting source JARs - please re-run the command and move on.", e); - throw e; - } - } - } - - private void initFiles() { - minecraftJson = new File(getExtension().getUserCache(), "minecraft-" + minecraftVersion + "-info.json"); - minecraftClientJar = new File(getExtension().getUserCache(), "minecraft-" + minecraftVersion + "-client.jar"); - minecraftServerJar = new File(getExtension().getUserCache(), "minecraft-" + minecraftVersion + "-server.jar"); - minecraftMergedJar = new File(getExtension().getUserCache(), "minecraft-" + minecraftVersion + "-merged.jar"); - versionManifestJson = new File(getExtension().getUserCache(), "version_manifest.json"); - } - - private void downloadMcJson(boolean offline) throws IOException { - if (getExtension().isShareCaches() && !getExtension().isRootProject() && versionManifestJson.exists() && !isRefreshDeps()) { - return; - } - - if (!offline && !isRefreshDeps() && hasRecentValidManifest()) { - // We have a recent valid manifest file, so do nothing - } else if (offline) { - if (versionManifestJson.exists()) { - // If there is the manifests already we'll presume that's good enough - getProject().getLogger().debug("Found version manifests, presuming up-to-date"); - } else { - // If we don't have the manifests then there's nothing more we can do - throw new GradleException("Version manifests not found at " + versionManifestJson.getAbsolutePath()); - } - } else { - getProject().getLogger().debug("Downloading version manifests"); - DownloadUtil.downloadIfChanged(new URL(Constants.VERSION_MANIFESTS), versionManifestJson, getProject().getLogger()); - } - - String versionManifest = Files.asCharSource(versionManifestJson, StandardCharsets.UTF_8).read(); - ManifestVersion mcManifest = LoomGradlePlugin.OBJECT_MAPPER.readValue(versionManifest, ManifestVersion.class); - - Optional optionalVersion = Optional.empty(); - - if (getExtension().customManifest != null) { - ManifestVersion.Versions customVersion = new ManifestVersion.Versions(); - customVersion.id = minecraftVersion; - customVersion.url = getExtension().customManifest; - optionalVersion = Optional.of(customVersion); - getProject().getLogger().lifecycle("Using custom minecraft manifest"); - } - - if (!optionalVersion.isPresent()) { - optionalVersion = mcManifest.versions().stream().filter(versions -> versions.id.equalsIgnoreCase(minecraftVersion)).findFirst(); - } - - if (optionalVersion.isPresent()) { - if (offline) { - if (minecraftJson.exists()) { - //If there is the manifest already we'll presume that's good enough - getProject().getLogger().debug("Found Minecraft {} manifest, presuming up-to-date", minecraftVersion); - } else { - //If we don't have the manifests then there's nothing more we can do - throw new GradleException("Minecraft " + minecraftVersion + " manifest not found at " + minecraftJson.getAbsolutePath()); - } - } else { - getProject().getLogger().debug("Downloading Minecraft {} manifest", minecraftVersion); - - ManifestVersion.Versions version = optionalVersion.get(); - String url = version.url; - - if (version.sha1 != null) { - HashedDownloadUtil.downloadIfInvalid(new URL(url), minecraftJson, version.sha1, getProject().getLogger(), true); - } else { - // Use the etag if no hash found from url - DownloadUtil.downloadIfChanged(new URL(url), minecraftJson, getProject().getLogger()); - } - } - } else { - throw new RuntimeException("Failed to find minecraft version: " + minecraftVersion); - } - } - - private boolean hasRecentValidManifest() throws IOException { - if (getExtension().customManifest != null) { - return false; - } - - if (!versionManifestJson.exists() || !minecraftJson.exists()) { - return false; - } - - if (versionManifestJson.lastModified() > System.currentTimeMillis() - 24 * 3_600_000) { - // Version manifest hasn't been modified in 24 hours, time to get a new one. - return false; - } - - ManifestVersion manifest = LoomGradlePlugin.OBJECT_MAPPER.readValue(Files.asCharSource(versionManifestJson, StandardCharsets.UTF_8).read(), ManifestVersion.class); - Optional version = manifest.versions().stream().filter(versions -> versions.id.equalsIgnoreCase(minecraftVersion)).findFirst(); - - // fail if the expected mc version was not found, will download the file again. - return version.isPresent(); - } - - private void downloadJars(Logger logger) throws IOException { - if (getExtension().isShareCaches() && !getExtension().isRootProject() && minecraftClientJar.exists() && minecraftServerJar.exists() && !isRefreshDeps()) { - return; - } - - MinecraftVersionMeta.Download client = versionInfo.download("client"); - MinecraftVersionMeta.Download server = versionInfo.download("server"); - - HashedDownloadUtil.downloadIfInvalid(new URL(client.url()), minecraftClientJar, client.sha1(), logger, false); - HashedDownloadUtil.downloadIfInvalid(new URL(server.url()), minecraftServerJar, server.sha1(), logger, false); - } - - private void mergeJars(Logger logger) throws IOException { - logger.info(":merging jars"); - - try (JarMerger jarMerger = new JarMerger(minecraftClientJar, minecraftServerJar, minecraftMergedJar)) { - jarMerger.enableSyntheticParamsOffset(); - jarMerger.merge(); - } - } - - public File getMergedJar() { - return minecraftMergedJar; - } - - public String getMinecraftVersion() { - return minecraftVersion; - } - - public MinecraftVersionMeta getVersionInfo() { - return versionInfo; - } - - public MinecraftLibraryProvider getLibraryProvider() { - return libraryProvider; - } - - @Override - public String getTargetConfig() { - return Constants.Configurations.MINECRAFT; - } + MinecraftVersionMeta getVersionInfo(); } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/MinecraftProviderImpl.java b/src/main/java/net/fabricmc/loom/configuration/providers/MinecraftProviderImpl.java new file mode 100644 index 0000000..2767755 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/MinecraftProviderImpl.java @@ -0,0 +1,249 @@ +/* + * 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.configuration.providers; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Optional; +import java.util.function.Consumer; + +import com.google.common.io.Files; +import org.gradle.api.GradleException; +import org.gradle.api.Project; +import org.gradle.api.logging.Logger; + +import net.fabricmc.loom.LoomGradlePlugin; +import net.fabricmc.loom.configuration.DependencyProvider; +import net.fabricmc.loom.configuration.providers.minecraft.ManifestVersion; +import net.fabricmc.loom.configuration.providers.minecraft.MinecraftLibraryProvider; +import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta; +import net.fabricmc.loom.util.Constants; +import net.fabricmc.loom.util.DownloadUtil; +import net.fabricmc.loom.util.HashedDownloadUtil; +import net.fabricmc.stitch.merge.JarMerger; + +public class MinecraftProviderImpl extends DependencyProvider implements MinecraftProvider { + private String minecraftVersion; + + private MinecraftVersionMeta versionInfo; + private MinecraftLibraryProvider libraryProvider; + + private File minecraftJson; + private File minecraftClientJar; + private File minecraftServerJar; + private File minecraftMergedJar; + private File versionManifestJson; + + public MinecraftProviderImpl(Project project) { + super(project); + } + + @Override + public void provide(DependencyInfo dependency, Consumer postPopulationScheduler) throws Exception { + minecraftVersion = dependency.getDependency().getVersion(); + + boolean offline = getProject().getGradle().getStartParameter().isOffline(); + + initFiles(); + + downloadMcJson(offline); + + try (FileReader reader = new FileReader(minecraftJson)) { + versionInfo = LoomGradlePlugin.OBJECT_MAPPER.readValue(reader, MinecraftVersionMeta.class); + } + + // Add Loom as an annotation processor + addDependency(getProject().files(this.getClass().getProtectionDomain().getCodeSource().getLocation()), "compileOnly"); + + if (offline) { + if (minecraftClientJar.exists() && minecraftServerJar.exists()) { + getProject().getLogger().debug("Found client and server jars, presuming up-to-date"); + } else if (minecraftMergedJar.exists()) { + //Strictly we don't need the split jars if the merged one exists, let's try go on + getProject().getLogger().warn("Missing game jar but merged jar present, things might end badly"); + } else { + throw new GradleException("Missing jar(s); Client: " + minecraftClientJar.exists() + ", Server: " + minecraftServerJar.exists()); + } + } else { + downloadJars(getProject().getLogger()); + } + + libraryProvider = new MinecraftLibraryProvider(); + libraryProvider.provide(this, getProject()); + + if (!minecraftMergedJar.exists() || isRefreshDeps()) { + try { + mergeJars(getProject().getLogger()); + } catch (Throwable e) { + HashedDownloadUtil.delete(minecraftClientJar); + HashedDownloadUtil.delete(minecraftServerJar); + minecraftMergedJar.delete(); + + getProject().getLogger().error("Could not merge JARs! Deleting source JARs - please re-run the command and move on.", e); + throw e; + } + } + } + + private void initFiles() { + minecraftJson = new File(getExtension().getUserCache(), "minecraft-" + minecraftVersion + "-info.json"); + minecraftClientJar = new File(getExtension().getUserCache(), "minecraft-" + minecraftVersion + "-client.jar"); + minecraftServerJar = new File(getExtension().getUserCache(), "minecraft-" + minecraftVersion + "-server.jar"); + minecraftMergedJar = new File(getExtension().getUserCache(), "minecraft-" + minecraftVersion + "-merged.jar"); + versionManifestJson = new File(getExtension().getUserCache(), "version_manifest.json"); + } + + private void downloadMcJson(boolean offline) throws IOException { + if (getExtension().isShareCaches() && !getExtension().isRootProject() && versionManifestJson.exists() && !isRefreshDeps()) { + return; + } + + if (!offline && !isRefreshDeps() && hasRecentValidManifest()) { + // We have a recent valid manifest file, so do nothing + } else if (offline) { + if (versionManifestJson.exists()) { + // If there is the manifests already we'll presume that's good enough + getProject().getLogger().debug("Found version manifests, presuming up-to-date"); + } else { + // If we don't have the manifests then there's nothing more we can do + throw new GradleException("Version manifests not found at " + versionManifestJson.getAbsolutePath()); + } + } else { + getProject().getLogger().debug("Downloading version manifests"); + DownloadUtil.downloadIfChanged(new URL(Constants.VERSION_MANIFESTS), versionManifestJson, getProject().getLogger()); + } + + String versionManifest = Files.asCharSource(versionManifestJson, StandardCharsets.UTF_8).read(); + ManifestVersion mcManifest = LoomGradlePlugin.OBJECT_MAPPER.readValue(versionManifest, ManifestVersion.class); + + Optional optionalVersion = Optional.empty(); + + if (getExtension().customManifest != null) { + ManifestVersion.Versions customVersion = new ManifestVersion.Versions(); + customVersion.id = minecraftVersion; + customVersion.url = getExtension().customManifest; + optionalVersion = Optional.of(customVersion); + getProject().getLogger().lifecycle("Using custom minecraft manifest"); + } + + if (!optionalVersion.isPresent()) { + optionalVersion = mcManifest.versions().stream().filter(versions -> versions.id.equalsIgnoreCase(minecraftVersion)).findFirst(); + } + + if (optionalVersion.isPresent()) { + if (offline) { + if (minecraftJson.exists()) { + //If there is the manifest already we'll presume that's good enough + getProject().getLogger().debug("Found Minecraft {} manifest, presuming up-to-date", minecraftVersion); + } else { + //If we don't have the manifests then there's nothing more we can do + throw new GradleException("Minecraft " + minecraftVersion + " manifest not found at " + minecraftJson.getAbsolutePath()); + } + } else { + getProject().getLogger().debug("Downloading Minecraft {} manifest", minecraftVersion); + + ManifestVersion.Versions version = optionalVersion.get(); + String url = version.url; + + if (version.sha1 != null) { + HashedDownloadUtil.downloadIfInvalid(new URL(url), minecraftJson, version.sha1, getProject().getLogger(), true); + } else { + // Use the etag if no hash found from url + DownloadUtil.downloadIfChanged(new URL(url), minecraftJson, getProject().getLogger()); + } + } + } else { + throw new RuntimeException("Failed to find minecraft version: " + minecraftVersion); + } + } + + private boolean hasRecentValidManifest() throws IOException { + if (getExtension().customManifest != null) { + return false; + } + + if (!versionManifestJson.exists() || !minecraftJson.exists()) { + return false; + } + + if (versionManifestJson.lastModified() > System.currentTimeMillis() - 24 * 3_600_000) { + // Version manifest hasn't been modified in 24 hours, time to get a new one. + return false; + } + + ManifestVersion manifest = LoomGradlePlugin.OBJECT_MAPPER.readValue(Files.asCharSource(versionManifestJson, StandardCharsets.UTF_8).read(), ManifestVersion.class); + Optional version = manifest.versions().stream().filter(versions -> versions.id.equalsIgnoreCase(minecraftVersion)).findFirst(); + + // fail if the expected mc version was not found, will download the file again. + return version.isPresent(); + } + + private void downloadJars(Logger logger) throws IOException { + if (getExtension().isShareCaches() && !getExtension().isRootProject() && minecraftClientJar.exists() && minecraftServerJar.exists() && !isRefreshDeps()) { + return; + } + + MinecraftVersionMeta.Download client = versionInfo.download("client"); + MinecraftVersionMeta.Download server = versionInfo.download("server"); + + HashedDownloadUtil.downloadIfInvalid(new URL(client.url()), minecraftClientJar, client.sha1(), logger, false); + HashedDownloadUtil.downloadIfInvalid(new URL(server.url()), minecraftServerJar, server.sha1(), logger, false); + } + + private void mergeJars(Logger logger) throws IOException { + logger.info(":merging jars"); + + try (JarMerger jarMerger = new JarMerger(minecraftClientJar, minecraftServerJar, minecraftMergedJar)) { + jarMerger.enableSyntheticParamsOffset(); + jarMerger.merge(); + } + } + + public File getMergedJar() { + return minecraftMergedJar; + } + + @Override + public String minecraftVersion() { + return minecraftVersion; + } + + @Override + public MinecraftVersionMeta getVersionInfo() { + return versionInfo; + } + + public MinecraftLibraryProvider getLibraryProvider() { + return libraryProvider; + } + + @Override + public String getTargetConfig() { + return Constants.Configurations.MINECRAFT; + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/GradleMappingContext.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/GradleMappingContext.java new file mode 100644 index 0000000..d935701 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/GradleMappingContext.java @@ -0,0 +1,74 @@ +/* + * 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.configuration.providers.mappings; + +import java.io.File; + +import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.logging.Logger; + +import net.fabricmc.loom.LoomGradleExtension; +import net.fabricmc.loom.configuration.providers.MinecraftProvider; + +public class GradleMappingContext implements MappingContext { + private final Project project; + private final LoomGradleExtension extension; + private final String workingDirName; + + public GradleMappingContext(Project project, String workingDirName) { + this.project = project; + this.extension = project.getExtensions().getByType(LoomGradleExtension.class); + this.workingDirName = workingDirName; + } + + @Override + public File mavenFile(String mavenNotation) { + Configuration configuration = project.getConfigurations().detachedConfiguration(project.getDependencies().create(mavenNotation)); + return configuration.getSingleFile(); + } + + @Override + public MappingsProvider mappingsProvider() { + return extension.getMappingsProvider(); + } + + @Override + public MinecraftProvider minecraftProvider() { + return extension.getMinecraftProvider(); + } + + @Override + public File workingDirectory(String name) { + File tempDir = new File(mappingsProvider().getMappingsDir().toFile(), workingDirName); + tempDir.mkdirs(); + return new File(tempDir, name); + } + + @Override + public Logger getLogger() { + return project.getLogger(); + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingSpec.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingSpec.java new file mode 100644 index 0000000..9f86fb5 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingSpec.java @@ -0,0 +1,34 @@ +/* + * 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.configuration.providers.mappings; + +import java.util.List; + +public record LayeredMappingSpec(List> layers) { + public String getVersion() { + // TODO something better? + return "layered+hash.%d".formatted(Math.abs(hashCode())); + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingSpecBuilder.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingSpecBuilder.java new file mode 100644 index 0000000..389df64 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingSpecBuilder.java @@ -0,0 +1,65 @@ +/* + * 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.configuration.providers.mappings; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import org.gradle.api.Action; + +import net.fabricmc.loom.configuration.providers.mappings.intermediary.IntermediaryMappingsSpec; +import net.fabricmc.loom.configuration.providers.mappings.mojmap.MojangMappingsSpec; +import net.fabricmc.loom.configuration.providers.mappings.parchment.ParchmentMappingsSpecBuilder; + +public class LayeredMappingSpecBuilder { + private final List> layers = new LinkedList<>(); + + public LayeredMappingSpecBuilder officalMojangMappings() { + layers.add(new MojangMappingsSpec()); + return this; + } + + public LayeredMappingSpecBuilder parchment(String mavenNotation) { + parchment(mavenNotation, parchmentMappingsSpecBuilder -> parchmentMappingsSpecBuilder.setRemovePrefix(true)); + return this; + } + + public LayeredMappingSpecBuilder parchment(String mavenNotation, Action action) { + var builder = ParchmentMappingsSpecBuilder.builder(mavenNotation); + action.execute(builder); + layers.add(builder.build()); + return this; + } + + public LayeredMappingSpec build() { + List> builtLayers = new LinkedList<>(); + // Intermediary is always the base layer + builtLayers.add(new IntermediaryMappingsSpec()); + builtLayers.addAll(layers); + + return new LayeredMappingSpec(Collections.unmodifiableList(builtLayers)); + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingsDependency.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingsDependency.java new file mode 100644 index 0000000..ddc1664 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingsDependency.java @@ -0,0 +1,143 @@ +/* + * 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.configuration.providers.mappings; + +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.Objects; +import java.util.Set; + +import org.gradle.api.artifacts.Dependency; +import org.gradle.api.artifacts.SelfResolvingDependency; +import org.gradle.api.tasks.TaskDependency; +import org.zeroturnaround.zip.ByteSource; +import org.zeroturnaround.zip.ZipEntrySource; +import org.zeroturnaround.zip.ZipUtil; + +import net.fabricmc.loom.LoomGradlePlugin; +import net.fabricmc.mappingio.adapter.MappingDstNsReorder; +import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch; +import net.fabricmc.mappingio.format.Tiny2Writer; +import net.fabricmc.mappingio.tree.MemoryMappingTree; + +public class LayeredMappingsDependency implements SelfResolvingDependency { + private static final String GROUP = "loom"; + private static final String MODULE = "mappings"; + + private final MappingContext mappingContext; + private final LayeredMappingSpec layeredMappingSpec; + private final String version; + + public LayeredMappingsDependency(MappingContext mappingContext, LayeredMappingSpec layeredMappingSpec, String version) { + this.mappingContext = mappingContext; + this.layeredMappingSpec = layeredMappingSpec; + this.version = version; + } + + @Override + public Set resolve() { + Path mappingsDir = mappingContext.mappingsProvider().getMappingsDir(); + Path mappingsFile = mappingsDir.resolve(String.format("%s.%s-%s.tiny", GROUP, MODULE, getVersion())); + + if (!Files.exists(mappingsFile) || LoomGradlePlugin.refreshDeps) { + try { + var processor = new LayeredMappingsProcessor(layeredMappingSpec); + MemoryMappingTree mappings = processor.getMappings(mappingContext); + + try (Writer writer = new StringWriter()) { + Tiny2Writer tiny2Writer = new Tiny2Writer(writer, false); + + MappingDstNsReorder nsReorder = new MappingDstNsReorder(tiny2Writer, Collections.singletonList(MappingNamespace.NAMED.stringValue())); + MappingSourceNsSwitch nsSwitch = new MappingSourceNsSwitch(nsReorder, MappingNamespace.INTERMEDIARY.stringValue()); + mappings.accept(nsSwitch); + + Files.deleteIfExists(mappingsFile); + + ZipUtil.pack(new ZipEntrySource[] { + new ByteSource("mappings/mappings.tiny", writer.toString().getBytes(StandardCharsets.UTF_8)) + }, mappingsFile.toFile()); + } + } catch (IOException e) { + throw new RuntimeException("Failed to resolve Mojang mappings", e); + } + } + + return Collections.singleton(mappingsFile.toFile()); + } + + @Override + public Set resolve(boolean transitive) { + return resolve(); + } + + @Override + public TaskDependency getBuildDependencies() { + return task -> Collections.emptySet(); + } + + @Override + public String getGroup() { + return GROUP; + } + + @Override + public String getName() { + return MODULE; + } + + @Override + public String getVersion() { + return version; + } + + @Override + public boolean contentEquals(Dependency dependency) { + if (dependency instanceof LayeredMappingsDependency layeredMappingsDependency) { + return Objects.equals(layeredMappingsDependency.getVersion(), this.getVersion()); + } + + return false; + } + + @Override + public Dependency copy() { + return new LayeredMappingsDependency(mappingContext, layeredMappingSpec, version); + } + + @Override + public String getReason() { + return null; + } + + @Override + public void because(String s) { + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingsProcessor.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingsProcessor.java new file mode 100644 index 0000000..cc45ea6 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/LayeredMappingsProcessor.java @@ -0,0 +1,89 @@ +/* + * 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.configuration.providers.mappings; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch; +import net.fabricmc.mappingio.tree.MemoryMappingTree; + +public class LayeredMappingsProcessor { + private final LayeredMappingSpec layeredMappingSpec; + + public LayeredMappingsProcessor(LayeredMappingSpec spec) { + this.layeredMappingSpec = spec; + } + + public MemoryMappingTree getMappings(MappingContext context) throws IOException { + MemoryMappingTree mappingTree = new MemoryMappingTree(); + + List> visitedLayers = new ArrayList<>(); + + for (MappingsSpec spec : layeredMappingSpec.layers()) { + MappingLayer layer = spec.createLayer(context); + + for (Class dependentLayer : layer.dependsOn()) { + if (!visitedLayers.contains(dependentLayer)) { + throw new RuntimeException("Layer %s depends on %s".formatted(layer.getClass().getName(), dependentLayer.getName())); + } + } + + visitedLayers.add(layer.getClass()); + + // We have to rebuild a new tree to work on when a layer doesnt merge into layered + boolean rebuild = layer.getSourceNamespace() != MappingNamespace.NAMED; + MemoryMappingTree workingTree; + + if (rebuild) { + var tempTree = new MemoryMappingTree(); + + // This can be null on the first layer + if (mappingTree.getSrcNamespace() != null) { + var sourceNsSwitch = new MappingSourceNsSwitch(tempTree, layer.getSourceNamespace().stringValue()); + mappingTree.accept(sourceNsSwitch); + } + + workingTree = tempTree; + } else { + workingTree = mappingTree; + } + + try { + layer.visit(workingTree); + } catch (IOException e) { + throw new IOException("Failed to visit: " + layer.getClass(), e); + } + + if (rebuild) { + mappingTree = new MemoryMappingTree(); + workingTree.accept(new MappingSourceNsSwitch(mappingTree, MappingNamespace.NAMED.stringValue())); + } + } + + return mappingTree; + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingContext.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingContext.java new file mode 100644 index 0000000..5ae5ea6 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingContext.java @@ -0,0 +1,50 @@ +/* + * 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.configuration.providers.mappings; + +import java.io.File; + +import org.gradle.api.logging.Logger; + +import net.fabricmc.loom.configuration.providers.MinecraftProvider; + +public interface MappingContext { + File mavenFile(String mavenNotation); + + MappingsProvider mappingsProvider(); + + MinecraftProvider minecraftProvider(); + + default String minecraftVersion() { + return minecraftProvider().minecraftVersion(); + } + + /** + * Creates a temporary working dir to be used to store working files. + */ + File workingDirectory(String name); + + Logger getLogger(); +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingLayer.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingLayer.java new file mode 100644 index 0000000..2fdd451 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingLayer.java @@ -0,0 +1,43 @@ +/* + * 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.configuration.providers.mappings; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +import net.fabricmc.mappingio.MappingVisitor; + +public interface MappingLayer { + void visit(MappingVisitor mappingVisitor) throws IOException; + + default MappingNamespace getSourceNamespace() { + return MappingNamespace.NAMED; + } + + default List> dependsOn() { + return Collections.emptyList(); + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingNamespace.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingNamespace.java new file mode 100644 index 0000000..8ac400a --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingNamespace.java @@ -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.configuration.providers.mappings; + +import java.util.Locale; + +public enum MappingNamespace { + OFFICIAL, + INTERMEDIARY, + NAMED; + + public String stringValue() { + return name().toLowerCase(Locale.ROOT); + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProvider.java index c19b379..c2c2828 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProvider.java @@ -24,390 +24,11 @@ package net.fabricmc.loom.configuration.providers.mappings; -import java.io.BufferedReader; import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.function.Consumer; -import com.google.common.base.Preconditions; -import com.google.common.net.UrlEscapers; -import com.google.gson.JsonObject; -import org.apache.commons.io.FileUtils; -import org.apache.tools.ant.util.StringUtils; -import org.gradle.api.Project; -import org.zeroturnaround.zip.FileSource; -import org.zeroturnaround.zip.ZipEntrySource; -import org.zeroturnaround.zip.ZipUtil; +public interface MappingsProvider { + Path getMappingsDir(); -import net.fabricmc.loom.LoomGradleExtension; -import net.fabricmc.loom.LoomGradlePlugin; -import net.fabricmc.loom.configuration.DependencyProvider; -import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor; -import net.fabricmc.loom.configuration.processors.JarProcessorManager; -import net.fabricmc.loom.configuration.processors.MinecraftProcessedProvider; -import net.fabricmc.loom.configuration.providers.MinecraftProvider; -import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMappedProvider; -import net.fabricmc.loom.util.Constants; -import net.fabricmc.loom.util.DeletingFileVisitor; -import net.fabricmc.loom.util.DownloadUtil; -import net.fabricmc.mapping.reader.v2.TinyV2Factory; -import net.fabricmc.mapping.tree.TinyTree; -import net.fabricmc.stitch.Command; -import net.fabricmc.stitch.commands.CommandProposeFieldNames; -import net.fabricmc.stitch.commands.tinyv2.CommandMergeTinyV2; -import net.fabricmc.stitch.commands.tinyv2.CommandReorderTinyV2; - -public class MappingsProvider extends DependencyProvider { - public MinecraftMappedProvider mappedProvider; - - public String mappingsName; - public String minecraftVersion; - public String mappingsVersion; - - private final Path mappingsDir; - private final Path mappingsStepsDir; - private Path intermediaryTiny; - private boolean hasRefreshed = false; - // The mappings that gradle gives us - private Path baseTinyMappings; - // The mappings we use in practice - public File tinyMappings; - public File tinyMappingsJar; - private File unpickDefinitionsFile; - private boolean hasUnpickDefinitions; - private UnpickMetadata unpickMetadata; - - public MappingsProvider(Project project) { - super(project); - mappingsDir = getExtension().getUserCache().toPath().resolve("mappings"); - mappingsStepsDir = mappingsDir.resolve("steps"); - } - - public void clean() throws IOException { - FileUtils.deleteDirectory(mappingsDir.toFile()); - } - - public TinyTree getMappings() throws IOException { - return MappingsCache.INSTANCE.get(tinyMappings.toPath()); - } - - @Override - public void provide(DependencyInfo dependency, Consumer postPopulationScheduler) throws Exception { - MinecraftProvider minecraftProvider = getDependencyManager().getProvider(MinecraftProvider.class); - - getProject().getLogger().info(":setting up mappings (" + dependency.getDependency().getName() + " " + dependency.getResolvedVersion() + ")"); - - String version = dependency.getResolvedVersion(); - File mappingsJar = dependency.resolveFile().orElseThrow(() -> new RuntimeException("Could not find yarn mappings: " + dependency)); - - this.mappingsName = StringUtils.removeSuffix(dependency.getDependency().getGroup() + "." + dependency.getDependency().getName(), "-unmerged"); - this.minecraftVersion = minecraftProvider.getMinecraftVersion(); - - boolean isV2; - - // Only do this for official yarn, there isn't really a way we can get the mc version for all mappings - if (dependency.getDependency().getGroup() != null && dependency.getDependency().getGroup().equals("net.fabricmc") && dependency.getDependency().getName().equals("yarn") && dependency.getDependency().getVersion() != null) { - String yarnVersion = dependency.getDependency().getVersion(); - char separator = yarnVersion.contains("+build.") ? '+' : yarnVersion.contains("-") ? '-' : '.'; - String yarnMinecraftVersion = yarnVersion.substring(0, yarnVersion.lastIndexOf(separator)); - - if (!yarnMinecraftVersion.equalsIgnoreCase(minecraftVersion)) { - throw new RuntimeException(String.format("Minecraft Version (%s) does not match yarn's minecraft version (%s)", minecraftVersion, yarnMinecraftVersion)); - } - - // We can save reading the zip file + header by checking the file name - isV2 = mappingsJar.getName().endsWith("-v2.jar"); - } else { - isV2 = doesJarContainV2Mappings(mappingsJar.toPath()); - } - - this.mappingsVersion = version + (isV2 ? "-v2" : ""); - - initFiles(); - - if (isRefreshDeps()) { - cleanFiles(); - } - - Files.createDirectories(mappingsDir); - Files.createDirectories(mappingsStepsDir); - - String[] depStringSplit = dependency.getDepString().split(":"); - String jarClassifier = "final"; - - if (depStringSplit.length >= 4) { - jarClassifier = jarClassifier + depStringSplit[3]; - } - - tinyMappings = mappingsDir.resolve(StringUtils.removeSuffix(mappingsJar.getName(), ".jar") + ".tiny").toFile(); - unpickDefinitionsFile = mappingsDir.resolve(StringUtils.removeSuffix(mappingsJar.getName(), ".jar") + ".unpick").toFile(); - tinyMappingsJar = new File(getExtension().getUserCache(), mappingsJar.getName().replace(".jar", "-" + jarClassifier + ".jar")); - - if (!tinyMappings.exists() || isRefreshDeps()) { - storeMappings(getProject(), minecraftProvider, mappingsJar.toPath()); - } else { - try (FileSystem fileSystem = FileSystems.newFileSystem(mappingsJar.toPath(), (ClassLoader) null)) { - extractUnpickDefinitions(fileSystem, unpickDefinitionsFile.toPath()); - } - } - - if (!tinyMappingsJar.exists() || isRefreshDeps()) { - ZipUtil.pack(new ZipEntrySource[] {new FileSource("mappings/mappings.tiny", tinyMappings)}, tinyMappingsJar); - } - - if (hasUnpickDefinitions()) { - String notation = String.format("%s:%s:%s:constants", - dependency.getDependency().getGroup(), - dependency.getDependency().getName(), - dependency.getDependency().getVersion() - ); - - getProject().getDependencies().add(Constants.Configurations.MAPPING_CONSTANTS, notation); - populateUnpickClasspath(); - } - - addDependency(tinyMappingsJar, Constants.Configurations.MAPPINGS_FINAL); - - LoomGradleExtension extension = getExtension(); - - if (extension.accessWidener != null) { - extension.addJarProcessor(new AccessWidenerJarProcessor(getProject())); - } - - JarProcessorManager processorManager = new JarProcessorManager(extension.getJarProcessors()); - extension.setJarProcessorManager(processorManager); - processorManager.setupProcessors(); - - if (processorManager.active()) { - mappedProvider = new MinecraftProcessedProvider(getProject(), processorManager); - getProject().getLogger().lifecycle("Using project based jar storage"); - } else { - mappedProvider = new MinecraftMappedProvider(getProject()); - } - - mappedProvider.initFiles(minecraftProvider, this); - mappedProvider.provide(dependency, postPopulationScheduler); - } - - private void storeMappings(Project project, MinecraftProvider minecraftProvider, Path yarnJar) throws IOException { - project.getLogger().info(":extracting " + yarnJar.getFileName()); - - try (FileSystem fileSystem = FileSystems.newFileSystem(yarnJar, (ClassLoader) null)) { - extractMappings(fileSystem, baseTinyMappings); - extractUnpickDefinitions(fileSystem, unpickDefinitionsFile.toPath()); - } - - if (baseMappingsAreV2()) { - // These are unmerged v2 mappings - mergeAndSaveMappings(project, yarnJar); - } else { - // These are merged v1 mappings - if (tinyMappings.exists()) { - tinyMappings.delete(); - } - - project.getLogger().lifecycle(":populating field names"); - suggestFieldNames(minecraftProvider, baseTinyMappings, tinyMappings.toPath()); - } - } - - private boolean baseMappingsAreV2() throws IOException { - try (BufferedReader reader = Files.newBufferedReader(baseTinyMappings)) { - TinyV2Factory.readMetadata(reader); - return true; - } catch (IllegalArgumentException e) { - // TODO: just check the mappings version when Parser supports V1 in readMetadata() - return false; - } - } - - private boolean doesJarContainV2Mappings(Path path) throws IOException { - try (FileSystem fs = FileSystems.newFileSystem(path, (ClassLoader) null)) { - try (BufferedReader reader = Files.newBufferedReader(fs.getPath("mappings", "mappings.tiny"))) { - TinyV2Factory.readMetadata(reader); - return true; - } catch (IllegalArgumentException e) { - return false; - } - } - } - - public static void extractMappings(FileSystem jar, Path extractTo) throws IOException { - Files.copy(jar.getPath("mappings/mappings.tiny"), extractTo, StandardCopyOption.REPLACE_EXISTING); - } - - private void extractUnpickDefinitions(FileSystem jar, Path extractTo) throws IOException { - Path unpickPath = jar.getPath("extras/definitions.unpick"); - Path unpickMetadataPath = jar.getPath("extras/unpick.json"); - - if (!Files.exists(unpickPath) || !Files.exists(unpickMetadataPath)) { - return; - } - - Files.copy(unpickPath, extractTo, StandardCopyOption.REPLACE_EXISTING); - - unpickMetadata = parseUnpickMetadata(unpickMetadataPath); - hasUnpickDefinitions = true; - } - - private UnpickMetadata parseUnpickMetadata(Path input) throws IOException { - JsonObject jsonObject = LoomGradlePlugin.GSON.fromJson(Files.readString(input), JsonObject.class); - - if (!jsonObject.has("version") || jsonObject.get("version").getAsInt() != 1) { - throw new UnsupportedOperationException("Unsupported unpick version"); - } - - return new UnpickMetadata( - jsonObject.get("unpickGroup").getAsString(), - jsonObject.get("unpickVersion").getAsString() - ); - } - - private void populateUnpickClasspath() { - String unpickCliName = "unpick-cli"; - getProject().getDependencies().add(Constants.Configurations.UNPICK_CLASSPATH, - String.format("%s:%s:%s", unpickMetadata.unpickGroup, unpickCliName, unpickMetadata.unpickVersion) - ); - } - - private void extractIntermediary(Path intermediaryJar, Path intermediaryTiny) throws IOException { - getProject().getLogger().info(":extracting " + intermediaryJar.getFileName()); - - try (FileSystem unmergedIntermediaryFs = FileSystems.newFileSystem(intermediaryJar, (ClassLoader) null)) { - extractMappings(unmergedIntermediaryFs, intermediaryTiny); - } - } - - private void mergeAndSaveMappings(Project project, Path unmergedYarnJar) throws IOException { - Path unmergedYarn = Paths.get(mappingsStepsDir.toString(), "unmerged-yarn.tiny"); - project.getLogger().info(":extracting " + unmergedYarnJar.getFileName()); - - try (FileSystem unmergedYarnJarFs = FileSystems.newFileSystem(unmergedYarnJar, (ClassLoader) null)) { - extractMappings(unmergedYarnJarFs, unmergedYarn); - } - - Path invertedIntermediary = Paths.get(mappingsStepsDir.toString(), "inverted-intermediary.tiny"); - reorderMappings(getIntermediaryTiny(), invertedIntermediary, "intermediary", "official"); - Path unorderedMergedMappings = Paths.get(mappingsStepsDir.toString(), "unordered-merged.tiny"); - project.getLogger().info(":merging"); - mergeMappings(invertedIntermediary, unmergedYarn, unorderedMergedMappings); - reorderMappings(unorderedMergedMappings, tinyMappings.toPath(), "official", "intermediary", "named"); - } - - private void reorderMappings(Path oldMappings, Path newMappings, String... newOrder) { - Command command = new CommandReorderTinyV2(); - String[] args = new String[2 + newOrder.length]; - args[0] = oldMappings.toAbsolutePath().toString(); - args[1] = newMappings.toAbsolutePath().toString(); - System.arraycopy(newOrder, 0, args, 2, newOrder.length); - runCommand(command, args); - } - - private void mergeMappings(Path intermediaryMappings, Path yarnMappings, Path newMergedMappings) { - try { - Command command = new CommandMergeTinyV2(); - runCommand(command, intermediaryMappings.toAbsolutePath().toString(), - yarnMappings.toAbsolutePath().toString(), - newMergedMappings.toAbsolutePath().toString(), - "intermediary", "official"); - } catch (Exception e) { - throw new RuntimeException("Could not merge mappings from " + intermediaryMappings.toString() - + " with mappings from " + yarnMappings, e); - } - } - - private void suggestFieldNames(MinecraftProvider minecraftProvider, Path oldMappings, Path newMappings) { - Command command = new CommandProposeFieldNames(); - runCommand(command, minecraftProvider.getMergedJar().getAbsolutePath(), - oldMappings.toAbsolutePath().toString(), - newMappings.toAbsolutePath().toString()); - } - - private void runCommand(Command command, String... args) { - try { - command.run(args); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private void initFiles() { - baseTinyMappings = mappingsDir.resolve(mappingsName + "-tiny-" + minecraftVersion + "-" + mappingsVersion + "-base"); - } - - public void cleanFiles() { - try { - if (Files.exists(mappingsStepsDir)) { - Files.walkFileTree(mappingsStepsDir, new DeletingFileVisitor()); - } - - if (Files.exists(baseTinyMappings)) { - Files.deleteIfExists(baseTinyMappings); - } - - if (tinyMappings != null) { - tinyMappings.delete(); - } - - if (tinyMappingsJar != null) { - tinyMappingsJar.delete(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - @Override - public String getTargetConfig() { - return Constants.Configurations.MAPPINGS; - } - - public Path getMappingsDir() { - return mappingsDir; - } - - public Path getIntermediaryTiny() throws IOException { - if (intermediaryTiny == null) { - minecraftVersion = getExtension().getMinecraftProvider().getMinecraftVersion(); - Preconditions.checkNotNull(minecraftVersion, "Minecraft version cannot be null"); - - intermediaryTiny = mappingsDir.resolve(String.format("intermediary-%s-v2.tiny", minecraftVersion)); - - if (!Files.exists(intermediaryTiny) || (isRefreshDeps() && !hasRefreshed)) { - hasRefreshed = true; - - // Download and extract intermediary - String encodedMinecraftVersion = UrlEscapers.urlFragmentEscaper().escape(minecraftVersion); - String intermediaryArtifactUrl = getExtension().getIntermediaryUrl().apply(encodedMinecraftVersion); - Path intermediaryJar = mappingsDir.resolve("v2-intermediary-" + minecraftVersion + ".jar"); - DownloadUtil.downloadIfChanged(new URL(intermediaryArtifactUrl), intermediaryJar.toFile(), getProject().getLogger()); - - extractIntermediary(intermediaryJar, intermediaryTiny); - } - } - - return intermediaryTiny; - } - - public String getMappingsKey() { - return mappingsName + "." + minecraftVersion.replace(' ', '_').replace('.', '_').replace('-', '_') + "." + mappingsVersion; - } - - public File getUnpickDefinitionsFile() { - return unpickDefinitionsFile; - } - - public boolean hasUnpickDefinitions() { - return hasUnpickDefinitions; - } - - public record UnpickMetadata(String unpickGroup, String unpickVersion) { - } + File intermediaryTinyFile(); } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProviderImpl.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProviderImpl.java new file mode 100644 index 0000000..bea337f --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProviderImpl.java @@ -0,0 +1,423 @@ +/* + * 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.configuration.providers.mappings; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.function.Consumer; + +import com.google.common.base.Preconditions; +import com.google.common.net.UrlEscapers; +import com.google.gson.JsonObject; +import org.apache.commons.io.FileUtils; +import org.apache.tools.ant.util.StringUtils; +import org.gradle.api.Project; +import org.zeroturnaround.zip.FileSource; +import org.zeroturnaround.zip.ZipEntrySource; +import org.zeroturnaround.zip.ZipUtil; + +import net.fabricmc.loom.LoomGradleExtension; +import net.fabricmc.loom.LoomGradlePlugin; +import net.fabricmc.loom.configuration.DependencyProvider; +import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor; +import net.fabricmc.loom.configuration.processors.JarProcessorManager; +import net.fabricmc.loom.configuration.processors.MinecraftProcessedProvider; +import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl; +import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMappedProvider; +import net.fabricmc.loom.util.Constants; +import net.fabricmc.loom.util.DeletingFileVisitor; +import net.fabricmc.loom.util.DownloadUtil; +import net.fabricmc.mapping.reader.v2.TinyV2Factory; +import net.fabricmc.mapping.tree.TinyTree; +import net.fabricmc.stitch.Command; +import net.fabricmc.stitch.commands.CommandProposeFieldNames; +import net.fabricmc.stitch.commands.tinyv2.CommandMergeTinyV2; +import net.fabricmc.stitch.commands.tinyv2.CommandReorderTinyV2; + +public class MappingsProviderImpl extends DependencyProvider implements MappingsProvider { + public MinecraftMappedProvider mappedProvider; + + public String mappingsName; + public String minecraftVersion; + public String mappingsVersion; + + private final Path mappingsDir; + private final Path mappingsStepsDir; + private Path intermediaryTiny; + private boolean hasRefreshed = false; + // The mappings that gradle gives us + private Path baseTinyMappings; + // The mappings we use in practice + public File tinyMappings; + public File tinyMappingsJar; + private File unpickDefinitionsFile; + private boolean hasUnpickDefinitions; + private UnpickMetadata unpickMetadata; + + public MappingsProviderImpl(Project project) { + super(project); + mappingsDir = getExtension().getUserCache().toPath().resolve("mappings"); + mappingsStepsDir = mappingsDir.resolve("steps"); + } + + public void clean() throws IOException { + FileUtils.deleteDirectory(mappingsDir.toFile()); + } + + public TinyTree getMappings() throws IOException { + return MappingsCache.INSTANCE.get(tinyMappings.toPath()); + } + + @Override + public void provide(DependencyInfo dependency, Consumer postPopulationScheduler) throws Exception { + MinecraftProviderImpl minecraftProvider = getDependencyManager().getProvider(MinecraftProviderImpl.class); + + getProject().getLogger().info(":setting up mappings (" + dependency.getDependency().getName() + " " + dependency.getResolvedVersion() + ")"); + + String version = dependency.getResolvedVersion(); + File mappingsJar = dependency.resolveFile().orElseThrow(() -> new RuntimeException("Could not find yarn mappings: " + dependency)); + + this.mappingsName = StringUtils.removeSuffix(dependency.getDependency().getGroup() + "." + dependency.getDependency().getName(), "-unmerged"); + this.minecraftVersion = minecraftProvider.minecraftVersion(); + + boolean isV2; + + // Only do this for official yarn, there isn't really a way we can get the mc version for all mappings + if (dependency.getDependency().getGroup() != null && dependency.getDependency().getGroup().equals("net.fabricmc") && dependency.getDependency().getName().equals("yarn") && dependency.getDependency().getVersion() != null) { + String yarnVersion = dependency.getDependency().getVersion(); + char separator = yarnVersion.contains("+build.") ? '+' : yarnVersion.contains("-") ? '-' : '.'; + String yarnMinecraftVersion = yarnVersion.substring(0, yarnVersion.lastIndexOf(separator)); + + if (!yarnMinecraftVersion.equalsIgnoreCase(minecraftVersion)) { + throw new RuntimeException(String.format("Minecraft Version (%s) does not match yarn's minecraft version (%s)", minecraftVersion, yarnMinecraftVersion)); + } + + // We can save reading the zip file + header by checking the file name + isV2 = mappingsJar.getName().endsWith("-v2.jar"); + } else { + isV2 = doesJarContainV2Mappings(mappingsJar.toPath()); + } + + this.mappingsVersion = version + (isV2 ? "-v2" : ""); + + initFiles(); + + if (isRefreshDeps()) { + cleanFiles(); + } + + Files.createDirectories(mappingsDir); + Files.createDirectories(mappingsStepsDir); + + String[] depStringSplit = dependency.getDepString().split(":"); + String jarClassifier = "final"; + + if (depStringSplit.length >= 4) { + jarClassifier = jarClassifier + depStringSplit[3]; + } + + tinyMappings = mappingsDir.resolve(StringUtils.removeSuffix(mappingsJar.getName(), ".jar") + ".tiny").toFile(); + unpickDefinitionsFile = mappingsDir.resolve(StringUtils.removeSuffix(mappingsJar.getName(), ".jar") + ".unpick").toFile(); + tinyMappingsJar = new File(getExtension().getUserCache(), mappingsJar.getName().replace(".jar", "-" + jarClassifier + ".jar")); + + if (!tinyMappings.exists() || isRefreshDeps()) { + storeMappings(getProject(), minecraftProvider, mappingsJar.toPath()); + } else { + try (FileSystem fileSystem = FileSystems.newFileSystem(mappingsJar.toPath(), (ClassLoader) null)) { + extractUnpickDefinitions(fileSystem, unpickDefinitionsFile.toPath()); + } + } + + if (!tinyMappingsJar.exists() || isRefreshDeps()) { + ZipUtil.pack(new ZipEntrySource[] {new FileSource("mappings/mappings.tiny", tinyMappings)}, tinyMappingsJar); + } + + if (hasUnpickDefinitions()) { + String notation = String.format("%s:%s:%s:constants", + dependency.getDependency().getGroup(), + dependency.getDependency().getName(), + dependency.getDependency().getVersion() + ); + + getProject().getDependencies().add(Constants.Configurations.MAPPING_CONSTANTS, notation); + populateUnpickClasspath(); + } + + addDependency(tinyMappingsJar, Constants.Configurations.MAPPINGS_FINAL); + + LoomGradleExtension extension = getExtension(); + + if (extension.accessWidener != null) { + extension.addJarProcessor(new AccessWidenerJarProcessor(getProject())); + } + + JarProcessorManager processorManager = new JarProcessorManager(extension.getJarProcessors()); + extension.setJarProcessorManager(processorManager); + processorManager.setupProcessors(); + + if (processorManager.active()) { + mappedProvider = new MinecraftProcessedProvider(getProject(), processorManager); + getProject().getLogger().lifecycle("Using project based jar storage"); + } else { + mappedProvider = new MinecraftMappedProvider(getProject()); + } + + mappedProvider.initFiles(minecraftProvider, this); + mappedProvider.provide(dependency, postPopulationScheduler); + } + + private void storeMappings(Project project, MinecraftProviderImpl minecraftProvider, Path yarnJar) throws IOException { + project.getLogger().info(":extracting " + yarnJar.getFileName()); + + try (FileSystem fileSystem = FileSystems.newFileSystem(yarnJar, (ClassLoader) null)) { + extractMappings(fileSystem, baseTinyMappings); + extractUnpickDefinitions(fileSystem, unpickDefinitionsFile.toPath()); + } + + if (baseMappingsAreV2()) { + // These are unmerged v2 mappings + mergeAndSaveMappings(project, yarnJar); + } else { + // These are merged v1 mappings + if (tinyMappings.exists()) { + tinyMappings.delete(); + } + + project.getLogger().lifecycle(":populating field names"); + suggestFieldNames(minecraftProvider, baseTinyMappings, tinyMappings.toPath()); + } + } + + private boolean baseMappingsAreV2() throws IOException { + try (BufferedReader reader = Files.newBufferedReader(baseTinyMappings)) { + TinyV2Factory.readMetadata(reader); + return true; + } catch (IllegalArgumentException e) { + // TODO: just check the mappings version when Parser supports V1 in readMetadata() + return false; + } + } + + private boolean doesJarContainV2Mappings(Path path) throws IOException { + try (FileSystem fs = FileSystems.newFileSystem(path, (ClassLoader) null)) { + try (BufferedReader reader = Files.newBufferedReader(fs.getPath("mappings", "mappings.tiny"))) { + TinyV2Factory.readMetadata(reader); + return true; + } catch (IllegalArgumentException e) { + return false; + } + } + } + + public static void extractMappings(FileSystem jar, Path extractTo) throws IOException { + Files.copy(jar.getPath("mappings/mappings.tiny"), extractTo, StandardCopyOption.REPLACE_EXISTING); + } + + private void extractUnpickDefinitions(FileSystem jar, Path extractTo) throws IOException { + Path unpickPath = jar.getPath("extras/definitions.unpick"); + Path unpickMetadataPath = jar.getPath("extras/unpick.json"); + + if (!Files.exists(unpickPath) || !Files.exists(unpickMetadataPath)) { + return; + } + + Files.copy(unpickPath, extractTo, StandardCopyOption.REPLACE_EXISTING); + + unpickMetadata = parseUnpickMetadata(unpickMetadataPath); + hasUnpickDefinitions = true; + } + + private UnpickMetadata parseUnpickMetadata(Path input) throws IOException { + JsonObject jsonObject = LoomGradlePlugin.GSON.fromJson(Files.readString(input), JsonObject.class); + + if (!jsonObject.has("version") || jsonObject.get("version").getAsInt() != 1) { + throw new UnsupportedOperationException("Unsupported unpick version"); + } + + return new UnpickMetadata( + jsonObject.get("unpickGroup").getAsString(), + jsonObject.get("unpickVersion").getAsString() + ); + } + + private void populateUnpickClasspath() { + String unpickCliName = "unpick-cli"; + getProject().getDependencies().add(Constants.Configurations.UNPICK_CLASSPATH, + String.format("%s:%s:%s", unpickMetadata.unpickGroup, unpickCliName, unpickMetadata.unpickVersion) + ); + } + + private void extractIntermediary(Path intermediaryJar, Path intermediaryTiny) throws IOException { + getProject().getLogger().info(":extracting " + intermediaryJar.getFileName()); + + try (FileSystem unmergedIntermediaryFs = FileSystems.newFileSystem(intermediaryJar, (ClassLoader) null)) { + extractMappings(unmergedIntermediaryFs, intermediaryTiny); + } + } + + private void mergeAndSaveMappings(Project project, Path unmergedYarnJar) throws IOException { + Path unmergedYarn = Paths.get(mappingsStepsDir.toString(), "unmerged-yarn.tiny"); + project.getLogger().info(":extracting " + unmergedYarnJar.getFileName()); + + try (FileSystem unmergedYarnJarFs = FileSystems.newFileSystem(unmergedYarnJar, (ClassLoader) null)) { + extractMappings(unmergedYarnJarFs, unmergedYarn); + } + + Path invertedIntermediary = Paths.get(mappingsStepsDir.toString(), "inverted-intermediary.tiny"); + reorderMappings(getIntermediaryTiny(), invertedIntermediary, "intermediary", "official"); + Path unorderedMergedMappings = Paths.get(mappingsStepsDir.toString(), "unordered-merged.tiny"); + project.getLogger().info(":merging"); + mergeMappings(invertedIntermediary, unmergedYarn, unorderedMergedMappings); + reorderMappings(unorderedMergedMappings, tinyMappings.toPath(), "official", "intermediary", "named"); + } + + private void reorderMappings(Path oldMappings, Path newMappings, String... newOrder) { + Command command = new CommandReorderTinyV2(); + String[] args = new String[2 + newOrder.length]; + args[0] = oldMappings.toAbsolutePath().toString(); + args[1] = newMappings.toAbsolutePath().toString(); + System.arraycopy(newOrder, 0, args, 2, newOrder.length); + runCommand(command, args); + } + + private void mergeMappings(Path intermediaryMappings, Path yarnMappings, Path newMergedMappings) { + try { + Command command = new CommandMergeTinyV2(); + runCommand(command, intermediaryMappings.toAbsolutePath().toString(), + yarnMappings.toAbsolutePath().toString(), + newMergedMappings.toAbsolutePath().toString(), + "intermediary", "official"); + } catch (Exception e) { + throw new RuntimeException("Could not merge mappings from " + intermediaryMappings.toString() + + " with mappings from " + yarnMappings, e); + } + } + + private void suggestFieldNames(MinecraftProviderImpl minecraftProvider, Path oldMappings, Path newMappings) { + Command command = new CommandProposeFieldNames(); + runCommand(command, minecraftProvider.getMergedJar().getAbsolutePath(), + oldMappings.toAbsolutePath().toString(), + newMappings.toAbsolutePath().toString()); + } + + private void runCommand(Command command, String... args) { + try { + command.run(args); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private void initFiles() { + baseTinyMappings = mappingsDir.resolve(mappingsName + "-tiny-" + minecraftVersion + "-" + mappingsVersion + "-base"); + } + + public void cleanFiles() { + try { + if (Files.exists(mappingsStepsDir)) { + Files.walkFileTree(mappingsStepsDir, new DeletingFileVisitor()); + } + + if (Files.exists(baseTinyMappings)) { + Files.deleteIfExists(baseTinyMappings); + } + + if (tinyMappings != null) { + tinyMappings.delete(); + } + + if (tinyMappingsJar != null) { + tinyMappingsJar.delete(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public String getTargetConfig() { + return Constants.Configurations.MAPPINGS; + } + + @Override + public Path getMappingsDir() { + return mappingsDir; + } + + public Path getIntermediaryTiny() throws IOException { + if (intermediaryTiny == null) { + minecraftVersion = getExtension().getMinecraftProvider().minecraftVersion(); + Preconditions.checkNotNull(minecraftVersion, "Minecraft version cannot be null"); + + intermediaryTiny = mappingsDir.resolve(String.format("intermediary-%s-v2.tiny", minecraftVersion)); + + if (!Files.exists(intermediaryTiny) || (isRefreshDeps() && !hasRefreshed)) { + hasRefreshed = true; + + // Download and extract intermediary + String encodedMinecraftVersion = UrlEscapers.urlFragmentEscaper().escape(minecraftVersion); + String intermediaryArtifactUrl = getExtension().getIntermediaryUrl().apply(encodedMinecraftVersion); + Path intermediaryJar = mappingsDir.resolve("v2-intermediary-" + minecraftVersion + ".jar"); + DownloadUtil.downloadIfChanged(new URL(intermediaryArtifactUrl), intermediaryJar.toFile(), getProject().getLogger()); + + extractIntermediary(intermediaryJar, intermediaryTiny); + } + } + + return intermediaryTiny; + } + + public String getMappingsKey() { + return mappingsName + "." + minecraftVersion.replace(' ', '_').replace('.', '_').replace('-', '_') + "." + mappingsVersion; + } + + public File getUnpickDefinitionsFile() { + return unpickDefinitionsFile; + } + + public boolean hasUnpickDefinitions() { + return hasUnpickDefinitions; + } + + @Override + public File intermediaryTinyFile() { + try { + return getIntermediaryTiny().toFile(); + } catch (IOException e) { + throw new RuntimeException("Failed to get intermediary", e); + } + } + + public record UnpickMetadata(String unpickGroup, String unpickVersion) { + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsSpec.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsSpec.java new file mode 100644 index 0000000..1666d95 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsSpec.java @@ -0,0 +1,29 @@ +/* + * 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.configuration.providers.mappings; + +public interface MappingsSpec { + L createLayer(MappingContext context); +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MojangMappingsDependency.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MojangMappingsDependency.java deleted file mode 100644 index 1cd80a4..0000000 --- a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MojangMappingsDependency.java +++ /dev/null @@ -1,275 +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.configuration.providers.mappings; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.StringWriter; -import java.io.Writer; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Collections; -import java.util.Set; -import java.util.function.Consumer; - -import org.cadixdev.lorenz.MappingSet; -import org.cadixdev.lorenz.io.TextMappingsWriter; -import org.cadixdev.lorenz.io.proguard.ProGuardReader; -import org.cadixdev.lorenz.model.ClassMapping; -import org.cadixdev.lorenz.model.FieldMapping; -import org.cadixdev.lorenz.model.InnerClassMapping; -import org.cadixdev.lorenz.model.MethodMapping; -import org.cadixdev.lorenz.model.TopLevelClassMapping; -import org.gradle.api.Project; -import org.gradle.api.artifacts.Dependency; -import org.gradle.api.artifacts.SelfResolvingDependency; -import org.gradle.api.tasks.TaskDependency; -import org.zeroturnaround.zip.ByteSource; -import org.zeroturnaround.zip.ZipEntrySource; -import org.zeroturnaround.zip.ZipUtil; - -import net.fabricmc.loom.LoomGradleExtension; -import net.fabricmc.loom.LoomGradlePlugin; -import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta; -import net.fabricmc.loom.util.HashedDownloadUtil; -import net.fabricmc.lorenztiny.TinyMappingsReader; -import net.fabricmc.mapping.tree.TinyMappingFactory; - -public class MojangMappingsDependency implements SelfResolvingDependency { - public static final String GROUP = "net.minecraft"; - public static final String MODULE = "mappings"; - // Keys in dependency manifest - private static final String MANIFEST_CLIENT_MAPPINGS = "client_mappings"; - private static final String MANIFEST_SERVER_MAPPINGS = "server_mappings"; - - private final Project project; - private final LoomGradleExtension extension; - - public MojangMappingsDependency(Project project, LoomGradleExtension extension) { - this.project = project; - this.extension = extension; - } - - @Override - public Set resolve() { - Path mappingsDir = extension.getMappingsProvider().getMappingsDir(); - Path mappingsFile = mappingsDir.resolve(String.format("%s.%s-%s.tiny", GROUP, MODULE, getVersion())); - Path clientMappings = mappingsDir.resolve(String.format("%s.%s-%s-client.map", GROUP, MODULE, getVersion())); - Path serverMappings = mappingsDir.resolve(String.format("%s.%s-%s-server.map", GROUP, MODULE, getVersion())); - - if (!Files.exists(mappingsFile) || LoomGradlePlugin.refreshDeps) { - MappingSet mappingSet; - - try { - mappingSet = getMappingsSet(clientMappings, serverMappings); - - try (Writer writer = new StringWriter()) { - new TinyWriter(writer, "intermediary", "named").write(mappingSet); - Files.deleteIfExists(mappingsFile); - - ZipUtil.pack(new ZipEntrySource[] { - new ByteSource("mappings/mappings.tiny", writer.toString().getBytes(StandardCharsets.UTF_8)) - }, mappingsFile.toFile()); - } - } catch (IOException e) { - throw new RuntimeException("Failed to resolve Mojang mappings", e); - } - } - - try (BufferedReader clientBufferedReader = Files.newBufferedReader(clientMappings, StandardCharsets.UTF_8)) { - project.getLogger().warn("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); - project.getLogger().warn("Using of the official minecraft mappings is at your own risk!"); - project.getLogger().warn("Please make sure to read and understand the following license:"); - project.getLogger().warn("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); - String line; - - while ((line = clientBufferedReader.readLine()).startsWith("#")) { - project.getLogger().warn(line); - } - - project.getLogger().warn("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); - } catch (IOException e) { - throw new RuntimeException("Failed to read client mappings", e); - } - - return Collections.singleton(mappingsFile.toFile()); - } - - private MappingSet getMappingsSet(Path clientMappings, Path serverMappings) throws IOException { - MinecraftVersionMeta versionInfo = extension.getMinecraftProvider().getVersionInfo(); - - if (versionInfo.download(MANIFEST_CLIENT_MAPPINGS) == null) { - throw new RuntimeException("Failed to find official mojang mappings for " + getVersion()); - } - - MinecraftVersionMeta.Download clientMappingsDownload = versionInfo.download(MANIFEST_CLIENT_MAPPINGS); - MinecraftVersionMeta.Download serverMappingsDownload = versionInfo.download(MANIFEST_CLIENT_MAPPINGS); - - HashedDownloadUtil.downloadIfInvalid(new URL(clientMappingsDownload.url()), clientMappings.toFile(), clientMappingsDownload.sha1(), project.getLogger(), false); - HashedDownloadUtil.downloadIfInvalid(new URL(serverMappingsDownload.url()), serverMappings.toFile(), clientMappingsDownload.sha1(), project.getLogger(), false); - - MappingSet mappings = MappingSet.create(); - - try (BufferedReader clientBufferedReader = Files.newBufferedReader(clientMappings, StandardCharsets.UTF_8); - BufferedReader serverBufferedReader = Files.newBufferedReader(serverMappings, StandardCharsets.UTF_8)) { - try (ProGuardReader proGuardReaderClient = new ProGuardReader(clientBufferedReader); - ProGuardReader proGuardReaderServer = new ProGuardReader(serverBufferedReader)) { - proGuardReaderClient.read(mappings); - proGuardReaderServer.read(mappings); - } - } - - MappingSet officialToNamed = mappings.reverse(); - MappingSet intermediaryToOfficial; - - try (BufferedReader reader = Files.newBufferedReader(extension.getMappingsProvider().getIntermediaryTiny(), StandardCharsets.UTF_8)) { - intermediaryToOfficial = new TinyMappingsReader(TinyMappingFactory.loadWithDetection(reader), "intermediary", "official").read(); - } - - MappingSet intermediaryToMojang = MappingSet.create(); - - // Merging. Don't use MappingSet#merge - iterateClasses(intermediaryToOfficial, inputMappings -> { - officialToNamed.getClassMapping(inputMappings.getFullDeobfuscatedName()) - .ifPresent(namedClass -> { - ClassMapping mojangClassMapping = intermediaryToMojang.getOrCreateClassMapping(inputMappings.getFullObfuscatedName()) - .setDeobfuscatedName(namedClass.getFullDeobfuscatedName()); - - for (FieldMapping fieldMapping : inputMappings .getFieldMappings()) { - namedClass.getFieldMapping(fieldMapping.getDeobfuscatedName()) - .ifPresent(namedField -> { - mojangClassMapping.getOrCreateFieldMapping(fieldMapping.getSignature()) - .setDeobfuscatedName(namedField.getDeobfuscatedName()); - }); - } - - for (MethodMapping methodMapping : inputMappings .getMethodMappings()) { - namedClass.getMethodMapping(methodMapping.getDeobfuscatedSignature()) - .ifPresent(namedMethod -> { - mojangClassMapping.getOrCreateMethodMapping(methodMapping.getSignature()) - .setDeobfuscatedName(namedMethod.getDeobfuscatedName()); - }); - } - }); - }); - - return intermediaryToMojang; - } - - @Override - public Set resolve(boolean transitive) { - return resolve(); - } - - @Override - public TaskDependency getBuildDependencies() { - return task -> Collections.emptySet(); - } - - @Override - public String getGroup() { - return GROUP; - } - - @Override - public String getName() { - return MODULE; - } - - @Override - public String getVersion() { - return extension.getMinecraftProvider().getMinecraftVersion(); - } - - @Override - public boolean contentEquals(Dependency dependency) { - if (dependency instanceof MojangMappingsDependency mojangMappingsDependency) { - return mojangMappingsDependency.extension.getMinecraftProvider().getMinecraftVersion().equals(getVersion()); - } - - return false; - } - - @Override - public Dependency copy() { - return new MojangMappingsDependency(project, extension); - } - - @Override - public String getReason() { - return null; - } - - @Override - public void because(String s) { - } - - private static void iterateClasses(MappingSet mappings, Consumer> consumer) { - for (TopLevelClassMapping classMapping : mappings.getTopLevelClassMappings()) { - iterateClass(classMapping, consumer); - } - } - - private static void iterateClass(ClassMapping classMapping, Consumer> consumer) { - consumer.accept(classMapping); - - for (InnerClassMapping innerClassMapping : classMapping.getInnerClassMappings()) { - iterateClass(innerClassMapping, consumer); - } - } - - private static class TinyWriter extends TextMappingsWriter { - private final String namespaceFrom; - private final String namespaceTo; - - protected TinyWriter(Writer writer, String namespaceFrom, String namespaceTo) { - super(writer); - this.namespaceFrom = namespaceFrom; - this.namespaceTo = namespaceTo; - } - - @Override - public void write(MappingSet mappings) { - writer.println("tiny\t2\t0\t" + namespaceFrom + "\t" + namespaceTo); - - iterateClasses(mappings, classMapping -> { - writer.println("c\t" + classMapping.getFullObfuscatedName() + "\t" + classMapping.getFullDeobfuscatedName()); - - for (FieldMapping fieldMapping : classMapping.getFieldMappings()) { - fieldMapping.getType().ifPresent(fieldType -> { - writer.println("\tf\t" + fieldType + "\t" + fieldMapping.getObfuscatedName() + "\t" + fieldMapping.getDeobfuscatedName()); - }); - } - - for (MethodMapping methodMapping : classMapping.getMethodMappings()) { - writer.println("\tm\t" + methodMapping.getSignature().getDescriptor() + "\t" + methodMapping.getObfuscatedName() + "\t" + methodMapping.getDeobfuscatedName()); - } - }); - } - } -} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/intermediary/IntermediaryMappingLayer.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/intermediary/IntermediaryMappingLayer.java new file mode 100644 index 0000000..e7fe393 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/intermediary/IntermediaryMappingLayer.java @@ -0,0 +1,55 @@ +/* + * 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.configuration.providers.mappings.intermediary; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.Collections; + +import net.fabricmc.loom.configuration.providers.mappings.MappingLayer; +import net.fabricmc.loom.configuration.providers.mappings.MappingNamespace; +import net.fabricmc.mappingio.MappingVisitor; +import net.fabricmc.mappingio.adapter.MappingNsCompleter; +import net.fabricmc.mappingio.format.Tiny2Reader; + +public record IntermediaryMappingLayer(File tinyFile) implements MappingLayer { + @Override + public MappingNamespace getSourceNamespace() { + return MappingNamespace.OFFICIAL; + } + + @Override + public void visit(MappingVisitor mappingVisitor) throws IOException { + // Populate named with intermediary and add Add a "named" namespace + MappingNsCompleter nsCompleter = new MappingNsCompleter(mappingVisitor, Collections.singletonMap(MappingNamespace.NAMED.stringValue(), MappingNamespace.INTERMEDIARY.stringValue()), true); + + try (BufferedReader reader = Files.newBufferedReader(tinyFile().toPath(), StandardCharsets.UTF_8)) { + Tiny2Reader.read(reader, nsCompleter); + } + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/intermediary/IntermediaryMappingsSpec.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/intermediary/IntermediaryMappingsSpec.java new file mode 100644 index 0000000..e4c71fd --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/intermediary/IntermediaryMappingsSpec.java @@ -0,0 +1,35 @@ +/* + * 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.configuration.providers.mappings.intermediary; + +import net.fabricmc.loom.configuration.providers.mappings.MappingContext; +import net.fabricmc.loom.configuration.providers.mappings.MappingsSpec; + +public record IntermediaryMappingsSpec() implements MappingsSpec { + @Override + public IntermediaryMappingLayer createLayer(MappingContext context) { + return new IntermediaryMappingLayer(context.mappingsProvider().intermediaryTinyFile()); + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/mojmap/MojangMappingLayer.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/mojmap/MojangMappingLayer.java new file mode 100644 index 0000000..31b5b88 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/mojmap/MojangMappingLayer.java @@ -0,0 +1,102 @@ +/* + * 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.configuration.providers.mappings.mojmap; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import org.gradle.api.logging.Logger; + +import net.fabricmc.loom.configuration.providers.mappings.MappingLayer; +import net.fabricmc.loom.configuration.providers.mappings.MappingNamespace; +import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta; +import net.fabricmc.loom.configuration.providers.mappings.intermediary.IntermediaryMappingLayer; +import net.fabricmc.loom.util.HashedDownloadUtil; +import net.fabricmc.mappingio.MappingVisitor; +import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch; +import net.fabricmc.mappingio.format.ProGuardReader; + +public record MojangMappingLayer(MinecraftVersionMeta.Download clientDownload, + MinecraftVersionMeta.Download serverDownload, + File workingDir, + Logger logger) implements MappingLayer { + @Override + public void visit(MappingVisitor mappingVisitor) throws IOException { + var clientMappings = new File(workingDir(), "client.txt"); + var serverMappings = new File(workingDir(), "server.txt"); + + download(clientMappings, serverMappings); + + printMappingsLicense(clientMappings.toPath()); + + // Make official the source namespace + MappingSourceNsSwitch nsSwitch = new MappingSourceNsSwitch(mappingVisitor, MappingNamespace.OFFICIAL.stringValue()); + + try (BufferedReader clientBufferedReader = Files.newBufferedReader(clientMappings.toPath(), StandardCharsets.UTF_8); + BufferedReader serverBufferedReader = Files.newBufferedReader(serverMappings.toPath(), StandardCharsets.UTF_8)) { + ProGuardReader.read(clientBufferedReader, MappingNamespace.NAMED.stringValue(), MappingNamespace.OFFICIAL.stringValue(), nsSwitch); + ProGuardReader.read(serverBufferedReader, MappingNamespace.NAMED.stringValue(), MappingNamespace.OFFICIAL.stringValue(), nsSwitch); + } + } + + private void download(File clientMappings, File serverMappings) throws IOException { + HashedDownloadUtil.downloadIfInvalid(new URL(clientDownload().url()), clientMappings, clientDownload().sha1(), logger(), false); + HashedDownloadUtil.downloadIfInvalid(new URL(serverDownload().url()), serverMappings, serverDownload().sha1(), logger(), false); + } + + private void printMappingsLicense(Path clientMappings) { + try (BufferedReader clientBufferedReader = Files.newBufferedReader(clientMappings, StandardCharsets.UTF_8)) { + logger().warn("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + logger().warn("Using of the official minecraft mappings is at your own risk!"); + logger().warn("Please make sure to read and understand the following license:"); + logger().warn("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + String line; + + while ((line = clientBufferedReader.readLine()).startsWith("#")) { + logger().warn(line); + } + + logger().warn("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + } catch (IOException e) { + throw new RuntimeException("Failed to read client mappings", e); + } + } + + @Override + public MappingNamespace getSourceNamespace() { + return MappingNamespace.OFFICIAL; + } + + @Override + public List> dependsOn() { + return List.of(IntermediaryMappingLayer.class); + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/mojmap/MojangMappingsSpec.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/mojmap/MojangMappingsSpec.java new file mode 100644 index 0000000..78cfc02 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/mojmap/MojangMappingsSpec.java @@ -0,0 +1,51 @@ +/* + * 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.configuration.providers.mappings.mojmap; + +import net.fabricmc.loom.configuration.providers.mappings.MappingContext; +import net.fabricmc.loom.configuration.providers.mappings.MappingsSpec; +import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta; + +public record MojangMappingsSpec() implements MappingsSpec { + // Keys in dependency manifest + private static final String MANIFEST_CLIENT_MAPPINGS = "client_mappings"; + private static final String MANIFEST_SERVER_MAPPINGS = "server_mappings"; + + @Override + public MojangMappingLayer createLayer(MappingContext context) { + MinecraftVersionMeta versionInfo = context.minecraftProvider().getVersionInfo(); + + if (versionInfo.download(MANIFEST_CLIENT_MAPPINGS) == null) { + throw new RuntimeException("Failed to find official mojang mappings for " + context.minecraftVersion()); + } + + return new MojangMappingLayer( + versionInfo.download(MANIFEST_CLIENT_MAPPINGS), + versionInfo.download(MANIFEST_SERVER_MAPPINGS), + context.workingDirectory("mojang"), + context.getLogger() + ); + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/parchment/ParchmentMappingLayer.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/parchment/ParchmentMappingLayer.java new file mode 100644 index 0000000..7076423 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/parchment/ParchmentMappingLayer.java @@ -0,0 +1,63 @@ +/* + * 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.configuration.providers.mappings.parchment; + +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Objects; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import net.fabricmc.loom.LoomGradlePlugin; +import net.fabricmc.loom.configuration.providers.mappings.MappingLayer; +import net.fabricmc.loom.configuration.providers.mappings.MappingNamespace; +import net.fabricmc.mappingio.MappingVisitor; + +public record ParchmentMappingLayer(File parchmentFile, boolean removePrefix) implements MappingLayer { + private static final String PARCHMENT_DATA_FILE_NAME = "parchment.json"; + + @Override + public void visit(MappingVisitor mappingVisitor) throws IOException { + ParchmentTreeV1 parchmentData = getParchmentData(); + + if (removePrefix()) { + mappingVisitor = new ParchmentPrefixStripingMappingVisitor(mappingVisitor); + } + + parchmentData.visit(mappingVisitor, MappingNamespace.NAMED.stringValue()); + } + + private ParchmentTreeV1 getParchmentData() throws IOException { + try (var zipFile = new ZipFile(parchmentFile())) { + ZipEntry zipFileEntry = zipFile.getEntry(PARCHMENT_DATA_FILE_NAME); + Objects.requireNonNull(zipFileEntry, "Could not find %s in parchment data file".formatted(PARCHMENT_DATA_FILE_NAME)); + + try (var reader = new InputStreamReader(zipFile.getInputStream(zipFileEntry))) { + return LoomGradlePlugin.OBJECT_MAPPER.readValue(reader, ParchmentTreeV1.class); + } + } + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/parchment/ParchmentMappingsSpec.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/parchment/ParchmentMappingsSpec.java new file mode 100644 index 0000000..efec61c --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/parchment/ParchmentMappingsSpec.java @@ -0,0 +1,35 @@ +/* + * 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.configuration.providers.mappings.parchment; + +import net.fabricmc.loom.configuration.providers.mappings.MappingContext; +import net.fabricmc.loom.configuration.providers.mappings.MappingsSpec; + +public record ParchmentMappingsSpec(String mavenNotation, boolean removePrefix) implements MappingsSpec { + @Override + public ParchmentMappingLayer createLayer(MappingContext context) { + return new ParchmentMappingLayer(context.mavenFile(mavenNotation()), removePrefix()); + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/parchment/ParchmentMappingsSpecBuilder.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/parchment/ParchmentMappingsSpecBuilder.java new file mode 100644 index 0000000..808e077 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/parchment/ParchmentMappingsSpecBuilder.java @@ -0,0 +1,48 @@ +/* + * 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.configuration.providers.mappings.parchment; + +public class ParchmentMappingsSpecBuilder { + private final String mavenNotation; + + private boolean removePrefix; + + private ParchmentMappingsSpecBuilder(String mavenNotation) { + this.mavenNotation = mavenNotation; + } + + public static ParchmentMappingsSpecBuilder builder(String depNotation) { + return new ParchmentMappingsSpecBuilder(depNotation); + } + + public ParchmentMappingsSpecBuilder setRemovePrefix(boolean removePrefix) { + this.removePrefix = removePrefix; + return this; + } + + public ParchmentMappingsSpec build() { + return new ParchmentMappingsSpec(mavenNotation, removePrefix); + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/parchment/ParchmentPrefixStripingMappingVisitor.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/parchment/ParchmentPrefixStripingMappingVisitor.java new file mode 100644 index 0000000..6280a5f --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/parchment/ParchmentPrefixStripingMappingVisitor.java @@ -0,0 +1,50 @@ +/* + * 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.configuration.providers.mappings.parchment; + +import java.util.Locale; + +import net.fabricmc.mappingio.MappingVisitor; +import net.fabricmc.mappingio.adapter.ForwardingMappingVisitor; + +public final class ParchmentPrefixStripingMappingVisitor extends ForwardingMappingVisitor { + protected ParchmentPrefixStripingMappingVisitor(MappingVisitor next) { + super(next); + } + + @Override + public boolean visitMethodArg(int argPosition, int lvIndex, String srcName) { + return super.visitMethodArg(argPosition, lvIndex, stripMethodArg(srcName)); + } + + public static String stripMethodArg(String arg) { + if (arg.length() > 1 && arg.startsWith("p") && Character.isUpperCase(arg.charAt(1))) { + String a2 = arg.substring(1); // Remove p + return a2.substring(0, 1).toLowerCase(Locale.ROOT) + a2.substring(1); // Make first char lowercase + } + + return arg; + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/parchment/ParchmentTreeV1.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/parchment/ParchmentTreeV1.java new file mode 100644 index 0000000..6d9c1a6 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/parchment/ParchmentTreeV1.java @@ -0,0 +1,165 @@ +/* + * 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.configuration.providers.mappings.parchment; + +import java.util.Collections; +import java.util.List; + +import org.jetbrains.annotations.Nullable; + +import net.fabricmc.mappingio.MappedElementKind; +import net.fabricmc.mappingio.MappingVisitor; + +public record ParchmentTreeV1( + String version, + @Nullable + List classes, + @Nullable + List packages +) { + public void visit(MappingVisitor visitor, String srcNamespace) { + while (true) { + if (visitor.visitHeader()) { + visitor.visitNamespaces(srcNamespace, Collections.emptyList()); + } + + if (visitor.visitContent()) { + if (classes() != null) { + for (Class c : classes()) { + c.visit(visitor); + } + } + } + + if (visitor.visitEnd()) { + break; + } + } + } + + public record Class( + String name, + @Nullable + List fields, + @Nullable + List methods, + @Nullable + List javadoc + ) { + public void visit(MappingVisitor visitor) { + if (visitor.visitClass(name())) { + if (!visitor.visitElementContent(MappedElementKind.CLASS)) { + return; + } + + if (fields() != null) { + for (Field field : fields()) { + field.visit(visitor); + } + } + + if (methods() != null) { + for (Method method : methods()) { + method.visit(visitor); + } + } + + if (javadoc() != null) { + visitor.visitComment(MappedElementKind.CLASS, String.join("\n", javadoc())); + } + } + } + } + + public record Field( + String name, + String descriptor, + @Nullable + List javadoc + ) { + public void visit(MappingVisitor visitor) { + if (visitor.visitField(name, descriptor)) { + if (!visitor.visitElementContent(MappedElementKind.FIELD)) { + return; + } + + if (javadoc() != null) { + visitor.visitComment(MappedElementKind.FIELD, String.join("\n", javadoc())); + } + } + } + } + + public record Method( + String name, + String descriptor, + @Nullable + List parameters, + @Nullable + List javadoc + ) { + public void visit(MappingVisitor visitor) { + if (visitor.visitMethod(name, descriptor)) { + if (!visitor.visitElementContent(MappedElementKind.METHOD)) { + return; + } + + if (parameters() != null) { + for (Parameter parameter : parameters()) { + parameter.visit(visitor); + } + } + + if (javadoc() != null) { + visitor.visitComment(MappedElementKind.METHOD, String.join("\n", javadoc())); + } + } + } + } + + public record Parameter( + int index, + String name, + @Nullable + String javadoc + ) { + public void visit(MappingVisitor visitor) { + if (visitor.visitMethodArg(index, index, name)) { + if (!visitor.visitElementContent(MappedElementKind.METHOD_ARG)) { + return; + } + + if (javadoc() != null) { + visitor.visitComment(MappedElementKind.METHOD_ARG, javadoc); + } + } + } + } + + public record Package( + String name, + List javadoc + ) { } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftLibraryProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftLibraryProvider.java index 130df4d..bfb42d7 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftLibraryProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftLibraryProvider.java @@ -29,13 +29,13 @@ import java.io.File; import org.gradle.api.Project; import net.fabricmc.loom.LoomGradleExtension; -import net.fabricmc.loom.configuration.providers.MinecraftProvider; +import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl; import net.fabricmc.loom.util.Constants; public class MinecraftLibraryProvider { public File MINECRAFT_LIBS; - public void provide(MinecraftProvider minecraftProvider, Project project) { + public void provide(MinecraftProviderImpl minecraftProvider, Project project) { MinecraftVersionMeta versionInfo = minecraftProvider.getVersionInfo(); initFiles(project, minecraftProvider); @@ -47,7 +47,7 @@ public class MinecraftLibraryProvider { } } - private void initFiles(Project project, MinecraftProvider minecraftProvider) { + private void initFiles(Project project, MinecraftProviderImpl minecraftProvider) { LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); MINECRAFT_LIBS = new File(extension.getUserCache(), "libraries"); } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java index a271809..1ca7179 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java @@ -36,8 +36,8 @@ import com.google.common.collect.ImmutableMap; import org.gradle.api.Project; import net.fabricmc.loom.configuration.DependencyProvider; -import net.fabricmc.loom.configuration.providers.MinecraftProvider; -import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider; +import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl; +import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.TinyRemapperMappingsHelper; import net.fabricmc.tinyremapper.OutputConsumerPath; @@ -53,7 +53,7 @@ public class MinecraftMappedProvider extends DependencyProvider { private File minecraftMappedJar; private File minecraftIntermediaryJar; - private MinecraftProvider minecraftProvider; + private MinecraftProviderImpl minecraftProvider; public MinecraftMappedProvider(Project project) { super(project); @@ -101,7 +101,7 @@ public class MinecraftMappedProvider extends DependencyProvider { private void mapMinecraftJar() throws IOException { String fromM = "official"; - MappingsProvider mappingsProvider = getExtension().getMappingsProvider(); + MappingsProviderImpl mappingsProvider = getExtension().getMappingsProvider(); Path input = minecraftProvider.getMergedJar().toPath(); Path outputMapped = minecraftMappedJar.toPath(); @@ -148,7 +148,7 @@ public class MinecraftMappedProvider extends DependencyProvider { getProject().getDependencies().module("net.minecraft:minecraft:" + getJarVersionString("mapped"))); } - public void initFiles(MinecraftProvider minecraftProvider, MappingsProvider mappingsProvider) { + public void initFiles(MinecraftProviderImpl minecraftProvider, MappingsProviderImpl mappingsProvider) { this.minecraftProvider = minecraftProvider; minecraftIntermediaryJar = new File(getExtension().getUserCache(), "minecraft-" + getJarVersionString("intermediary") + ".jar"); minecraftMappedJar = new File(getJarDirectory(getExtension().getUserCache(), "mapped"), "minecraft-" + getJarVersionString("mapped") + ".jar"); @@ -159,7 +159,7 @@ public class MinecraftMappedProvider extends DependencyProvider { } protected String getJarVersionString(String type) { - return String.format("%s-%s-%s-%s", minecraftProvider.getMinecraftVersion(), type, getExtension().getMappingsProvider().mappingsName, getExtension().getMappingsProvider().mappingsVersion); + return String.format("%s-%s-%s-%s", minecraftProvider.minecraftVersion(), type, getExtension().getMappingsProvider().mappingsName, getExtension().getMappingsProvider().mappingsVersion); } public File getIntermediaryJar() { diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/assets/MinecraftAssetsProvider.java b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/assets/MinecraftAssetsProvider.java index fd1ad73..566e924 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/assets/MinecraftAssetsProvider.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/minecraft/assets/MinecraftAssetsProvider.java @@ -41,14 +41,14 @@ import org.gradle.api.Project; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.LoomGradlePlugin; -import net.fabricmc.loom.configuration.providers.MinecraftProvider; +import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta; import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.HashedDownloadUtil; import net.fabricmc.loom.util.gradle.ProgressLogger; public class MinecraftAssetsProvider { - public static void provide(MinecraftProvider minecraftProvider, Project project) throws IOException { + public static void provide(MinecraftProviderImpl minecraftProvider, Project project) throws IOException { LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); boolean offline = project.getGradle().getStartParameter().isOffline(); @@ -62,7 +62,7 @@ public class MinecraftAssetsProvider { assets.mkdirs(); } - File assetsInfo = new File(assets, "indexes" + File.separator + assetIndex.fabricId(minecraftProvider.getMinecraftVersion()) + ".json"); + File assetsInfo = new File(assets, "indexes" + File.separator + assetIndex.fabricId(minecraftProvider.minecraftVersion()) + ".json"); project.getLogger().info(":downloading asset index"); diff --git a/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java b/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java index 25d6fe4..2c2b3ce 100644 --- a/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java +++ b/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java @@ -41,7 +41,7 @@ import org.gradle.api.tasks.TaskAction; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.api.decompilers.DecompilationMetadata; import net.fabricmc.loom.api.decompilers.LoomDecompiler; -import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider; +import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; import net.fabricmc.loom.decompilers.LineNumberRemapper; import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.gradle.ProgressLogger; @@ -102,7 +102,7 @@ public class GenerateSourcesTask extends AbstractLoomTask { private File getMappedJarFileWithSuffix(String suffix) { LoomGradleExtension extension = getProject().getExtensions().getByType(LoomGradleExtension.class); - MappingsProvider mappingsProvider = extension.getMappingsProvider(); + MappingsProviderImpl mappingsProvider = extension.getMappingsProvider(); File mappedJar = mappingsProvider.mappedProvider.getMappedJar(); String path = mappedJar.getAbsolutePath(); diff --git a/src/main/java/net/fabricmc/loom/task/LoomTasks.java b/src/main/java/net/fabricmc/loom/task/LoomTasks.java index 1b1de6a..b9221f8 100644 --- a/src/main/java/net/fabricmc/loom/task/LoomTasks.java +++ b/src/main/java/net/fabricmc/loom/task/LoomTasks.java @@ -33,7 +33,7 @@ import org.gradle.api.tasks.TaskContainer; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.api.decompilers.LoomDecompiler; import net.fabricmc.loom.configuration.ide.RunConfigSettings; -import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider; +import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; import net.fabricmc.loom.decompilers.fernflower.FabricFernFlowerDecompiler; public final class LoomTasks { @@ -113,7 +113,7 @@ public final class LoomTasks { LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); project.afterEvaluate(p -> { - MappingsProvider mappingsProvider = extension.getMappingsProvider(); + MappingsProviderImpl mappingsProvider = extension.getMappingsProvider(); File inputJar = mappingsProvider.mappedProvider.getMappedJar(); if (mappingsProvider.hasUnpickDefinitions()) { diff --git a/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java b/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java index 97217fc..6151f93 100644 --- a/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java +++ b/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java @@ -49,9 +49,10 @@ import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.options.Option; import net.fabricmc.loom.LoomGradleExtension; -import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider; -import net.fabricmc.loom.configuration.providers.mappings.MojangMappingsDependency; +import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftMappedProvider; +import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuilder; +import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsDependency; import net.fabricmc.loom.util.SourceRemapper; import net.fabricmc.lorenztiny.TinyMappingsJoiner; import net.fabricmc.mapping.tree.TinyMappingFactory; @@ -96,7 +97,7 @@ public class MigrateMappingsTask extends AbstractLoomTask { Files.createDirectories(outputDir); File mappings = loadMappings(); - MappingsProvider mappingsProvider = extension.getMappingsProvider(); + MappingsProviderImpl mappingsProvider = extension.getMappingsProvider(); try { TinyTree currentMappings = mappingsProvider.getMappings(); @@ -118,12 +119,13 @@ public class MigrateMappingsTask extends AbstractLoomTask { Set files; try { - if (mappings.startsWith(MojangMappingsDependency.GROUP + ':' + MojangMappingsDependency.MODULE + ':') || mappings.startsWith("net.mojang.minecraft:mappings:")) { - if (!mappings.endsWith(":" + project.getExtensions().getByType(LoomGradleExtension.class).getMinecraftProvider().getMinecraftVersion())) { + if (mappings.startsWith("net.minecraft:mappings:") || mappings.startsWith("net.mojang.minecraft:mappings:")) { + if (!mappings.endsWith(":" + project.getExtensions().getByType(LoomGradleExtension.class).getMinecraftProvider().minecraftVersion())) { throw new UnsupportedOperationException("Migrating Mojang mappings is currently only supported for the specified minecraft version"); } - files = new MojangMappingsDependency(project, getExtension()).resolve(); + LayeredMappingsDependency dep = (LayeredMappingsDependency) getExtension().layered(LayeredMappingSpecBuilder::officalMojangMappings); + files = dep.resolve(); } else { Dependency dependency = project.getDependencies().create(mappings); files = project.getConfigurations().detachedConfiguration(dependency).resolve(); diff --git a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java index 79e2f23..cc0ff75 100644 --- a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java +++ b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java @@ -58,7 +58,7 @@ import net.fabricmc.loom.build.nesting.MergedNestedJarProvider; import net.fabricmc.loom.build.nesting.NestedDependencyProvider; import net.fabricmc.loom.build.nesting.NestedJarProvider; import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor; -import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider; +import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.TinyRemapperMappingsHelper; import net.fabricmc.loom.util.ZipReprocessorUtil; @@ -113,7 +113,7 @@ public class RemapJarTask extends Jar { throw new FileNotFoundException(input.toString()); } - MappingsProvider mappingsProvider = extension.getMappingsProvider(); + MappingsProviderImpl mappingsProvider = extension.getMappingsProvider(); String fromM = "named"; String toM = "intermediary"; diff --git a/src/main/java/net/fabricmc/loom/util/SourceRemapper.java b/src/main/java/net/fabricmc/loom/util/SourceRemapper.java index ed4957a..1e3eb80 100644 --- a/src/main/java/net/fabricmc/loom/util/SourceRemapper.java +++ b/src/main/java/net/fabricmc/loom/util/SourceRemapper.java @@ -44,7 +44,7 @@ import org.zeroturnaround.zip.ZipUtil; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.configuration.RemappedConfigurationEntry; import net.fabricmc.loom.configuration.providers.LaunchProvider; -import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider; +import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; import net.fabricmc.loom.util.gradle.ProgressLogger; import net.fabricmc.lorenztiny.TinyMappingsReader; import net.fabricmc.mapping.tree.TinyTree; @@ -163,7 +163,7 @@ public class SourceRemapper { } LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); - MappingsProvider mappingsProvider = extension.getMappingsProvider(); + MappingsProviderImpl mappingsProvider = extension.getMappingsProvider(); MappingSet mappings = extension.getOrCreateSrcMappingCache(toNamed ? 1 : 0, () -> { try { diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/dependencyResolutionManagement.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/DependencyResolutionManagementTest.groovy similarity index 100% rename from src/test/groovy/net/fabricmc/loom/test/integration/dependencyResolutionManagement.groovy rename to src/test/groovy/net/fabricmc/loom/test/integration/DependencyResolutionManagementTest.groovy diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/ParchmentTest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/ParchmentTest.groovy new file mode 100644 index 0000000..836ba58 --- /dev/null +++ b/src/test/groovy/net/fabricmc/loom/test/integration/ParchmentTest.groovy @@ -0,0 +1,52 @@ +/* + * 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.test.integration + +import net.fabricmc.loom.test.util.ProjectTestTrait +import spock.lang.Specification +import spock.lang.Unroll + +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS + +class ParchmentTest extends Specification implements ProjectTestTrait { + @Override + String name() { + "parchment" + } + + @Unroll + def "parchment #gradle"() { + when: + def result = create("build", gradle) + + then: + result.task(":build").outcome == SUCCESS + + where: + gradle | _ + DEFAULT_GRADLE | _ + PRE_RELEASE_GRADLE | _ + } +} diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/IntermediaryMappingLayerTest.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/IntermediaryMappingLayerTest.groovy new file mode 100644 index 0000000..3184ceb --- /dev/null +++ b/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/IntermediaryMappingLayerTest.groovy @@ -0,0 +1,43 @@ +/* + * 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.test.unit.layeredmappings + +import net.fabricmc.loom.configuration.providers.mappings.intermediary.IntermediaryMappingsSpec + +class IntermediaryMappingLayerTest extends LayeredMappingsSpecification { + def "Read intermediary mappings" () { + setup: + mockMappingsProvider.intermediaryTinyFile() >> extractFileFromZip(downloadFile(INTERMEDIARY_1_17_URL, "intermediary.jar"), "mappings/mappings.tiny") + when: + def mappings = getSingleMapping(new IntermediaryMappingsSpec()) + def tiny = getTiny(mappings) + then: + mappings.srcNamespace == "official" + mappings.dstNamespaces == ["intermediary", "named"] + mappings.classes.size() == 6107 + mappings.getClass("abc").getDstName(0) == "net/minecraft/class_3191" + mappings.getClass("abc").getDstName(1) == "net/minecraft/class_3191" + } +} diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingSpecBuilderTest.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingSpecBuilderTest.groovy new file mode 100644 index 0000000..035ac11 --- /dev/null +++ b/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingSpecBuilderTest.groovy @@ -0,0 +1,118 @@ +/* + * 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.test.unit.layeredmappings + +import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpec +import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuilder +import net.fabricmc.loom.configuration.providers.mappings.intermediary.IntermediaryMappingsSpec +import net.fabricmc.loom.configuration.providers.mappings.mojmap.MojangMappingsSpec +import net.fabricmc.loom.configuration.providers.mappings.parchment.ParchmentMappingsSpec +import org.gradle.api.Action +import org.gradle.util.ConfigureUtil +import spock.lang.Specification + +class LayeredMappingSpecBuilderTest extends Specification { + def "simple mojmap" () { + when: + def spec = layered() { + officalMojangMappings() + } + def layers = spec.layers() + then: + spec.version == "layered+hash.961" + layers.size() == 2 + layers[0].class == IntermediaryMappingsSpec + layers[1].class == MojangMappingsSpec + } + + def "simple mojmap with parchment" () { + when: + def spec = layered() { + officalMojangMappings() + parchment("I like cake") + } + def layers = spec.layers() + def parchment = layers[2] as ParchmentMappingsSpec + then: + spec.version == "layered+hash.863714404" + layers.size() == 3 + layers[0].class == IntermediaryMappingsSpec + layers[1].class == MojangMappingsSpec + layers[2].class == ParchmentMappingsSpec + parchment.mavenNotation() == "I like cake" + parchment.removePrefix() == true + } + + def "simple mojmap with parchment keep prefix" () { + when: + def spec = layered() { + officalMojangMappings() + parchment("I like cake") { + it.removePrefix = false + } + } + def layers = spec.layers() + def parchment = layers[2] as ParchmentMappingsSpec + then: + spec.version == "layered+hash.863714410" + layers.size() == 3 + layers[0].class == IntermediaryMappingsSpec + layers[1].class == MojangMappingsSpec + layers[2].class == ParchmentMappingsSpec + parchment.mavenNotation() == "I like cake" + parchment.removePrefix() == false + } + + def "simple mojmap with parchment keep prefix alternate hash" () { + when: + def spec = layered() { + officalMojangMappings() + parchment("I really like cake") { + it.removePrefix = false + } + } + def layers = spec.layers() + def parchment = layers[2] as ParchmentMappingsSpec + then: + spec.version == "layered+hash.1144465487" + layers.size() == 3 + layers[0].class == IntermediaryMappingsSpec + layers[1].class == MojangMappingsSpec + layers[2].class == ParchmentMappingsSpec + parchment.mavenNotation() == "I really like cake" + parchment.removePrefix() == false + } + + // Gradle does this big of magic behind the scenes + LayeredMappingSpec layered(@DelegatesTo(LayeredMappingSpecBuilder) Closure cl) { + return layeredAction(ConfigureUtil.configureUsing(cl)) + } + + LayeredMappingSpec layeredAction(Action action) { + LayeredMappingSpecBuilder builder = new LayeredMappingSpecBuilder() + action.execute(builder) + return builder.build() + } +} diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingsSpecification.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingsSpecification.groovy new file mode 100644 index 0000000..8fa26b3 --- /dev/null +++ b/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingsSpecification.groovy @@ -0,0 +1,121 @@ +/* + * 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.test.unit.layeredmappings + +import groovy.transform.CompileStatic +import net.fabricmc.loom.configuration.providers.MinecraftProvider +import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpec +import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsProcessor +import net.fabricmc.loom.configuration.providers.mappings.MappingContext +import net.fabricmc.loom.configuration.providers.mappings.MappingLayer +import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider +import net.fabricmc.loom.configuration.providers.mappings.MappingsSpec +import net.fabricmc.mappingio.format.Tiny2Writer +import net.fabricmc.mappingio.tree.MappingTree +import net.fabricmc.mappingio.tree.MemoryMappingTree +import org.gradle.api.logging.Logger +import spock.lang.Specification + +import java.util.zip.ZipFile + +abstract class LayeredMappingsSpecification extends Specification implements LayeredMappingsTestConstants { + Logger mockLogger = Mock(Logger) + MappingsProvider mockMappingsProvider = Mock(MappingsProvider) + MinecraftProvider mockMinecraftProvider = Mock(MinecraftProvider) + + MappingContext mappingContext = new TestMappingContext() + + File tempDir = File.createTempDir() + + Map mavenFiles = [:] + + def withMavenFile(String mavenNotation, File file) { + mavenFiles.put(mavenNotation, file) + } + + File downloadFile(String url, String name) { + File dst = new File(tempDir, name) + dst.parentFile.mkdirs() + dst << new URL(url).newInputStream() + return dst + } + + File extractFileFromZip(File zipFile, String name) { + File dst = new File(tempDir, name) + dst.parentFile.mkdirs() + + new ZipFile(zipFile).withCloseable { + dst << it.getInputStream(it.getEntry(name)) + } + return dst + } + + MemoryMappingTree getSingleMapping(MappingsSpec spec) { + MemoryMappingTree mappingTree = new MemoryMappingTree() + spec.createLayer(mappingContext).visit(mappingTree) + return mappingTree + } + + MemoryMappingTree getLayeredMappings(MappingsSpec... specs) { + LayeredMappingSpec spec = new LayeredMappingSpec(specs.toList()) + LayeredMappingsProcessor processor = new LayeredMappingsProcessor(spec) + return processor.getMappings(mappingContext) + } + + String getTiny(MemoryMappingTree mappingTree) { + def sw = new StringWriter() + mappingTree.accept(new Tiny2Writer(sw, false)) + return sw.toString() + } + + @CompileStatic + class TestMappingContext implements MappingContext { + @Override + File mavenFile(String mavenNotation) { + assert mavenFiles.containsKey(mavenNotation) + return mavenFiles.get(mavenNotation) + } + + @Override + MappingsProvider mappingsProvider() { + return mockMappingsProvider + } + + @Override + MinecraftProvider minecraftProvider() { + return mockMinecraftProvider + } + + @Override + File workingDirectory(String name) { + return new File(tempDir, name) + } + + @Override + Logger getLogger() { + return mockLogger + } + } +} diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingsTestConstants.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingsTestConstants.groovy new file mode 100644 index 0000000..1827ccd --- /dev/null +++ b/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingsTestConstants.groovy @@ -0,0 +1,47 @@ +/* + * 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.test.unit.layeredmappings + +import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta + +interface LayeredMappingsTestConstants { + public static final String INTERMEDIARY_1_17_URL = "https://maven.fabricmc.net/net/fabricmc/intermediary/1.17/intermediary-1.17-v2.jar" + public static final String INTERMEDIARY_1_16_5_URL = "https://maven.fabricmc.net/net/fabricmc/intermediary/1.16.5/intermediary-1.16.5-v2.jar" + + public static final Map DOWNLOADS_1_17 = [ + client_mappings:new MinecraftVersionMeta.Download(null, "227d16f520848747a59bef6f490ae19dc290a804", 6431705, "https://launcher.mojang.com/v1/objects/227d16f520848747a59bef6f490ae19dc290a804/client.txt"), + server_mappings:new MinecraftVersionMeta.Download(null, "84d80036e14bc5c7894a4fad9dd9f367d3000334", 4948536, "https://launcher.mojang.com/v1/objects/84d80036e14bc5c7894a4fad9dd9f367d3000334/server.txt") + ] + public static final MinecraftVersionMeta VERSION_META_1_17 = new MinecraftVersionMeta(null, null, null, 0, DOWNLOADS_1_17, null, null, null, null, 0, null, null, null) + + public static final Map DOWNLOADS_1_16_5 = [ + client_mappings:new MinecraftVersionMeta.Download(null, "e3dfb0001e1079a1af72ee21517330edf52e6192", 5746047, "https://launcher.mojang.com/v1/objects/e3dfb0001e1079a1af72ee21517330edf52e6192/client.txt"), + server_mappings:new MinecraftVersionMeta.Download(null, "81d5c793695d8cde63afddb40dde88e3a88132ac", 4400926, "https://launcher.mojang.com/v1/objects/81d5c793695d8cde63afddb40dde88e3a88132ac/server.txt") + ] + public static final MinecraftVersionMeta VERSION_META_1_16_5 = new MinecraftVersionMeta(null, null, null, 0, DOWNLOADS_1_16_5, null, null, null, null, 0, null, null, null) + + public static final String PARCHMENT_NOTATION = "org.parchmentmc.data:parchment-1.16.5:20210608-SNAPSHOT@zip" + public static final String PARCHMENT_URL = "https://ldtteam.jfrog.io/artifactory/parchmentmc-snapshots/org/parchmentmc/data/parchment-1.16.5/20210608-SNAPSHOT/parchment-1.16.5-20210608-SNAPSHOT.zip" +} \ No newline at end of file diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/MojangMappingLayerTest.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/MojangMappingLayerTest.groovy new file mode 100644 index 0000000..28e058d --- /dev/null +++ b/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/MojangMappingLayerTest.groovy @@ -0,0 +1,49 @@ +/* + * 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.test.unit.layeredmappings + +import net.fabricmc.loom.configuration.providers.mappings.intermediary.IntermediaryMappingsSpec +import net.fabricmc.loom.configuration.providers.mappings.mojmap.MojangMappingsSpec + +class MojangMappingLayerTest extends LayeredMappingsSpecification { + def "Read mojang mappings" () { + setup: + mockMappingsProvider.intermediaryTinyFile() >> extractFileFromZip(downloadFile(INTERMEDIARY_1_17_URL, "intermediary.jar"), "mappings/mappings.tiny") + mockMinecraftProvider.getVersionInfo() >> VERSION_META_1_17 + when: + def mappings = getLayeredMappings( + new IntermediaryMappingsSpec(), + new MojangMappingsSpec() + ) + def tiny = getTiny(mappings) + then: + mappings.srcNamespace == "named" + mappings.dstNamespaces == ["intermediary", "official"] + mappings.classes.size() == 6113 + mappings.classes[0].srcName.hashCode() == 1869546970 // MojMap name, just check the hash + mappings.classes[0].getDstName(0) == "net/minecraft/class_2354" + mappings.classes[0].methods[0].args.size() == 0 // No Args + } +} diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/ParchmentMappingLayerTest.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/ParchmentMappingLayerTest.groovy new file mode 100644 index 0000000..597e17f --- /dev/null +++ b/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/ParchmentMappingLayerTest.groovy @@ -0,0 +1,74 @@ +/* + * 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.test.unit.layeredmappings + +import net.fabricmc.loom.configuration.providers.mappings.intermediary.IntermediaryMappingsSpec +import net.fabricmc.loom.configuration.providers.mappings.mojmap.MojangMappingsSpec +import net.fabricmc.loom.configuration.providers.mappings.parchment.ParchmentMappingsSpec +import net.fabricmc.loom.configuration.providers.minecraft.MinecraftVersionMeta + +class ParchmentMappingLayerTest extends LayeredMappingsSpecification { + def "Read parchment mappings" () { + setup: + mockMappingsProvider.intermediaryTinyFile() >> extractFileFromZip(downloadFile(INTERMEDIARY_1_16_5_URL, "intermediary.jar"), "mappings/mappings.tiny") + mockMinecraftProvider.getVersionInfo() >> VERSION_META_1_16_5 + when: + withMavenFile(PARCHMENT_NOTATION, downloadFile(PARCHMENT_URL, "parchment.zip")) + def mappings = getLayeredMappings( + new IntermediaryMappingsSpec(), + new MojangMappingsSpec(), + new ParchmentMappingsSpec(PARCHMENT_NOTATION, false) + ) + def tiny = getTiny(mappings) + then: + mappings.srcNamespace == "named" + mappings.dstNamespaces == ["intermediary", "official"] + mappings.classes.size() == 5747 + mappings.classes[0].srcName.hashCode() == -1112444138 // MojMap name, just check the hash + mappings.classes[0].getDstName(0) == "net/minecraft/class_2573" + mappings.classes[0].methods[0].args[0].srcName == "pStack" + } + + def "Read parchment mappings remove prefix" () { + setup: + mockMappingsProvider.intermediaryTinyFile() >> extractFileFromZip(downloadFile(INTERMEDIARY_1_16_5_URL, "intermediary.jar"), "mappings/mappings.tiny") + mockMinecraftProvider.getVersionInfo() >> VERSION_META_1_16_5 + when: + withMavenFile(PARCHMENT_NOTATION, downloadFile(PARCHMENT_URL, "parchment.zip")) + def mappings = getLayeredMappings( + new IntermediaryMappingsSpec(), + new MojangMappingsSpec(), + new ParchmentMappingsSpec(PARCHMENT_NOTATION, true) + ) + def tiny = getTiny(mappings) + then: + mappings.srcNamespace == "named" + mappings.dstNamespaces == ["intermediary", "official"] + mappings.classes.size() == 5747 + mappings.classes[0].srcName.hashCode() == -1112444138 // MojMap name, just check the hash + mappings.classes[0].getDstName(0) == "net/minecraft/class_2573" + mappings.classes[0].methods[0].args[0].srcName == "stack" + } +} diff --git a/src/test/resources/projects/parchment/build.gradle b/src/test/resources/projects/parchment/build.gradle new file mode 100644 index 0000000..255e98e --- /dev/null +++ b/src/test/resources/projects/parchment/build.gradle @@ -0,0 +1,20 @@ +plugins { + id 'fabric-loom' +} + +repositories { + maven { + name = "ldtteam" + url = "https://ldtteam.jfrog.io/artifactory/parchmentmc-snapshots/" + } +} + +dependencies { + minecraft "com.mojang:minecraft:1.16.5" + mappings loom.layered() { + officalMojangMappings() + parchment("org.parchmentmc.data:parchment-1.16.5:20210608-SNAPSHOT@zip") + } + + modImplementation "net.fabricmc:fabric-loader:0.11.3" +}