fix: downloading java runtime from mojang

This commit is contained in:
huanghongxun
2021-05-23 14:24:53 +08:00
parent f55fe0fc45
commit e8a64f52f0
6 changed files with 126 additions and 46 deletions

View File

@@ -22,12 +22,14 @@ import javafx.stage.Stage;
import org.jackhuang.hmcl.Launcher;
import org.jackhuang.hmcl.auth.*;
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorDownloadException;
import org.jackhuang.hmcl.download.DefaultCacheRepository;
import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.LibraryAnalyzer;
import org.jackhuang.hmcl.download.MaintainTask;
import org.jackhuang.hmcl.download.game.GameAssetIndexDownloadTask;
import org.jackhuang.hmcl.download.game.GameVerificationFixTask;
import org.jackhuang.hmcl.download.game.LibraryDownloadException;
import org.jackhuang.hmcl.download.java.JavaDownloadTask;
import org.jackhuang.hmcl.launch.NotDecompressingNativesException;
import org.jackhuang.hmcl.launch.PermissionException;
import org.jackhuang.hmcl.launch.ProcessCreationException;
@@ -64,6 +66,7 @@ import java.io.IOException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.RejectedExecutionException;
@@ -316,6 +319,20 @@ public final class LauncherHelper {
flag = true;
}
if (version.getJavaVersion() != null) {
if (java.getParsedVersion() < version.getJavaVersion().getMajorVersion()) {
Optional<JavaVersion> acceptableJava = JavaVersion.getJavas().stream()
.filter(javaVersion -> javaVersion.getParsedVersion() >= version.getJavaVersion().getMajorVersion())
.max(Comparator.comparing(JavaVersion::getVersionNumber));
if (acceptableJava.isPresent()) {
setting.setJavaVersion(acceptableJava.get());
} else {
downloadJava(version.getJavaVersion(), profile).thenAccept(x -> onAccept.run());
flag = true;
}
}
}
// Game later than 1.7.2 accepts Java 8.
if (!flag && java.getParsedVersion() < JavaVersion.JAVA_8 && gameVersion.compareTo(VersionNumber.asVersion("1.7.2")) > 0) {
Optional<JavaVersion> java8 = JavaVersion.getJavas().stream()
@@ -446,6 +463,36 @@ public final class LauncherHelper {
onAccept.run();
}
private static CompletableFuture<Void> downloadJava(org.jackhuang.hmcl.game.JavaVersion javaVersion, Profile profile) {
CompletableFuture<Void> future = new CompletableFuture<>();
TaskExecutorDialogPane javaDownloadingPane = new TaskExecutorDialogPane(it -> {});
TaskExecutor executor = new JavaDownloadTask(javaVersion,
DefaultCacheRepository.getInstance().getCacheDirectory().resolve("java"),
profile.getDependency().getDownloadProvider()).executor(false);
executor.addTaskListener(new TaskListener() {
@Override
public void onStop(boolean success, TaskExecutor executor) {
super.onStop(success, executor);
Platform.runLater(() -> {
if (!success) {
future.completeExceptionally(executor.getException());
} else {
future.complete(null);
}
});
}
});
javaDownloadingPane.setExecutor(executor, true);
Controllers.dialog(javaDownloadingPane);
executor.start();
return future;
}
private void checkExit() {
switch (launcherVisibility) {
case HIDE_AND_REOPEN:

View File

@@ -78,6 +78,7 @@ public class BMCLAPIDownloadProvider implements DownloadProvider {
@Override
public String injectURL(String baseURL) {
if (baseURL.contains("v1/products/java-runtime")) return baseURL;
return baseURL
.replace("https://bmclapi2.bangbang93.com", apiRoot)
.replace("https://launchermeta.mojang.com", apiRoot)

View File

@@ -36,31 +36,31 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
public class JavaDownloadTask extends Task<Void> {
private final String javaName;
private final org.jackhuang.hmcl.game.JavaVersion javaVersion;
private final Path rootDir;
private final String platform;
private String platform;
private final Task<RemoteFiles> javaDownloadsTask;
private JavaDownloads.JavaDownload download;
private final List<Task<?>> dependencies = new ArrayList<>();
public JavaDownloadTask(String javaName, String javaVersion, Path rootDir, DownloadProvider downloadProvider) throws UnsupportedPlatformException {
this.javaName = javaName;
public JavaDownloadTask(org.jackhuang.hmcl.game.JavaVersion javaVersion, Path rootDir, DownloadProvider downloadProvider) {
this.javaVersion = javaVersion;
this.rootDir = rootDir;
this.platform = getCurrentJavaPlatform().orElseThrow(UnsupportedPlatformException::new);
this.javaDownloadsTask = new GetTask(NetworkUtils.toURL(downloadProvider.injectURL(
"https://launchermeta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json")))
this.javaDownloadsTask = new GetTask(NetworkUtils.toURL(
"https://launchermeta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json"))
.thenComposeAsync(javaDownloadsJson -> {
JavaDownloads allDownloads = JsonUtils.fromNonNullJson(javaDownloadsJson, JavaDownloads.class);
if (!allDownloads.getDownloads().containsKey(platform)) throw new UnsupportedPlatformException();
Map<String, List<JavaDownloads.JavaDownload>> osDownloads = allDownloads.getDownloads().get(platform);
if (!osDownloads.containsKey(javaName)) throw new UnsupportedPlatformException();
List<JavaDownloads.JavaDownload> candidates = osDownloads.get(javaName);
if (!osDownloads.containsKey(javaVersion.getComponent())) throw new UnsupportedPlatformException();
List<JavaDownloads.JavaDownload> candidates = osDownloads.get(javaVersion.getComponent());
for (JavaDownloads.JavaDownload download : candidates) {
if (VersionNumber.VERSION_COMPARATOR.compare(download.getVersion().getName(), javaVersion) >= 0) {
if (VersionNumber.VERSION_COMPARATOR.compare(download.getVersion().getName(), Integer.toString(javaVersion.getMajorVersion())) >= 0) {
this.download = download;
return new GetTask(NetworkUtils.toURL(download.getManifest().getUrl()));
}
@@ -70,6 +70,16 @@ public class JavaDownloadTask extends Task<Void> {
.thenApplyAsync(javaDownloadJson -> JsonUtils.fromNonNullJson(javaDownloadJson, RemoteFiles.class));
}
@Override
public boolean doPreExecute() {
return true;
}
@Override
public void preExecute() throws Exception {
this.platform = getCurrentJavaPlatform().orElseThrow(UnsupportedPlatformException::new);
}
@Override
public Collection<Task<?>> getDependents() {
return Collections.singleton(javaDownloadsTask);
@@ -77,26 +87,34 @@ public class JavaDownloadTask extends Task<Void> {
@Override
public void execute() throws Exception {
Path jvmDir = rootDir.resolve(javaName).resolve(platform).resolve(javaName);
for (Map.Entry<String, RemoteFiles.RemoteFile> file : javaDownloadsTask.getResult().getFiles().entrySet()) {
Path dest = jvmDir.resolve(file.getKey());
if (file.getValue().getDownloads().containsKey("lzma")) {
DownloadInfo download = file.getValue().getDownloads().get("lzma");
File tempFile = Files.createTempFile("hmcl", "tmp").toFile();
FileDownloadTask task = new FileDownloadTask(NetworkUtils.toURL(download.getUrl()), tempFile, new FileDownloadTask.IntegrityCheck("SHA-1", download.getSha1()));
dependencies.add(task.thenRunAsync(() -> {
try {
Files.copy(new LZMAInputStream(new FileInputStream(tempFile)), dest);
} catch (IOException e) {
throw new ArtifactMalformedException("File " + file.getKey() + " is malformed");
}
}));
} else if (file.getValue().getDownloads().containsKey("raw")) {
DownloadInfo download = file.getValue().getDownloads().get("raw");
FileDownloadTask task = new FileDownloadTask(NetworkUtils.toURL(download.getUrl()), dest.toFile(), new FileDownloadTask.IntegrityCheck("SHA-1", download.getSha1()));
dependencies.add(task);
} else {
throw new UnsupportedOperationException();
Path jvmDir = rootDir.resolve(javaVersion.getComponent()).resolve(platform).resolve(javaVersion.getComponent());
for (Map.Entry<String, RemoteFiles.Remote> entry : javaDownloadsTask.getResult().getFiles().entrySet()) {
Path dest = jvmDir.resolve(entry.getKey());
if (entry.getValue() instanceof RemoteFiles.RemoteFile) {
RemoteFiles.RemoteFile file = ((RemoteFiles.RemoteFile) entry.getValue());
if (file.getDownloads().containsKey("lzma")) {
DownloadInfo download = file.getDownloads().get("lzma");
File tempFile = Files.createTempFile("hmcl", "tmp").toFile();
FileDownloadTask task = new FileDownloadTask(NetworkUtils.toURL(download.getUrl()), tempFile, new FileDownloadTask.IntegrityCheck("SHA-1", download.getSha1()));
dependencies.add(task.thenRunAsync(() -> {
try {
Files.copy(new LZMAInputStream(new FileInputStream(tempFile)), dest);
} catch (IOException e) {
throw new ArtifactMalformedException("File " + entry.getKey() + " is malformed");
}
}));
} else if (file.getDownloads().containsKey("raw")) {
DownloadInfo download = file.getDownloads().get("raw");
FileDownloadTask task = new FileDownloadTask(NetworkUtils.toURL(download.getUrl()), dest.toFile(), new FileDownloadTask.IntegrityCheck("SHA-1", download.getSha1()));
dependencies.add(task);
} else {
continue;
}
} else if (entry.getValue() instanceof RemoteFiles.RemoteDirectory) {
Files.createDirectories(dest);
} else if (entry.getValue() instanceof RemoteFiles.RemoteLink) {
RemoteFiles.RemoteLink link = ((RemoteFiles.RemoteLink) entry.getValue());
Files.createSymbolicLink(dest, Paths.get(link.getTarget()));
}
}
}
@@ -113,10 +131,14 @@ public class JavaDownloadTask extends Task<Void> {
@Override
public void postExecute() throws Exception {
FileUtils.writeText(rootDir.resolve(javaName).resolve(platform).resolve(".version").toFile(), download.getVersion().getName());
FileUtils.writeText(rootDir.resolve(javaName).resolve(platform).resolve(javaName + ".sha1").toFile(),
FileUtils.writeText(rootDir.resolve(javaVersion.getComponent()).resolve(platform).resolve(".version").toFile(), download.getVersion().getName());
FileUtils.writeText(rootDir.resolve(javaVersion.getComponent()).resolve(platform).resolve(javaVersion.getComponent() + ".sha1").toFile(),
javaDownloadsTask.getResult().getFiles().entrySet().stream()
.map(entry -> entry.getKey() + " /#// " + entry.getValue().getDownloads().get("raw").getSha1() + " " + entry.getValue().getDownloads().get("raw").getSize())
.filter(entry -> entry.getValue() instanceof RemoteFiles.RemoteFile)
.map(entry -> {
RemoteFiles.RemoteFile file = (RemoteFiles.RemoteFile) entry.getValue();
return entry.getKey() + " /#// " + file.getDownloads().get("raw").getSha1() + " " + file.getDownloads().get("raw").getSize();
})
.collect(Collectors.joining(OperatingSystem.LINE_SEPARATOR)));
}

View File

@@ -21,16 +21,17 @@ import org.jackhuang.hmcl.game.DownloadInfo;
import org.jackhuang.hmcl.util.gson.JsonSubtype;
import org.jackhuang.hmcl.util.gson.JsonType;
import java.util.Collections;
import java.util.Map;
public class RemoteFiles {
private final Map<String, RemoteFile> files;
private final Map<String, Remote> files;
public RemoteFiles(Map<String, RemoteFile> files) {
public RemoteFiles(Map<String, Remote> files) {
this.files = files;
}
public Map<String, RemoteFile> getFiles() {
public Map<String, Remote> getFiles() {
return files;
}
@@ -69,7 +70,7 @@ public class RemoteFiles {
}
public Map<String, DownloadInfo> getDownloads() {
return downloads;
return downloads == null ? Collections.emptyMap() : downloads;
}
}

View File

@@ -59,6 +59,7 @@ public class Version implements Comparable<Version>, Validation {
private final AssetIndexInfo assetIndex;
private final String assets;
private final Integer complianceLevel;
@Nullable
private final JavaVersion javaVersion;
private final List<Library> libraries;
private final List<CompatibilityRule> compatibilityRules;
@@ -80,9 +81,10 @@ public class Version implements Comparable<Version>, Validation {
/**
* Constructor for patch
* @param id patch id
* @param version patch version
* @param priority patch priority
*
* @param id patch id
* @param version patch version
* @param priority patch priority
* @param arguments patch additional arguments
* @param mainClass main class to override
* @param libraries additional libraries
@@ -172,11 +174,21 @@ public class Version implements Comparable<Version>, Validation {
return minimumLauncherVersion == null ? 0 : minimumLauncherVersion;
}
public Integer getComplianceLevel() {
return complianceLevel;
}
public JavaVersion getJavaVersion() {
return javaVersion;
}
public boolean isHidden() {
return hidden == null ? false : hidden;
}
public boolean isRoot() { return root == null ? false : root; }
public boolean isRoot() {
return root == null ? false : root;
}
public boolean isResolved() {
return resolved;
@@ -391,7 +403,7 @@ public class Version implements Comparable<Version>, Validation {
}
public Version clearPatches() {
return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, complianceLevel, javaVersion, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, root,null);
return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, complianceLevel, javaVersion, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, root, null);
}
public Version removePatchById(String patchId) {

View File

@@ -127,10 +127,7 @@ public enum Architecture {
}
static {
String arch = System.getProperty("sun.arch.data.model");
if (arch == null)
arch = System.getProperty("os.arch");
SYSTEM_ARCHITECTURE = arch;
SYSTEM_ARCHITECTURE = System.getProperty("os.arch");
CURRENT = normalizeArch(SYSTEM_ARCHITECTURE);
}