mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-01-30 14:39:56 +08:00
parent
0c172e5d08
commit
08d7ff138b
@ -17,6 +17,7 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.game;
|
||||
|
||||
import com.jfoenix.controls.JFXButton;
|
||||
import javafx.application.Platform;
|
||||
import javafx.stage.Stage;
|
||||
import org.jackhuang.hmcl.Launcher;
|
||||
@ -35,6 +36,8 @@ import org.jackhuang.hmcl.mod.ModpackProvider;
|
||||
import org.jackhuang.hmcl.setting.*;
|
||||
import org.jackhuang.hmcl.task.*;
|
||||
import org.jackhuang.hmcl.ui.*;
|
||||
import org.jackhuang.hmcl.ui.account.ClassicAccountLoginDialog;
|
||||
import org.jackhuang.hmcl.ui.account.OAuthAccountLoginDialog;
|
||||
import org.jackhuang.hmcl.ui.construct.*;
|
||||
import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType;
|
||||
import org.jackhuang.hmcl.util.*;
|
||||
@ -62,6 +65,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
||||
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
|
||||
import static org.jackhuang.hmcl.util.Lang.resolveException;
|
||||
import static org.jackhuang.hmcl.util.Logging.LOG;
|
||||
import static org.jackhuang.hmcl.util.Pair.pair;
|
||||
@ -171,17 +175,7 @@ public final class LauncherHelper {
|
||||
.thenComposeAsync(() -> {
|
||||
return gameVersion.map(s -> new GameVerificationFixTask(dependencyManager, s, version.get())).orElse(null);
|
||||
})
|
||||
.thenComposeAsync(Task.supplyAsync(() -> {
|
||||
try {
|
||||
return account.logIn();
|
||||
} catch (CredentialExpiredException e) {
|
||||
LOG.log(Level.INFO, "Credential has expired", e);
|
||||
return DialogController.logIn(account);
|
||||
} catch (AuthenticationException e) {
|
||||
LOG.log(Level.WARNING, "Authentication failed, try playing offline", e);
|
||||
return account.playOffline().orElseThrow(() -> e);
|
||||
}
|
||||
}).withStage("launch.state.logging_in"))
|
||||
.thenComposeAsync(() -> logIn(account).withStage("launch.state.logging_in"))
|
||||
.thenComposeAsync(authInfo -> Task.supplyAsync(() -> {
|
||||
LaunchOptions launchOptions = repository.getLaunchOptions(selectedVersion, javaVersionRef.get(), profile.getGameDir(), javaAgents, scriptFile != null);
|
||||
return new HMCLGameLauncher(
|
||||
@ -618,6 +612,43 @@ public final class LauncherHelper {
|
||||
return future;
|
||||
}
|
||||
|
||||
private static Task<AuthInfo> logIn(Account account) {
|
||||
return Task.composeAsync(() -> {
|
||||
try {
|
||||
return Task.completed(account.logIn());
|
||||
} catch (CredentialExpiredException e) {
|
||||
LOG.log(Level.INFO, "Credential has expired", e);
|
||||
|
||||
return Task.completed(DialogController.logIn(account));
|
||||
} catch (AuthenticationException e) {
|
||||
LOG.log(Level.WARNING, "Authentication failed, try playing offline", e);
|
||||
|
||||
CompletableFuture<Task<AuthInfo>> future = new CompletableFuture<>();
|
||||
runInFX(() -> {
|
||||
JFXButton loginOfflineButton = new JFXButton(i18n("account.login.offline"));
|
||||
loginOfflineButton.setOnAction(event -> {
|
||||
try {
|
||||
future.complete(Task.completed(account.playOffline()));
|
||||
} catch (AuthenticationException e2) {
|
||||
future.completeExceptionally(e2);
|
||||
}
|
||||
});
|
||||
JFXButton retryButton = new JFXButton(i18n("button.retry"));
|
||||
retryButton.setOnAction(event -> {
|
||||
future.complete(logIn(account));
|
||||
});
|
||||
Controllers.dialog(new MessageDialogPane.Builder(i18n("account.failed.server_disconnected"), i18n("account.failed"), MessageType.ERROR)
|
||||
.addAction(loginOfflineButton)
|
||||
.addAction(retryButton)
|
||||
.addCancel(() ->
|
||||
future.completeExceptionally(new CancellationException()))
|
||||
.build());
|
||||
});
|
||||
return Task.fromCompletableFuture(future).thenComposeAsync(task -> task);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static Optional<String> getLog4jPatch(Version version) {
|
||||
Optional<String> log4jVersion = version.getLibraries().stream()
|
||||
.filter(it -> it.is("org.apache.logging.log4j", "log4j-core")
|
||||
|
@ -123,10 +123,11 @@ public final class MessageDialogPane extends StackPane {
|
||||
|
||||
public Builder addAction(Node actionNode) {
|
||||
dialog.addButton(actionNode);
|
||||
actionNode.getStyleClass().add("dialog-accept");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder ok(Runnable ok) {
|
||||
public Builder ok(@Nullable Runnable ok) {
|
||||
JFXButton btnOk = new JFXButton(i18n("button.ok"));
|
||||
btnOk.getStyleClass().add("dialog-accept");
|
||||
if (ok != null) {
|
||||
@ -137,7 +138,22 @@ public final class MessageDialogPane extends StackPane {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder yesOrNo(Runnable yes, Runnable no) {
|
||||
public Builder addCancel(@Nullable Runnable cancel) {
|
||||
return addCancel(i18n("button.cancel"), cancel);
|
||||
}
|
||||
|
||||
public Builder addCancel(String cancelText, @Nullable Runnable cancel) {
|
||||
JFXButton btnCancel = new JFXButton(cancelText);
|
||||
btnCancel.getStyleClass().add("dialog-cancel");
|
||||
if (cancel != null) {
|
||||
btnCancel.setOnAction(e -> cancel.run());
|
||||
}
|
||||
dialog.addButton(btnCancel);
|
||||
dialog.setCancelButton(btnCancel);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder yesOrNo(@Nullable Runnable yes, @Nullable Runnable no) {
|
||||
JFXButton btnYes = new JFXButton(i18n("button.yes"));
|
||||
btnYes.getStyleClass().add("dialog-accept");
|
||||
if (yes != null) {
|
||||
@ -145,27 +161,14 @@ public final class MessageDialogPane extends StackPane {
|
||||
}
|
||||
dialog.addButton(btnYes);
|
||||
|
||||
JFXButton btnNo = new JFXButton(i18n("button.no"));
|
||||
btnNo.getStyleClass().add("dialog-cancel");
|
||||
if (no != null) {
|
||||
btnNo.setOnAction(e -> no.run());
|
||||
}
|
||||
dialog.addButton(btnNo);
|
||||
dialog.setCancelButton(btnNo);
|
||||
addCancel(i18n("button.no"), no);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder actionOrCancel(ButtonBase actionButton, Runnable cancel) {
|
||||
dialog.addButton(actionButton);
|
||||
|
||||
JFXButton btnCancel = new JFXButton(i18n("button.cancel"));
|
||||
btnCancel.getStyleClass().add("dialog-cancel");
|
||||
if (cancel != null) {
|
||||
btnCancel.setOnAction(e -> cancel.run());
|
||||
}
|
||||
dialog.addButton(btnCancel);
|
||||
dialog.setCancelButton(btnCancel);
|
||||
|
||||
addCancel(cancel);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,8 @@ package org.jackhuang.hmcl.util;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jackhuang.hmcl.util.Logging.LOG;
|
||||
|
||||
/**
|
||||
* Utility for Adding JavaFX to module path.
|
||||
*
|
||||
@ -30,6 +32,6 @@ public final class JavaFXPatcher {
|
||||
}
|
||||
|
||||
public static void patch(Set<String> modules, Path... jarPaths) {
|
||||
// Nothing to do with Java 8
|
||||
LOG.info("No need to patch JavaFX with Java 8");
|
||||
}
|
||||
}
|
||||
|
@ -72,6 +72,7 @@ account.failed.invalid_password=Invalid password
|
||||
account.failed.invalid_token=Please try to re-login again.
|
||||
account.failed.migration=Your account needs to be migrated to a Microsoft account. If you already did, you should re-login to your migrated Microsoft account instead.
|
||||
account.failed.no_character=There are no characters linked to this account.
|
||||
account.failed.server_disconnected=Cannot access authentication server. You can log in offline or try to re-login.
|
||||
account.failed.server_response_malformed=Invalid server response, the authentication server may not be working.
|
||||
account.failed.wrong_account=You have logged in to the wrong account.
|
||||
account.hmcl.hint=You need to click on "Login" and complete the process in the opened tab in your browser.
|
||||
@ -85,6 +86,7 @@ account.injector.server_url=Server URL
|
||||
account.injector.server_name=Server Name
|
||||
account.login=Login
|
||||
account.login.hint=We will not store your password.
|
||||
account.login.offline=Login offline
|
||||
account.login.refresh=Re-login
|
||||
account.logout=Logout
|
||||
account.register=Register
|
||||
@ -169,6 +171,7 @@ button.ok=OK
|
||||
button.refresh=Refresh
|
||||
button.remove=Remove
|
||||
button.remove.confirm=Are you sure you want to permanently remove it? This action cannot be undone\!
|
||||
button.retry=Retry
|
||||
button.save=Save
|
||||
button.save_as=Save As
|
||||
button.select_all=Select All
|
||||
|
@ -70,6 +70,7 @@ account.failed.invalid_password=密碼無效
|
||||
account.failed.invalid_token=請嘗試登出並重新輸入密碼登入
|
||||
account.failed.migration=你的帳號需要被遷移至微軟帳號。如果你已經遷移,你需要使用微軟登錄方式登錄遷移後的微軟帳號。
|
||||
account.failed.no_character=該帳戶沒有角色
|
||||
account.failed.server_disconnected=無法訪問登錄伺服器。是否以離線模式繼續登錄(進入遊戲後無法進入有正版驗證的伺服器)?或嘗試重新登入?
|
||||
account.failed.server_response_malformed=無法解析認證伺服器回應,可能是伺服器故障
|
||||
account.failed.wrong_account=登錄了錯誤的帳號
|
||||
account.hmcl.hint=你需要點擊“登入”按鈕,並在打開的網頁中完成登入
|
||||
@ -83,6 +84,7 @@ account.injector.server_url=伺服器位址
|
||||
account.injector.server_name=伺服器名稱
|
||||
account.login=登入
|
||||
account.login.hint=我們不會保存你的密碼
|
||||
account.login.offline=以離線模式登錄
|
||||
account.login.refresh=重新登錄
|
||||
account.logout=登出
|
||||
account.register=註冊
|
||||
@ -157,6 +159,7 @@ button.ok=確定
|
||||
button.refresh=重新整理
|
||||
button.remove=刪除
|
||||
button.remove.confirm=您確認要刪除嗎?該操作無法撤銷!
|
||||
button.retry=重試
|
||||
button.save=儲存
|
||||
button.save_as=另存為
|
||||
button.select_all=全選
|
||||
|
@ -70,7 +70,7 @@ account.failed.invalid_password=无效的密码
|
||||
account.failed.invalid_token=请尝试登出并重新输入密码登录
|
||||
account.failed.migration=你的帐号需要被迁移至微软帐号。如果你已经迁移,你需要使用微软登录方式登录迁移后的微软帐号。
|
||||
account.failed.no_character=该帐号没有角色
|
||||
account.failed.server_disconnected=无法访问登录服务器。离线模式继续登录,或者
|
||||
account.failed.server_disconnected=无法访问登录服务器。是否以离线模式继续登录(进入游戏后无法进入有正版验证的服务器)?或尝试重新登录?
|
||||
account.failed.server_response_malformed=无法解析认证服务器响应,可能是服务器故障
|
||||
account.failed.wrong_account=登录了错误的帐号
|
||||
account.hmcl.hint=你需要点击“登录”按钮,并在打开的网页中完成登录
|
||||
@ -84,6 +84,7 @@ account.injector.server_url=服务器地址
|
||||
account.injector.server_name=服务器名称
|
||||
account.login=登录
|
||||
account.login.hint=我们不会保存你的密码
|
||||
account.login.offline=以离线模式登录
|
||||
account.login.refresh=重新登录
|
||||
account.logout=登出
|
||||
account.register=注册
|
||||
@ -158,6 +159,7 @@ button.ok=确定
|
||||
button.refresh=刷新
|
||||
button.remove=删除
|
||||
button.remove.confirm=您确定要删除吗?此操作无法撤销!
|
||||
button.retry=重试
|
||||
button.save=保存
|
||||
button.save_as=另存为
|
||||
button.select_all=全选
|
||||
|
@ -64,7 +64,7 @@ public abstract class Account implements Observable {
|
||||
* Play offline.
|
||||
* @return the specific offline player's info.
|
||||
*/
|
||||
public abstract Optional<AuthInfo> playOffline() throws AuthenticationException;
|
||||
public abstract AuthInfo playOffline() throws AuthenticationException;
|
||||
|
||||
public abstract Map<Object, Object> toStorage();
|
||||
|
||||
|
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth;
|
||||
|
||||
public class NotLoggedInException extends AuthenticationException {
|
||||
}
|
@ -17,10 +17,7 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth.authlibinjector;
|
||||
|
||||
import org.jackhuang.hmcl.auth.AuthInfo;
|
||||
import org.jackhuang.hmcl.auth.AuthenticationException;
|
||||
import org.jackhuang.hmcl.auth.CharacterSelector;
|
||||
import org.jackhuang.hmcl.auth.ServerDisconnectException;
|
||||
import org.jackhuang.hmcl.auth.*;
|
||||
import org.jackhuang.hmcl.auth.yggdrasil.CompleteGameProfile;
|
||||
import org.jackhuang.hmcl.auth.yggdrasil.TextureType;
|
||||
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
|
||||
@ -66,15 +63,15 @@ public class AuthlibInjectorAccount extends YggdrasilAccount {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<AuthInfo> playOffline() {
|
||||
Optional<AuthInfo> auth = super.playOffline();
|
||||
public AuthInfo playOffline() throws AuthenticationException {
|
||||
AuthInfo auth = super.playOffline();
|
||||
Optional<AuthlibInjectorArtifactInfo> artifact = downloader.getArtifactInfoImmediately();
|
||||
Optional<String> prefetchedMeta = server.getMetadataResponse();
|
||||
|
||||
if (auth.isPresent() && artifact.isPresent() && prefetchedMeta.isPresent()) {
|
||||
return Optional.of(new AuthlibInjectorAuthInfo(auth.get(), artifact.get(), server, prefetchedMeta.get()));
|
||||
if (artifact.isPresent() && prefetchedMeta.isPresent()) {
|
||||
return new AuthlibInjectorAuthInfo(auth, artifact.get(), server, prefetchedMeta.get());
|
||||
} else {
|
||||
return Optional.empty();
|
||||
throw new NotLoggedInException();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,8 +117,8 @@ public class MicrosoftAccount extends OAuthAccount {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<AuthInfo> playOffline() {
|
||||
return Optional.of(session.toAuthInfo());
|
||||
public AuthInfo playOffline() {
|
||||
return session.toAuthInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -180,8 +180,8 @@ public class OfflineAccount extends Account {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<AuthInfo> playOffline() throws AuthenticationException {
|
||||
return Optional.of(logIn());
|
||||
public AuthInfo playOffline() throws AuthenticationException {
|
||||
return logIn();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -161,8 +161,8 @@ public class YggdrasilAccount extends ClassicAccount {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<AuthInfo> playOffline() {
|
||||
return Optional.of(session.toAuthInfo());
|
||||
public AuthInfo playOffline() throws AuthenticationException {
|
||||
return session.toAuthInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -74,7 +74,7 @@ if (!jfxInClasspath && JavaVersion.current() >= JavaVersion.VERSION_11) {
|
||||
val classifier = platform.classifier
|
||||
rootProject.subprojects {
|
||||
for (module in jfxModules) {
|
||||
dependencies.add("compileOnly", "$groupId:javafx-$module:$version:$classifier")
|
||||
dependencies.add("implementation", "$groupId:javafx-$module:$version:$classifier")
|
||||
dependencies.add("testImplementation", "$groupId:javafx-$module:$version:$classifier")
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user