From 76ab6657c7b49fe7dbeb08cdedd6f18716ec3a12 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Sat, 5 Jun 2021 00:48:07 +0100 Subject: [PATCH] Move to a more linear connection flow and remove the need for a second port --- .../org/geysermc/connect/MasterServer.java | 3 + .../org/geysermc/connect/PacketHandler.java | 14 ++-- .../connect/proxy/GeyserProxySession.java | 64 ------------------ .../GeyserProxyUpstreamPacketHandler.java | 50 -------------- .../ProxyConnectorServerEventHandler.java | 39 +---------- .../connect/storage/JsonStorageManager.java | 4 +- .../connect/storage/MySQLStorageManager.java | 4 +- .../connect/storage/SQLiteStorageManager.java | 4 +- .../org/geysermc/connect/utils/Player.java | 67 +++++++++++++------ 9 files changed, 62 insertions(+), 187 deletions(-) delete mode 100644 src/main/java/org/geysermc/connect/proxy/GeyserProxySession.java delete mode 100644 src/main/java/org/geysermc/connect/proxy/GeyserProxyUpstreamPacketHandler.java diff --git a/src/main/java/org/geysermc/connect/MasterServer.java b/src/main/java/org/geysermc/connect/MasterServer.java index 7c01eea..51d967c 100644 --- a/src/main/java/org/geysermc/connect/MasterServer.java +++ b/src/main/java/org/geysermc/connect/MasterServer.java @@ -200,6 +200,9 @@ public class MasterServer { public void createGeyserProxy() { if (geyserProxy == null) { + // Make sure Geyser doesn't start the listener + GeyserConnector.setShouldStartListener(false); + this.geyserProxy = new GeyserProxyBootstrap(); geyserProxy.onEnable(); } diff --git a/src/main/java/org/geysermc/connect/PacketHandler.java b/src/main/java/org/geysermc/connect/PacketHandler.java index f40e778..bd4864e 100644 --- a/src/main/java/org/geysermc/connect/PacketHandler.java +++ b/src/main/java/org/geysermc/connect/PacketHandler.java @@ -76,13 +76,13 @@ public class PacketHandler implements BedrockPacketHandler { public void disconnect(DisconnectReason reason) { if (player != null) { - masterServer.getLogger().info(player.getDisplayName() + " has disconnected from the master server (" + reason + ")"); + masterServer.getLogger().info(player.getAuthData().getName() + " has disconnected from the master server (" + reason + ")"); masterServer.getStorageManager().saveServers(player); if (player.getCurrentServer() != null && !player.getCurrentServer().isBedrock()) { - masterServer.getTransferringPlayers().put(player.getXuid(), player); + masterServer.getTransferringPlayers().put(player.getAuthData().getXboxUUID(), player); } - masterServer.getPlayers().remove(player.getXuid(), player); + masterServer.getPlayers().remove(player.getAuthData().getXboxUUID(), player); } } @@ -155,7 +155,7 @@ public class PacketHandler implements BedrockPacketHandler { // Create a new player and add it to the players list player = new Player(extraData, session); - masterServer.getPlayers().put(player.getXuid(), player); + masterServer.getPlayers().put(player.getAuthData().getXboxUUID(), player); // Store the full client data player.setClientData(OBJECT_MAPPER.convertValue(OBJECT_MAPPER.readTree(skinData.getPayload().toBytes()), BedrockClientData.class)); @@ -184,7 +184,7 @@ public class PacketHandler implements BedrockPacketHandler { public boolean handle(ResourcePackClientResponsePacket packet) { switch (packet.getStatus()) { case COMPLETED: - masterServer.getLogger().info("Logged in " + player.getDisplayName() + " (" + player.getXuid() + ", " + player.getIdentity() + ")"); + masterServer.getLogger().info("Logged in " + player.getAuthData().getName() + " (" + player.getAuthData().getXboxUUID() + ", " + player.getAuthData().getUUID() + ")"); player.sendStartGame(); break; case HAVE_ALL_PACKS: @@ -204,7 +204,7 @@ public class PacketHandler implements BedrockPacketHandler { @Override public boolean handle(SetLocalPlayerAsInitializedPacket packet) { - masterServer.getLogger().debug("Player initialized: " + player.getDisplayName()); + masterServer.getLogger().debug("Player initialized: " + player.getAuthData().getName()); // Handle the virtual host if specified GeyserConnectConfig.VirtualHostSection vhost = MasterServer.getInstance().getGeyserConnectConfig().getVhost(); @@ -235,7 +235,7 @@ public class PacketHandler implements BedrockPacketHandler { } // Log the virtual host usage - masterServer.getLogger().info(player.getDisplayName() + " is using virtualhost: " + address + ":" + port + (!online ? " (offline)" : "")); + masterServer.getLogger().info(player.getAuthData().getName() + " is using virtualhost: " + address + ":" + port + (!online ? " (offline)" : "")); // Send the player to the wanted server player.sendToServer(new Server(address, port, online, false)); diff --git a/src/main/java/org/geysermc/connect/proxy/GeyserProxySession.java b/src/main/java/org/geysermc/connect/proxy/GeyserProxySession.java deleted file mode 100644 index f6909bb..0000000 --- a/src/main/java/org/geysermc/connect/proxy/GeyserProxySession.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/GeyserConnect - */ - -package org.geysermc.connect.proxy; - -import com.nukkitx.protocol.bedrock.BedrockServerSession; -import lombok.Getter; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.common.AuthType; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connect.MasterServer; -import org.geysermc.connect.utils.Player; -import org.geysermc.connector.network.session.auth.AuthData; - -public class GeyserProxySession extends GeyserSession { - - private final BedrockServerSession bedrockServerSession; - @Getter - private Player player; - - public GeyserProxySession(GeyserConnector connector, BedrockServerSession bedrockServerSession) { - super(connector, bedrockServerSession); - this.bedrockServerSession = bedrockServerSession; - } - - @Override - public void setAuthenticationData(AuthData authData) { - super.setAuthenticationData(authData); - - player = MasterServer.getInstance().getTransferringPlayers().getIfPresent(authData.getXboxUUID()); - if (player == null) { - bedrockServerSession.disconnect("Please connect to the master server and pick a server first!"); - } else { - MasterServer.getInstance().getTransferringPlayers().invalidate(authData.getXboxUUID()); - } - } - - @Override - protected void disableSrvResolving() { - // Do nothing - } -} diff --git a/src/main/java/org/geysermc/connect/proxy/GeyserProxyUpstreamPacketHandler.java b/src/main/java/org/geysermc/connect/proxy/GeyserProxyUpstreamPacketHandler.java deleted file mode 100644 index 3396f0a..0000000 --- a/src/main/java/org/geysermc/connect/proxy/GeyserProxyUpstreamPacketHandler.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/GeyserConnect - */ - -package org.geysermc.connect.proxy; - -import com.nukkitx.protocol.bedrock.packet.SetLocalPlayerAsInitializedPacket; -import org.geysermc.connect.MasterServer; -import org.geysermc.connect.utils.Player; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.common.AuthType; -import org.geysermc.connector.network.UpstreamPacketHandler; -import org.geysermc.connector.network.session.GeyserSession; - -public class GeyserProxyUpstreamPacketHandler extends UpstreamPacketHandler { - public GeyserProxyUpstreamPacketHandler(GeyserConnector connector, GeyserSession session) { - super(connector, session); - } - - @Override - public boolean handle(SetLocalPlayerAsInitializedPacket packet) { - Player player = ((GeyserProxySession) session).getPlayer(); - session.setRemoteAddress(player.getCurrentServer().getAddress()); - session.setRemotePort(player.getCurrentServer().getPort()); - session.setRemoteAuthType(player.getCurrentServer().isOnline() ? AuthType.ONLINE : AuthType.OFFLINE); - - return super.handle(packet); - } -} diff --git a/src/main/java/org/geysermc/connect/proxy/ProxyConnectorServerEventHandler.java b/src/main/java/org/geysermc/connect/proxy/ProxyConnectorServerEventHandler.java index ab95c05..8551d51 100644 --- a/src/main/java/org/geysermc/connect/proxy/ProxyConnectorServerEventHandler.java +++ b/src/main/java/org/geysermc/connect/proxy/ProxyConnectorServerEventHandler.java @@ -35,50 +35,13 @@ import java.util.concurrent.TimeUnit; public class ProxyConnectorServerEventHandler extends ConnectorServerEventHandler { - private final GeyserConnector connector; - public ProxyConnectorServerEventHandler(GeyserConnector connector) { super(connector); - this.connector = connector; - MasterServer.getInstance().getLogger().debug("Registered custom ConnectorServerEventHandler"); } @Override public void onSessionCreation(BedrockServerSession bedrockServerSession) { super.onSessionCreation(bedrockServerSession); - - // This doesn't clean up the old packet handler, so may cause a memory leak? - GeyserProxySession session = new GeyserProxySession(connector, bedrockServerSession); - bedrockServerSession.setPacketHandler(new GeyserProxyUpstreamPacketHandler(connector, session)); - - // Add another disconnect handler to remove the player on final disconnect - bedrockServerSession.addDisconnectHandler(disconnectReason -> { - // Make sure nothing is null before locating the player - if (MasterServer.getInstance() == null - || session.getAuthData() == null - || session.getAuthData().getXboxUUID() == null) { - return; - } - - Player player = session.getPlayer(); - if (player != null) { - MasterServer.getInstance().getLogger().debug("Player disconnected from Geyser proxy: " + player.getDisplayName() + " (" + disconnectReason + ")"); - - // Set the last disconnect time - MasterServer.getInstance().setLastDisconnectTime(System.currentTimeMillis()); - - int shutdownTime = MasterServer.getInstance().getGeyserConnectConfig().getGeyser().getShutdownTime(); - - if (shutdownTime != -1) { - MasterServer.getInstance().getGeneralThreadPool().schedule(() -> { - if (System.currentTimeMillis() - MasterServer.getInstance().getLastDisconnectTime() > shutdownTime * 1000L - && connector != null - && connector.getPlayers().size() <= 0) { - MasterServer.getInstance().shutdownGeyserProxy(); - } - }, shutdownTime, TimeUnit.SECONDS); - } - } - }); + bedrockServerSession.disconnect("Not sure how you managed it, but you shouldn't be here!"); } } diff --git a/src/main/java/org/geysermc/connect/storage/JsonStorageManager.java b/src/main/java/org/geysermc/connect/storage/JsonStorageManager.java index d51e560..6f79913 100644 --- a/src/main/java/org/geysermc/connect/storage/JsonStorageManager.java +++ b/src/main/java/org/geysermc/connect/storage/JsonStorageManager.java @@ -51,7 +51,7 @@ public class JsonStorageManager extends AbstractStorageManager { @Override public void saveServers(Player player) { try { - mapper.writeValue(dataFolder.resolve(player.getXuid() + ".json").toFile(), player.getServers()); + mapper.writeValue(dataFolder.resolve(player.getAuthData().getXboxUUID() + ".json").toFile(), player.getServers()); } catch (IOException ignored) { } } @@ -60,7 +60,7 @@ public class JsonStorageManager extends AbstractStorageManager { List servers = new ArrayList<>(); try { - List loadedServers = mapper.readValue(dataFolder.resolve(player.getXuid() + ".json").toFile(), new TypeReference>(){}); + List loadedServers = mapper.readValue(dataFolder.resolve(player.getAuthData().getXboxUUID() + ".json").toFile(), new TypeReference>(){}); servers.addAll(loadedServers); } catch (IOException ignored) { } diff --git a/src/main/java/org/geysermc/connect/storage/MySQLStorageManager.java b/src/main/java/org/geysermc/connect/storage/MySQLStorageManager.java index 68f3bb7..7d6cc31 100644 --- a/src/main/java/org/geysermc/connect/storage/MySQLStorageManager.java +++ b/src/main/java/org/geysermc/connect/storage/MySQLStorageManager.java @@ -69,7 +69,7 @@ public class MySQLStorageManager extends AbstractStorageManager { public void saveServers(Player player) { try { Statement updatePlayersServers = connection.createStatement(); - updatePlayersServers.executeUpdate("REPLACE INTO players(xuid, servers) VALUES('" + player.getXuid() + "', '" + mapper.writeValueAsString(player.getServers()) + "');"); + updatePlayersServers.executeUpdate("REPLACE INTO players(xuid, servers) VALUES('" + player.getAuthData().getXboxUUID() + "', '" + mapper.writeValueAsString(player.getServers()) + "');"); updatePlayersServers.close(); } catch (IOException | SQLException ignored) { } } @@ -80,7 +80,7 @@ public class MySQLStorageManager extends AbstractStorageManager { try { Statement getPlayersServers = connection.createStatement(); - ResultSet rs = getPlayersServers.executeQuery("SELECT servers FROM players WHERE xuid='" + player.getXuid() + "';"); + ResultSet rs = getPlayersServers.executeQuery("SELECT servers FROM players WHERE xuid='" + player.getAuthData().getXboxUUID() + "';"); while (rs.next()) { List loadedServers = mapper.readValue(rs.getString("servers"), new TypeReference>(){}); diff --git a/src/main/java/org/geysermc/connect/storage/SQLiteStorageManager.java b/src/main/java/org/geysermc/connect/storage/SQLiteStorageManager.java index b20aca5..6a3dcfd 100644 --- a/src/main/java/org/geysermc/connect/storage/SQLiteStorageManager.java +++ b/src/main/java/org/geysermc/connect/storage/SQLiteStorageManager.java @@ -67,7 +67,7 @@ public class SQLiteStorageManager extends AbstractStorageManager { public void saveServers(Player player) { try { Statement updatePlayersServers = connection.createStatement(); - updatePlayersServers.executeUpdate("INSERT OR REPLACE INTO players(xuid, servers) VALUES('" + player.getXuid() + "', '" + mapper.writeValueAsString(player.getServers()) + "');"); + updatePlayersServers.executeUpdate("INSERT OR REPLACE INTO players(xuid, servers) VALUES('" + player.getAuthData().getXboxUUID() + "', '" + mapper.writeValueAsString(player.getServers()) + "');"); updatePlayersServers.close(); } catch (IOException | SQLException ignored) { } } @@ -78,7 +78,7 @@ public class SQLiteStorageManager extends AbstractStorageManager { try { Statement getPlayersServers = connection.createStatement(); - ResultSet rs = getPlayersServers.executeQuery("SELECT servers FROM players WHERE xuid='" + player.getXuid() + "';"); + ResultSet rs = getPlayersServers.executeQuery("SELECT servers FROM players WHERE xuid='" + player.getAuthData().getXboxUUID() + "';"); while (rs.next()) { List loadedServers = mapper.readValue(rs.getString("servers"), new TypeReference>() {}); diff --git a/src/main/java/org/geysermc/connect/utils/Player.java b/src/main/java/org/geysermc/connect/utils/Player.java index 725de67..e056bf7 100644 --- a/src/main/java/org/geysermc/connect/utils/Player.java +++ b/src/main/java/org/geysermc/connect/utils/Player.java @@ -33,6 +33,7 @@ import com.nukkitx.protocol.bedrock.BedrockServerSession; import com.nukkitx.protocol.bedrock.data.*; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.*; +import com.nukkitx.protocol.bedrock.v428.Bedrock_v428; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import lombok.Getter; @@ -41,7 +42,15 @@ import org.geysermc.common.window.FormWindow; import org.geysermc.connect.MasterServer; import org.geysermc.connect.ui.FormID; import org.geysermc.connect.ui.UIHandler; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.common.AuthType; +import org.geysermc.connector.network.UpstreamPacketHandler; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.session.auth.AuthData; import org.geysermc.connector.network.session.auth.BedrockClientData; +import org.geysermc.connector.network.translators.world.block.BlockTranslator1_16_100; +import org.geysermc.connector.network.translators.world.block.BlockTranslator1_16_210; +import org.geysermc.connector.utils.DimensionUtils; import java.util.ArrayList; import java.util.List; @@ -50,9 +59,7 @@ import java.util.UUID; @Getter public class Player { - private final String xuid; - private final UUID identity; - private final String displayName; + private final AuthData authData; private final BedrockServerSession session; @@ -72,9 +79,11 @@ public class Player { private ServerCategory serverCategory; public Player(JsonNode extraData, BedrockServerSession session) { - this.xuid = extraData.get("XUID").asText(); - this.identity = UUID.fromString(extraData.get("identity").asText()); - this.displayName = extraData.get("displayName").asText(); + this.authData = new AuthData( + extraData.get("displayName").asText(), + UUID.fromString(extraData.get("identity").asText()), + extraData.get("XUID").asText() + ); this.session = session; @@ -206,29 +215,43 @@ public class Player { * Send the player to the Geyser proxy server or straight to the bedrock server if it is */ public void connectToProxy() { - // Use the clients connecting IP then fallback to the remote address from config - String address = clientData.getServerAddress().split(":")[0].trim(); - if (address.isEmpty()) { - address = MasterServer.getInstance().getGeyserConnectConfig().getRemoteAddress(); - } - - int port = MasterServer.getInstance().getGeyserConnectConfig().getGeyser().getPort(); - if (currentServer.isBedrock()) { - address = currentServer.getAddress(); - port = currentServer.getPort(); - } + TransferPacket transferPacket = new TransferPacket(); + transferPacket.setAddress(currentServer.getAddress()); + transferPacket.setPort(currentServer.getPort()); + session.sendPacket(transferPacket); + } else { + GeyserSession geyserSession = new GeyserSession(GeyserConnector.getInstance(), session); + session.setPacketHandler(new UpstreamPacketHandler(GeyserConnector.getInstance(), geyserSession)); - TransferPacket transferPacket = new TransferPacket(); - transferPacket.setAddress(address); - transferPacket.setPort(port); - session.sendPacket(transferPacket); + geyserSession.getUpstream().getSession().setPacketCodec(session.getPacketCodec()); + + // Set the block translation based off of version + geyserSession.setBlockTranslator(session.getPacketCodec().getProtocolVersion() >= Bedrock_v428.V428_CODEC.getProtocolVersion() + ? BlockTranslator1_16_210.INSTANCE : BlockTranslator1_16_100.INSTANCE); + + geyserSession.setAuthData(authData); + geyserSession.setClientData(clientData); + + geyserSession.setDimension(DimensionUtils.THE_END); + + geyserSession.setRemoteAddress(currentServer.getAddress()); + geyserSession.setRemotePort(currentServer.getPort()); + geyserSession.setRemoteAuthType(currentServer.isOnline() ? AuthType.ONLINE : AuthType.OFFLINE); + + // Tell Geyser to handle the login + SetLocalPlayerAsInitializedPacket initializedPacket = new SetLocalPlayerAsInitializedPacket(); + initializedPacket.setRuntimeEntityId(geyserSession.getPlayerEntity().getGeyserId()); + session.getPacketHandler().handle(initializedPacket); + } } public void sendToServer(Server server) { // Tell the user we are connecting them // This wont show up in a lot of cases as the client connects quite quickly - sendWindow(FormID.CONNECTING, UIHandler.getWaitingScreen(server)); + if (!server.isOnline()) { + sendWindow(FormID.CONNECTING, UIHandler.getWaitingScreen(server)); + } if (!server.isBedrock()) { // Create the Geyser instance if its not already running