Fix + test minecraft metadata downloading (#905)

This commit is contained in:
modmuss
2023-06-13 21:24:46 +01:00
committed by GitHub
parent ed5e4ac8dd
commit 590686fe1a
6 changed files with 407 additions and 90 deletions

View File

@@ -27,8 +27,18 @@ package net.fabricmc.loom.configuration.providers.minecraft;
import java.util.List;
import java.util.Map;
import org.jetbrains.annotations.Nullable;
public record ManifestVersion(List<Versions> versions, Map<String, String> latest) {
public static class Versions {
public String id, url, sha1;
}
@Nullable
public Versions getVersion(String id) {
return versions.stream()
.filter(versions -> versions.id.equalsIgnoreCase(id))
.findFirst()
.orElse(null);
}
}

View File

@@ -0,0 +1,161 @@
/*
* This file is part of fabric-loom, licensed under the MIT License (MIT).
*
* Copyright (c) 2023 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.minecraft;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.util.List;
import java.util.function.Function;
import org.gradle.api.Project;
import org.jetbrains.annotations.Nullable;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.LoomGradlePlugin;
import net.fabricmc.loom.util.MirrorUtil;
import net.fabricmc.loom.util.download.DownloadBuilder;
public final class MinecraftMetadataProvider {
private final Options options;
private final Function<String, DownloadBuilder> download;
private ManifestVersion.Versions versionEntry;
private MinecraftVersionMeta versionMeta;
public MinecraftMetadataProvider(Options options, Function<String, DownloadBuilder> download) {
this.options = options;
this.download = download;
}
public MinecraftVersionMeta getVersionMeta() {
try {
if (versionEntry == null) {
versionEntry = getVersionEntry();
}
if (versionMeta == null) {
versionMeta = readVersionMeta();
}
} catch (IOException e) {
throw new UncheckedIOException(e.getMessage(), e);
}
return versionMeta;
}
private ManifestVersion.Versions getVersionEntry() throws IOException {
// Custom URL always takes priority
if (options.customManifestUrl() != null) {
ManifestVersion.Versions customVersion = new ManifestVersion.Versions();
customVersion.id = options.minecraftVersion();
customVersion.url = options.customManifestUrl();
return customVersion;
}
final List<ManifestVersionSupplier> suppliers = List.of(
// First try finding the version with caching
() -> getVersions(false),
// Then try finding the experimental version with caching
() -> getExperimentalVersions(false),
// Then force download Mojang's metadata to find the version
() -> getVersions(true),
// Finally try a force downloaded experimental metadata.
() -> getExperimentalVersions(true)
);
for (ManifestVersionSupplier supplier : suppliers) {
final ManifestVersion.Versions version = supplier.get().getVersion(options.minecraftVersion());
if (version != null) {
return version;
}
}
throw new RuntimeException("Failed to find minecraft version: " + options.minecraftVersion());
}
private ManifestVersion getVersions(boolean forceDownload) throws IOException {
return getVersions(options.versionManifestUrl(), options.versionManifestPath(), forceDownload);
}
private ManifestVersion getExperimentalVersions(boolean forceDownload) throws IOException {
return getVersions(options.experimentalVersionManifestUrl(), options.experimentalVersionManifestPath(), forceDownload);
}
private ManifestVersion getVersions(String url, Path cacheFile, boolean forceDownload) throws IOException {
DownloadBuilder builder = download.apply(url);
if (forceDownload) {
builder = builder.forceDownload();
} else {
builder = builder.defaultCache();
}
final String versionManifest = builder.downloadString(cacheFile);
return LoomGradlePlugin.OBJECT_MAPPER.readValue(versionManifest, ManifestVersion.class);
}
private MinecraftVersionMeta readVersionMeta() throws IOException {
final DownloadBuilder builder = download.apply(versionEntry.url);
if (versionEntry.sha1 != null) {
builder.sha1(versionEntry.sha1);
} else {
builder.defaultCache();
}
final String json = builder.downloadString(options.minecraftMetadataPath());
return LoomGradlePlugin.OBJECT_MAPPER.readValue(json, MinecraftVersionMeta.class);
}
public record Options(String minecraftVersion,
String versionManifestUrl,
String experimentalVersionManifestUrl,
@Nullable String customManifestUrl,
Path versionManifestPath,
Path experimentalVersionManifestPath,
Path minecraftMetadataPath) {
public static Options create(String minecraftVersion, Project project, Path minecraftMetadataPath) {
final LoomGradleExtension extension = LoomGradleExtension.get(project);
final Path userCache = extension.getFiles().getUserCache().toPath();
return new Options(
minecraftVersion,
MirrorUtil.getVersionManifests(project),
MirrorUtil.getExperimentalVersions(project),
extension.getCustomMinecraftManifest().getOrNull(),
userCache.resolve("version_manifest.json"),
userCache.resolve("experimental_version_manifest.json"),
minecraftMetadataPath
);
}
}
@FunctionalInterface
private interface ManifestVersionSupplier {
ManifestVersion get() throws IOException;
}
}

View File

@@ -25,7 +25,6 @@
package net.fabricmc.loom.configuration.providers.minecraft;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
@@ -37,25 +36,19 @@ import org.gradle.api.logging.Logger;
import org.jetbrains.annotations.Nullable;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.LoomGradlePlugin;
import net.fabricmc.loom.configuration.ConfigContext;
import net.fabricmc.loom.configuration.DependencyInfo;
import net.fabricmc.loom.configuration.providers.BundleMetadata;
import net.fabricmc.loom.util.Constants;
import net.fabricmc.loom.util.MirrorUtil;
import net.fabricmc.loom.util.download.DownloadBuilder;
import net.fabricmc.loom.util.download.DownloadExecutor;
import net.fabricmc.loom.util.download.GradleDownloadProgressListener;
import net.fabricmc.loom.util.gradle.ProgressGroup;
public abstract class MinecraftProvider {
private String minecraftVersion;
private MinecraftVersionMeta versionInfo;
private MinecraftLibraryProvider libraryProvider;
private MinecraftMetadataProvider metadataProvider;
private File workingDir;
private File minecraftJson;
private File minecraftClientJar;
// Note this will be the boostrap jar starting with 21w39a
private File minecraftServerJar;
@@ -63,8 +56,6 @@ public abstract class MinecraftProvider {
private File minecraftExtractedServerJar;
@Nullable
private BundleMetadata serverBundleMetadata;
private File versionManifestJson;
private File experimentalVersionsJson;
private final Project project;
@@ -86,11 +77,14 @@ public abstract class MinecraftProvider {
initFiles();
downloadMcJson();
try (FileReader reader = new FileReader(minecraftJson)) {
versionInfo = LoomGradlePlugin.OBJECT_MAPPER.readValue(reader, MinecraftVersionMeta.class);
}
metadataProvider = new MinecraftMetadataProvider(
MinecraftMetadataProvider.Options.create(
minecraftVersion,
getProject(),
file("minecraft-info.json").toPath()
),
getExtension()::download
);
downloadJars();
@@ -98,16 +92,13 @@ public abstract class MinecraftProvider {
serverBundleMetadata = BundleMetadata.fromJar(minecraftServerJar.toPath());
}
libraryProvider = new MinecraftLibraryProvider(this, project);
final MinecraftLibraryProvider libraryProvider = new MinecraftLibraryProvider(this, project);
libraryProvider.provide();
}
protected void initFiles() {
workingDir = new File(getExtension().getFiles().getUserCache(), minecraftVersion);
workingDir.mkdirs();
minecraftJson = file("minecraft-info.json");
versionManifestJson = new File(getExtension().getFiles().getUserCache(), "version_manifest.json");
experimentalVersionsJson = new File(getExtension().getFiles().getUserCache(), "experimental_version_manifest.json");
if (provideClient()) {
minecraftClientJar = file("minecraft-client.jar");
@@ -119,73 +110,11 @@ public abstract class MinecraftProvider {
}
}
private void downloadMcJson() throws IOException {
final String versionManifestUrl = MirrorUtil.getVersionManifests(getProject());
final String versionManifest = getExtension().download(versionManifestUrl)
.defaultCache()
.downloadString(versionManifestJson.toPath());
final ManifestVersion mcManifest = LoomGradlePlugin.OBJECT_MAPPER.readValue(versionManifest, ManifestVersion.class);
ManifestVersion.Versions version = null;
if (getExtension().getCustomMinecraftManifest().isPresent()) {
ManifestVersion.Versions customVersion = new ManifestVersion.Versions();
customVersion.id = minecraftVersion;
customVersion.url = getExtension().getCustomMinecraftManifest().get();
version = customVersion;
getProject().getLogger().lifecycle("Using custom minecraft manifest");
}
if (version == null) {
version = mcManifest.versions().stream()
.filter(versions -> versions.id.equalsIgnoreCase(minecraftVersion))
.findFirst().orElse(null);
}
if (version == null) {
version = findExperimentalVersion();
}
if (version == null) {
throw new RuntimeException("Failed to find minecraft version: " + minecraftVersion);
}
getProject().getLogger().debug("Downloading Minecraft {} manifest", minecraftVersion);
final DownloadBuilder download = getExtension().download(version.url);
if (version.sha1 != null) {
download.sha1(version.sha1);
} else {
download.defaultCache();
}
download.downloadPath(minecraftJson.toPath());
}
// This attempts to find the version from fabric's own fallback version manifest json.
private ManifestVersion.Versions findExperimentalVersion() throws IOException {
final String expVersionManifest = getExtension().download(MirrorUtil.getExperimentalVersions(getProject()))
.defaultCache()
.downloadString(experimentalVersionsJson.toPath());
final ManifestVersion expManifest = LoomGradlePlugin.OBJECT_MAPPER.readValue(expVersionManifest, ManifestVersion.class);
final ManifestVersion.Versions result = expManifest.versions().stream()
.filter(versions -> versions.id.equalsIgnoreCase(minecraftVersion))
.findFirst()
.orElse(null);
if (result != null) {
getProject().getLogger().lifecycle("Using fallback experimental version {}", minecraftVersion);
}
return result;
}
private void downloadJars() throws IOException {
try (ProgressGroup progressGroup = new ProgressGroup(getProject(), "Download Minecraft jars");
DownloadExecutor executor = new DownloadExecutor(2)) {
if (provideClient()) {
final MinecraftVersionMeta.Download client = versionInfo.download("client");
final MinecraftVersionMeta.Download client = getVersionInfo().download("client");
getExtension().download(client.url())
.sha1(client.sha1())
.progress(new GradleDownloadProgressListener("Minecraft client", progressGroup::createProgressLogger))
@@ -193,7 +122,7 @@ public abstract class MinecraftProvider {
}
if (provideServer()) {
final MinecraftVersionMeta.Download server = versionInfo.download("server");
final MinecraftVersionMeta.Download server = getVersionInfo().download("server");
getExtension().download(server.url())
.sha1(server.sha1())
.progress(new GradleDownloadProgressListener("Minecraft server", progressGroup::createProgressLogger))
@@ -256,7 +185,7 @@ public abstract class MinecraftProvider {
}
public MinecraftVersionMeta getVersionInfo() {
return versionInfo;
return Objects.requireNonNull(metadataProvider, "Metadata provider not setup").getVersionMeta();
}
@Nullable