Merge remote-tracking branch 'FabricMC/dev/0.9' into dev/0.9

# Conflicts:
#	build.gradle
#	src/main/java/net/fabricmc/loom/LoomGradleExtension.java
#	src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java
#	src/main/java/net/fabricmc/loom/configuration/providers/MinecraftProvider.java
#	src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProvider.java
#	src/main/java/net/fabricmc/loom/configuration/providers/mappings/MojangMappingsDependency.java
#	src/main/java/net/fabricmc/loom/configuration/providers/minecraft/MinecraftMappedProvider.java
#	src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java
#	src/main/java/net/fabricmc/loom/util/SourceRemapper.java
This commit is contained in:
shedaniel
2021-06-17 23:44:48 +08:00
47 changed files with 2482 additions and 1174 deletions

View File

@@ -60,6 +60,7 @@ import net.fabricmc.loom.configuration.ide.RunConfigSettings;
import net.fabricmc.loom.configuration.launch.LaunchProviderSettings;
import net.fabricmc.loom.configuration.processors.JarProcessor;
import net.fabricmc.loom.configuration.processors.JarProcessorManager;
import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl;
import net.fabricmc.loom.configuration.providers.MinecraftProvider;
import net.fabricmc.loom.configuration.providers.forge.FieldMigratedMappingsProvider;
import net.fabricmc.loom.configuration.providers.forge.ForgeProvider;
@@ -71,6 +72,11 @@ import net.fabricmc.loom.configuration.providers.forge.SrgProvider;
import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider;
import net.fabricmc.loom.configuration.providers.mappings.MojangMappingsDependency;
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;
import net.fabricmc.loom.util.ModPlatform;
import net.fabricmc.loom.util.function.LazyBool;
@@ -220,7 +226,14 @@ public class LoomGradleExtension {
}
public Dependency officialMojangMappings() {
return new MojangMappingsDependency(project, this);
return layered(LayeredMappingSpecBuilder::officalMojangMappings);
}
public Dependency layered(Action<LayeredMappingSpecBuilder> 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) {
@@ -355,7 +368,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();
@@ -384,16 +397,16 @@ public class LoomGradleExtension {
return getDependencyManager().getProvider(PatchProvider.class);
}
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(isForge() ? FieldMigratedMappingsProvider.class : MappingsProvider.class);
public MappingsProviderImpl getMappingsProvider() {
return getDependencyManager().getProvider(isForge() ? FieldMigratedMappingsProvider.class : MappingsProviderImpl.class);
}
public McpConfigProvider getMcpConfigProvider() {
@@ -520,7 +533,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;
}

View File

@@ -39,7 +39,7 @@ 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.MinecraftProviderImpl;
import net.fabricmc.loom.configuration.providers.forge.FieldMigratedMappingsProvider;
import net.fabricmc.loom.configuration.providers.forge.ForgeProvider;
import net.fabricmc.loom.configuration.providers.forge.ForgeUniversalProvider;
@@ -47,7 +47,7 @@ import net.fabricmc.loom.configuration.providers.forge.ForgeUserdevProvider;
import net.fabricmc.loom.configuration.providers.forge.McpConfigProvider;
import net.fabricmc.loom.configuration.providers.forge.PatchProvider;
import net.fabricmc.loom.configuration.providers.forge.SrgProvider;
import net.fabricmc.loom.configuration.providers.mappings.MappingsProvider;
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
import net.fabricmc.loom.task.GenVsCodeProjectTask;
import net.fabricmc.loom.util.Constants;
@@ -151,7 +151,7 @@ public final class CompileConfiguration {
LoomDependencyManager dependencyManager = new LoomDependencyManager();
extension.setDependencyManager(dependencyManager);
dependencyManager.addProvider(new MinecraftProvider(project));
dependencyManager.addProvider(new MinecraftProviderImpl(project));
if (extension.isForge()) {
dependencyManager.addProvider(new ForgeProvider(project));
@@ -168,7 +168,7 @@ public final class CompileConfiguration {
dependencyManager.addProvider(new ForgeUniversalProvider(project));
}
dependencyManager.addProvider(extension.isForge() ? new FieldMigratedMappingsProvider(project) : new MappingsProvider(project));
dependencyManager.addProvider(extension.isForge() ? new FieldMigratedMappingsProvider(project) : new MappingsProviderImpl(project));
dependencyManager.addProvider(new LaunchProvider(project));
dependencyManager.handleDependencies(project);

View File

@@ -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<Runnable> 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;
}
}

View File

@@ -64,7 +64,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.LoggerFilter;
@@ -142,7 +142,7 @@ public class ModProcessor {
String toM = "named";
MinecraftMappedProvider mappedProvider = extension.getMinecraftMappedProvider();
MappingsProvider mappingsProvider = extension.getMappingsProvider();
MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
Path mc = extension.isForge() ? mappedProvider.getSrgJar().toPath() : mappedProvider.getIntermediaryJar().toPath();
Path[] mcDeps = project.getConfigurations().getByName(Constants.Configurations.LOADER_DEPENDENCIES).getFiles()

View File

@@ -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;
@@ -86,7 +86,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");

View File

@@ -66,7 +66,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());

View File

@@ -24,247 +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.base.Stopwatch;
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;
public File minecraftClientJar;
public File minecraftServerJar;
private File minecraftMergedJar;
private File versionManifestJson;
private String jarSuffix = "";
public MinecraftProvider(Project project) {
super(project);
}
@Override
public void provide(DependencyInfo dependency, Consumer<Runnable> postPopulationScheduler) throws Exception {
minecraftVersion = dependency.getDependency().getVersion();
if (getExtension().shouldGenerateSrgTiny() && !getExtension().isForge()) {
addDependency("de.oceanlabs.mcp:mcp_config:" + minecraftVersion, Constants.Configurations.SRG);
}
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");
}
public void deleteFiles() {
DownloadUtil.delete(minecraftClientJar);
DownloadUtil.delete(minecraftServerJar);
DownloadUtil.delete(minecraftMergedJar);
}
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<ManifestVersion.Versions> 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<ManifestVersion.Versions> 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");
Stopwatch stopwatch = Stopwatch.createStarted();
try (JarMerger jarMerger = new JarMerger(minecraftClientJar, minecraftServerJar, minecraftMergedJar)) {
jarMerger.enableSyntheticParamsOffset();
jarMerger.merge();
}
logger.info(":merged jars in " + stopwatch);
}
public File getMergedJar() {
return minecraftMergedJar;
}
public String getMinecraftVersion() {
return minecraftVersion;
}
public MinecraftVersionMeta getVersionInfo() {
return versionInfo;
}
public MinecraftLibraryProvider getLibraryProvider() {
return libraryProvider;
}
public String getJarSuffix() {
return jarSuffix;
}
public void setJarSuffix(String jarSuffix) {
this.jarSuffix = jarSuffix;
}
@Override
public String getTargetConfig() {
return Constants.Configurations.MINECRAFT;
}
MinecraftVersionMeta getVersionInfo();
}

View File

@@ -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<Runnable> 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<ManifestVersion.Versions> 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<ManifestVersion.Versions> 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;
}
}

View File

@@ -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();
}
}

View File

@@ -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<MappingsSpec<?>> layers) {
public String getVersion() {
// TODO something better?
return "layered+hash.%d".formatted(Math.abs(hashCode()));
}
}

View File

@@ -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<MappingsSpec<?>> 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<ParchmentMappingsSpecBuilder> action) {
var builder = ParchmentMappingsSpecBuilder.builder(mavenNotation);
action.execute(builder);
layers.add(builder.build());
return this;
}
public LayeredMappingSpec build() {
List<MappingsSpec<?>> builtLayers = new LinkedList<>();
// Intermediary is always the base layer
builtLayers.add(new IntermediaryMappingsSpec());
builtLayers.addAll(layers);
return new LayeredMappingSpec(Collections.unmodifiableList(builtLayers));
}
}

View File

@@ -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<File> 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<File> 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) {
}
}

View File

@@ -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<Class<? extends MappingLayer>> visitedLayers = new ArrayList<>();
for (MappingsSpec<?> spec : layeredMappingSpec.layers()) {
MappingLayer layer = spec.createLayer(context);
for (Class<? extends MappingLayer> 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;
}
}

View File

@@ -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();
}

View File

@@ -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<Class<? extends MappingLayer>> dependsOn() {
return Collections.emptyList();
}
}

View File

@@ -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);
}
}

View File

@@ -24,549 +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.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import com.google.common.base.Preconditions;
import com.google.common.base.Stopwatch;
import com.google.common.net.UrlEscapers;
import com.google.gson.JsonObject;
import dev.architectury.mappingslayers.api.utils.MappingsModificationUtils;
import dev.architectury.mappingslayers.api.utils.MappingsUtils;
import org.apache.commons.io.FileUtils;
import org.apache.tools.ant.util.StringUtils;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
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.forge.MinecraftPatchedProvider;
import net.fabricmc.loom.configuration.providers.forge.SrgProvider;
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.loom.util.srg.MCPReader;
import net.fabricmc.loom.util.srg.SrgMerger;
import net.fabricmc.loom.util.srg.SrgNamedWriter;
import net.fabricmc.mapping.reader.v2.TinyMetadata;
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.TinyFile;
import net.fabricmc.stitch.commands.tinyv2.TinyV2Writer;
public class MappingsProvider extends DependencyProvider {
public MinecraftMappedProvider mappedProvider;
public MinecraftPatchedProvider patchedProvider;
public String mappingsName;
public String minecraftVersion;
public String mappingsVersion;
public String removeSuffix;
protected final Path mappingsDir;
protected Path mappingsVersionedDir;
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;
// tinyMappings wrapped in a jar
public File tinyMappingsJar;
public Path tinyMappingsWithSrg;
public File mixinTinyMappingsWithSrg; // FORGE: The mixin mappings have srg names in intermediary.
public File srgToNamedSrg; // FORGE: srg to named in srg file format
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 Path getMappingsVersionedDir() throws IOException {
if (mappingsVersionedDir == null) {
mappingsVersionedDir = mappingsDir.resolve(getExtension().getMinecraftProvider().getMinecraftVersion());
if (!Files.exists(mappingsVersionedDir)) {
Files.createDirectories(mappingsVersionedDir);
}
}
return mappingsVersionedDir;
}
public Path getMappedVersionedDir(String name) throws IOException {
Path dir = getMappingsVersionedDir().resolve(name);
if (!Files.exists(dir)) {
Files.createDirectories(dir);
}
return dir;
}
public void clean() throws IOException {
FileUtils.deleteDirectory(mappingsDir.toFile());
}
public TinyTree getMappings() throws IOException {
return MappingsCache.INSTANCE.get(tinyMappings.toPath());
}
public TinyTree getMappingsWithSrg() throws IOException {
if (getExtension().shouldGenerateSrgTiny()) {
return MappingsCache.INSTANCE.get(tinyMappingsWithSrg);
}
throw new UnsupportedOperationException("Not running with Forge support / Tiny srg support.");
}
@Override
public void provide(DependencyInfo dependency, Consumer<Runnable> 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;
if (isMCP(mappingsJar.toPath())) {
File old = mappingsJar;
mappingsJar = mappingsDir.resolve(StringUtils.removeSuffix(mappingsJar.getName(), ".zip") + "-" + minecraftVersion + ".jar").toFile();
FileUtils.copyFile(old, mappingsJar);
mappingsName += "-" + minecraftVersion;
}
// 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") || mappingsJar.getName().endsWith("-mergedv2.jar");
} else {
isV2 = doesJarContainV2Mappings(mappingsJar.toPath());
}
removeSuffix = StringUtils.removeSuffix(mappingsJar.getName(), ".jar");
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];
}
Path mappedVersionedDir = getMappedVersionedDir(removeSuffix);
tinyMappings = mappedVersionedDir.resolve("mappings.tiny").toFile();
unpickDefinitionsFile = mappedVersionedDir.resolve("definitions.unpick").toFile();
tinyMappingsJar = new File(getExtension().getUserCache(), removeSuffix + "-" + jarClassifier + ".jar");
tinyMappingsWithSrg = mappedVersionedDir.resolve("mappings-srg.tiny");
mixinTinyMappingsWithSrg = mappedVersionedDir.resolve("mappings-mixin-srg.tiny").toFile();
srgToNamedSrg = mappedVersionedDir.resolve("mappings-srg-named.srg").toFile();
if (!tinyMappings.exists() || isRefreshDeps()) {
storeMappings(getProject(), minecraftProvider, mappingsJar.toPath(), postPopulationScheduler);
} else {
try (FileSystem fileSystem = FileSystems.newFileSystem(mappingsJar.toPath(), (ClassLoader) null)) {
extractUnpickDefinitions(fileSystem, unpickDefinitionsFile.toPath());
}
}
if (getExtension().isForge()) {
patchedProvider = new MinecraftPatchedProvider(getProject());
patchedProvider.provide(dependency, postPopulationScheduler);
}
manipulateMappings(mappingsJar.toPath());
if (getExtension().shouldGenerateSrgTiny()) {
if (Files.notExists(tinyMappingsWithSrg) || isRefreshDeps()) {
// Merge tiny mappings with srg
SrgMerger.mergeSrg(getExtension().getSrgProvider().getSrg().toPath(), tinyMappings.toPath(), tinyMappingsWithSrg, true);
}
}
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();
}
if (getExtension().isForge()) {
if (!getExtension().shouldGenerateSrgTiny()) {
throw new IllegalStateException("We have to generate srg tiny in a forge environment!");
}
if (!mixinTinyMappingsWithSrg.exists() || isRefreshDeps()) {
List<String> lines = new ArrayList<>(Files.readAllLines(tinyMappingsWithSrg));
lines.set(0, lines.get(0).replace("intermediary", "yraidemretni").replace("srg", "intermediary"));
Files.deleteIfExists(mixinTinyMappingsWithSrg.toPath());
Files.write(mixinTinyMappingsWithSrg.toPath(), lines);
}
if (!srgToNamedSrg.exists() || isRefreshDeps()) {
SrgNamedWriter.writeTo(getProject().getLogger(), srgToNamedSrg.toPath(), getMappingsWithSrg(), "srg", "named");
}
}
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 (extension.isForge()) {
patchedProvider.finishProvide();
}
if (processorManager.active() || (extension.isForge() && patchedProvider.usesProjectCache())) {
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);
}
public void manipulateMappings(Path mappingsJar) throws IOException { }
private void storeMappings(Project project, MinecraftProvider minecraftProvider, Path yarnJar, Consumer<Runnable> postPopulationScheduler)
throws Exception {
project.getLogger().info(":extracting " + yarnJar.getFileName());
if (isMCP(yarnJar)) {
readAndMergeMCP(yarnJar, postPopulationScheduler);
return;
}
try (FileSystem fileSystem = FileSystems.newFileSystem(yarnJar, (ClassLoader) null)) {
extractMappings(fileSystem, baseTinyMappings);
extractUnpickDefinitions(fileSystem, unpickDefinitionsFile.toPath());
}
if (baseMappingsAreMergedV2()) {
// Architectury Loom Patch
// If a merged tiny v2 mappings file is provided
// Skip merging, should save a lot of time
Files.copy(baseTinyMappings, tinyMappings.toPath(), StandardCopyOption.REPLACE_EXISTING);
} else 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 void readAndMergeMCP(Path mcpJar, Consumer<Runnable> postPopulationScheduler) throws Exception {
Path intermediaryTinyPath = getIntermediaryTiny();
SrgProvider provider = getExtension().getSrgProvider();
if (provider == null) {
if (!getExtension().shouldGenerateSrgTiny()) {
Configuration srg = getProject().getConfigurations().maybeCreate(Constants.Configurations.SRG);
srg.setTransitive(false);
}
provider = new SrgProvider(getProject());
getProject().getDependencies().add(provider.getTargetConfig(), "de.oceanlabs.mcp:mcp_config:" + minecraftVersion);
Configuration configuration = getProject().getConfigurations().getByName(provider.getTargetConfig());
provider.provide(DependencyInfo.create(getProject(), configuration.getDependencies().iterator().next(), configuration), postPopulationScheduler);
}
Path srgPath = provider.getSrg().toPath();
TinyFile file = new MCPReader(intermediaryTinyPath, srgPath).read(mcpJar);
TinyV2Writer.write(file, tinyMappings.toPath());
}
private boolean isMCP(Path path) throws IOException {
try (FileSystem fs = FileSystems.newFileSystem(path, (ClassLoader) null)) {
return Files.exists(fs.getPath("fields.csv")) && Files.exists(fs.getPath("methods.csv"));
}
}
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 | NoSuchFileException e) {
return false;
}
}
}
private boolean baseMappingsAreMergedV2() throws IOException {
try (BufferedReader reader = Files.newBufferedReader(baseTinyMappings)) {
TinyMetadata metadata = TinyV2Factory.readMetadata(reader);
return metadata.getNamespaces().containsAll(Arrays.asList("named", "intermediary", "official"));
} 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);
}
Stopwatch stopwatch = Stopwatch.createStarted();
project.getLogger().info(":merging mappings");
Path invertedIntermediary = Paths.get(mappingsStepsDir.toString(), "inverted-intermediary.tiny");
reorderMappings(getIntermediaryTiny(), invertedIntermediary, "intermediary", "official");
Path unorderedMergedMappings = Paths.get(mappingsStepsDir.toString(), "unordered-merged.tiny");
mergeMappings(invertedIntermediary, unmergedYarn, unorderedMergedMappings);
reorderMappings(unorderedMergedMappings, tinyMappings.toPath(), "official", "intermediary", "named");
Files.deleteIfExists(invertedIntermediary);
Files.deleteIfExists(unorderedMergedMappings);
project.getLogger().info(":merged mappings in " + stopwatch.stop());
}
private void reorderMappings(Path oldMappings, Path newMappings, String... newOrder) throws IOException {
MappingsModificationUtils.modify(oldMappings, newMappings, tree ->
MappingsUtils.reorderNamespaces(tree, Arrays.asList(newOrder)));
}
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() throws IOException {
baseTinyMappings = getMappedVersionedDir(removeSuffix).resolve("mappings-base.tiny");
if (Files.exists(mappingsStepsDir)) {
Files.walkFileTree(mappingsStepsDir, new DeletingFileVisitor());
}
}
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 (isRefreshDeps() && !hasRefreshed) {
Files.deleteIfExists(intermediaryTiny);
}
if (!Files.exists(intermediaryTiny)) {
hasRefreshed = true;
intermediaryTiny = getMappingsVersionedDir().resolve("intermediary-v2.tiny");
// Download and extract intermediary
String encodedMinecraftVersion = UrlEscapers.urlFragmentEscaper().escape(minecraftVersion);
String intermediaryArtifactUrl = getExtension().getIntermediaryUrl().apply(encodedMinecraftVersion);
Path intermediaryJar = getMappingsVersionedDir().resolve("intermediary-v2.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();
}

View File

@@ -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<Runnable> 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) {
}
}

View File

@@ -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 extends MappingLayer> {
L createLayer(MappingContext context);
}

View File

@@ -1,345 +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.UncheckedIOException;
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.Action;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.artifacts.ExternalModuleDependency;
import org.gradle.api.artifacts.ModuleIdentifier;
import org.gradle.api.artifacts.ModuleVersionIdentifier;
import org.gradle.api.artifacts.MutableVersionConstraint;
import org.gradle.api.artifacts.SelfResolvingDependency;
import org.gradle.api.artifacts.VersionConstraint;
import org.gradle.api.internal.artifacts.DefaultModuleIdentifier;
import org.gradle.api.internal.artifacts.ModuleVersionSelectorStrictSpec;
import org.gradle.api.internal.artifacts.dependencies.AbstractModuleDependency;
import org.gradle.api.internal.artifacts.dependencies.DefaultMutableVersionConstraint;
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 extends AbstractModuleDependency implements SelfResolvingDependency, ExternalModuleDependency {
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;
private boolean changing;
private boolean force;
public MojangMappingsDependency(Project project, LoomGradleExtension extension) {
super(null);
this.project = project;
this.extension = extension;
}
@Override
public ExternalModuleDependency copy() {
MojangMappingsDependency copiedProjectDependency = new MojangMappingsDependency(project, extension);
this.copyTo(copiedProjectDependency);
return copiedProjectDependency;
}
@Override
public void version(Action<? super MutableVersionConstraint> action) {
}
@Override
public boolean isForce() {
return this.force;
}
@Override
public ExternalModuleDependency setForce(boolean force) {
this.validateMutation(this.force, force);
this.force = force;
return this;
}
@Override
public boolean isChanging() {
return this.changing;
}
@Override
public ExternalModuleDependency setChanging(boolean changing) {
this.validateMutation(this.changing, changing);
this.changing = changing;
return this;
}
@Override
public Set<File> resolve() {
Path mappingsDir;
try {
mappingsDir = extension.getMappingsProvider().getMappedVersionedDir(String.format("mojang/%s.%s-%s", GROUP, MODULE, getVersion()));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
Path mappingsFile = mappingsDir.resolve(String.format("mojmap-mappings-%s.jar", getVersion()));
Path clientMappings = mappingsDir.resolve("client.map");
Path serverMappings = mappingsDir.resolve("server.map");
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);
}
}
if (!extension.isSilentMojangMappingsLicenseEnabled()) {
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<File> 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() {
if (extension.getDependencyManager() == null) return "1.0.0";
return extension.getMinecraftProvider().getMinecraftVersion();
}
@Override
public VersionConstraint getVersionConstraint() {
return new DefaultMutableVersionConstraint(getVersion());
}
@Override
public boolean matchesStrictly(ModuleVersionIdentifier identifier) {
return (new ModuleVersionSelectorStrictSpec(this)).isSatisfiedBy(identifier);
}
@Override
public ModuleIdentifier getModule() {
return DefaultModuleIdentifier.newId(GROUP, MODULE);
}
@Override
public boolean contentEquals(Dependency dependency) {
if (dependency instanceof MojangMappingsDependency mojangMappingsDependency) {
return mojangMappingsDependency.extension.getMinecraftProvider().getMinecraftVersion().equals(getVersion());
}
return false;
}
@Override
public String getReason() {
return null;
}
@Override
public void because(String s) {
}
private static void iterateClasses(MappingSet mappings, Consumer<ClassMapping<?, ?>> consumer) {
for (TopLevelClassMapping classMapping : mappings.getTopLevelClassMappings()) {
iterateClass(classMapping, consumer);
}
}
private static void iterateClass(ClassMapping<?, ?> classMapping, Consumer<ClassMapping<?, ?>> 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());
}
});
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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<IntermediaryMappingLayer> {
@Override
public IntermediaryMappingLayer createLayer(MappingContext context) {
return new IntermediaryMappingLayer(context.mappingsProvider().intermediaryTinyFile());
}
}

View File

@@ -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<Class<? extends MappingLayer>> dependsOn() {
return List.of(IntermediaryMappingLayer.class);
}
}

View File

@@ -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<MojangMappingLayer> {
// 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()
);
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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<ParchmentMappingLayer> {
@Override
public ParchmentMappingLayer createLayer(MappingContext context) {
return new ParchmentMappingLayer(context.mavenFile(mavenNotation()), removePrefix());
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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<Class> classes,
@Nullable
List<Package> 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<Field> fields,
@Nullable
List<Method> methods,
@Nullable
List<String> 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<String> 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<Parameter> parameters,
@Nullable
List<String> 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<String> javadoc
) { }
}

View File

@@ -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");
}

View File

@@ -54,8 +54,8 @@ import org.gradle.api.Project;
import org.jetbrains.annotations.Nullable;
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.configuration.providers.minecraft.tr.OutputRemappingHandler;
import net.fabricmc.loom.configuration.sources.ForgeSourcesRemapper;
import net.fabricmc.loom.util.Constants;
@@ -81,7 +81,7 @@ public class MinecraftMappedProvider extends DependencyProvider {
private File minecraftIntermediaryJar;
private File minecraftSrgJar;
private MinecraftProvider minecraftProvider;
private MinecraftProviderImpl minecraftProvider;
public MinecraftMappedProvider(Project project) {
super(project);
@@ -151,7 +151,7 @@ public class MinecraftMappedProvider extends DependencyProvider {
private void mapMinecraftJar() throws Exception {
String fromM = "official";
MappingsProvider mappingsProvider = getExtension().getMappingsProvider();
MappingsProviderImpl mappingsProvider = getExtension().getMappingsProvider();
Path input = inputJar.toPath();
Path outputMapped = minecraftMappedJar.toPath();
@@ -295,7 +295,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");
minecraftSrgJar = !getExtension().isForge() ? null : new File(getExtension().getUserCache(), "minecraft-" + getJarVersionString("srg") + ".jar");
@@ -308,7 +308,7 @@ public class MinecraftMappedProvider extends DependencyProvider {
}
protected String getJarVersionString(String type) {
return String.format("%s-%s-%s-%s%s", minecraftProvider.getMinecraftVersion(), type, getExtension().getMappingsProvider().mappingsName, getExtension().getMappingsProvider().mappingsVersion, minecraftProvider.getJarSuffix());
return String.format("%s-%s-%s-%s%s", minecraftProvider.minecraftVersion(), type, getExtension().getMappingsProvider().mappingsName, getExtension().getMappingsProvider().mappingsVersion, minecraftProvider.getJarSuffix());
}
public File getIntermediaryJar() {

View File

@@ -43,13 +43,13 @@ 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;
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();
@@ -63,7 +63,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");

View File

@@ -42,7 +42,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.configuration.sources.ForgeSourcesRemapper;
import net.fabricmc.loom.decompilers.LineNumberRemapper;
import net.fabricmc.loom.util.Constants;
@@ -111,7 +111,7 @@ public class GenerateSourcesTask extends AbstractLoomTask {
public static File getMappedJarFileWithSuffix(Project project, String suffix) {
LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class);
MappingsProvider mappingsProvider = extension.getMappingsProvider();
MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
File mappedJar = mappingsProvider.mappedProvider.getMappedJar();
String path = mappedJar.getAbsolutePath();

View File

@@ -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;
import net.fabricmc.loom.util.Constants;
@@ -125,7 +125,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()) {

View File

@@ -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<File> 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();

View File

@@ -81,7 +81,7 @@ import net.fabricmc.loom.build.nesting.NestedDependencyProvider;
import net.fabricmc.loom.build.nesting.NestedJarPathProvider;
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.SourceRemapper;
import net.fabricmc.loom.util.TinyRemapperMappingsHelper;
@@ -211,7 +211,7 @@ public class RemapJarTask extends Jar {
throw new FileNotFoundException(input.toString());
}
MappingsProvider mappingsProvider = extension.getMappingsProvider();
MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
String fromM = this.fromM.get();
String toM = this.toM.get();

View File

@@ -45,7 +45,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.configuration.providers.minecraft.tr.MercuryUtils;
import net.fabricmc.lorenztiny.TinyMappingsReader;
import net.fabricmc.mapping.tree.TinyTree;
@@ -175,7 +175,7 @@ public class SourceRemapper {
}
LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class);
MappingsProvider mappingsProvider = extension.getMappingsProvider();
MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
String intermediary = extension.isForge() ? "srg" : "intermediary";
int id = -1;