From e8a64f52f0ace114f2522474cef752fb43fd07a2 Mon Sep 17 00:00:00 2001 From: huanghongxun Date: Sun, 23 May 2021 14:24:53 +0800 Subject: [PATCH] fix: downloading java runtime from mojang --- .../jackhuang/hmcl/game/LauncherHelper.java | 47 ++++++++++ .../download/BMCLAPIDownloadProvider.java | 1 + .../hmcl/download/java/JavaDownloadTask.java | 88 ++++++++++++------- .../hmcl/download/java/RemoteFiles.java | 9 +- .../java/org/jackhuang/hmcl/game/Version.java | 22 +++-- .../hmcl/util/platform/Architecture.java | 5 +- 6 files changed, 126 insertions(+), 46 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java index 2c123f232..76c2e939f 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java @@ -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 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 java8 = JavaVersion.getJavas().stream() @@ -446,6 +463,36 @@ public final class LauncherHelper { onAccept.run(); } + private static CompletableFuture downloadJava(org.jackhuang.hmcl.game.JavaVersion javaVersion, Profile profile) { + CompletableFuture 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: diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/BMCLAPIDownloadProvider.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/BMCLAPIDownloadProvider.java index e92023fa8..fc07a01fe 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/BMCLAPIDownloadProvider.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/BMCLAPIDownloadProvider.java @@ -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) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/JavaDownloadTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/JavaDownloadTask.java index 7b2dbdbb9..8528fca62 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/JavaDownloadTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/JavaDownloadTask.java @@ -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 { - 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 javaDownloadsTask; private JavaDownloads.JavaDownload download; private final List> 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> osDownloads = allDownloads.getDownloads().get(platform); - if (!osDownloads.containsKey(javaName)) throw new UnsupportedPlatformException(); - List candidates = osDownloads.get(javaName); + if (!osDownloads.containsKey(javaVersion.getComponent())) throw new UnsupportedPlatformException(); + List 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 { .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> getDependents() { return Collections.singleton(javaDownloadsTask); @@ -77,26 +87,34 @@ public class JavaDownloadTask extends Task { @Override public void execute() throws Exception { - Path jvmDir = rootDir.resolve(javaName).resolve(platform).resolve(javaName); - for (Map.Entry 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 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 { @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))); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/RemoteFiles.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/RemoteFiles.java index 45a4d2d3b..d880863ca 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/RemoteFiles.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/RemoteFiles.java @@ -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 files; + private final Map files; - public RemoteFiles(Map files) { + public RemoteFiles(Map files) { this.files = files; } - public Map getFiles() { + public Map getFiles() { return files; } @@ -69,7 +70,7 @@ public class RemoteFiles { } public Map getDownloads() { - return downloads; + return downloads == null ? Collections.emptyMap() : downloads; } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Version.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Version.java index ff485e59e..e10ad11b2 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Version.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/game/Version.java @@ -59,6 +59,7 @@ public class Version implements Comparable, Validation { private final AssetIndexInfo assetIndex; private final String assets; private final Integer complianceLevel; + @Nullable private final JavaVersion javaVersion; private final List libraries; private final List compatibilityRules; @@ -80,9 +81,10 @@ public class Version implements Comparable, 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, 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, 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) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/Architecture.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/Architecture.java index 597303965..5a3098a98 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/Architecture.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/Architecture.java @@ -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); }