From 35f2d89a2335c9d0b3c98e4fdb5f1e9b96783b8e Mon Sep 17 00:00:00 2001 From: huanghongxun Date: Mon, 27 Sep 2021 12:38:43 +0800 Subject: [PATCH] fix(multiplayer): bind to 0.0.0.0 instead of 127.0.0.1. --- .../multiplayer/LocalServerBroadcaster.java | 2 +- .../ui/multiplayer/LocalServerDetector.java | 2 +- .../ui/multiplayer/MultiplayerManager.java | 10 +-- .../ui/multiplayer/MultiplayerPageSkin.java | 14 +++- .../resources/assets/lang/I18N.properties | 1 + .../resources/assets/lang/I18N_zh.properties | 3 +- .../assets/lang/I18N_zh_CN.properties | 1 + .../multiplayer/LocalServerBroadcastTest.java | 69 +++++++++++++++++++ .../multiplayer/LocalServerDetectorTest.java | 49 +++++++++++++ .../java/org/jackhuang/hmcl/util/Lang.java | 19 +++++ .../java/org/jackhuang/hmcl/util/Logging.java | 12 +++- 11 files changed, 170 insertions(+), 12 deletions(-) create mode 100644 HMCL/src/test/java/org/jackhuang/hmcl/ui/multiplayer/LocalServerBroadcastTest.java create mode 100644 HMCL/src/test/java/org/jackhuang/hmcl/ui/multiplayer/LocalServerDetectorTest.java diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/LocalServerBroadcaster.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/LocalServerBroadcaster.java index 9323c5e88..b441261a4 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/LocalServerBroadcaster.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/LocalServerBroadcaster.java @@ -57,7 +57,7 @@ public class LocalServerBroadcaster implements Runnable { byte[] data = String.format("[MOTD]%s[/MOTD][AD]%d[/AD]", i18n("multiplayer.session.name.motd", session.getName()), port).getBytes(StandardCharsets.UTF_8); DatagramPacket packet = new DatagramPacket(data, 0, data.length, broadcastAddress, 4445); socket.send(packet); - LOG.fine("Broadcast server 127.0.0.1:" + port); + LOG.fine("Broadcast server 0.0.0.0:" + port); } catch (IOException e) { LOG.log(Level.WARNING, "Failed to send motd packet", e); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/LocalServerDetector.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/LocalServerDetector.java index 8006e5c39..ba04a626c 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/LocalServerDetector.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/multiplayer/LocalServerDetector.java @@ -79,7 +79,7 @@ public class LocalServerDetector extends Thread { } String response = new String(packet.getData(), packet.getOffset(), packet.getLength(), StandardCharsets.UTF_8); - LOG.fine("Local server broadcast message: " + response); + LOG.fine("Local server " + packet.getAddress() + ":" + packet.getPort() + " broadcast message: " + response); onDetectedLanServer.fireEvent(new DetectedLanServerEvent(this, PingResponse.parsePingResponse(response))); break; } 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 c82b2e242..5d69a79c1 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 @@ -59,7 +59,7 @@ import static org.jackhuang.hmcl.util.Logging.LOG; */ public final class MultiplayerManager { private static final String CATO_DOWNLOAD_URL = "https://files.huangyuhui.net/maven/"; - static final String CATO_VERSION = "1.0.8"; + static final String CATO_VERSION = "1.0.9"; private static final String CATO_PATH = getCatoPath(); private MultiplayerManager() { @@ -96,8 +96,8 @@ public final class MultiplayerManager { String[] commands = new String[]{exe.toString(), "--token", StringUtils.isBlank(token) ? "new" : token, "--id", peer, - "--local", String.format("127.0.0.1:%d", localPort), - "--remote", String.format("127.0.0.1:%d", remotePort), + "--local", String.format("0.0.0.0:%d", localPort), + "--remote", String.format("0.0.0.0:%d", remotePort), "--mode", "relay"}; Process process; try { @@ -130,7 +130,7 @@ public final class MultiplayerManager { client.onConnected().register(connectedEvent -> { try { int port = findAvailablePort(); - writer.write(String.format("net add %s 127.0.0.1:%d 127.0.0.1:%d p2p\n", peer, port, connectedEvent.getPort())); + writer.write(String.format("net add %s 0.0.0.0:%d 0.0.0.0:%d p2p\n", peer, port, connectedEvent.getPort())); future.complete(session); } catch (IOException e) { future.completeExceptionally(e); @@ -154,7 +154,7 @@ public final class MultiplayerManager { String[] commands = new String[]{exe.toString(), "--token", StringUtils.isBlank(token) ? "new" : token, - "--allows", String.format("127.0.0.1:%d,127.0.0.1:%d", port, server.getPort()), + "--allows", String.format("0.0.0.0:%d/0.0.0.0:%d", port, server.getPort()), "--mode", "relay"}; Process process = new ProcessBuilder() .command(commands) 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 fbfeee9ba..80a6e8a5f 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 @@ -17,9 +17,11 @@ */ package org.jackhuang.hmcl.ui.multiplayer; +import com.jfoenix.controls.JFXButton; import de.javawi.jstun.test.DiscoveryInfo; import javafx.beans.binding.Bindings; import javafx.geometry.Insets; +import javafx.geometry.Pos; import javafx.scene.control.Label; import javafx.scene.control.ScrollPane; import javafx.scene.control.SkinBase; @@ -172,16 +174,22 @@ public class MultiplayerPageSkin extends SkinBase { masterPane.getChildren().setAll(label); } - VBox slavePane = new VBox(8); + BorderPane slavePane = new BorderPane(); { HintPane slaveHintPane = new HintPane(); slaveHintPane.setText(i18n("multiplayer.state.slave.hint")); + slavePane.setTop(slaveHintPane); Label label = new Label(); label.textProperty().bind(Bindings.createStringBinding(() -> - i18n("multiplayer.state.slave", control.getSession() == null ? "" : control.getSession().getName(), control.getPort()), + i18n("multiplayer.state.slave", control.getSession() == null ? "" : control.getSession().getName(), "0.0.0.0:" + control.getPort()), control.sessionProperty(), control.portProperty())); - slavePane.getChildren().setAll(slaveHintPane, label); + BorderPane.setAlignment(label, Pos.CENTER_LEFT); + slavePane.setCenter(label); + + JFXButton copyButton = new JFXButton(i18n("multiplayer.state.slave.copy")); + copyButton.setOnAction(e -> FXUtils.copyText("0.0.0.0:" + control.getPort())); + slavePane.setRight(copyButton); } FXUtils.onChangeAndOperate(getSkinnable().multiplayerStateProperty(), state -> { diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index b2aee909c..48c5ff3c4 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -643,6 +643,7 @@ multiplayer.state.disconnected=Not created/entered a multiplayer session multiplayer.state.disconnected.hint=Someone should create a multiplayer session, and others join the session to play the game together. multiplayer.state.master=Created room: %1$s, port: %2$d multiplayer.state.slave=Joined room: %1$s, address: %2$s +multiplayer.state.slave.copy=Copy address multiplayer.state.slave.hint=After joining multiplayer room, you should get to multiplayer page in Minecraft and connect to the "HMCL Multiplayer Session" server, or manually add a server with address shown below. datapack=Datapacks diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index 2b2b2a647..6e573c1c8 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -641,7 +641,8 @@ multiplayer.state.connecting=連接中 multiplayer.state.disconnected=未創建/加入房間 multiplayer.state.disconnected.hint=多人聯機功能需要先有一位玩家創建房間後,其他玩家加入房間後繼續遊戲。 multiplayer.state.master=你已創建房間:%1$s,埠號 %2$d -multiplayer.state.slave=你已加入房間: %1$s,地址為 %2$s +multiplayer.state.slave=你已加入房間: %1$s,位址為 %2$s +multiplayer.state.slave.copy=拷貝位址 multiplayer.state.slave.hint=加入房間後,你需要在 Minecraft 的多人遊戲頁面選擇 HMCL 多人聯機房間伺服器,或者手動添加下方的地址的伺服器。 datapack=資料包 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 d28b24616..286203cc2 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -642,6 +642,7 @@ multiplayer.state.disconnected=未创建/加入房间 multiplayer.state.disconnected.hint=多人联机功能需要先有一位玩家创建房间后,其他玩家加入房间后继续游戏。 multiplayer.state.master=你已创建房间:%1$s,端口号 %2$d multiplayer.state.slave=你已加入房间: %1$s,地址为 %2$s +multiplayer.state.slave.copy=拷贝地址 multiplayer.state.slave.hint=加入房间后,你需要在 Minecraft 的多人游戏页面选择 HMCL 多人联机房间服务器,或者手动添加下方的地址的服务器。 datapack=数据包 diff --git a/HMCL/src/test/java/org/jackhuang/hmcl/ui/multiplayer/LocalServerBroadcastTest.java b/HMCL/src/test/java/org/jackhuang/hmcl/ui/multiplayer/LocalServerBroadcastTest.java new file mode 100644 index 000000000..39e29683c --- /dev/null +++ b/HMCL/src/test/java/org/jackhuang/hmcl/ui/multiplayer/LocalServerBroadcastTest.java @@ -0,0 +1,69 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2020 huangyuhui 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 . + */ +package org.jackhuang.hmcl.ui.multiplayer; + +import org.junit.Ignore; +import org.junit.Test; + +import java.io.IOException; +import java.net.*; +import java.nio.charset.StandardCharsets; + +import static org.jackhuang.hmcl.util.i18n.I18n.i18n; + +public class LocalServerBroadcastTest { + + @Test + @Ignore("for manually testing") + public void test() { + int port = 12345; + DatagramSocket socket; + InetAddress broadcastAddress; + try { + socket = new DatagramSocket(); + broadcastAddress = InetAddress.getByName("224.0.2.60"); + } catch (IOException e) { + e.printStackTrace(); + return; + } + + while (true) { + try { + byte[] data = String.format("[MOTD]%s[/MOTD][AD]%d[/AD]", i18n("multiplayer.session.name.motd", "Test server"), port).getBytes(StandardCharsets.UTF_8); + DatagramPacket packet = new DatagramPacket(data, 0, data.length, broadcastAddress, 4445); + socket.send(packet); + System.out.println("Broadcast server 127.0.0.1:" + port); + } catch (IOException e) { + e.printStackTrace(); + } + + try { + Thread.sleep(1500); + } catch (InterruptedException ignored) { + return; + } + } + } + + @Test + @Ignore + public void printLocalAddress() throws IOException { + DatagramSocket socket = new DatagramSocket(new InetSocketAddress((InetAddress) null, 4444)); + System.out.println(socket.getLocalAddress()); + } +} diff --git a/HMCL/src/test/java/org/jackhuang/hmcl/ui/multiplayer/LocalServerDetectorTest.java b/HMCL/src/test/java/org/jackhuang/hmcl/ui/multiplayer/LocalServerDetectorTest.java new file mode 100644 index 000000000..2836c7e2f --- /dev/null +++ b/HMCL/src/test/java/org/jackhuang/hmcl/ui/multiplayer/LocalServerDetectorTest.java @@ -0,0 +1,49 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2021 huangyuhui 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 . + */ +package org.jackhuang.hmcl.ui.multiplayer; + +import org.jackhuang.hmcl.util.Lang; +import org.jackhuang.hmcl.util.Logging; +import org.junit.Ignore; +import org.junit.Test; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; + +public class LocalServerDetectorTest { + + @Test + @Ignore("for manually testing") + public void test() { + try { + for (NetworkInterface networkInterface : Lang.toIterable(NetworkInterface.getNetworkInterfaces())) { + System.out.println(networkInterface.getName()); + for (InetAddress address : Lang.toIterable(networkInterface.getInetAddresses())) { + System.out.println(address); + } + } + } catch (SocketException e) { + e.printStackTrace(); + } + + Logging.initForTest(); + LocalServerDetector detector = new LocalServerDetector(3); + detector.run(); + } +} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java index eb8dbdd9e..8fa5b7aec 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Lang.java @@ -330,6 +330,25 @@ public final class Lang { return optional.map(Stream::of).orElseGet(Stream::empty); } + public static Iterable toIterable(Enumeration enumeration) { + if (enumeration == null) { + throw new NullPointerException(); + } + return () -> new Iterator() { + public boolean hasNext() { + return enumeration.hasMoreElements(); + } + + public T next() { + return enumeration.nextElement(); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + public static Iterable toIterable(Stream stream) { return stream::iterator; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Logging.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Logging.java index d7246c4a6..aa0946330 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Logging.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Logging.java @@ -1,6 +1,6 @@ /* * Hello Minecraft! Launcher - * Copyright (C) 2020 huangyuhui and contributors + * Copyright (C) 2021 huangyuhui 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 @@ -72,6 +72,16 @@ public final class Logging { LOG.addHandler(streamHandler); } + public static void initForTest() { + LOG.setLevel(Level.ALL); + LOG.setUseParentHandlers(false); + + ConsoleHandler consoleHandler = new ConsoleHandler(); + consoleHandler.setFormatter(DefaultFormatter.INSTANCE); + consoleHandler.setLevel(Level.FINER); + LOG.addHandler(consoleHandler); + } + public static byte[] getRawLogs() { return storedLogs.toByteArray(); }