diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/MultiplayerManager.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/MultiplayerManager.java index 786de8c34..86d9539bb 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/MultiplayerManager.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/MultiplayerManager.java @@ -18,6 +18,7 @@ package org.jackhuang.hmcl.ui.multiplayer; import com.google.gson.JsonParseException; +import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanBinding; import org.jackhuang.hmcl.Metadata; @@ -26,9 +27,9 @@ import org.jackhuang.hmcl.event.EventManager; import org.jackhuang.hmcl.setting.ConfigHolder; import org.jackhuang.hmcl.task.FileDownloadTask; import org.jackhuang.hmcl.task.Task; +import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.util.*; -import org.jackhuang.hmcl.util.gson.DateTypeAdapter; import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.HttpRequest; @@ -44,6 +45,9 @@ import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; import java.nio.file.*; import java.nio.file.attribute.PosixFilePermission; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -54,6 +58,7 @@ import static org.jackhuang.hmcl.setting.ConfigHolder.globalConfig; import static org.jackhuang.hmcl.util.Lang.*; import static org.jackhuang.hmcl.util.Logging.LOG; import static org.jackhuang.hmcl.util.Pair.pair; +import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.io.ChecksumMismatchException.verifyChecksum; /** @@ -105,9 +110,14 @@ public final class MultiplayerManager { static final boolean IS_ADMINISTRATOR; static final BooleanBinding tokenInvalid = Bindings.createBooleanBinding( - () -> !StringUtils.isAlphabeticOrNumber(globalConfig().multiplayerTokenProperty().getValue()), + () -> { + String token = globalConfig().multiplayerTokenProperty().getValue(); + return token == null || token.isEmpty() || !StringUtils.isAlphabeticOrNumber(token); + }, globalConfig().multiplayerTokenProperty()); + private static final DateFormat HIPER_VALID_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + static { boolean isAdministrator = false; if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) { @@ -220,11 +230,8 @@ public final class MultiplayerManager { } public static CompletableFuture startHiper(String token) { - return getPackagesHash().thenApplyAsync(wrap(packagesHash -> { - if (!Files.isRegularFile(HIPER_PATH)) { - throw new HiperNotExistsException(HIPER_PATH); - } - + return getPackagesHash().thenComposeAsync(packagesHash -> { + CompletableFuture future = new CompletableFuture<>(); try { if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) { verifyChecksum(getHiperLocalDirectory().resolve("hiper.exe"), "SHA-1", packagesHash.get(String.format("%s/hiper.exe", HIPER_TARGET_NAME))); @@ -235,12 +242,20 @@ public final class MultiplayerManager { } else { verifyChecksum(getHiperLocalDirectory().resolve("hiper"), "SHA-1", packagesHash.get(String.format("%s/hiper", HIPER_TARGET_NAME))); } - } catch (IOException e) { - // force redownload - Files.deleteIfExists(HIPER_PATH); - throw e; - } + future.complete(null); + } catch (IOException e) { + LOG.log(Level.WARNING, "Failed to verify HiPer files", e); + Platform.runLater(() -> Controllers.taskDialog(MultiplayerManager.downloadHiper() + .whenComplete(exception -> { + if (exception == null) + future.complete(null); + else + future.completeExceptionally(exception); + }), i18n("multiplayer.download"), TaskCancellationAction.NORMAL)); + } + return future; + }).thenApplyAsync(wrap(ignored -> { Path configPath = getConfigPath(token); Files.createDirectories(configPath.getParent()); @@ -361,9 +376,11 @@ public final class MultiplayerManager { Optional validUntil = tryCast(logJson.get("valid"), String.class); if (validUntil.isPresent()) { try { - Date date = DateTypeAdapter.deserializeToDate(validUntil.get()); - onValidUntil.fireEvent(new HiperShowValidUntilEvent(this, date)); - } catch (JsonParseException e) { + synchronized (HIPER_VALID_TIME_FORMAT) { + Date date = HIPER_VALID_TIME_FORMAT.parse(validUntil.get()); + onValidUntil.fireEvent(new HiperShowValidUntilEvent(this, date)); + } + } catch (JsonParseException | ParseException e) { LOG.log(Level.WARNING, "Failed to parse certification expire time string: " + validUntil.get()); } } @@ -527,18 +544,6 @@ public final class MultiplayerManager { } } - public static class HiperNotExistsException extends RuntimeException { - private final Path file; - - public HiperNotExistsException(Path file) { - this.file = file; - } - - public Path getFile() { - return file; - } - } - public static class HiperInvalidTokenException extends RuntimeException { } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/MultiplayerPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/MultiplayerPage.java index b26ab6905..3cc29f8ce 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/MultiplayerPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/MultiplayerPage.java @@ -217,11 +217,8 @@ public class MultiplayerPage extends DecoratorAnimatedPage implements DecoratorP } else if (e instanceof MultiplayerManager.HiperInvalidConfigurationException) { LOG.warning("HiPer invalid configuration"); return i18n("multiplayer.token.malformed"); - } else if (e instanceof MultiplayerManager.HiperNotExistsException) { - LOG.log(Level.WARNING, "Hiper not found " + ((MultiplayerManager.HiperNotExistsException) e).getFile(), e); - return i18n("multiplayer.error.file_not_found"); } else if (e instanceof ChecksumMismatchException) { - LOG.log(Level.WARNING, "HiPer files are not verified", e); + LOG.log(Level.WARNING, "Failed to verify HiPer files", e); return i18n("multiplayer.error.file_not_found"); } else if (e instanceof MultiplayerManager.HiperExitException) { int exitCode = ((MultiplayerManager.HiperExitException) e).getExitCode(); @@ -284,6 +281,7 @@ public class MultiplayerPage extends DecoratorAnimatedPage implements DecoratorP private void clearSession() { this.session.set(null); + this.expireTime.set(null); this.onExit = null; this.onIPAllocated = null; this.onValidUntil = null; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/MultiplayerPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/MultiplayerPageSkin.java index 42b4b0ef8..3110bceba 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/MultiplayerPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/MultiplayerPageSkin.java @@ -184,7 +184,7 @@ public class MultiplayerPageSkin extends DecoratorAnimatedPage.DecoratorAnimated expirationLabel.textProperty().bind(Bindings.createStringBinding(() -> control.getExpireTime() == null ? "" : Locales.SIMPLE_DATE_FORMAT.get().format(control.getExpireTime()), control.expireTimeProperty())); - expirationPane.setCenter(expirationLabel); + expirationPane.setRight(expirationLabel); GridPane masterPane = new GridPane(); masterPane.setVgap(8); diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index b8a165631..ba76c4730 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -907,7 +907,7 @@ multiplayer.slave.server_address=Creator server address multiplayer.slave.server_address.start=Join multiplayer.slave.server_address.stop=Exit multiplayer.slave.video_tutorial=Video Tutorial -multiplayer.session.expiration=Expire Time +multiplayer.session.expiration=Token Expiration Time datapack=Datapacks datapack.add=Install datapack diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index 1ce6e3684..0359ab49a 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -752,7 +752,7 @@ multiplayer.slave.server_address=創建方伺服器地址 multiplayer.slave.server_address.start=加入 multiplayer.slave.server_address.stop=退出 multiplayer.slave.video_tutorial=教學影片 -multiplayer.session.expiration=本次使用截止時間 +multiplayer.session.expiration=索引碼到期時間 datapack=資料包 datapack.add=加入資料包 diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index 90cec9ba7..21bc3e796 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -752,7 +752,7 @@ multiplayer.slave.server_address=创建方服务器地址 multiplayer.slave.server_address.start=加入 multiplayer.slave.server_address.stop=退出 multiplayer.slave.video_tutorial=参与者视频教程 -multiplayer.session.expiration=本次使用截止时间 +multiplayer.session.expiration=索引码到期时间 datapack=数据包 datapack.add=添加数据包