Reorganized login process...

...in order to improve stability and maintainability.
This commit is contained in:
Adrian Bergqvist 2023-02-15 20:25:15 +01:00
parent c77fcbd09f
commit ce5420768d
No known key found for this signature in database
GPG Key ID: FAE7D8EDE225E686
11 changed files with 139 additions and 146 deletions

View File

@ -42,7 +42,7 @@ public class FML2CRPMClientConnectionPhase extends VelocityForgeClientConnection
} }
MinecraftConnection connection = player.getConnection(); MinecraftConnection connection = player.getConnection();
connection.setSessionHandler(new VelocityForgeHandshakeSessionHandler(connection.getSessionHandler(),this)); connection.setSessionHandler(new VelocityForgeHandshakeSessionHandler(connection.getSessionHandler(),player));
((VelocityServer) Ambassador.getInstance().server).unregisterConnection(player); ((VelocityServer) Ambassador.getInstance().server).unregisterConnection(player);
this.clientPhase = null; this.clientPhase = null;
@ -63,25 +63,7 @@ public class FML2CRPMClientConnectionPhase extends VelocityForgeClientConnection
connection.write(new PluginMessage("fml:handshake",Unpooled.wrappedBuffer(ForgeHandshakeUtils.generatePluginResetPacket()))); connection.write(new PluginMessage("fml:handshake",Unpooled.wrappedBuffer(ForgeHandshakeUtils.generatePluginResetPacket())));
return future; return future;
} }
public void complete(VelocityServer server, ConnectedPlayer player, MinecraftConnection connection) {
VelocityConfiguration configuration = (VelocityConfiguration) server.getConfiguration();
UUID playerUniqueId = player.getUniqueId();
if (configuration.getPlayerInfoForwardingMode() == PlayerInfoForwarding.NONE) {
playerUniqueId = UuidUtils.generateOfflinePlayerUuid(player.getUsername());
}
ServerLoginSuccess success = new ServerLoginSuccess();
success.setUsername(player.getUsername());
success.setUuid(playerUniqueId);
connection.write(success);
this.clientPhase = this.clientPhase == ClientPhase.MODLIST ? ClientPhase.MODDED : ClientPhase.VANILLA;
connection.setState(StateRegistry.PLAY);
connection.setSessionHandler(((VelocityForgeHandshakeSessionHandler) connection.getSessionHandler()).getOriginal());
((VelocityServer) Ambassador.getInstance().server).registerConnection(player);
backupServer = null;
}
public void handleKick(KickedFromServerEvent event) { public void handleKick(KickedFromServerEvent event) {
if (backupServer != null && !(event.getResult() instanceof KickedFromServerEvent.RedirectPlayer)) { if (backupServer != null && !(event.getResult() instanceof KickedFromServerEvent.RedirectPlayer)) {

View File

@ -8,21 +8,24 @@ import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage; import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage;
import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.adde0109.ambassador.Ambassador; import org.adde0109.ambassador.Ambassador;
import org.adde0109.ambassador.velocity.VelocityForgeClientConnectionPhase; import org.adde0109.ambassador.velocity.VelocityForgeClientConnectionPhase;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays; import java.util.Arrays;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class FML2ClientConnectionPhase extends VelocityForgeClientConnectionPhase { public class FML2ClientConnectionPhase extends VelocityForgeClientConnectionPhase {
private Throwable throwable; private Throwable throwable;
private RegisteredServer triedServer; private RegisteredServer triedServer;
private Continuation continuation; private CompletableFuture<Void> onServerSuccess;
private CompletableFuture<Void> onJoinGame; private CompletableFuture<Void> onJoinGame;
private static final Method CONNECT_TO_INITIAL_SERVER; private static final Method CONNECT_TO_INITIAL_SERVER;
@ -47,20 +50,9 @@ public class FML2ClientConnectionPhase extends VelocityForgeClientConnectionPhas
} }
@Override @Override
public void handleLogin(ConnectedPlayer player, VelocityServer server, Continuation continuation) { public RegisteredServer chooseServer(ConnectedPlayer player) {
this.continuation = continuation;
final MinecraftConnection connection = player.getConnection();
forced = Ambassador.getTemporaryForced().remove(player.getUsername()); forced = Ambassador.getTemporaryForced().remove(player.getUsername());
if (forced != null) { return forced;
player.createConnectionRequest(forced).fireAndForget();
} else {
try {
CONNECT_TO_INITIAL_SERVER.invoke(player.getConnection().getSessionHandler(),player);
} catch (ReflectiveOperationException e) {
continuation.resumeWithException(e);
}
}
} }
@Override @Override
@ -77,17 +69,6 @@ public class FML2ClientConnectionPhase extends VelocityForgeClientConnectionPhas
return future; return future;
} }
@Override
public void complete(VelocityServer server, ConnectedPlayer player, MinecraftConnection connection) {
if (triedServer != null)
player.sendMessage(Component.translatable("velocity.error.connecting-server-error",
Component.text(triedServer.getServerInfo().getName())));
clientPhase = clientPhase == ClientPhase.MODLIST ? ClientPhase.MODDED : ClientPhase.VANILLA;
internalServerConnection = player.getConnectionInFlight();
player.resetInFlightConnection();
this.onJoinGame = new CompletableFuture<>();
continuation.resume();
}
public void handleJoinGame() { public void handleJoinGame() {
this.onJoinGame.complete(null); this.onJoinGame.complete(null);

View File

@ -7,6 +7,7 @@ public class ForgeConstants {
public static final String MARKER_ADDER = "FML2/3 Marker Adder"; public static final String MARKER_ADDER = "FML2/3 Marker Adder";
public static final String OUTBOUND_CATCHER_NAME = "ambassador-catcher"; public static final String OUTBOUND_CATCHER_NAME = "ambassador-catcher";
public static final String RESET_LISTENER = "ambassador-reset-listener"; public static final String RESET_LISTENER = "ambassador-reset-listener";
public static final String SERVER_SUCCESS_LISTENER = "ambassador-server-success-listener";
public static final String FML2Marker = "\0FML2\0"; public static final String FML2Marker = "\0FML2\0";
public static final String FML3Marker = "\0FML3\0"; public static final String FML3Marker = "\0FML3\0";

View File

@ -24,7 +24,7 @@ public class ForgeFMLConnectionType implements ConnectionType {
@Override @Override
public BackendConnectionPhase getInitialBackendPhase() { public BackendConnectionPhase getInitialBackendPhase() {
return new VelocityForgeBackendConnectionPhase(); return VelocityForgeBackendConnectionPhase.NOT_STARTED;
} }
@Override @Override

View File

@ -3,19 +3,15 @@ package org.adde0109.ambassador.velocity;
import com.velocitypowered.api.event.Continuation; import com.velocitypowered.api.event.Continuation;
import com.velocitypowered.api.event.PostOrder; import com.velocitypowered.api.event.PostOrder;
import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.connection.LoginEvent;
import com.velocitypowered.api.event.connection.PostLoginEvent; import com.velocitypowered.api.event.connection.PostLoginEvent;
import com.velocitypowered.api.event.permission.PermissionsSetupEvent;
import com.velocitypowered.api.event.player.*; import com.velocitypowered.api.event.player.*;
import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.proxy.connection.backend.VelocityServerConnection; import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.protocol.packet.ClientSettings; import com.velocitypowered.proxy.protocol.StateRegistry;
import org.adde0109.ambassador.Ambassador; import org.adde0109.ambassador.Ambassador;
import org.adde0109.ambassador.forge.FML2CRPMClientConnectionPhase; import org.adde0109.ambassador.forge.FML2CRPMClientConnectionPhase;
import org.adde0109.ambassador.forge.FML2ClientConnectionPhase;
import org.adde0109.ambassador.forge.ForgeConstants;
import org.adde0109.ambassador.forge.ForgeFMLConnectionType;
import org.adde0109.ambassador.velocity.backend.VelocityForgeBackendConnectionPhase;
public class VelocityEventHandler { public class VelocityEventHandler {
@ -26,16 +22,22 @@ public class VelocityEventHandler {
} }
@Subscribe @Subscribe
public void onPermissionsSetupEvent(PermissionsSetupEvent event, Continuation continuation) { public void onLoginEvent(LoginEvent event, Continuation continuation) {
if(!(event.getSubject() instanceof ConnectedPlayer player)) { ConnectedPlayer player = (ConnectedPlayer) event.getPlayer();
continuation.resume(); if (player.getPhase() instanceof VelocityForgeClientConnectionPhase) {
return; player.getConnection().eventLoop().submit(() -> player.getConnection().setState(StateRegistry.LOGIN));
} }
if (!(player.getPhase() instanceof VelocityForgeClientConnectionPhase phase)) { continuation.resume();
continuation.resume(); }
return;
@Subscribe
public void onPostLoginEvent(PostLoginEvent event, Continuation continuation) {
ConnectedPlayer player = (ConnectedPlayer) event.getPlayer();
if (player.getPhase() instanceof VelocityForgeClientConnectionPhase phase) {
VelocityForgeHandshakeSessionHandler sessionHandler = new VelocityForgeHandshakeSessionHandler(player.getConnection().getSessionHandler(), player);
player.getConnection().eventLoop().submit(() -> player.getConnection().setSessionHandler(sessionHandler));
} }
player.getConnection().eventLoop().submit(() -> phase.fireLoginEvent(player, (VelocityServer) ambassador.server,continuation)); continuation.resume();
} }
@Subscribe(order = PostOrder.LAST) @Subscribe(order = PostOrder.LAST)
@ -72,40 +74,10 @@ public class VelocityEventHandler {
continuation.resume(); continuation.resume();
return; return;
} }
if (event.getInitialServer().isEmpty()) RegisteredServer chosenServer = phase.chooseServer(player);
event.setInitialServer(phase.internalServerConnection.getServer()); if (chosenServer != null)
event.setInitialServer(chosenServer);
continuation.resume(); continuation.resume();
} }
@Subscribe(order = PostOrder.LAST)
public void onServerPostConnectEvent(ServerPostConnectEvent event, Continuation continuation) {
ConnectedPlayer player = (ConnectedPlayer) event.getPlayer();
if (!(player.getPhase() instanceof VelocityForgeClientConnectionPhase phase)) {
continuation.resume();
return;
}
if (phase instanceof FML2ClientConnectionPhase specialPhase) {
specialPhase.handleJoinGame();
}
//if (((ConnectedPlayer) event.getPlayer()).getConnectedServer() != null && ((ConnectedPlayer) event.getPlayer()).getConnectedServer().getConnection() != null) {
// ((ConnectedPlayer) event.getPlayer()).getConnectedServer().getConnection().write(new ClientSettings("en_GB", (byte) 10, 0, true, (short) 0xFF,1,false,true));
//}
continuation.resume();
}
@Subscribe
public void onLoginEvent(PostLoginEvent event, Continuation continuation) {
ConnectedPlayer player = (ConnectedPlayer) event.getPlayer();
if (!(player.getPhase() instanceof VelocityForgeClientConnectionPhase phase)) {
continuation.resume();
return;
}
if (phase instanceof FML2ClientConnectionPhase specialPhase) {
specialPhase.awaitJoinGame().thenAcceptAsync((ignored) -> {
player.setConnectedServer(null);
continuation.resume();
},player.getConnection().eventLoop());
}
}
} }

View File

@ -1,6 +1,5 @@
package org.adde0109.ambassador.velocity; package org.adde0109.ambassador.velocity;
import com.velocitypowered.api.event.Continuation;
import com.velocitypowered.api.proxy.ServerConnection; import com.velocitypowered.api.proxy.ServerConnection;
import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.VelocityServer;
@ -11,6 +10,7 @@ import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage; import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage;
import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse; import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public abstract class VelocityForgeClientConnectionPhase implements ClientConnectionPhase { public abstract class VelocityForgeClientConnectionPhase implements ClientConnectionPhase {
@ -30,45 +30,31 @@ public abstract class VelocityForgeClientConnectionPhase implements ClientConnec
protected VelocityForgeClientConnectionPhase() { protected VelocityForgeClientConnectionPhase() {
} }
public void handleLogin(ConnectedPlayer player, VelocityServer server, Continuation continuation) { public RegisteredServer chooseServer(ConnectedPlayer player) {
return null;
} }
public CompletableFuture<Boolean> reset(RegisteredServer server, ConnectedPlayer player) { public CompletableFuture<Boolean> reset(RegisteredServer server, ConnectedPlayer player) {
return CompletableFuture.completedFuture(false); return CompletableFuture.completedFuture(false);
} }
public void complete(VelocityServer server, ConnectedPlayer player, MinecraftConnection connection) {
}
final void fireLoginEvent(ConnectedPlayer player, VelocityServer server, Continuation continuation) { final void onFirstLogin(ConnectedPlayer player, VelocityServer server) throws InterruptedException, InvocationTargetException, IllegalAccessException {
payloadManager = new VelocityLoginPayloadManager(player.getConnection());
handleLogin(player,server,continuation);
VelocityForgeHandshakeSessionHandler sessionHandler = new VelocityForgeHandshakeSessionHandler(player.getConnection().getSessionHandler(), this);
player.getConnection().setSessionHandler(sessionHandler);
} }
public void handleForward(VelocityServerConnection serverConnection, LoginPluginMessage payload) { public void handleForward(VelocityServerConnection serverConnection, LoginPluginMessage payload) {
} }
final public void forwardPayload(VelocityServerConnection serverConnection, LoginPluginMessage payload) {
handleForward(serverConnection,payload);
if (payloadManager == null) {
payload.release();
return;
}
payloadManager.sendPayload("fml:loginwrapper",payload.content()).thenAccept((responseData) -> {
//Move this to the backend. Backend should have its own forwarder.
serverConnection.getConnection().write(new LoginPluginResponse(payload.getId(),responseData.isReadable(),responseData.retain()));
});
clientPhase = ClientPhase.MODLIST;
}
public final VelocityLoginPayloadManager getPayloadManager() { public final VelocityLoginPayloadManager getPayloadManager() {
return payloadManager; return payloadManager;
} }
public boolean handle(ConnectedPlayer player, LoginPluginResponse response, VelocityServerConnection server) {
server.getConnection().write(response.retain());
return true;
}
public enum ClientPhase { public enum ClientPhase {
VANILLA, VANILLA,
HANDSHAKE, HANDSHAKE,

View File

@ -1,26 +1,29 @@
package org.adde0109.ambassador.velocity; package org.adde0109.ambassador.velocity;
import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse; import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
public class VelocityForgeHandshakeSessionHandler implements MinecraftSessionHandler { public class VelocityForgeHandshakeSessionHandler implements MinecraftSessionHandler {
private final MinecraftSessionHandler original; private final MinecraftSessionHandler original;
private final VelocityForgeClientConnectionPhase phase; private final ConnectedPlayer player;
public VelocityForgeHandshakeSessionHandler(MinecraftSessionHandler original, VelocityForgeClientConnectionPhase phase) { public VelocityForgeHandshakeSessionHandler(MinecraftSessionHandler original, ConnectedPlayer player) {
this.original = original; this.original = original;
this.phase = phase; this.player = player;
} }
@Override @Override
public boolean handle(LoginPluginResponse packet) { public boolean handle(LoginPluginResponse packet) {
if (phase.getPayloadManager().handlePayload(packet)) { if (player.getPhase() instanceof VelocityForgeClientConnectionPhase phase) {
return true; if (phase.handle(player,packet,player.getConnectionInFlight())) {
} else { return true;
return original.handle(packet); }
} }
return original.handle(packet);
} }
@Override @Override
public void handleUnknown(ByteBuf buf) { public void handleUnknown(ByteBuf buf) {

View File

@ -4,11 +4,13 @@ import com.velocitypowered.proxy.connection.ConnectionTypes;
import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.MinecraftConnection;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.connection.client.HandshakeSessionHandler; import com.velocitypowered.proxy.connection.client.HandshakeSessionHandler;
import com.velocitypowered.proxy.network.Connections;
import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.StateRegistry;
import com.velocitypowered.proxy.protocol.packet.Handshake; import com.velocitypowered.proxy.protocol.packet.Handshake;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import org.adde0109.ambassador.forge.ForgeConstants; import org.adde0109.ambassador.forge.ForgeConstants;
import org.adde0109.ambassador.velocity.client.OutboundSuccessHolder;
public class VelocityHandshakeSessionHandler implements MinecraftSessionHandler { public class VelocityHandshakeSessionHandler implements MinecraftSessionHandler {
private final HandshakeSessionHandler original; private final HandshakeSessionHandler original;
@ -26,8 +28,14 @@ public class VelocityHandshakeSessionHandler implements MinecraftSessionHandler
final String[] markerSplit = handshake.getServerAddress().split("\0"); final String[] markerSplit = handshake.getServerAddress().split("\0");
if (connection.getState() == StateRegistry.LOGIN && markerSplit.length > 1) { if (connection.getState() == StateRegistry.LOGIN && markerSplit.length > 1) {
switch (markerSplit[1]) { switch (markerSplit[1]) {
case "FML2" -> connection.setType(ForgeConstants.ForgeFML2); case "FML2":
case "FML3" -> connection.setType(ForgeConstants.ForgeFML3); connection.setType(ForgeConstants.ForgeFML2);
connection.getChannel().pipeline().addAfter(Connections.MINECRAFT_ENCODER,ForgeConstants.SERVER_SUCCESS_LISTENER, new OutboundSuccessHolder());
break;
case "FML3":
connection.setType(ForgeConstants.ForgeFML3);
connection.getChannel().pipeline().addAfter(Connections.MINECRAFT_ENCODER,ForgeConstants.SERVER_SUCCESS_LISTENER, new OutboundSuccessHolder());
break;
} }
} }
} }

View File

@ -2,6 +2,7 @@ package org.adde0109.ambassador.velocity.backend;
import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.connection.backend.BackendConnectionPhases;
import com.velocitypowered.proxy.connection.backend.LoginSessionHandler; import com.velocitypowered.proxy.connection.backend.LoginSessionHandler;
import com.velocitypowered.proxy.connection.backend.VelocityServerConnection; import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.MinecraftPacket;
@ -31,16 +32,11 @@ public class ForgeHandshakeSessionHandler implements MinecraftSessionHandler {
@Override @Override
public boolean handle(LoginPluginMessage packet) { public boolean handle(LoginPluginMessage packet) {
if (packet.getChannel().equals("fml:loginwrapper")) { if (packet.getChannel().equals("fml:loginwrapper")) {
if (!(serverConnection.getConnection().getType() instanceof ForgeFMLConnectionType)) { if (serverConnection.getPhase() == BackendConnectionPhases.UNKNOWN) {
if (!(serverConnection.getPlayer().getConnection().getType() instanceof ForgeFMLConnectionType clientType)) { VelocityForgeBackendConnectionPhase.NOT_STARTED.handle(serverConnection,serverConnection.getPlayer(),packet);
final String reason = "This server has mods that require Forge to be installed on the client. Contact your server admin for more details."; } else if (serverConnection.getPhase() instanceof VelocityForgeBackendConnectionPhase phase1) {
original.handle(Disconnect.create(Component.text(reason, NamedTextColor.RED),serverConnection.getPlayer().getProtocolVersion())); phase1.handle(serverConnection,serverConnection.getPlayer(),packet);
return true;
}
serverConnection.getConnection().setType(clientType);
serverConnection.setConnectionPhase(clientType.getInitialBackendPhase());
} }
((VelocityForgeBackendConnectionPhase) serverConnection.getPhase()).handle(serverConnection,serverConnection.getPlayer(),packet);
return true; return true;
} }
return original.handle(packet); return original.handle(packet);
@ -48,8 +44,8 @@ public class ForgeHandshakeSessionHandler implements MinecraftSessionHandler {
@Override @Override
public boolean handle(ServerLoginSuccess packet) { public boolean handle(ServerLoginSuccess packet) {
if ((serverConnection.getPlayer().getPhase() instanceof VelocityForgeClientConnectionPhase phase)) { if ((serverConnection.getPhase() instanceof VelocityForgeBackendConnectionPhase phase)) {
phase.complete(server,serverConnection.getPlayer(),serverConnection.getPlayer().getConnection()); phase.onLoginSuccess(serverConnection,serverConnection.getPlayer());
} }
return original.handle(packet); return original.handle(packet);
} }

View File

@ -1,26 +1,51 @@
package org.adde0109.ambassador.velocity.backend; package org.adde0109.ambassador.velocity.backend;
import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.connection.MinecraftConnection;
import com.velocitypowered.proxy.connection.backend.BackendConnectionPhase; import com.velocitypowered.proxy.connection.backend.BackendConnectionPhase;
import com.velocitypowered.proxy.connection.backend.VelocityServerConnection; import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.protocol.StateRegistry;
import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage; import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage;
import io.netty.buffer.ByteBuf; import org.adde0109.ambassador.forge.ForgeConstants;
import io.netty.util.ReferenceCountUtil;
import org.adde0109.ambassador.velocity.VelocityForgeClientConnectionPhase; import org.adde0109.ambassador.velocity.VelocityForgeClientConnectionPhase;
import java.util.ArrayList; public enum VelocityForgeBackendConnectionPhase implements BackendConnectionPhase {
import java.util.List; NOT_STARTED() {
@Override
VelocityForgeBackendConnectionPhase nextPhase() {
return WAITING_FOR_ACK;
}
},
WAITING_FOR_ACK() {
@Override
public void onLoginSuccess(VelocityServerConnection serverCon, ConnectedPlayer player) {
serverCon.setConnectionPhase(VelocityForgeBackendConnectionPhase.COMPLETE);
public class VelocityForgeBackendConnectionPhase implements BackendConnectionPhase { MinecraftConnection connection = player.getConnection();
connection.getChannel().pipeline().remove(ForgeConstants.SERVER_SUCCESS_LISTENER);
connection.setState(StateRegistry.PLAY);
}
},
COMPLETE() {
@Override
public boolean consideredComplete() {
return true;
}
};
public VelocityForgeBackendConnectionPhase() { VelocityForgeBackendConnectionPhase() {
} }
public void handle(VelocityServerConnection server, ConnectedPlayer player, LoginPluginMessage message) { public void handle(VelocityServerConnection server, ConnectedPlayer player, LoginPluginMessage message) {
VelocityForgeBackendConnectionPhase newPhase = nextPhase();
server.setConnectionPhase(newPhase);
VelocityForgeClientConnectionPhase clientPhase = ((VelocityForgeClientConnectionPhase) player.getPhase()); VelocityForgeClientConnectionPhase clientPhase = ((VelocityForgeClientConnectionPhase) player.getPhase());
if (clientPhase.clientPhase == VelocityForgeClientConnectionPhase.ClientPhase.VANILLA) { if (player.getConnection().getState() != StateRegistry.LOGIN) {
final LoginPluginMessage msg = message; final LoginPluginMessage msg = message;
msg.content().retain().discardSomeReadBytes(); msg.content().retain().discardSomeReadBytes();
@ -28,14 +53,25 @@ public class VelocityForgeBackendConnectionPhase implements BackendConnectionPha
server.getConnection().getChannel().config().setAutoRead(false); server.getConnection().getChannel().config().setAutoRead(false);
clientPhase.reset(server.getServer(),player).thenAccept((success) -> { clientPhase.reset(server.getServer(),player).thenAccept((success) -> {
if (success) { if (success) {
clientPhase.forwardPayload(server,msg); player.getConnection().write(msg);
server.getConnection().getChannel().config().setAutoRead(true); server.getConnection().getChannel().config().setAutoRead(true);
} else { } else {
msg.release(); msg.release();
} }
}); });
} else { } else {
clientPhase.forwardPayload(server, (LoginPluginMessage) message.retain()); player.getConnection().write(message.retain());
} }
} }
public void onLoginSuccess(VelocityServerConnection serverCon, ConnectedPlayer player) {
}
VelocityForgeBackendConnectionPhase nextPhase() {
return this;
}
public boolean consideredComplete() {
return false;
}
} }

View File

@ -0,0 +1,28 @@
package org.adde0109.ambassador.velocity.client;
import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
public class OutboundSuccessHolder extends ChannelOutboundHandlerAdapter {
private ServerLoginSuccess packet;
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
if ((msg instanceof ServerLoginSuccess packet)) {
this.packet = packet;
} else {
ctx.write(msg, promise);
}
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
if (ctx.channel().isActive()) {
ctx.write(packet, ctx.voidPromise());
ctx.flush();
}
}
}