mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-04-12 18:30:26 +08:00
feat(java): download java 8/16 when auto selected java not found.
This commit is contained in:
parent
71c23df971
commit
a4f22671c6
@ -17,13 +17,13 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import com.jfoenix.controls.JFXButton;
|
||||
import javafx.application.Platform;
|
||||
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.DefaultDependencyManager;
|
||||
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||
import org.jackhuang.hmcl.download.MaintainTask;
|
||||
import org.jackhuang.hmcl.download.game.GameAssetIndexDownloadTask;
|
||||
import org.jackhuang.hmcl.download.game.GameVerificationFixTask;
|
||||
@ -38,16 +38,14 @@ import org.jackhuang.hmcl.mod.mcbbs.McbbsModpackCompletionTask;
|
||||
import org.jackhuang.hmcl.mod.mcbbs.McbbsModpackLocalInstallTask;
|
||||
import org.jackhuang.hmcl.mod.server.ServerModpackCompletionTask;
|
||||
import org.jackhuang.hmcl.mod.server.ServerModpackLocalInstallTask;
|
||||
import org.jackhuang.hmcl.setting.DownloadProviders;
|
||||
import org.jackhuang.hmcl.setting.LauncherVisibility;
|
||||
import org.jackhuang.hmcl.setting.Profile;
|
||||
import org.jackhuang.hmcl.setting.VersionSetting;
|
||||
import org.jackhuang.hmcl.task.*;
|
||||
import org.jackhuang.hmcl.ui.*;
|
||||
import org.jackhuang.hmcl.ui.construct.DialogCloseEvent;
|
||||
import org.jackhuang.hmcl.ui.construct.MessageDialogPane;
|
||||
import org.jackhuang.hmcl.ui.construct.*;
|
||||
import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType;
|
||||
import org.jackhuang.hmcl.ui.construct.PromptDialogPane;
|
||||
import org.jackhuang.hmcl.ui.construct.TaskExecutorDialogPane;
|
||||
import org.jackhuang.hmcl.util.*;
|
||||
import org.jackhuang.hmcl.util.i18n.I18n;
|
||||
import org.jackhuang.hmcl.util.io.ResponseCodeException;
|
||||
@ -337,9 +335,28 @@ public final class LauncherHelper {
|
||||
Runnable continueAction = () -> future.complete(JavaVersion.fromCurrentEnvironment());
|
||||
|
||||
if (setting.isJavaAutoSelected()) {
|
||||
// JavaVersionConstraint.VersionRange range = JavaVersionConstraint.findSuitableJavaVersionRange(gameVersion, version);
|
||||
// TODO: download java 16 if necessary!
|
||||
Controllers.dialog(i18n("launch.failed.no_accepted_java"), i18n("message.warning"), MessageType.WARNING, continueAction);
|
||||
JavaVersionConstraint.VersionRanges range = JavaVersionConstraint.findSuitableJavaVersionRange(gameVersion, version);
|
||||
GameJavaVersion targetJavaVersion;
|
||||
|
||||
if (range.getMandatory().contains(VersionNumber.asVersion("16"))) {
|
||||
targetJavaVersion = GameJavaVersion.JAVA_16;
|
||||
} else if (range.getMandatory().contains(VersionNumber.asVersion("1.8.0_51"))) {
|
||||
targetJavaVersion = GameJavaVersion.JAVA_8;
|
||||
} else {
|
||||
targetJavaVersion = null;
|
||||
}
|
||||
|
||||
if (targetJavaVersion != null) {
|
||||
downloadJava(gameVersion.toString(), targetJavaVersion, profile)
|
||||
.thenAcceptAsync(downloadedJavaVersion -> {
|
||||
future.complete(downloadedJavaVersion);
|
||||
})
|
||||
.exceptionally(throwable -> {
|
||||
LOG.log(Level.WARNING, "Failed to download java", throwable);
|
||||
Controllers.dialog(i18n("launch.failed.no_accepted_java"), i18n("message.warning"), MessageType.WARNING, continueAction);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
Controllers.dialog(i18n("launch.wrong_javadir"), i18n("message.warning"), MessageType.WARNING, continueAction);
|
||||
|
||||
@ -391,47 +408,15 @@ public final class LauncherHelper {
|
||||
} else {
|
||||
switch (violatedMandatoryConstraint) {
|
||||
case GAME_JSON:
|
||||
MessageDialogPane dialog = new MessageDialogPane(
|
||||
i18n("launch.advice.require_newer_java_version",
|
||||
gameVersion.toString(),
|
||||
version.getJavaVersion().getMajorVersion()),
|
||||
i18n("message.warning"),
|
||||
MessageType.QUESTION);
|
||||
|
||||
JFXButton linkButton = new JFXButton(i18n("download.external_link"));
|
||||
linkButton.setOnAction(e -> FXUtils.openLink("https://adoptium.net/?variant=openjdk17"));
|
||||
linkButton.getStyleClass().add("dialog-accept");
|
||||
dialog.addButton(linkButton);
|
||||
|
||||
JFXButton yesButton = new JFXButton(i18n("button.ok"));
|
||||
yesButton.setOnAction(event -> {
|
||||
downloadJava(version.getJavaVersion(), profile)
|
||||
.thenAcceptAsync(x -> {
|
||||
try {
|
||||
Optional<JavaVersion> newAcceptableJava = JavaVersion.getJavas().stream()
|
||||
.filter(newJava -> newJava.getParsedVersion() >= version.getJavaVersion().getMajorVersion())
|
||||
.max(Comparator.comparing(JavaVersion::getVersionNumber));
|
||||
if (newAcceptableJava.isPresent()) {
|
||||
setting.setJavaVersion(newAcceptableJava.get());
|
||||
future.complete(newAcceptableJava.get());
|
||||
return;
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
LOG.log(Level.SEVERE, "Cannot list javas", e);
|
||||
}
|
||||
future.complete(javaVersion);
|
||||
}, Platform::runLater)
|
||||
.exceptionally(Lang.handleUncaught);
|
||||
});
|
||||
yesButton.getStyleClass().add("dialog-accept");
|
||||
dialog.addButton(yesButton);
|
||||
|
||||
JFXButton noButton = new JFXButton(i18n("button.cancel"));
|
||||
noButton.getStyleClass().add("dialog-cancel");
|
||||
dialog.addButton(noButton);
|
||||
dialog.setCancelButton(noButton);
|
||||
|
||||
Controllers.dialog(dialog);
|
||||
downloadJava(gameVersion.toString(), version.getJavaVersion(), profile)
|
||||
.thenAcceptAsync(downloadedJavaVersion -> {
|
||||
setting.setJavaVersion(downloadedJavaVersion);
|
||||
future.complete(downloadedJavaVersion);
|
||||
})
|
||||
.exceptionally(throwable -> {
|
||||
LOG.log(Level.WARNING, "Failed to download java", throwable);
|
||||
return null;
|
||||
});
|
||||
return Task.fromCompletableFuture(future);
|
||||
case VANILLA_JAVA_16:
|
||||
Controllers.confirm(i18n("launch.advice.require_newer_java_version", gameVersion.toString(), 16), i18n("message.warning"), () -> {
|
||||
@ -539,33 +524,64 @@ public final class LauncherHelper {
|
||||
}).withStage("launch.state.java");
|
||||
}
|
||||
|
||||
private static CompletableFuture<Void> downloadJava(GameJavaVersion javaVersion, Profile profile) {
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
private static CompletableFuture<JavaVersion> downloadJava(String gameVersion, GameJavaVersion javaVersion, Profile profile) {
|
||||
CompletableFuture<JavaVersion> future = new CompletableFuture<>();
|
||||
|
||||
JFXHyperlink link = new JFXHyperlink(i18n("download.external_link"));
|
||||
link.setOnAction(e -> FXUtils.openLink("https://adoptium.net/?variant=openjdk17"));
|
||||
|
||||
Controllers.dialog(new MessageDialogPane.Builder(
|
||||
i18n("launch.advice.require_newer_java_version",
|
||||
gameVersion,
|
||||
javaVersion.getMajorVersion()),
|
||||
i18n("message.warning"),
|
||||
MessageType.QUESTION)
|
||||
.addAction(link)
|
||||
.yesOrNo(() -> {
|
||||
downloadJavaImpl(javaVersion, profile.getDependency().getDownloadProvider())
|
||||
.thenAcceptAsync(downloadedJava -> {
|
||||
future.complete(downloadedJava);
|
||||
})
|
||||
.exceptionally(throwable -> {
|
||||
LOG.log(Level.WARNING, "Failed to download java", throwable);
|
||||
Controllers.dialog(DownloadProviders.localizeErrorMessage(throwable), i18n("download.failed"));
|
||||
future.completeExceptionally(new CancellationException());
|
||||
return null;
|
||||
});
|
||||
}, () -> {
|
||||
future.completeExceptionally(new CancellationException());
|
||||
}).build());
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly start java downloading.
|
||||
*
|
||||
* @param javaVersion target Java version
|
||||
* @param downloadProvider download provider
|
||||
* @return JavaVersion, null if we failed to download java, failed if an error occurred when downloading.
|
||||
*/
|
||||
private static CompletableFuture<JavaVersion> downloadJavaImpl(GameJavaVersion javaVersion, DownloadProvider downloadProvider) {
|
||||
CompletableFuture<JavaVersion> future = new CompletableFuture<>();
|
||||
|
||||
TaskExecutorDialogPane javaDownloadingPane = new TaskExecutorDialogPane(it -> {
|
||||
});
|
||||
|
||||
TaskExecutor executor = JavaRepository.downloadJava(javaVersion,
|
||||
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(Optional.ofNullable(executor.getException()).orElseGet(InterruptedException::new));
|
||||
TaskExecutor executor = JavaRepository.downloadJava(javaVersion, downloadProvider)
|
||||
.whenComplete(Schedulers.javafx(), (downloadedJava, exception) -> {
|
||||
if (exception != null) {
|
||||
future.completeExceptionally(exception);
|
||||
} else {
|
||||
future.complete(null);
|
||||
future.complete(downloadedJava);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
})
|
||||
.executor(false);
|
||||
|
||||
javaDownloadingPane.setExecutor(executor, true);
|
||||
Controllers.dialog(javaDownloadingPane);
|
||||
executor.start();
|
||||
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
|
@ -137,7 +137,7 @@ public final class DownloadProviders {
|
||||
return config().isAutoChooseDownloadType() ? currentDownloadProvider : fileDownloadProvider;
|
||||
}
|
||||
|
||||
public static String localizeErrorMessage(Exception exception) {
|
||||
public static String localizeErrorMessage(Throwable exception) {
|
||||
if (exception instanceof DownloadException) {
|
||||
URL url = ((DownloadException) exception).getUrl();
|
||||
if (exception.getCause() instanceof SocketTimeoutException) {
|
||||
@ -153,9 +153,13 @@ public final class DownloadProviders {
|
||||
return i18n("download.code.404", url);
|
||||
} else if (exception.getCause() instanceof AccessDeniedException) {
|
||||
return i18n("install.failed.downloading.detail", url) + "\n" + i18n("exception.access_denied", ((AccessDeniedException) exception.getCause()).getFile());
|
||||
} else if (exception.getCause() instanceof ArtifactMalformedException) {
|
||||
return i18n("install.failed.downloading.detail", url) + "\n" + i18n("exception.artifact_malformed");
|
||||
} else {
|
||||
return i18n("install.failed.downloading.detail", url) + "\n" + StringUtils.getStackTrace(exception.getCause());
|
||||
}
|
||||
} else if (exception instanceof ArtifactMalformedException) {
|
||||
return i18n("exception.artifact_malformed");
|
||||
}
|
||||
return StringUtils.getStackTrace(exception);
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ package org.jackhuang.hmcl.ui.construct;
|
||||
import com.jfoenix.controls.JFXButton;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.ButtonBase;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.HBox;
|
||||
@ -99,7 +100,7 @@ public final class MessageDialogPane extends StackPane {
|
||||
});
|
||||
}
|
||||
|
||||
public void addButton(ButtonBase btn) {
|
||||
public void addButton(Node btn) {
|
||||
btn.addEventHandler(ActionEvent.ACTION, e -> fireEvent(new DialogCloseEvent()));
|
||||
actions.getChildren().add(btn);
|
||||
}
|
||||
@ -119,6 +120,11 @@ public final class MessageDialogPane extends StackPane {
|
||||
this.dialog = new MessageDialogPane(text, title, type);
|
||||
}
|
||||
|
||||
public Builder addAction(Node actionNode) {
|
||||
dialog.addButton(actionNode);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder ok(Runnable ok) {
|
||||
JFXButton btnOk = new JFXButton(i18n("button.ok"));
|
||||
btnOk.getStyleClass().add("dialog-accept");
|
||||
|
@ -292,6 +292,7 @@ download.javafx.prepare=Ready to download
|
||||
exception.access_denied=It's denied by operating system to access file %s. Maybe we don't have permission to access this file, or this file has already been opened by other program.\n\
|
||||
Please check if current operating system user has permission to access that file.\n\
|
||||
For Windows users, you can also try the Resource Monitor, find if some programs is holding the file, try to close related program, or restart your computer.
|
||||
exception.artifact_malformed=The file cannot pass verification.
|
||||
|
||||
extension.bat=Windows Bat file
|
||||
extension.mod=Mod file
|
||||
|
@ -292,6 +292,7 @@ download.javafx.prepare=準備開始下載
|
||||
exception.access_denied=因為無法訪問文件 %s,HMCL 沒有對該文件的訪問權限,或者該文件被其他程序打開。\n\
|
||||
請你檢查當前操作系統帳戶是否能訪問該文件,比如非管理員用戶可能不能訪問其他帳戶的個人文件夾內的文件。\n\
|
||||
對於 Windows 用戶,你還可以嘗試通過資源監視器查看是否有程序占用了該文件,如果是,你可以關閉占用此文件相關程序,或者重啟電腦再試。
|
||||
exception.artifact_malformed=下載的文件正確,無法通過校驗。
|
||||
|
||||
extension.bat=Windows 指令碼
|
||||
extension.mod=模組檔案
|
||||
|
@ -292,6 +292,7 @@ download.javafx.prepare=准备开始下载
|
||||
exception.access_denied=因为无法访问文件 %s,HMCL 没有对该文件的访问权限,或者该文件被其他程序打开。\n\
|
||||
请你检查当前操作系统帐户是否能访问该文件,比如非管理员用户可能不能访问其他帐户的个人文件夹内的文件。\n\
|
||||
对于 Windows 用户,你还可以尝试通过资源监视器查看是否有程序占用了该文件,如果是,你可以关闭占用此文件相关程序,或者重启电脑再试。
|
||||
exception.artifact_malformed=下载的文件正确,无法通过校验。
|
||||
|
||||
extension.bat=Windows 脚本
|
||||
extension.mod=模组文件
|
||||
|
@ -101,7 +101,7 @@ public class JavaDownloadTask extends Task<Void> {
|
||||
try (LZMAInputStream input = new LZMAInputStream(new FileInputStream(tempFile))) {
|
||||
Files.copy(input, dest);
|
||||
} catch (IOException e) {
|
||||
throw new ArtifactMalformedException("File " + entry.getKey() + " is malformed");
|
||||
throw new ArtifactMalformedException("File " + entry.getKey() + " is malformed", e);
|
||||
}
|
||||
}));
|
||||
} else if (file.getDownloads().containsKey("raw")) {
|
||||
|
@ -21,23 +21,25 @@ public final class JavaRepository {
|
||||
private JavaRepository() {
|
||||
}
|
||||
|
||||
public static Task<?> downloadJava(GameJavaVersion javaVersion, DownloadProvider downloadProvider) {
|
||||
public static Task<JavaVersion> downloadJava(GameJavaVersion javaVersion, DownloadProvider downloadProvider) {
|
||||
return new JavaDownloadTask(javaVersion, getJavaStoragePath(), downloadProvider)
|
||||
.thenRunAsync(() -> {
|
||||
Optional<String> platform = getSystemJavaPlatform();
|
||||
if (platform.isPresent()) {
|
||||
addJava(getJavaHome(javaVersion, platform.get()));
|
||||
}
|
||||
.thenSupplyAsync(() -> {
|
||||
String platform = getSystemJavaPlatform().orElseThrow(JavaDownloadTask.UnsupportedPlatformException::new);
|
||||
return addJava(getJavaHome(javaVersion, platform));
|
||||
});
|
||||
}
|
||||
|
||||
public static void addJava(Path javaHome) throws InterruptedException, IOException {
|
||||
public static JavaVersion addJava(Path javaHome) throws InterruptedException, IOException {
|
||||
if (Files.isDirectory(javaHome)) {
|
||||
Path executable = JavaVersion.getExecutable(javaHome);
|
||||
if (Files.isRegularFile(executable)) {
|
||||
JavaVersion.getJavas().add(JavaVersion.fromExecutable(executable));
|
||||
JavaVersion javaVersion = JavaVersion.fromExecutable(executable);
|
||||
JavaVersion.getJavas().add(javaVersion);
|
||||
return javaVersion;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IOException("Incorrect java home " + javaHome);
|
||||
}
|
||||
|
||||
public static void initialize() throws IOException, InterruptedException {
|
||||
|
@ -37,4 +37,7 @@ public class GameJavaVersion {
|
||||
public int getMajorVersion() {
|
||||
return majorVersion;
|
||||
}
|
||||
|
||||
public static final GameJavaVersion JAVA_16 = new GameJavaVersion("java-runtime-alpha", 16);
|
||||
public static final GameJavaVersion JAVA_8 = new GameJavaVersion("jre-legacy", 8);
|
||||
}
|
||||
|
@ -17,9 +17,9 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.util.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.jackhuang.hmcl.download.ArtifactMalformedException;
|
||||
|
||||
public class ChecksumMismatchException extends IOException {
|
||||
public class ChecksumMismatchException extends ArtifactMalformedException {
|
||||
|
||||
private final String algorithm;
|
||||
private final String expectedChecksum;
|
||||
|
@ -25,6 +25,8 @@ import java.util.*;
|
||||
/**
|
||||
* Copied from org.apache.maven.artifact.versioning.ComparableVersion
|
||||
* Apache License 2.0
|
||||
*
|
||||
* Maybe we can migrate to org.jenkins-ci:version-number:1.7?
|
||||
* @see <a href="http://maven.apache.org/pom.html#Version_Order_Specification">Specification</a>
|
||||
*/
|
||||
public class VersionNumber implements Comparable<VersionNumber> {
|
||||
|
Loading…
x
Reference in New Issue
Block a user