LoginPhaseProxy
Black magic reflection stuff to make Login Plugin messages work over Velocity
LoginPhaseProxy is a somewhat "simple" Velocity Plugin that allows you to proxy the LoginPluginMessagePacket from backend server to the player and LoginPluginResponsePacket from the player to the backend server. This is useful for modded backend servers that rely on Login Plugin Message communication to work, such as AutoModpack.
Disclaimer: This plugin is in early development and may contain bugs and performance issues. Use it at your own risk.
❓ What does it solve (detailed)

Normal Setup ⦁ Made in Figma
On a normal Velocity setup, when a player connects to the proxy, they go through the (P ↔ V) Login Phase, exchanging packets with the Velocity until the proxy sends a Server Login Success Packet, completing the (P ↔ V) Login Phase and triggering the backend connection process. The backend server then goes through its own (V ↔ B) Login Phase, where it may send Login Plugin Message Packets to the Velocity, and they can't be forwarded to the player, because the (P ↔ V) Login Phase is already complete, so Velocity reponds them with an empty data Login Plugin Response Packet, as it doesn't know how to handle them. This is a problem for modded backend servers that rely on Login Plugin Message communication to work, such as AutoModpack, as they won't be able to send the necessary data to the player during the Login Phase, and the player won't be able to join the backend server. This plugin tries to solve this issue by proxying the Login Plugin Message communication between the player and the backend server, allowing modded backend servers to work with Velocity without any issues.
✨ How it works (detailed)
Basically black magic 🪄🔮. It uses Java Reflection to access the internal Velocity classes ProxyServer -> ConnectionManager[1] to override the serverChannelInitializer[2] and backendChannelInitializer[3], so it can intercept the Velocity communication with the player (P <-> V)[4] and backend server (V <-> S)[5], respectively.

Plugin Implementation ⦁ Made in Figma
With that, our plugin watches the Login Phase player connection until it sees a SetCompressionPacket(5) (optionally) and ServerLoginSuccessPacket(6), adding them to a buffer instead of sending them to the player and synthetically sends a loginAcknowledgedPacket(7) to the Velocity pipeline, tricking it into thinking the Login Phase is complete and starting the backend connection process. To make sure the Velocity doesn't mess the packet interception and sending process, our plugin removes stealthly (so that it doesn't trigger it's handlerRemoved lifecycle[6]) the handlers from the Velocity serverChannel pipeline[4] that were added after the Login Phase to Config Phase transition (MinecraftCompressorAndLengthEncoder and MinecraftCompressDecoder, others are removed naturally afterwards). Also, our plugin adds the MinecraftVarintLengthEncoder[4] back (was removed at the transition) and sets the MinecraftDecoder state to StateRegistry.LOGIN[4] so the packets are properly encoded and decoded.
If the backend server sends a LoginPluginMessagePacket(10) during its Login Phase, our plugin will intercept it and send it to the player(11), and if the player sends a LoginPluginResponsePacket(12), our plugin will intercept it and send it to the backend server(13). This way, we can effectively proxy the LoginPluginMessagePacket and LoginPluginResponsePacket between the player and the backend server, allowing modded backend servers to work with Velocity without any issues. Then, when the backend server ends the Login Phase sending the ServerLoginSuccessPacket(15), our plugin will flush the buffered packets to the player, completing the Login Phase and allowing the player to join the backend server as normal. Afterwards, if the user sends a LoginAcknowledgedPacket (clientProtocolVersion >= ProtocolVersion.MINECRAFT_1_20_2)(16) after the Login Phase is complete, our plugin will simply ignore it, as it is not expected to be sent by the player at that point. Finally, the plugin will restore the MinecraftDecoder state to its previous state (Config Phase).
So, yeah, basically black magic 🪄🔮. Yayyyy!
🔁 Compatibility
| Author(s) | Mod | Compatibility |
|---|---|---|
| Skidam | AutoModpack (Fabric/Forge/Neoforge) | ✅ Compatible |
| adde0109 | Ambassador (Velocity) | 🚫 Incompatible |
🙏 Acknowledgement
Huge thanks to Skidam, who inspired me to create this plugin!
