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 7c15f012c..5de8eec03 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 @@ -17,7 +17,76 @@ */ package org.jackhuang.hmcl.ui.multiplayer; +import org.jackhuang.hmcl.Metadata; +import org.jackhuang.hmcl.game.Artifact; +import org.jackhuang.hmcl.task.FileDownloadTask; +import org.jackhuang.hmcl.task.Task; +import org.jackhuang.hmcl.task.TaskExecutor; +import org.jackhuang.hmcl.ui.Controllers; +import org.jackhuang.hmcl.ui.construct.TaskExecutorDialogPane; +import org.jackhuang.hmcl.util.io.NetworkUtils; +import org.jackhuang.hmcl.util.platform.ManagedProcess; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; + +import static org.jackhuang.hmcl.util.i18n.I18n.i18n; + +/** + * Cato Management. + */ public class MultiplayerManager { + private static final String CATO_DOWNLOAD_URL = "https://hmcl.huangyuhui.net/maven/"; + private static final String CATO_VERSION = "2021-09-01"; + private static final Artifact CATO_ARTIFACT = new Artifact("cato", "cato", CATO_VERSION); + + public static void fetchIdAndToken() { + // TODO + } + + public static Task downloadCato() { + return new FileDownloadTask( + NetworkUtils.toURL(CATO_DOWNLOAD_URL + CATO_ARTIFACT.getPath()), + getCatoExecutable().toFile() + ); + } + + public static Path getCatoExecutable() { + return CATO_ARTIFACT.getPath(Metadata.HMCL_DIRECTORY); + } + + public static ManagedProcess joinRoom(String token, String peer, String localAddress, String remoteAddress) throws IOException { + Path exe = getCatoExecutable(); + if (!Files.isRegularFile(exe)) { + throw new IllegalStateException("Cato file not found"); + } + String[] commands = new String[]{exe.toString(), "--peer", peer, "--from", localAddress, "--to", remoteAddress}; + Process process = new ProcessBuilder() + .command(commands) + .inheritIO() + .start(); + ManagedProcess managedProcess = new ManagedProcess(process, Arrays.asList(commands)); + managedProcess.getProcess().getOutputStream().write(token.getBytes(StandardCharsets.UTF_8)); + return managedProcess; + } + + public static ManagedProcess createRoom(String token, String peer, String localAddress) throws IOException { + Path exe = getCatoExecutable(); + if (!Files.isRegularFile(exe)) { + throw new IllegalStateException("Cato file not found"); + } + String[] commands = new String[]{exe.toString(), "--peer", peer, "--from", localAddress}; + Process process = new ProcessBuilder() + .command(commands) + .inheritIO() + .start(); + ManagedProcess managedProcess = new ManagedProcess(process, Arrays.asList(commands)); + managedProcess.getProcess().getOutputStream().write(token.getBytes(StandardCharsets.UTF_8)); + return managedProcess; + } enum State { DISCONNECTED, 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 e3edf4e58..c8c0a1b73 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 @@ -19,14 +19,13 @@ package org.jackhuang.hmcl.ui.multiplayer; import de.javawi.jstun.test.DiscoveryInfo; import de.javawi.jstun.test.DiscoveryTest; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.ReadOnlyObjectProperty; -import javafx.beans.property.ReadOnlyObjectWrapper; -import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.*; import javafx.scene.control.Control; import javafx.scene.control.Skin; import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Task; +import org.jackhuang.hmcl.task.TaskExecutor; +import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.decorator.DecoratorPage; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -39,6 +38,7 @@ public class MultiplayerPage extends Control implements DecoratorPage { public MultiplayerPage() { testNAT(); + downloadCatoIfNecessary(); } @Override @@ -66,7 +66,7 @@ public class MultiplayerPage extends Control implements DecoratorPage { return natState.getReadOnlyProperty(); } - public void testNAT() { + private void testNAT() { Task.supplyAsync(() -> { DiscoveryTest tester = new DiscoveryTest(null, 0, "stun.qq.com", 3478); return tester.test(); @@ -79,6 +79,19 @@ public class MultiplayerPage extends Control implements DecoratorPage { }).start(); } + private void downloadCatoIfNecessary() { + if (!MultiplayerManager.getCatoExecutable().toFile().exists()) { + setDisabled(true); + TaskExecutor executor = MultiplayerManager.downloadCato() + .thenRunAsync(Schedulers.javafx(), () -> { + setDisabled(false); + }).executor(false); + Controllers.taskDialog(executor, i18n("multiplayer.download")); + } else { + setDisabled(false); + } + } + @Override public ReadOnlyObjectProperty stateProperty() { return state;