mirror of
https://github.com/GeyserMC/GeyserConnect.git
synced 2025-06-26 22:16:37 +02:00
Move to a more linear connection flow and remove the need for a second port
This commit is contained in:
parent
6b874def46
commit
76ab6657c7
9 changed files with 62 additions and 187 deletions
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Server> servers = new ArrayList<>();
|
||||
|
||||
try {
|
||||
List<Server> loadedServers = mapper.readValue(dataFolder.resolve(player.getXuid() + ".json").toFile(), new TypeReference<List<Server>>(){});
|
||||
List<Server> loadedServers = mapper.readValue(dataFolder.resolve(player.getAuthData().getXboxUUID() + ".json").toFile(), new TypeReference<List<Server>>(){});
|
||||
servers.addAll(loadedServers);
|
||||
} catch (IOException ignored) { }
|
||||
|
||||
|
|
|
@ -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<Server> loadedServers = mapper.readValue(rs.getString("servers"), new TypeReference<List<Server>>(){});
|
||||
|
|
|
@ -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<Server> loadedServers = mapper.readValue(rs.getString("servers"), new TypeReference<List<Server>>() {});
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue