mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2024-11-27 06:10:08 +08:00
fix(multiplayer): wrong port.
This commit is contained in:
parent
a58de31d4b
commit
8a3cdfb14c
@ -67,7 +67,6 @@ import java.util.function.Consumer;
|
||||
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.mapOf;
|
||||
import static org.jackhuang.hmcl.util.Logging.LOG;
|
||||
import static org.jackhuang.hmcl.util.Pair.pair;
|
||||
@ -489,6 +488,10 @@ public final class LauncherHelper {
|
||||
}
|
||||
}
|
||||
|
||||
if (!suggested) {
|
||||
future.complete(javaVersion);
|
||||
}
|
||||
|
||||
return Task.fromCompletableFuture(future);
|
||||
}).thenAcceptAsync(Schedulers.javafx(), javaVersion -> {
|
||||
if (javaVersion == null) {
|
||||
|
@ -22,6 +22,7 @@ import com.google.gson.annotations.JsonAdapter;
|
||||
import javafx.beans.InvalidationListener;
|
||||
import javafx.beans.property.*;
|
||||
import org.jackhuang.hmcl.game.*;
|
||||
import org.jackhuang.hmcl.task.Schedulers;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
@ -39,6 +40,8 @@ import java.util.Optional;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.jfoenix.concurrency.JFXUtilities.runInFX;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
@ -590,10 +593,12 @@ public final class VersionSetting implements Cloneable {
|
||||
}
|
||||
|
||||
public Task<JavaVersion> getJavaVersion(VersionNumber gameVersion, Version version, boolean checkJava) {
|
||||
return Task.supplyAsync(() -> {
|
||||
return Task.runAsync(Schedulers.javafx(), () -> {
|
||||
if (StringUtils.isBlank(getJava())) {
|
||||
setJava(StringUtils.isBlank(getJavaDir()) ? "Default" : "Custom");
|
||||
}
|
||||
}).thenSupplyAsync(() -> {
|
||||
try {
|
||||
if (StringUtils.isBlank(getJava()))
|
||||
setJava(StringUtils.isBlank(getJavaDir()) ? "Default" : "Custom");
|
||||
if ("Default".equals(getJava())) {
|
||||
return JavaVersion.fromCurrentEnvironment();
|
||||
} else if (isJavaAutoSelected()) {
|
||||
@ -612,7 +617,9 @@ public final class VersionSetting implements Cloneable {
|
||||
.filter(java -> java.getVersion().equals(getJava()))
|
||||
.collect(Collectors.toList());
|
||||
if (matchedJava.isEmpty()) {
|
||||
setJava("Default");
|
||||
runInFX(() -> {
|
||||
setJava("Default");
|
||||
});
|
||||
return JavaVersion.fromCurrentEnvironment();
|
||||
} else {
|
||||
return matchedJava.stream()
|
||||
|
@ -32,6 +32,8 @@ public class MultiplayerClient extends Thread {
|
||||
private final String id;
|
||||
private final int port;
|
||||
|
||||
private int gamePort;
|
||||
|
||||
private final EventManager<ConnectedEvent> onConnected = new EventManager<>();
|
||||
private final EventManager<Event> onDisconnected = new EventManager<>();
|
||||
|
||||
@ -43,6 +45,14 @@ public class MultiplayerClient extends Thread {
|
||||
setDaemon(true);
|
||||
}
|
||||
|
||||
public void setGamePort(int gamePort) {
|
||||
this.gamePort = gamePort;
|
||||
}
|
||||
|
||||
public int getGamePort() {
|
||||
return gamePort;
|
||||
}
|
||||
|
||||
public EventManager<ConnectedEvent> onConnected() {
|
||||
return onConnected;
|
||||
}
|
||||
@ -53,6 +63,7 @@ public class MultiplayerClient extends Thread {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
LOG.info("Connecting to 127.0.0.1:" + port);
|
||||
try (Socket socket = new Socket(InetAddress.getLoopbackAddress(), port);
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))) {
|
||||
@ -68,6 +79,7 @@ public class MultiplayerClient extends Thread {
|
||||
}
|
||||
|
||||
MultiplayerServer.JoinResponse response = JsonUtils.fromNonNullJson(line, MultiplayerServer.JoinResponse.class);
|
||||
setGamePort(response.getPort());
|
||||
onConnected.fireEvent(new ConnectedEvent(this, response.getPort()));
|
||||
|
||||
LOG.fine("Received join response with port " + response.getPort());
|
||||
@ -85,6 +97,7 @@ public class MultiplayerClient extends Thread {
|
||||
} catch (IOException | JsonParseException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
LOG.info("Lost connection to 127.0.0.1:" + port);
|
||||
onDisconnected.fireEvent(new Event(this));
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
package org.jackhuang.hmcl.ui.multiplayer;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import org.jackhuang.hmcl.Metadata;
|
||||
import org.jackhuang.hmcl.event.Event;
|
||||
import org.jackhuang.hmcl.event.EventManager;
|
||||
@ -62,6 +63,9 @@ public final class MultiplayerManager {
|
||||
static final String CATO_VERSION = "1.0.9";
|
||||
private static final String CATO_PATH = getCatoPath();
|
||||
|
||||
private static final String REMOTE_ADDRESS = "127.0.0.1";
|
||||
private static final String LOCAL_ADDRESS = "127.0.0.1";
|
||||
|
||||
private MultiplayerManager() {
|
||||
}
|
||||
|
||||
@ -96,8 +100,8 @@ public final class MultiplayerManager {
|
||||
String[] commands = new String[]{exe.toString(),
|
||||
"--token", StringUtils.isBlank(token) ? "new" : token,
|
||||
"--id", peer,
|
||||
"--local", String.format("0.0.0.0:%d", localPort),
|
||||
"--remote", String.format("0.0.0.0:%d", remotePort)};
|
||||
"--local", String.format("%s:%d", LOCAL_ADDRESS, localPort),
|
||||
"--remote", String.format("%s:%d", REMOTE_ADDRESS, remotePort)};
|
||||
Process process;
|
||||
try {
|
||||
process = new ProcessBuilder()
|
||||
@ -129,7 +133,7 @@ public final class MultiplayerManager {
|
||||
client.onConnected().register(connectedEvent -> {
|
||||
try {
|
||||
int port = findAvailablePort();
|
||||
writer.write(String.format("net add %s 0.0.0.0:%d 0.0.0.0:%d p2p\n", peer, port, connectedEvent.getPort()));
|
||||
writer.write(String.format("net add %s %s:%d %s:%d p2p\n", peer, LOCAL_ADDRESS, port, REMOTE_ADDRESS, connectedEvent.getPort()));
|
||||
future.complete(session);
|
||||
} catch (IOException e) {
|
||||
future.completeExceptionally(e);
|
||||
@ -142,18 +146,18 @@ public final class MultiplayerManager {
|
||||
});
|
||||
}
|
||||
|
||||
public static CatoSession createSession(String token, String sessionName, int port) throws IOException {
|
||||
public static CatoSession createSession(String token, String sessionName, int gamePort) throws IOException {
|
||||
Path exe = getCatoExecutable();
|
||||
if (!Files.isRegularFile(exe)) {
|
||||
throw new IllegalStateException("Cato file not found");
|
||||
}
|
||||
|
||||
MultiplayerServer server = new MultiplayerServer(port);
|
||||
MultiplayerServer server = new MultiplayerServer(gamePort);
|
||||
server.startServer();
|
||||
|
||||
String[] commands = new String[]{exe.toString(),
|
||||
"--token", StringUtils.isBlank(token) ? "new" : token,
|
||||
"--allows", String.format("0.0.0.0:%d/0.0.0.0:%d", port, server.getPort())};
|
||||
"--allows", String.format("%s:%d/%s:%d", REMOTE_ADDRESS, server.getPort(), REMOTE_ADDRESS, gamePort)};
|
||||
Process process = new ProcessBuilder()
|
||||
.command(commands)
|
||||
.start();
|
||||
@ -291,11 +295,11 @@ public final class MultiplayerManager {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String generateInvitationCode(int gamePort, int serverPort) {
|
||||
public String generateInvitationCode(int serverPort) {
|
||||
if (id == null) {
|
||||
throw new IllegalStateException("id not generated");
|
||||
}
|
||||
String json = JsonUtils.GSON.toJson(new Invitation(CATO_VERSION, id, name, gamePort, serverPort));
|
||||
String json = JsonUtils.GSON.toJson(new Invitation(CATO_VERSION, id, name, serverPort));
|
||||
return new String(Base64.getEncoder().encode(json.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
@ -312,7 +316,7 @@ public final class MultiplayerManager {
|
||||
}
|
||||
|
||||
private static final Pattern TEMP_TOKEN_PATTERN = Pattern.compile("id\\(mix(?<id>\\w+)\\)");
|
||||
private static final Pattern PEER_CONNECTED_PATTERN = Pattern.compile("Peer connected");
|
||||
private static final Pattern PEER_CONNECTED_PATTERN = Pattern.compile("Connection established");
|
||||
private static final Pattern LOG_PATTERN = Pattern.compile("(\\[\\d+])\\s+(\\w+)\\s+(\\w+-{0,1}\\w+):\\s(.*)");
|
||||
}
|
||||
|
||||
@ -353,17 +357,18 @@ public final class MultiplayerManager {
|
||||
}
|
||||
|
||||
public static class Invitation {
|
||||
@SerializedName("v")
|
||||
private final String version;
|
||||
private final String id;
|
||||
@SerializedName("n")
|
||||
private final String sessionName;
|
||||
private final int gamePort;
|
||||
@SerializedName("p")
|
||||
private final int channelPort;
|
||||
|
||||
public Invitation(String version, String id, String sessionName, int gamePort, int channelPort) {
|
||||
public Invitation(String version, String id, String sessionName, int channelPort) {
|
||||
this.version = version;
|
||||
this.id = id;
|
||||
this.sessionName = sessionName;
|
||||
this.gamePort = gamePort;
|
||||
this.channelPort = channelPort;
|
||||
}
|
||||
|
||||
@ -379,10 +384,6 @@ public final class MultiplayerManager {
|
||||
return sessionName;
|
||||
}
|
||||
|
||||
public int getGamePort() {
|
||||
return gamePort;
|
||||
}
|
||||
|
||||
public int getChannelPort() {
|
||||
return channelPort;
|
||||
}
|
||||
|
@ -21,6 +21,8 @@ import de.javawi.jstun.test.DiscoveryInfo;
|
||||
import de.javawi.jstun.test.DiscoveryTest;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.*;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.scene.control.Control;
|
||||
import javafx.scene.control.Skin;
|
||||
import org.jackhuang.hmcl.event.Event;
|
||||
@ -49,8 +51,9 @@ public class MultiplayerPage extends Control implements DecoratorPage, PageAware
|
||||
private final ObjectProperty<MultiplayerManager.State> multiplayerState = new SimpleObjectProperty<>(MultiplayerManager.State.DISCONNECTED);
|
||||
private final ReadOnlyStringWrapper token = new ReadOnlyStringWrapper();
|
||||
private final ReadOnlyObjectWrapper<DiscoveryInfo> natState = new ReadOnlyObjectWrapper<>();
|
||||
private final ReadOnlyIntegerWrapper port = new ReadOnlyIntegerWrapper(-1);
|
||||
private final ReadOnlyIntegerWrapper gamePort = new ReadOnlyIntegerWrapper(-1);
|
||||
private final ReadOnlyObjectWrapper<MultiplayerManager.CatoSession> session = new ReadOnlyObjectWrapper<>();
|
||||
private final ObservableList<MultiplayerServer.CatoClient> clients = FXCollections.observableArrayList();
|
||||
|
||||
private Consumer<MultiplayerManager.CatoExitEvent> onExit;
|
||||
private Consumer<MultiplayerManager.CatoIdEvent> onIdGenerated;
|
||||
@ -70,6 +73,10 @@ public class MultiplayerPage extends Control implements DecoratorPage, PageAware
|
||||
return new MultiplayerPageSkin(this);
|
||||
}
|
||||
|
||||
public ObservableList<MultiplayerServer.CatoClient> getClients() {
|
||||
return clients;
|
||||
}
|
||||
|
||||
public MultiplayerManager.State getMultiplayerState() {
|
||||
return multiplayerState.get();
|
||||
}
|
||||
@ -98,12 +105,12 @@ public class MultiplayerPage extends Control implements DecoratorPage, PageAware
|
||||
return token.getReadOnlyProperty();
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port.get();
|
||||
public int getGamePort() {
|
||||
return gamePort.get();
|
||||
}
|
||||
|
||||
public ReadOnlyIntegerProperty portProperty() {
|
||||
return port.getReadOnlyProperty();
|
||||
public ReadOnlyIntegerProperty gamePortProperty() {
|
||||
return gamePort.getReadOnlyProperty();
|
||||
}
|
||||
|
||||
public MultiplayerManager.CatoSession getSession() {
|
||||
@ -158,11 +165,11 @@ public class MultiplayerPage extends Control implements DecoratorPage, PageAware
|
||||
}
|
||||
|
||||
public void copyInvitationCode() {
|
||||
if (getSession() == null || !getSession().isReady() || port.get() < 0 || getMultiplayerState() != MultiplayerManager.State.MASTER) {
|
||||
if (getSession() == null || !getSession().isReady() || gamePort.get() < 0 || getMultiplayerState() != MultiplayerManager.State.MASTER) {
|
||||
throw new IllegalStateException("CatoSession not ready");
|
||||
}
|
||||
|
||||
FXUtils.copyText(getSession().generateInvitationCode(port.get(), 0));
|
||||
FXUtils.copyText(getSession().generateInvitationCode(getSession().getServer().getPort()));
|
||||
}
|
||||
|
||||
public void createRoom() {
|
||||
@ -171,16 +178,22 @@ public class MultiplayerPage extends Control implements DecoratorPage, PageAware
|
||||
}
|
||||
|
||||
Controllers.dialog(new CreateMultiplayerRoomDialog((result, resolve, reject) -> {
|
||||
int port = result.getAd();
|
||||
int gamePort = result.getAd();
|
||||
try {
|
||||
initCatoSession(MultiplayerManager.createSession(config().getMultiplayerToken(), result.getMotd(), port));
|
||||
MultiplayerManager.CatoSession session = MultiplayerManager.createSession(config().getMultiplayerToken(), result.getMotd(), gamePort);
|
||||
session.getServer().onClientAdded().register(event -> {
|
||||
runInFX(() -> {
|
||||
clients.add(event);
|
||||
});
|
||||
});
|
||||
initCatoSession(session);
|
||||
} catch (Exception e) {
|
||||
LOG.log(Level.WARNING, "Failed to create session", e);
|
||||
reject.accept(i18n("multiplayer.session.create.error"));
|
||||
return;
|
||||
}
|
||||
|
||||
this.port.set(port);
|
||||
this.gamePort.set(gamePort);
|
||||
setMultiplayerState(MultiplayerManager.State.CONNECTING);
|
||||
resolve.run();
|
||||
}));
|
||||
@ -202,7 +215,7 @@ public class MultiplayerPage extends Control implements DecoratorPage, PageAware
|
||||
return;
|
||||
}
|
||||
|
||||
int localPort;
|
||||
int localPort; // invitation channel
|
||||
try {
|
||||
localPort = MultiplayerManager.findAvailablePort();
|
||||
} catch (Exception e) {
|
||||
@ -211,7 +224,7 @@ public class MultiplayerPage extends Control implements DecoratorPage, PageAware
|
||||
}
|
||||
|
||||
try {
|
||||
MultiplayerManager.joinSession(config().getMultiplayerToken(), invitation.getVersion(), invitation.getSessionName(), invitation.getId(), invitation.getGamePort(), localPort)
|
||||
MultiplayerManager.joinSession(config().getMultiplayerToken(), invitation.getVersion(), invitation.getSessionName(), invitation.getId(), invitation.getChannelPort(), localPort)
|
||||
.thenAcceptAsync(session -> {
|
||||
initCatoSession(session);
|
||||
|
||||
@ -222,7 +235,7 @@ public class MultiplayerPage extends Control implements DecoratorPage, PageAware
|
||||
});
|
||||
});
|
||||
|
||||
port.set(localPort);
|
||||
gamePort.set(session.getClient().getGamePort());
|
||||
setMultiplayerState(MultiplayerManager.State.CONNECTING);
|
||||
resolve.run();
|
||||
}, Platform::runLater).exceptionally(throwable -> {
|
||||
@ -270,6 +283,7 @@ public class MultiplayerPage extends Control implements DecoratorPage, PageAware
|
||||
onIdGenerated = session.onIdGenerated().registerWeak(this::onCatoIdGenerated);
|
||||
onPeerConnected = session.onPeerConnected().registerWeak(this::onCatoPeerConnected);
|
||||
|
||||
this.clients.clear();
|
||||
this.session.set(session);
|
||||
});
|
||||
}
|
||||
@ -282,7 +296,7 @@ public class MultiplayerPage extends Control implements DecoratorPage, PageAware
|
||||
private void clearCatoSession() {
|
||||
this.session.set(null);
|
||||
this.token.set(null);
|
||||
this.port.set(-1);
|
||||
this.gamePort.set(-1);
|
||||
this.multiplayerState.set(MultiplayerManager.State.DISCONNECTED);
|
||||
}
|
||||
|
||||
|
@ -21,8 +21,10 @@ import com.jfoenix.controls.JFXButton;
|
||||
import com.jfoenix.controls.JFXTextField;
|
||||
import de.javawi.jstun.test.DiscoveryInfo;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.control.SkinBase;
|
||||
@ -38,6 +40,7 @@ import org.jackhuang.hmcl.ui.animation.TransitionPane;
|
||||
import org.jackhuang.hmcl.ui.construct.*;
|
||||
import org.jackhuang.hmcl.ui.versions.Versions;
|
||||
import org.jackhuang.hmcl.util.javafx.BindingMapping;
|
||||
import org.jackhuang.hmcl.util.javafx.MappedObservableList;
|
||||
|
||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
||||
import static org.jackhuang.hmcl.ui.versions.VersionPage.wrap;
|
||||
@ -45,6 +48,8 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
|
||||
public class MultiplayerPageSkin extends SkinBase<MultiplayerPage> {
|
||||
|
||||
private ObservableList<Node> clients;
|
||||
|
||||
/**
|
||||
* Constructor for all SkinBase instances.
|
||||
*
|
||||
@ -174,9 +179,14 @@ public class MultiplayerPageSkin extends SkinBase<MultiplayerPage> {
|
||||
|
||||
Label label = new Label(i18n("multiplayer.state.master"));
|
||||
label.textProperty().bind(Bindings.createStringBinding(() ->
|
||||
i18n("multiplayer.state.master", control.getSession() == null ? "" : control.getSession().getName(), control.getPort()),
|
||||
control.portProperty(), control.sessionProperty()));
|
||||
masterPane.getChildren().setAll(masterHintPane, label);
|
||||
i18n("multiplayer.state.master", control.getSession() == null ? "" : control.getSession().getName(), control.getGamePort()),
|
||||
control.gamePortProperty(), control.sessionProperty()));
|
||||
|
||||
VBox clientsPane = new VBox(8);
|
||||
clients = MappedObservableList.create(control.getClients(), client -> new ClientItem(client));
|
||||
Bindings.bindContent(clientsPane.getChildren(), clients);
|
||||
|
||||
masterPane.getChildren().setAll(masterHintPane, label, clientsPane);
|
||||
}
|
||||
|
||||
BorderPane slavePane = new BorderPane();
|
||||
@ -187,13 +197,13 @@ public class MultiplayerPageSkin extends SkinBase<MultiplayerPage> {
|
||||
|
||||
Label label = new Label();
|
||||
label.textProperty().bind(Bindings.createStringBinding(() ->
|
||||
i18n("multiplayer.state.slave", control.getSession() == null ? "" : control.getSession().getName(), "0.0.0.0:" + control.getPort()),
|
||||
control.sessionProperty(), control.portProperty()));
|
||||
i18n("multiplayer.state.slave", control.getSession() == null ? "" : control.getSession().getName(), "0.0.0.0:" + control.getGamePort()),
|
||||
control.sessionProperty(), control.gamePortProperty()));
|
||||
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()));
|
||||
copyButton.setOnAction(e -> FXUtils.copyText("0.0.0.0:" + control.getGamePort()));
|
||||
slavePane.setRight(copyButton);
|
||||
}
|
||||
|
||||
@ -289,4 +299,15 @@ public class MultiplayerPageSkin extends SkinBase<MultiplayerPage> {
|
||||
return i18n("multiplayer.nat.type.unknown");
|
||||
}
|
||||
}
|
||||
|
||||
private static class ClientItem extends StackPane {
|
||||
ClientItem(MultiplayerServer.CatoClient client) {
|
||||
BorderPane pane = new BorderPane();
|
||||
pane.setLeft(new Label(client.getUsername()));
|
||||
|
||||
RipplerContainer container = new RipplerContainer(pane);
|
||||
getChildren().setAll(container);
|
||||
getStyleClass().add("md-list-cell");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,8 @@
|
||||
package org.jackhuang.hmcl.ui.multiplayer;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import org.jackhuang.hmcl.event.Event;
|
||||
import org.jackhuang.hmcl.event.EventManager;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.gson.JsonSubtype;
|
||||
import org.jackhuang.hmcl.util.gson.JsonType;
|
||||
@ -33,6 +35,8 @@ public class MultiplayerServer extends Thread {
|
||||
private ServerSocket socket;
|
||||
private final int gamePort;
|
||||
|
||||
private final EventManager<CatoClient> onClientAdded = new EventManager<CatoClient>();
|
||||
|
||||
public MultiplayerServer(int gamePort) {
|
||||
this.gamePort = gamePort;
|
||||
|
||||
@ -40,6 +44,10 @@ public class MultiplayerServer extends Thread {
|
||||
setDaemon(true);
|
||||
}
|
||||
|
||||
public EventManager<CatoClient> onClientAdded() {
|
||||
return onClientAdded;
|
||||
}
|
||||
|
||||
public void startServer() throws IOException {
|
||||
if (socket != null) {
|
||||
throw new IllegalStateException("MultiplayerServer already started");
|
||||
@ -59,6 +67,7 @@ public class MultiplayerServer extends Thread {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
LOG.info("Multiplayer Server listening 127.0.0.1:" + socket.getLocalPort());
|
||||
try {
|
||||
while (!isInterrupted()) {
|
||||
Socket clientSocket = socket.accept();
|
||||
@ -117,6 +126,8 @@ public class MultiplayerServer extends Thread {
|
||||
LOG.fine("Received join request with clientVersion=" + clientVersion + ", id=" + username);
|
||||
|
||||
writer.write(JsonUtils.GSON.toJson(new JoinResponse(server.gamePort)));
|
||||
|
||||
server.onClientAdded.fireEvent(new CatoClient(server, username));
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,4 +182,17 @@ public class MultiplayerServer extends Thread {
|
||||
return timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
public static class CatoClient extends Event {
|
||||
private final String username;
|
||||
|
||||
public CatoClient(Object source, String username) {
|
||||
super(source);
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -770,7 +770,6 @@ settings.game.java_directory=Java 路径
|
||||
settings.game.java_directory.auto=自动选择合适的 Java
|
||||
settings.game.java_directory.bit=,%s 位
|
||||
settings.game.java_directory.choose=选择 Java 路径
|
||||
settings.game.
|
||||
settings.game.management=管理
|
||||
settings.game.working_directory=版本隔离(修改后请自行移动相关游戏文件,如存档模组配置等)
|
||||
settings.game.working_directory.choose=选择运行路径
|
||||
|
@ -20,8 +20,7 @@ package org.jackhuang.hmcl.util;
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Range<T> {
|
||||
|
||||
public final class Range<T> {
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private enum ComparableComparator implements Comparator {
|
||||
|
Loading…
Reference in New Issue
Block a user