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 b07b8245f..936db3f19 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 @@ -19,6 +19,7 @@ package org.jackhuang.hmcl.ui.multiplayer; import com.google.gson.JsonParseException; import com.google.gson.annotations.SerializedName; +import jdk.nashorn.internal.parser.JSONParser; import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.event.Event; import org.jackhuang.hmcl.event.EventManager; @@ -26,6 +27,7 @@ import org.jackhuang.hmcl.task.FileDownloadTask; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.util.Lang; +import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.io.ChecksumMismatchException; import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.HttpRequest; @@ -50,8 +52,7 @@ import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; -import static org.jackhuang.hmcl.util.Lang.mapOf; -import static org.jackhuang.hmcl.util.Lang.wrap; +import static org.jackhuang.hmcl.util.Lang.*; import static org.jackhuang.hmcl.util.Logging.LOG; import static org.jackhuang.hmcl.util.Pair.pair; @@ -188,7 +189,7 @@ public final class MultiplayerManager { // 下载 HiPer 配置文件 String certFileContent; try { - certFileContent = HttpRequest.GET(String.format("https://cert.mcer.cn/%s.yml", token)).getString(); + certFileContent = HttpRequest.GET(String.format("https://cert.mcer.cn/%s.yml", token)).getString() + "\nlogging:\n format: json\n file_path: ./hiper.log"; } catch (IOException e) { throw new HiperInvalidTokenException(); } @@ -219,6 +220,7 @@ public final class MultiplayerManager { private final EventManager onExit = new EventManager<>(); private final EventManager onIPAllocated = new EventManager<>(); private final BufferedWriter writer; + private int error = 0; HiperSession(Process process, List commands) { super(process, commands); @@ -237,8 +239,30 @@ public final class MultiplayerManager { private void onLog(String log) { LOG.info("[Hiper] " + log); - if (log.contains("IP")) { - // TODO + if (log.contains("failed to load config")) { + error = HiperExitEvent.INVALID_CONFIGURATION; + return; + } + + try { + Map logJson = JsonUtils.fromNonNullJson(log, Map.class); + String msg = ""; + if (logJson.containsKey("msg")) { + msg = tryCast(logJson.get("msg"), String.class).orElse(""); + if (msg.contains("Failed to get a tun/tap device")) { + error = HiperExitEvent.FAILED_GET_DEVICE; + } + } + + if (logJson.containsKey("network")) { + Map network = tryCast(logJson.get("network"), Map.class).orElse(Collections.emptyMap()); + if (network.containsKey("IP") && msg.contains("Main HostMap created")) { + Optional ip = tryCast(network.get("IP"), String.class); + ip.ifPresent(s -> onIPAllocated.fireEvent(new HiperIPEvent(this, s))); + } + } + } catch (JsonParseException e) { + LOG.log(Level.WARNING, "Failed to parse hiper log: " + log, e); } } @@ -246,7 +270,11 @@ public final class MultiplayerManager { try { int exitCode = getProcess().waitFor(); LOG.info("Hiper exited with exitcode " + exitCode); - onExit.fireEvent(new HiperExitEvent(this, exitCode)); + if (error != 0) { + onExit.fireEvent(new HiperExitEvent(this, error)); + } else { + onExit.fireEvent(new HiperExitEvent(this, exitCode)); + } } catch (InterruptedException e) { onExit.fireEvent(new HiperExitEvent(this, HiperExitEvent.INTERRUPTED)); } finally { @@ -283,9 +311,9 @@ public final class MultiplayerManager { } public static final int INTERRUPTED = -1; - - public static final int INVALID_CONFIGURATION = 1; - public static final int CERTIFICATE_EXPIRED = 11; + public static final int INVALID_CONFIGURATION = -2; + public static final int CERTIFICATE_EXPIRED = -3; + public static final int FAILED_GET_DEVICE = -4; } public static class HiperIPEvent extends Event { 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 f89010b3b..69a45e590 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 @@ -251,6 +251,9 @@ public class MultiplayerPage extends DecoratorAnimatedPage implements DecoratorP case MultiplayerManager.HiperExitEvent.INTERRUPTED: // do nothing break; + case MultiplayerManager.HiperExitEvent.FAILED_GET_DEVICE: + Controllers.dialog(i18n("multiplayer.error.failed_get_device")); + break; default: Controllers.dialog(i18n("multiplayer.exit", event.getExitCode())); break; 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 5994b7943..add124e1a 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -690,6 +690,7 @@ multiplayer.download=正在下载依赖 multiplayer.download.failed=初始化失败,部分文件未能完成下载 multiplayer.download.success=多人联机初始化完成 multiplayer.download.unsupported=多人联机依赖不支持当前系统或平台 +multiplayer.error.failed_get_device=HiPer 无法创建网络设备,可能是缺少 root 权限。 multiplayer.error.file_not_found=找不到 HiPer 程序。该程序应该在进入多人联机页面时完成下载。请重启 HMCL 再试。\n请检查你电脑的杀毒软件是否将 HiPer 标记为病毒,如果是,请恢复 HiPer。 multiplayer.exit=HiPer 意外退出,退出码 %d multiplayer.hint=多人联机功能处于实验阶段,如果有问题请前往 mcer.cn 反馈