diff --git a/src/main/java/org/adde0109/ambassador/Ambassador.java b/src/main/java/org/adde0109/ambassador/Ambassador.java index 81a5cd6..03624a4 100644 --- a/src/main/java/org/adde0109/ambassador/Ambassador.java +++ b/src/main/java/org/adde0109/ambassador/Ambassador.java @@ -10,18 +10,23 @@ import com.velocitypowered.api.plugin.Plugin; import com.velocitypowered.api.plugin.annotation.DataDirectory; import com.velocitypowered.api.proxy.ProxyServer; +import java.lang.reflect.Field; import java.util.concurrent.Callable; + +import com.velocitypowered.proxy.VelocityServer; +import com.velocitypowered.proxy.network.ConnectionManager; +import io.netty.channel.ChannelInitializer; import org.adde0109.ambassador.forge.ForgeConnection; import org.adde0109.ambassador.forge.ForgeHandshakeHandler; import org.adde0109.ambassador.forge.ForgeHandshakeUtils; import org.adde0109.ambassador.forge.ForgeServerSwitchHandler; -import org.bstats.MetricsBase; +import org.adde0109.ambassador.velocity.VelocityChannelInitializer; +import org.adde0109.ambassador.velocity.VelocityEventHandler; import org.bstats.charts.SingleLineChart; import org.bstats.velocity.Metrics; import org.slf4j.Logger; import java.nio.file.Path; -import java.util.*; @Plugin(id = "ambassador", name = "Ambassador", version = "0.4.0-reset", authors = {"adde0109"}) public class Ambassador { @@ -46,14 +51,14 @@ public class Ambassador { } @Subscribe - public void onProxyInitialization(ProxyInitializeEvent event) { + public void onProxyInitialization(ProxyInitializeEvent event) throws ReflectiveOperationException { initMetrics(); config = AmbassadorConfig.readOrCreateConfig(dataDirectory,server,logger); if(config != null) { forgeHandshakeHandler = new ForgeHandshakeHandler(this); forgeServerSwitchHandler = new ForgeServerSwitchHandler(this); - server.getEventManager().register(this, forgeHandshakeHandler); + server.getEventManager().register(this, new VelocityEventHandler(this)); server.getEventManager().register(this,forgeServerSwitchHandler); } else { @@ -61,6 +66,14 @@ public class Ambassador { } ForgeHandshakeUtils.HandshakeReceiver.logger = logger; + inject(); + } + + private void inject() throws ReflectiveOperationException { + Field cmField = VelocityServer.class.getDeclaredField("cm"); + cmField.setAccessible(true); + ChannelInitializer original = ((ConnectionManager) cmField.get(server)).serverChannelInitializer.get(); + ((ConnectionManager) cmField.get(server)).serverChannelInitializer.set(new VelocityChannelInitializer(original)); } @Subscribe diff --git a/src/main/java/org/adde0109/ambassador/forge/ForgeHandshakeHandler.java b/src/main/java/org/adde0109/ambassador/forge/ForgeHandshakeHandler.java index 07b62dc..dfdad56 100644 --- a/src/main/java/org/adde0109/ambassador/forge/ForgeHandshakeHandler.java +++ b/src/main/java/org/adde0109/ambassador/forge/ForgeHandshakeHandler.java @@ -1,14 +1,10 @@ package org.adde0109.ambassador.forge; import com.velocitypowered.api.event.Continuation; -import com.velocitypowered.api.event.PostOrder; import com.velocitypowered.api.event.Subscribe; -import com.velocitypowered.api.event.connection.PreLoginEvent; import com.velocitypowered.api.event.permission.PermissionsSetupEvent; import com.velocitypowered.api.event.player.KickedFromServerEvent; import com.velocitypowered.api.event.player.ServerLoginPluginMessageEvent; -import com.velocitypowered.api.network.ProtocolVersion; -import com.velocitypowered.api.proxy.LoginPhaseConnection; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.messages.ChannelIdentifier; import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier; @@ -17,18 +13,15 @@ import java.net.InetSocketAddress; import java.util.HashMap; import java.util.Map; import java.util.Optional; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; -import com.velocitypowered.proxy.connection.ConnectionType; -import com.velocitypowered.proxy.connection.ConnectionTypes; -import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TranslatableComponent; import net.kyori.adventure.text.format.NamedTextColor; import org.adde0109.ambassador.Ambassador; -import org.checkerframework.checker.units.qual.A; +import org.adde0109.ambassador.velocity.ForgeClientConnectionPhase; public class ForgeHandshakeHandler { @@ -45,47 +38,27 @@ public class ForgeHandshakeHandler { this.ambassador = ambassador; } - @Subscribe(order = PostOrder.LAST) - public void onPreLoginEvent(PreLoginEvent event, Continuation continuation) { - if (event.getConnection().getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_13) < 0) { - continuation.resume(); - return; - } - MinecraftConnection connection = (MinecraftConnection)event.getConnection(); - ((LoginPhaseConnection) event.getConnection()).sendLoginPluginMessage( - MinecraftChannelIdentifier.create("fml","loginwrapper"), - ForgeHandshakeUtils.generateTestPacket(),(msg) -> { - if (connection.getType() == ConnectionTypes.VANILLA) { - if (msg != null) { - connection.setType(new ForgeConnectionType()); - } - } + + public void handleLogin(ConnectedPlayer player, ForgeClientConnectionPhase phase, Continuation continuation) { + getInitialHandshake(player).whenComplete((msg,ex) -> { + if (ex != null) { + //SEND RESET PACKET + } else { + //SEND MODLIST + } }); - //SEND ===CLIENT MODLIST REQUEST=== - ((LoginPhaseConnection) event.getConnection()).sendLoginPluginMessage( - MinecraftChannelIdentifier.create("fml","loginwrapper"), - ForgeHandshakeUtils.generateTestPacket(),(msg) -> { - if (msg != null) { - connection.setType(new ForgeConnectionType()); - //Handle the response - } - }); - continuation.resume(); } - @Subscribe - public void onPermissionsSetupEvent(PermissionsSetupEvent event, Continuation continuation) { - //Filters... - if (!(event.getSubject() instanceof ConnectedPlayer)) { - continuation.resume(); - return; + + private CompletableFuture getInitialHandshake(ConnectedPlayer player) { + CompletableFuture future; + RegisteredServer initialServer; + if((initialServer = ambassador.config.getServer(player.getConnection().getProtocolVersion().getProtocol())) != null) { + future = ForgeHandshakeUtils.HandshakeReceiver.downloadHandshake(initialServer); + } else { + future = CompletableFuture.failedFuture(new Exception("No initial server specified")); } - ConnectedPlayer player = ((ConnectedPlayer) event.getSubject()); - if (!(player.getConnection().getType() instanceof ForgeConnectionType)) { - continuation.resume(); - return; - } - ((ForgeClientConnectionPhase) player.getPhase()).handleLogin(); + return future; } private void registerForgeConnection(ForgeConnection forgeConnection) { diff --git a/src/main/java/org/adde0109/ambassador/forge/ForgeSessionHandler.java b/src/main/java/org/adde0109/ambassador/forge/ForgeSessionHandler.java deleted file mode 100644 index e904ec1..0000000 --- a/src/main/java/org/adde0109/ambassador/forge/ForgeSessionHandler.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.adde0109.ambassador.forge; - -import com.velocitypowered.proxy.connection.MinecraftConnection; -import com.velocitypowered.proxy.connection.MinecraftSessionHandler; -import com.velocitypowered.proxy.protocol.MinecraftPacket; -import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage; -import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse; -import io.netty.buffer.Unpooled; - -public class ForgeSessionHandler implements MinecraftSessionHandler { - private final MinecraftSessionHandler delegate; - private final MinecraftConnection connection; - - public ForgeSessionHandler(MinecraftSessionHandler delegate, MinecraftConnection connection) { - this.delegate = delegate; - this.connection = connection; - } - - @Override - public void handleGeneric(MinecraftPacket packet) { - packet.handle(delegate); - } - - @Override - public void activated() { - } - - @Override - public boolean handle(LoginPluginResponse packet) { - //DETECT FML or PCF - return false; -} diff --git a/src/main/java/org/adde0109/ambassador/forge/ForgeClientConnectionPhase.java b/src/main/java/org/adde0109/ambassador/velocity/ForgeClientConnectionPhase.java similarity index 53% rename from src/main/java/org/adde0109/ambassador/forge/ForgeClientConnectionPhase.java rename to src/main/java/org/adde0109/ambassador/velocity/ForgeClientConnectionPhase.java index f1f0e06..6789f97 100644 --- a/src/main/java/org/adde0109/ambassador/forge/ForgeClientConnectionPhase.java +++ b/src/main/java/org/adde0109/ambassador/velocity/ForgeClientConnectionPhase.java @@ -1,12 +1,14 @@ -package org.adde0109.ambassador.forge; +package org.adde0109.ambassador.velocity; -import com.velocitypowered.proxy.connection.backend.VelocityServerConnection; +import com.velocitypowered.api.event.Continuation; +import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.client.ClientConnectionPhase; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; -import com.velocitypowered.proxy.protocol.packet.PluginMessage; public class ForgeClientConnectionPhase implements ClientConnectionPhase { + ForgeClientConnectionPhase(MinecraftConnection connection) { + } public void handleLogin() { } diff --git a/src/main/java/org/adde0109/ambassador/forge/ForgeConnectionType.java b/src/main/java/org/adde0109/ambassador/velocity/ForgeConnectionType.java similarity index 64% rename from src/main/java/org/adde0109/ambassador/forge/ForgeConnectionType.java rename to src/main/java/org/adde0109/ambassador/velocity/ForgeConnectionType.java index efecbce..a5760a7 100644 --- a/src/main/java/org/adde0109/ambassador/forge/ForgeConnectionType.java +++ b/src/main/java/org/adde0109/ambassador/velocity/ForgeConnectionType.java @@ -1,15 +1,23 @@ -package org.adde0109.ambassador.forge; +package org.adde0109.ambassador.velocity; import com.velocitypowered.api.util.GameProfile; import com.velocitypowered.proxy.config.PlayerInfoForwarding; import com.velocitypowered.proxy.connection.ConnectionType; +import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.backend.BackendConnectionPhase; import com.velocitypowered.proxy.connection.client.ClientConnectionPhase; +import org.adde0109.ambassador.velocity.ForgeClientConnectionPhase; public class ForgeConnectionType implements ConnectionType { + + private final MinecraftConnection connection; + public ForgeConnectionType(MinecraftConnection connection) { + this.connection = connection; + } + @Override public ClientConnectionPhase getInitialClientPhase() { - return new ForgeClientConnectionPhase(); + return new ForgeClientConnectionPhase(connection); } @Override diff --git a/src/main/java/org/adde0109/ambassador/velocity/VelocityChannelInitializer.java b/src/main/java/org/adde0109/ambassador/velocity/VelocityChannelInitializer.java new file mode 100644 index 0000000..05b5a3b --- /dev/null +++ b/src/main/java/org/adde0109/ambassador/velocity/VelocityChannelInitializer.java @@ -0,0 +1,39 @@ +package org.adde0109.ambassador.velocity; + +import com.velocitypowered.proxy.connection.MinecraftConnection; +import com.velocitypowered.proxy.connection.client.HandshakeSessionHandler; +import com.velocitypowered.proxy.network.Connections; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelInitializer; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.Method; + +public class VelocityChannelInitializer extends ChannelInitializer { + private static final Method INIT_CHANNEL; + + private final ChannelInitializer original; + + static { + try { + INIT_CHANNEL = ChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class); + INIT_CHANNEL.setAccessible(true); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + public VelocityChannelInitializer(ChannelInitializer original) { + this.original = original; + } + + @Override + protected void initChannel(@NotNull Channel ch) throws Exception { + INIT_CHANNEL.invoke(original,ch); + ChannelHandler handler = ch.pipeline().get(Connections.HANDLER); + if (!(handler instanceof final MinecraftConnection connection)) throw new Exception("plugin conflict"); + HandshakeSessionHandler originalSessionHandler = (HandshakeSessionHandler) connection.getSessionHandler(); + connection.setSessionHandler(new VelocityHandshakeSessionHandler(originalSessionHandler, connection)); + } +} diff --git a/src/main/java/org/adde0109/ambassador/velocity/VelocityEventHandler.java b/src/main/java/org/adde0109/ambassador/velocity/VelocityEventHandler.java new file mode 100644 index 0000000..14877bf --- /dev/null +++ b/src/main/java/org/adde0109/ambassador/velocity/VelocityEventHandler.java @@ -0,0 +1,29 @@ +package org.adde0109.ambassador.velocity; + +import com.velocitypowered.api.event.Continuation; +import com.velocitypowered.api.event.Subscribe; +import com.velocitypowered.api.event.permission.PermissionsSetupEvent; +import com.velocitypowered.proxy.connection.client.ConnectedPlayer; +import org.adde0109.ambassador.Ambassador; + +public class VelocityEventHandler { + + private final Ambassador ambassador; + + public VelocityEventHandler(Ambassador ambassador) { + this.ambassador = ambassador; + } + + @Subscribe + public void onPermissionsSetupEvent(PermissionsSetupEvent event, Continuation continuation) { + if(!(event.getSubject() instanceof ConnectedPlayer player)) { + continuation.resume(); + return; + } + if (!(player.getPhase() instanceof ForgeClientConnectionPhase phase)) { + continuation.resume(); + return; + } + ambassador.forgeHandshakeHandler.handleLogin(player,phase,continuation); + } +} diff --git a/src/main/java/org/adde0109/ambassador/velocity/VelocityForgeHandshakeSessionHandler.java b/src/main/java/org/adde0109/ambassador/velocity/VelocityForgeHandshakeSessionHandler.java new file mode 100644 index 0000000..23526a4 --- /dev/null +++ b/src/main/java/org/adde0109/ambassador/velocity/VelocityForgeHandshakeSessionHandler.java @@ -0,0 +1,6 @@ +package org.adde0109.ambassador.velocity; + +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; + +public class VelocityForgeHandshakeSessionHandler implements MinecraftSessionHandler { +} diff --git a/src/main/java/org/adde0109/ambassador/velocity/VelocityHandshakeSessionHandler.java b/src/main/java/org/adde0109/ambassador/velocity/VelocityHandshakeSessionHandler.java new file mode 100644 index 0000000..6660b3b --- /dev/null +++ b/src/main/java/org/adde0109/ambassador/velocity/VelocityHandshakeSessionHandler.java @@ -0,0 +1,42 @@ +package org.adde0109.ambassador.velocity; + +import com.velocitypowered.proxy.connection.ConnectionTypes; +import com.velocitypowered.proxy.connection.MinecraftConnection; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; +import com.velocitypowered.proxy.connection.client.HandshakeSessionHandler; +import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.StateRegistry; +import com.velocitypowered.proxy.protocol.packet.Handshake; +import io.netty.buffer.ByteBuf; + +public class VelocityHandshakeSessionHandler implements MinecraftSessionHandler { + private final HandshakeSessionHandler original; + private final MinecraftConnection connection; + + public VelocityHandshakeSessionHandler(HandshakeSessionHandler original, MinecraftConnection connection) { + this.original = original; + this.connection = connection; + } + + @Override + public boolean handle(Handshake handshake) { + handshake.handle(original); + if (connection.getType() == ConnectionTypes.VANILLA && connection.getState() == StateRegistry.LOGIN) { + if (handshake.getServerAddress().split("\0")[1].equals("FML2")) { + connection.setType(new ForgeConnectionType(connection)); + } + } + return true; + } + + + @Override + public void handleGeneric(MinecraftPacket packet) { + packet.handle(original); + } + + @Override + public void handleUnknown(ByteBuf buf) { + original.handleUnknown(buf); + } +}