From 7751c2a42887e617dfe04f9dc95933b172d6437f Mon Sep 17 00:00:00 2001 From: Adrian Bergqvist Date: Sat, 25 Jun 2022 03:56:46 +0200 Subject: [PATCH] WIP, not tested yet --- .../org/adde0109/ambassador/Ambassador.java | 68 +++++++++++++++- .../adde0109/ambassador/ForgeConnection.java | 51 ++++++++++++ .../ambassador/ForgeHandshakeDataHandler.java | 79 ++++++------------- .../ambassador/ForgeServerConnection.java | 58 ++++++++++++++ 4 files changed, 201 insertions(+), 55 deletions(-) create mode 100644 src/main/java/org/adde0109/ambassador/ForgeConnection.java create mode 100644 src/main/java/org/adde0109/ambassador/ForgeServerConnection.java diff --git a/src/main/java/org/adde0109/ambassador/Ambassador.java b/src/main/java/org/adde0109/ambassador/Ambassador.java index 61e9269..4d5bbde 100644 --- a/src/main/java/org/adde0109/ambassador/Ambassador.java +++ b/src/main/java/org/adde0109/ambassador/Ambassador.java @@ -1,13 +1,18 @@ package org.adde0109.ambassador; import com.google.inject.Inject; +import com.velocitypowered.api.event.Continuation; import com.velocitypowered.api.event.Subscribe; +import com.velocitypowered.api.event.connection.PreLoginEvent; import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; import com.velocitypowered.api.plugin.Plugin; import com.velocitypowered.api.plugin.annotation.DataDirectory; +import com.velocitypowered.api.proxy.LoginPhaseConnection; import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.server.RegisteredServer; +import java.net.InetSocketAddress; +import java.util.concurrent.atomic.AtomicBoolean; import org.slf4j.Logger; import java.nio.file.Path; @@ -24,6 +29,9 @@ public class Ambassador { private static ForgeHandshakeDataHandler forgeHandshakeDataHandler; + public Map forgeServerConnectionMap; + public Map incomingForgeConnections; + @Inject public Ambassador(ProxyServer server, Logger logger, @DataDirectory Path dataDirectory) { this.server = server; @@ -35,7 +43,7 @@ public class Ambassador { public void onProxyInitialization(ProxyInitializeEvent event) { config = AmbassadorConfig.readOrCreateConfig(dataDirectory,server,logger); if(config != null) { - forgeHandshakeDataHandler = new ForgeHandshakeDataHandler(config,logger,server); + forgeHandshakeDataHandler = new ForgeHandshakeDataHandler(logger,server); server.getEventManager().register(this, forgeHandshakeDataHandler); } else { @@ -43,6 +51,64 @@ public class Ambassador { } } + @Subscribe + public void onPreLoginEvent(PreLoginEvent event, Continuation continuation) { + if (!config.shouldHandle(event.getConnection().getProtocolVersion().getProtocol())) { + continuation.resume(); + return; + } + RegisteredServer defaultServer = config.getServer(event.getConnection().getProtocolVersion().getProtocol()); + + this.server.getEventManager().fire(new PreSyncEvent(event.getUsername(),event.getConnection(), defaultServer)) + .thenAccept((e) -> { + if (e.getResult().getServer().isEmpty()) { + //Do not sync + return; + } + RegisteredServer newServer = e.getResult().getServer().get(); + + ForgeConnection forgeConnection = new ForgeConnection((LoginPhaseConnection) event.getConnection()); + + //If a connection does not already exist, create one. + if (!forgeServerConnectionMap.containsKey(newServer)) { + forgeServerConnectionMap.put(newServer, new ForgeServerConnection(this,logger,newServer)); + } + + ForgeServerConnection forgeServerConnection = forgeServerConnectionMap.get(newServer); + + //Syncing + forgeServerConnection.getHandshake().whenComplete((msg,ex) -> { + if (ex != null) { + logger.warn("Could not sync player '" + event.getUsername() + "' to server '" + + forgeServerConnection.getServerInfo().getName() +"' Cause: " + ex.getMessage()); + } else { + forgeConnection.sendModlist(msg.modListPacket).thenAccept((response) -> { + if (response != null) { + forgeServerConnection.setDefaultClientModlist(response); + } + }); + forgeConnection.sendOther(msg.otherPackets).thenAccept((response) -> { + if (response != null) { + forgeServerConnection.setDefaultClientACK(response); + } + onSyncComplete(forgeConnection); + }); + } + //Writes the messages + continuation.resume(); + }); + }); + } + + public void onSyncComplete(ForgeConnection forgeConnection) { + if (forgeConnection.isModded()) { + incomingForgeConnections.values().removeIf((c) -> !c.getConnection().isActive()); + incomingForgeConnections.put(forgeConnection.getConnection().getRemoteAddress(), forgeConnection); + } + } + + + } diff --git a/src/main/java/org/adde0109/ambassador/ForgeConnection.java b/src/main/java/org/adde0109/ambassador/ForgeConnection.java new file mode 100644 index 0000000..fefc85d --- /dev/null +++ b/src/main/java/org/adde0109/ambassador/ForgeConnection.java @@ -0,0 +1,51 @@ +package org.adde0109.ambassador; + +import com.velocitypowered.api.proxy.InboundConnection; +import com.velocitypowered.api.proxy.LoginPhaseConnection; +import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier; +import com.velocitypowered.api.proxy.server.RegisteredServer; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +public class ForgeConnection { + + private final LoginPhaseConnection connection; + + private byte[] recivedClientModlist; + + private boolean isModded = false; + + ForgeConnection(LoginPhaseConnection connection) { + this.connection = connection; + } + + public CompletableFuture sendModlist(byte[] modListPacket) { + CompletableFuture future = new CompletableFuture(); + connection.sendLoginPluginMessage(MinecraftChannelIdentifier.create("fml","loginwrapper"), modListPacket, + responseBody -> { + if (responseBody != null) { + isModded = true; + } + recivedClientModlist = responseBody; + future.complete(recivedClientModlist); + }); + return future; + } + + CompletableFuture sendOther(List otherPackets) { + CompletableFuture future = new CompletableFuture(); + for (int i = 0;i {} : future::complete); + } + return future; + } + + public boolean isModded() { + return isModded; + } + public LoginPhaseConnection getConnection() { + return connection; + } + +} diff --git a/src/main/java/org/adde0109/ambassador/ForgeHandshakeDataHandler.java b/src/main/java/org/adde0109/ambassador/ForgeHandshakeDataHandler.java index 8397a47..0e45e8b 100644 --- a/src/main/java/org/adde0109/ambassador/ForgeHandshakeDataHandler.java +++ b/src/main/java/org/adde0109/ambassador/ForgeHandshakeDataHandler.java @@ -6,6 +6,7 @@ import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.connection.PreLoginEvent; import com.velocitypowered.api.event.player.ServerLoginPluginMessageEvent; import com.velocitypowered.api.event.player.ServerPostConnectEvent; +import com.velocitypowered.api.proxy.ConnectionRequestBuilder; import com.velocitypowered.api.proxy.InboundConnection; import com.velocitypowered.api.proxy.LoginPhaseConnection; import com.velocitypowered.api.proxy.Player; @@ -26,7 +27,7 @@ import java.util.concurrent.CompletableFuture; public class ForgeHandshakeDataHandler { - public Map cachedServerHandshake = new HashMap(); + public Map cachedServerHandshake = new HashMap(); public byte[] recivedClientACK; public Map recivedClientModlist = new HashMap(); public LoginPhaseConnection connection; @@ -36,45 +37,14 @@ public class ForgeHandshakeDataHandler { private static final int PACKET_LENGTH_INDEX = 14; //length of "fml:handshake"+1 - private final AmbassadorConfig config; private final Logger logger; private final ProxyServer server; - public ForgeHandshakeDataHandler(AmbassadorConfig config, Logger logger, ProxyServer server) { - this.config = config; + public ForgeHandshakeDataHandler(Logger logger, ProxyServer server) { this.logger = logger; this.server = server; } - @Subscribe - public void onPreLoginEvent(PreLoginEvent event, Continuation continuation) { - if (!config.shouldHandle(event.getConnection().getProtocolVersion().getProtocol())) { - continuation.resume(); - return; - } - RegisteredServer server = config.getServer(event.getConnection().getProtocolVersion().getProtocol()); - - this.server.getEventManager().fire(new PreSyncEvent(event.getUsername(),event.getConnection(), server)) - .thenAccept((e) -> { - if (!e.getResult().getServer().isPresent()) { - //Do not sync - return; - } - getHandshake(server).whenComplete((msg,ex) -> { - if (ex != null) { - logger.warn("Could not sync player '" + event.getUsername() + "' to server '" - + server.getServerInfo().getName() +"' Cause: " + ex.getMessage()); - } else { - AtomicBoolean isForge = new AtomicBoolean(false); - sendModlist(msg.modListPacket, (LoginPhaseConnection) event.getConnection(), server).thenAccept(isForge::set); - sendOther(msg.otherPackets, (LoginPhaseConnection) event.getConnection(), server).thenAccept((ignored) -> {}); - } - //Writes the messages - continuation.resume(); - }); - }); - } - @Subscribe public void onServerPostConnectEvent(ServerPostConnectEvent event) { @@ -121,8 +91,8 @@ public class ForgeHandshakeDataHandler { } - public CompletableFuture getHandshake(RegisteredServer handshakeServer) { - CompletableFuture future; + public CompletableFuture getHandshake(RegisteredServer handshakeServer) { + CompletableFuture future; if((handshakeServer.getPlayersConnected().isEmpty()) || (!cachedServerHandshake.containsKey(handshakeServer))) { handshakeReceiver receiver = new handshakeReceiver(handshakeServer, logger); future = receiver.downloadHandshake(); @@ -139,7 +109,7 @@ public class ForgeHandshakeDataHandler { } //Should return ForgePlayer instead of Boolean in the future... - private CompletableFuture sendModlist(byte[] modListPacket, LoginPhaseConnection connection, RegisteredServer server) { + CompletableFuture sendModlist(byte[] modListPacket, LoginPhaseConnection connection, RegisteredServer server) { CompletableFuture future = new CompletableFuture(); connection.sendLoginPluginMessage(MinecraftChannelIdentifier.create("fml","loginwrapper"), modListPacket, responseBody -> { if (responseBody != null) { @@ -152,7 +122,7 @@ public class ForgeHandshakeDataHandler { return future; } - private CompletableFuture sendOther(List otherPackets, LoginPhaseConnection connection, RegisteredServer server) { + CompletableFuture sendOther(List otherPackets, LoginPhaseConnection connection, RegisteredServer server) { CompletableFuture future = new CompletableFuture(); for (int i = 0;i future) { numberOfRecivedParts++; - if ((!status.getModinfo().isPresent()) || (!Objects.equals(status.getModinfo().get().getType(), "ambassador"))) { + if ((status.getModinfo().isEmpty()) || (!Objects.equals(status.getModinfo().get().getType(), "ambassador"))) { future.completeExceptionally(new Exception("The specified Forge server is not running the Forge-side version of this plugin!")); return; } @@ -252,8 +222,8 @@ public class ForgeHandshakeDataHandler { private void placePartInArray(byte[] temp, int partNr) { int head = partNr * partLength; - for (int i = 0; i < temp.length; i++) { - recivedParts[head] = temp[i]; + for (byte b : temp) { + recivedParts[head] = b; head++; recivedBytes++; } @@ -262,9 +232,9 @@ public class ForgeHandshakeDataHandler { private byte[] getPacket(byte[] data, int startByteIndex, int lastByteIndex) { byte[] temp = new byte[lastByteIndex - startByteIndex + 1]; - for (int i = startByteIndex; i <= lastByteIndex; i++) { - temp[i - startByteIndex] = data[i]; - } + if (lastByteIndex + 1 - startByteIndex >= 0) + System.arraycopy(data, startByteIndex, temp, 0, + lastByteIndex + 1 - startByteIndex); return temp; } @@ -279,16 +249,17 @@ public class ForgeHandshakeDataHandler { } - private class CachedServerHandshake { - private String sessionID; - private byte[] modListPacket; - private List otherPackets; - private CachedServerHandshake(String sessionID,byte[] modListPacket,List otherPackets) { - this.sessionID = sessionID; - this.modListPacket = modListPacket; - this.otherPackets = otherPackets; - } + } + public static class CachedServerHandshake { + private String sessionID; + public byte[] modListPacket; + public List otherPackets; + + private CachedServerHandshake(String sessionID,byte[] modListPacket,List otherPackets) { + this.sessionID = sessionID; + this.modListPacket = modListPacket; + this.otherPackets = otherPackets; } } } diff --git a/src/main/java/org/adde0109/ambassador/ForgeServerConnection.java b/src/main/java/org/adde0109/ambassador/ForgeServerConnection.java new file mode 100644 index 0000000..adef711 --- /dev/null +++ b/src/main/java/org/adde0109/ambassador/ForgeServerConnection.java @@ -0,0 +1,58 @@ +package org.adde0109.ambassador; + +import com.velocitypowered.api.proxy.server.RegisteredServer; +import com.velocitypowered.api.proxy.server.ServerInfo; +import java.util.concurrent.CompletableFuture; +import org.slf4j.Logger; + +public class ForgeServerConnection { + + private final Ambassador ambassador; + private final Logger logger; + private final RegisteredServer handshakeServer; + + private ForgeHandshakeDataHandler.CachedServerHandshake handshake; + + private byte[] defaultClientModlist; + private byte[] defaultClientACK; + + public RegisteredServer getServer() { + return handshakeServer; + } + + public ForgeServerConnection(Ambassador ambassador, Logger logger, RegisteredServer handshakeServer) { + this.ambassador = ambassador; + this.logger = logger; + this.handshakeServer = handshakeServer; + } + + public CompletableFuture getHandshake() { + CompletableFuture future; + if (handshakeServer.getPlayersConnected().isEmpty() || (handshake == null)) { + ForgeHandshakeDataHandler.handshakeReceiver + receiver = new ForgeHandshakeDataHandler.handshakeReceiver(handshakeServer, logger); + future = receiver.downloadHandshake(); + future.thenAccept(p -> { + handshake = p; + }); + return future; + } else { + future = new CompletableFuture<>(); + future.complete(handshake); + return future; + } + } + + public void setDefaultClientModlist(byte[] modlist) { + this.defaultClientModlist = modlist; + } + + public void setDefaultClientACK(byte[] ACK) { + this.defaultClientACK = ACK; + } + + public ServerInfo getServerInfo() { + return handshakeServer.getServerInfo(); + } + +}