mirror of
https://github.com/GeyserMC/GeyserConnect.git
synced 2025-06-26 14:15:22 +02:00
Clean files and add comments
This commit is contained in:
parent
872ebdf76d
commit
516057e439
11 changed files with 82 additions and 48 deletions
|
@ -1,15 +1,7 @@
|
|||
package org.geysermc.multi;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.BedrockPacketCodec;
|
||||
import com.nukkitx.protocol.bedrock.v390.Bedrock_v390;
|
||||
|
||||
public class GeyserMulti {
|
||||
|
||||
public static final BedrockPacketCodec CODEC = Bedrock_v390.V390_CODEC;
|
||||
|
||||
private static MasterServer masterServer;
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
new MasterServer();
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package org.geysermc.multi;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.BedrockPong;
|
||||
import com.nukkitx.protocol.bedrock.BedrockServer;
|
||||
import com.nukkitx.protocol.bedrock.BedrockServerEventHandler;
|
||||
import com.nukkitx.protocol.bedrock.BedrockServerSession;
|
||||
import com.nukkitx.protocol.bedrock.*;
|
||||
import com.nukkitx.protocol.bedrock.v390.Bedrock_v390;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.multi.proxy.GeyserProxyBootstrap;
|
||||
import org.geysermc.multi.utils.Logger;
|
||||
|
@ -20,6 +18,8 @@ import java.util.concurrent.ScheduledExecutorService;
|
|||
|
||||
public class MasterServer {
|
||||
|
||||
public static final BedrockPacketCodec CODEC = Bedrock_v390.V390_CODEC;
|
||||
|
||||
private final Timer timer;
|
||||
private BedrockServer bdServer;
|
||||
private BedrockPong bdPong;
|
||||
|
@ -72,8 +72,8 @@ public class MasterServer {
|
|||
bdPong.setMaximumPlayerCount(1337);
|
||||
bdPong.setGameType("Survival");
|
||||
bdPong.setIpv4Port(port);
|
||||
bdPong.setProtocolVersion(GeyserMulti.CODEC.getProtocolVersion());
|
||||
bdPong.setVersion(GeyserMulti.CODEC.getMinecraftVersion());
|
||||
bdPong.setProtocolVersion(MasterServer.CODEC.getProtocolVersion());
|
||||
bdPong.setVersion(MasterServer.CODEC.getMinecraftVersion());
|
||||
|
||||
bdServer.setHandler(new BedrockServerEventHandler() {
|
||||
@Override
|
||||
|
|
|
@ -48,9 +48,9 @@ public class PacketHandler implements BedrockPacketHandler {
|
|||
|
||||
// Check the protocol version is correct
|
||||
int protocol = packet.getProtocolVersion();
|
||||
if (protocol != GeyserMulti.CODEC.getProtocolVersion()) {
|
||||
if (protocol != MasterServer.CODEC.getProtocolVersion()) {
|
||||
PlayStatusPacket status = new PlayStatusPacket();
|
||||
if (protocol > GeyserMulti.CODEC.getProtocolVersion()) {
|
||||
if (protocol > MasterServer.CODEC.getProtocolVersion()) {
|
||||
status.setStatus(PlayStatusPacket.Status.FAILED_SERVER);
|
||||
} else {
|
||||
status.setStatus(PlayStatusPacket.Status.FAILED_CLIENT);
|
||||
|
@ -59,8 +59,9 @@ public class PacketHandler implements BedrockPacketHandler {
|
|||
}
|
||||
|
||||
// Set the session codec
|
||||
session.setPacketCodec(GeyserMulti.CODEC);
|
||||
session.setPacketCodec(MasterServer.CODEC);
|
||||
|
||||
// Read the raw chain data
|
||||
JsonNode rawChainData;
|
||||
try {
|
||||
rawChainData = OBJECT_MAPPER.readTree(packet.getChainData().toByteArray());
|
||||
|
@ -68,6 +69,7 @@ public class PacketHandler implements BedrockPacketHandler {
|
|||
throw new AssertionError("Unable to read chain data!");
|
||||
}
|
||||
|
||||
// Get the parsed chain data
|
||||
JsonNode chainData = rawChainData.get("chain");
|
||||
if (chainData.getNodeType() != JsonNodeType.ARRAY) {
|
||||
throw new AssertionError("Invalid chain data!");
|
||||
|
@ -78,22 +80,29 @@ public class PacketHandler implements BedrockPacketHandler {
|
|||
JWSObject jwsObject;
|
||||
jwsObject = JWSObject.parse(chainData.get(chainData.size() - 1).asText());
|
||||
|
||||
// Read the JWS payload
|
||||
JsonNode payload = OBJECT_MAPPER.readTree(jwsObject.getPayload().toBytes());
|
||||
|
||||
// Check the identityPublicKey is there
|
||||
if (payload.get("identityPublicKey").getNodeType() != JsonNodeType.STRING) {
|
||||
throw new AssertionError("Missing identity public key!");
|
||||
}
|
||||
|
||||
// Create an ECPublicKey from the identityPublicKey
|
||||
ECPublicKey identityPublicKey = EncryptionUtils.generateKey(payload.get("identityPublicKey").textValue());
|
||||
|
||||
// Get the skin data to validate the JWS token
|
||||
JWSObject skinData = JWSObject.parse(packet.getSkinData().toString());
|
||||
if (skinData.verify(new DefaultJWSVerifierFactory().createJWSVerifier(skinData.getHeader(), identityPublicKey))) {
|
||||
// Make sure the client sent over the username, xuid and other info
|
||||
if (payload.get("extraData").getNodeType() != JsonNodeType.OBJECT) {
|
||||
throw new AssertionError("Missing client data");
|
||||
}
|
||||
|
||||
// Fetch the client data
|
||||
JsonNode extraData = payload.get("extraData");
|
||||
|
||||
// Create a new player and add it to the players list
|
||||
player = new Player(extraData, session);
|
||||
masterServer.getPlayers().put(session.getAddress(), player);
|
||||
|
||||
|
@ -145,26 +154,25 @@ public class PacketHandler implements BedrockPacketHandler {
|
|||
|
||||
player.sendWindow(FormID.MAIN, UIHandler.getServerListFormPacket(player.getServers()));;
|
||||
|
||||
/*TransferPacket transferPacket = new TransferPacket();
|
||||
transferPacket.setAddress("81.174.164.211");
|
||||
transferPacket.setPort(27040);
|
||||
session.sendPacket(transferPacket);*/
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(ModalFormResponsePacket packet) {
|
||||
// Make sure the form is valid
|
||||
FormID id = FormID.fromId(packet.getFormId());
|
||||
if (id != player.getCurrentWindowId())
|
||||
return false;
|
||||
|
||||
// Fetch the form and parse the response
|
||||
FormWindow window = player.getCurrentWindow();
|
||||
window.setResponse(packet.getFormData().trim());
|
||||
|
||||
// Resend the form if they closed it
|
||||
if (window.getResponse() == null) {
|
||||
player.resendWindow();
|
||||
} else {
|
||||
// Send the response to the correct response function
|
||||
switch (id) {
|
||||
case MAIN:
|
||||
UIHandler.handleServerListResponse(player, (SimpleFormResponse) window.getResponse());
|
||||
|
@ -178,10 +186,4 @@ public class PacketHandler implements BedrockPacketHandler {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(NetworkStackLatencyPacket packet) {
|
||||
masterServer.getLogger().debug(packet.toString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,8 +29,10 @@ public class GeyserProxyBootstrap implements GeyserBootstrap {
|
|||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
// Setup a logger
|
||||
geyserLogger = new GeyserProxyLogger();
|
||||
|
||||
// Read the static config from resources
|
||||
try {
|
||||
InputStream configFile = GeyserProxyBootstrap.class.getClassLoader().getResourceAsStream("proxy_config.yml");
|
||||
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
|
||||
|
@ -39,13 +41,18 @@ public class GeyserProxyBootstrap implements GeyserBootstrap {
|
|||
geyserLogger.severe("Failed to read proxy_config.yml! Make sure it's up to date and/or readable+writable!", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
// Not sure there is a point in doing this as its a static config
|
||||
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
|
||||
|
||||
// Create the connector and command manager
|
||||
connector = GeyserConnector.start(PlatformType.STANDALONE, this);
|
||||
geyserCommandManager = new GeyserProxyCommandManager(connector);
|
||||
|
||||
// Start the ping passthrough thread, again don't think there is a point
|
||||
geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector);
|
||||
|
||||
// Swap the normal handler to our custom handler so we can change some
|
||||
connector.getBedrockServer().setHandler(new ProxyConnectorServerEventHandler(connector));
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import java.nio.file.Paths;
|
|||
public class GeyserProxyConfiguration extends GeyserJacksonConfiguration {
|
||||
|
||||
@JsonProperty("floodgate-key-file")
|
||||
private String floodgateKeyFile = "";
|
||||
private String floodgateKeyFile;
|
||||
|
||||
@Override
|
||||
public Path getFloodgateKeyFile() {
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
package org.geysermc.multi.proxy;
|
||||
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.apache.logging.log4j.core.config.Configurator;
|
||||
import org.geysermc.common.ChatColor;
|
||||
import org.geysermc.multi.utils.Logger;
|
||||
|
||||
@Log4j2
|
||||
public class GeyserProxyLogger extends Logger {
|
||||
/**
|
||||
* Disable debug messages
|
||||
*/
|
||||
public void debug(String message) { }
|
||||
}
|
||||
|
|
|
@ -18,12 +18,15 @@ public class GeyserProxySession extends GeyserSession {
|
|||
}
|
||||
|
||||
public void authenticate(String username, String password) {
|
||||
// Get the player based on the connection address
|
||||
Player player = MasterServer.getInstance().getPlayers().get(bedrockServerSession.getAddress());
|
||||
if (player != null) {
|
||||
if (player != null && player.getCurrentServer() != null) {
|
||||
// Set the remote server info for the player
|
||||
connector.getRemoteServer().setAddress(player.getCurrentServer().getAddress());
|
||||
connector.getRemoteServer().setPort(player.getCurrentServer().getPort());
|
||||
super.authenticate(username, password);
|
||||
}else{
|
||||
// Disconnect the player if they haven't picked a server on the master server list
|
||||
bedrockServerSession.disconnect("Please connect to the master server and pick a server first!");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import com.nukkitx.protocol.bedrock.BedrockServerSession;
|
|||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.ConnectorServerEventHandler;
|
||||
import org.geysermc.connector.network.UpstreamPacketHandler;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.multi.MasterServer;
|
||||
import org.geysermc.multi.utils.Player;
|
||||
|
||||
|
@ -27,7 +26,11 @@ public class ProxyConnectorServerEventHandler extends ConnectorServerEventHandle
|
|||
|
||||
super.onSessionCreation(bedrockServerSession);
|
||||
|
||||
// This doesn't clean up the old packet handler, so may cause a memory leak?
|
||||
bedrockServerSession.setPacketHandler(new UpstreamPacketHandler(connector, new GeyserProxySession(connector, bedrockServerSession)));
|
||||
bedrockServerSession.setPacketCodec(GeyserConnector.BEDROCK_PACKET_CODEC); // Only done here as it sometimes gets cleared
|
||||
|
||||
// Add another disconnect handler to remove the player on final disconnect
|
||||
bedrockServerSession.addDisconnectHandler(disconnectReason -> {
|
||||
MasterServer.getInstance().getLogger().debug("Player disconnected from geyser proxy: " + player.getDisplayName() + " (" + disconnectReason + ")");
|
||||
MasterServer.getInstance().getPlayers().remove(bedrockServerSession.getAddress());
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package org.geysermc.multi.ui;
|
||||
|
||||
import com.nukkitx.protocol.bedrock.packet.TransferPacket;
|
||||
import org.geysermc.common.window.FormWindow;
|
||||
import org.geysermc.common.window.SimpleFormWindow;
|
||||
import org.geysermc.common.window.button.FormButton;
|
||||
|
@ -13,34 +12,52 @@ import org.geysermc.multi.utils.Server;
|
|||
import java.util.List;
|
||||
|
||||
public class UIHandler {
|
||||
/**
|
||||
* Create a list of servers for the client based on the passed servers list
|
||||
*
|
||||
* @param servers A list of {@link Server} objects
|
||||
* @return A {@link SimpleFormWindow} object
|
||||
*/
|
||||
public static FormWindow getServerListFormPacket(List<Server> servers) {
|
||||
SimpleFormWindow window = new SimpleFormWindow("Servers", "");
|
||||
|
||||
// Add a button for each server with the server icon as the image
|
||||
for (Server server : servers) {
|
||||
window.getButtons().add(new FormButton(server.getAddress(), new FormImage(FormImage.FormImageType.URL, "https://eu.mc-api.net/v3/server/favicon/" + server.getAddress() + ":" + server.getPort() + ".png")));
|
||||
window.getButtons().add(new FormButton(server.toString(), new FormImage(FormImage.FormImageType.URL, "https://eu.mc-api.net/v3/server/favicon/" + server.getAddress() + ":" + server.getPort() + ".png")));
|
||||
}
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a simple connecting message form
|
||||
*
|
||||
* @param server The server info to display
|
||||
* @return A {@link SimpleFormWindow} object
|
||||
*/
|
||||
public static FormWindow getWaitingScreen(Server server) {
|
||||
SimpleFormWindow window = new SimpleFormWindow("Servers", "Please wait while we connect you to " + server.toString());
|
||||
SimpleFormWindow window = new SimpleFormWindow("Connecting", "Please wait while we connect you to " + server.toString());
|
||||
return window;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the server list response
|
||||
*
|
||||
* @param player The player that submitted the response
|
||||
* @param data The form response data
|
||||
*/
|
||||
public static void handleServerListResponse(Player player, SimpleFormResponse data) {
|
||||
MasterServer.getInstance().getLogger().debug(data.getClickedButton().getText());
|
||||
|
||||
// Get the server
|
||||
Server server = player.getServers().get(data.getClickedButtonId());
|
||||
|
||||
// Tell the user we are connecting them
|
||||
// this wont show up in alot of cases as the client connects quite quickly
|
||||
player.sendWindow(FormID.CONNECTING, getWaitingScreen(server));
|
||||
|
||||
// Create the geyser instance if its not already running
|
||||
// Create the Geyser instance if its not already running
|
||||
MasterServer.getInstance().createGeyserProxy();
|
||||
|
||||
// Send the user over to the serverty
|
||||
// Send the user over to the server
|
||||
player.setCurrentServer(server);
|
||||
player.connectToProxy();
|
||||
}
|
||||
|
|
|
@ -11,10 +11,8 @@ import lombok.Getter;
|
|||
import lombok.Setter;
|
||||
import org.geysermc.common.window.FormWindow;
|
||||
import org.geysermc.multi.MasterServer;
|
||||
import org.geysermc.multi.proxy.GeyserProxyBootstrap;
|
||||
import org.geysermc.multi.ui.FormID;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
@ -48,7 +46,11 @@ public class Player {
|
|||
servers.add(new Server("81.174.164.211", 25580));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a few different packets to get the client to load in
|
||||
*/
|
||||
public void sendStartGame() {
|
||||
// A lot of this likely doesn't need to be changed
|
||||
StartGamePacket startGamePacket = new StartGamePacket();
|
||||
startGamePacket.setUniqueEntityId(1);
|
||||
startGamePacket.setRuntimeEntityId(1);
|
||||
|
@ -94,9 +96,7 @@ public class Player {
|
|||
startGamePacket.setEnchantmentSeed(0);
|
||||
startGamePacket.setMultiplayerCorrelationId("");
|
||||
startGamePacket.setBlockPalette(PalleteManger.BLOCK_PALLETE);
|
||||
//startGamePacket.setItemEntries(ItemRegistry.ITEMS);
|
||||
startGamePacket.setVanillaVersion("*");
|
||||
// startGamePacket.setMovementServerAuthoritative(true);
|
||||
session.sendPacket(startGamePacket);
|
||||
|
||||
// Send an empty chunk
|
||||
|
@ -125,7 +125,13 @@ public class Player {
|
|||
session.sendPacket(setEntityMotionPacket);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a window with the specified id and content
|
||||
* Also cache it against the player for later use
|
||||
*
|
||||
* @param id The {@link FormID} to use for the form
|
||||
* @param window The {@link FormWindow} to turn into json and send
|
||||
*/
|
||||
public void sendWindow(FormID id, FormWindow window) {
|
||||
this.currentWindow = window;
|
||||
this.currentWindowId = id;
|
||||
|
@ -133,16 +139,19 @@ public class Player {
|
|||
ModalFormRequestPacket modalFormRequestPacket = new ModalFormRequestPacket();
|
||||
modalFormRequestPacket.setFormId(id.ordinal());
|
||||
modalFormRequestPacket.setFormData(window.getJSONData());
|
||||
session.sendPacket(modalFormRequestPacket);
|
||||
session.sendPacketImmediately(modalFormRequestPacket);
|
||||
}
|
||||
|
||||
public void resendWindow() {
|
||||
sendWindow(currentWindowId, currentWindow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the player to the Geyser proxy server
|
||||
*/
|
||||
public void connectToProxy() {
|
||||
TransferPacket transferPacket = new TransferPacket();
|
||||
transferPacket.setAddress("127.0.0.1");
|
||||
transferPacket.setAddress("127.0.0.1"); // Need to find a good way of getting this
|
||||
transferPacket.setPort(MasterServer.getInstance().getGeyserProxy().getGeyserConfig().getBedrock().getPort());
|
||||
session.sendPacket(transferPacket);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,6 @@ public class Server {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return address + ":" + port;
|
||||
return address + (port != 25565 ? ":" + port : "");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue