Server switch logic rewritten
This commit is contained in:
parent
ce5420768d
commit
d6cc47aba1
|
|
@ -24,6 +24,7 @@ dependencies {
|
||||||
compileOnly("io.netty:netty-buffer:4.1.86.Final")
|
compileOnly("io.netty:netty-buffer:4.1.86.Final")
|
||||||
compileOnly("io.netty:netty-transport:4.1.86.Final")
|
compileOnly("io.netty:netty-transport:4.1.86.Final")
|
||||||
compileOnly("io.netty:netty-codec:4.1.86.Final")
|
compileOnly("io.netty:netty-codec:4.1.86.Final")
|
||||||
|
compileOnly("io.netty:netty-handler:4.1.86.Final")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
|
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
||||||
package org.adde0109.ambassador.forge;
|
|
||||||
|
|
||||||
import com.velocitypowered.api.event.player.KickedFromServerEvent;
|
|
||||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
|
||||||
import com.velocitypowered.api.util.UuidUtils;
|
|
||||||
import com.velocitypowered.proxy.VelocityServer;
|
|
||||||
import com.velocitypowered.proxy.config.PlayerInfoForwarding;
|
|
||||||
import com.velocitypowered.proxy.config.VelocityConfiguration;
|
|
||||||
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
|
||||||
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
|
||||||
import com.velocitypowered.proxy.network.Connections;
|
|
||||||
import com.velocitypowered.proxy.protocol.StateRegistry;
|
|
||||||
import com.velocitypowered.proxy.protocol.packet.PluginMessage;
|
|
||||||
import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess;
|
|
||||||
import io.netty.buffer.Unpooled;
|
|
||||||
import org.adde0109.ambassador.Ambassador;
|
|
||||||
import org.adde0109.ambassador.velocity.VelocityForgeClientConnectionPhase;
|
|
||||||
import org.adde0109.ambassador.velocity.VelocityForgeHandshakeSessionHandler;
|
|
||||||
import org.adde0109.ambassador.velocity.VelocityLoginPayloadManager;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.ScheduledFuture;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
public class FML2CRPMClientConnectionPhase extends VelocityForgeClientConnectionPhase {
|
|
||||||
|
|
||||||
//TODO: Use modData inside ConnectedPlayer instead
|
|
||||||
public byte[] modListData;
|
|
||||||
private RegisteredServer backupServer;
|
|
||||||
|
|
||||||
public FML2CRPMClientConnectionPhase(VelocityForgeClientConnectionPhase.ClientPhase clientPhase, VelocityLoginPayloadManager payloadManager) {
|
|
||||||
super(clientPhase,payloadManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompletableFuture<Boolean> reset(RegisteredServer server, ConnectedPlayer player) {
|
|
||||||
CompletableFuture<Boolean> future = new CompletableFuture<>();
|
|
||||||
if (player.getConnectedServer() != null) {
|
|
||||||
backupServer = player.getConnectedServer().getServer();
|
|
||||||
player.getConnectedServer().disconnect();
|
|
||||||
player.setConnectedServer(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
MinecraftConnection connection = player.getConnection();
|
|
||||||
connection.setSessionHandler(new VelocityForgeHandshakeSessionHandler(connection.getSessionHandler(),player));
|
|
||||||
|
|
||||||
((VelocityServer) Ambassador.getInstance().server).unregisterConnection(player);
|
|
||||||
this.clientPhase = null;
|
|
||||||
|
|
||||||
ScheduledFuture<?> scheduledFuture = connection.eventLoop().schedule(()-> {
|
|
||||||
connection.getChannel().pipeline().remove(ForgeConstants.RESET_LISTENER);
|
|
||||||
future.complete(false);
|
|
||||||
}, Ambassador.getInstance().config.getResetTimeout(), TimeUnit.MILLISECONDS);
|
|
||||||
connection.getChannel().pipeline().addBefore(Connections.MINECRAFT_DECODER, ForgeConstants.RESET_LISTENER,new FML2CRPMResetCompleteDecoder());
|
|
||||||
getPayloadManager().listenFor(98).thenAccept(ignore -> {
|
|
||||||
if (scheduledFuture.cancel(false)) {
|
|
||||||
connection.getChannel().pipeline().remove(ForgeConstants.RESET_LISTENER);
|
|
||||||
connection.setState(StateRegistry.LOGIN);
|
|
||||||
this.clientPhase = ClientPhase.HANDSHAKE;
|
|
||||||
future.complete(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
connection.write(new PluginMessage("fml:handshake",Unpooled.wrappedBuffer(ForgeHandshakeUtils.generatePluginResetPacket())));
|
|
||||||
return future;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void handleKick(KickedFromServerEvent event) {
|
|
||||||
if (backupServer != null && !(event.getResult() instanceof KickedFromServerEvent.RedirectPlayer)) {
|
|
||||||
net.kyori.adventure.text.Component reason = event.getServerKickReason().orElse(null);
|
|
||||||
event.setResult(KickedFromServerEvent.RedirectPlayer.create(backupServer,reason));
|
|
||||||
backupServer = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,54 +1,17 @@
|
||||||
package org.adde0109.ambassador.forge;
|
package org.adde0109.ambassador.forge;
|
||||||
|
|
||||||
import com.velocitypowered.api.event.Continuation;
|
|
||||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||||
import com.velocitypowered.proxy.VelocityServer;
|
|
||||||
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
|
||||||
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.packet.LoginPluginMessage;
|
|
||||||
import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse;
|
|
||||||
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.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 {
|
||||||
|
|
||||||
private Throwable throwable;
|
|
||||||
private RegisteredServer triedServer;
|
|
||||||
private CompletableFuture<Void> onServerSuccess;
|
|
||||||
private CompletableFuture<Void> onJoinGame;
|
|
||||||
|
|
||||||
private static final Method CONNECT_TO_INITIAL_SERVER;
|
|
||||||
|
|
||||||
static {
|
|
||||||
Class clazz;
|
|
||||||
try {
|
|
||||||
clazz = Class.forName("com.velocitypowered.proxy.connection.client.LoginSessionHandler");
|
|
||||||
} catch (ClassNotFoundException ignored){
|
|
||||||
try {
|
|
||||||
clazz = Class.forName("com.velocitypowered.proxy.connection.client.AuthSessionHandler");
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
CONNECT_TO_INITIAL_SERVER = clazz.getDeclaredMethod("connectToInitialServer", ConnectedPlayer.class);
|
|
||||||
CONNECT_TO_INITIAL_SERVER.setAccessible(true);
|
|
||||||
} catch (ReflectiveOperationException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/*
|
||||||
@Override
|
@Override
|
||||||
public RegisteredServer chooseServer(ConnectedPlayer player) {
|
public RegisteredServer chooseServer(ConnectedPlayer player) {
|
||||||
forced = Ambassador.getTemporaryForced().remove(player.getUsername());
|
forced = Ambassador.getTemporaryForced().remove(player.getUsername());
|
||||||
|
|
@ -70,15 +33,8 @@ public class FML2ClientConnectionPhase extends VelocityForgeClientConnectionPhas
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void handleJoinGame() {
|
|
||||||
this.onJoinGame.complete(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompletableFuture<Void> awaitJoinGame() {
|
/*
|
||||||
return this.onJoinGame;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleForward(VelocityServerConnection serverConnection, LoginPluginMessage payload) {
|
public void handleForward(VelocityServerConnection serverConnection, LoginPluginMessage payload) {
|
||||||
final ByteBuf buf = payload.content().duplicate();
|
final ByteBuf buf = payload.content().duplicate();
|
||||||
ProtocolUtils.readString(buf); //Channel
|
ProtocolUtils.readString(buf); //Channel
|
||||||
|
|
@ -96,5 +52,7 @@ public class FML2ClientConnectionPhase extends VelocityForgeClientConnectionPhas
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@ import com.velocitypowered.proxy.connection.ConnectionType;
|
||||||
public class ForgeConstants {
|
public class ForgeConstants {
|
||||||
public static final String HANDLER = "Modern Forge handler";
|
public static final String HANDLER = "Modern Forge handler";
|
||||||
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 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 SERVER_SUCCESS_LISTENER = "ambassador-server-success-listener";
|
||||||
|
public static final String FORGE_HANDSHAKE_HOLDER = "ambassador-forge-handshake-holder";
|
||||||
|
|
||||||
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";
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import com.velocitypowered.proxy.config.PlayerInfoForwarding;
|
||||||
import com.velocitypowered.proxy.connection.ConnectionType;
|
import com.velocitypowered.proxy.connection.ConnectionType;
|
||||||
import com.velocitypowered.proxy.connection.backend.BackendConnectionPhase;
|
import com.velocitypowered.proxy.connection.backend.BackendConnectionPhase;
|
||||||
import com.velocitypowered.proxy.connection.client.ClientConnectionPhase;
|
import com.velocitypowered.proxy.connection.client.ClientConnectionPhase;
|
||||||
|
import org.adde0109.ambassador.velocity.VelocityForgeClientConnectionPhase;
|
||||||
import org.adde0109.ambassador.velocity.backend.VelocityForgeBackendConnectionPhase;
|
import org.adde0109.ambassador.velocity.backend.VelocityForgeBackendConnectionPhase;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
@ -19,7 +20,7 @@ public class ForgeFMLConnectionType implements ConnectionType {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientConnectionPhase getInitialClientPhase() {
|
public ClientConnectionPhase getInitialClientPhase() {
|
||||||
return new FML2ClientConnectionPhase();
|
return VelocityForgeClientConnectionPhase.NOT_STARTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ 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.StateRegistry;
|
||||||
import org.adde0109.ambassador.Ambassador;
|
import org.adde0109.ambassador.Ambassador;
|
||||||
import org.adde0109.ambassador.forge.FML2CRPMClientConnectionPhase;
|
|
||||||
|
|
||||||
public class VelocityEventHandler {
|
public class VelocityEventHandler {
|
||||||
|
|
||||||
|
|
@ -40,31 +39,9 @@ public class VelocityEventHandler {
|
||||||
continuation.resume();
|
continuation.resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe(order = PostOrder.LAST)
|
|
||||||
public void onKickedFromServerEvent(KickedFromServerEvent event, Continuation continuation) {
|
|
||||||
if (((ConnectedPlayer) event.getPlayer()).getPhase() instanceof FML2CRPMClientConnectionPhase phase) {
|
|
||||||
phase.handleKick(event);
|
|
||||||
}
|
|
||||||
continuation.resume();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Subscribe(order = PostOrder.LAST)
|
@Subscribe(order = PostOrder.LAST)
|
||||||
public void onServerPreConnectEvent(ServerPreConnectEvent event, Continuation continuation) {
|
public void onServerPreConnectEvent(ServerPreConnectEvent event, Continuation continuation) {
|
||||||
ConnectedPlayer player = (ConnectedPlayer) event.getPlayer();
|
continuation.resume();
|
||||||
if (!(player.getPhase() instanceof VelocityForgeClientConnectionPhase phase)) {
|
|
||||||
continuation.resume();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (phase.internalServerConnection != null) {
|
|
||||||
event.setResult(ServerPreConnectEvent.ServerResult.denied());
|
|
||||||
player.setConnectedServer((VelocityServerConnection) phase.internalServerConnection);
|
|
||||||
phase.internalServerConnection = null;
|
|
||||||
} else if (phase.clientPhase == VelocityForgeClientConnectionPhase.ClientPhase.MODDED) {
|
|
||||||
player.getConnection().eventLoop().submit(() -> phase.reset(event.getOriginalServer(), (ConnectedPlayer) event.getPlayer())
|
|
||||||
.thenAccept((ignored) -> continuation.resume()));
|
|
||||||
} else {
|
|
||||||
continuation.resume();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe(order = PostOrder.LAST)
|
@Subscribe(order = PostOrder.LAST)
|
||||||
|
|
@ -74,7 +51,7 @@ public class VelocityEventHandler {
|
||||||
continuation.resume();
|
continuation.resume();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
RegisteredServer chosenServer = phase.chooseServer(player);
|
RegisteredServer chosenServer = Ambassador.getTemporaryForced().remove(player.getUsername());
|
||||||
if (chosenServer != null)
|
if (chosenServer != null)
|
||||||
event.setInitialServer(chosenServer);
|
event.setInitialServer(chosenServer);
|
||||||
continuation.resume();
|
continuation.resume();
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package org.adde0109.ambassador.velocity;
|
package org.adde0109.ambassador.velocity;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.event.player.KickedFromServerEvent;
|
||||||
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;
|
||||||
|
|
@ -7,58 +8,115 @@ import com.velocitypowered.proxy.connection.MinecraftConnection;
|
||||||
import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
|
import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
|
||||||
import com.velocitypowered.proxy.connection.client.ClientConnectionPhase;
|
import com.velocitypowered.proxy.connection.client.ClientConnectionPhase;
|
||||||
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
||||||
|
import com.velocitypowered.proxy.network.Connections;
|
||||||
|
import com.velocitypowered.proxy.protocol.StateRegistry;
|
||||||
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 com.velocitypowered.proxy.protocol.packet.PluginMessage;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.adde0109.ambassador.Ambassador;
|
||||||
|
import org.adde0109.ambassador.forge.FML2CRPMResetCompleteDecoder;
|
||||||
|
import org.adde0109.ambassador.forge.ForgeConstants;
|
||||||
|
import org.adde0109.ambassador.forge.ForgeHandshakeUtils;
|
||||||
|
import org.adde0109.ambassador.velocity.client.OutboundForgeHandshakeHolder;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
|
||||||
public abstract class VelocityForgeClientConnectionPhase implements ClientConnectionPhase {
|
public enum VelocityForgeClientConnectionPhase implements ClientConnectionPhase {
|
||||||
//TODO:Make class when PCF is done
|
//TODO:Make class when PCF is done
|
||||||
|
|
||||||
|
NOT_STARTED {
|
||||||
|
@Override
|
||||||
|
VelocityForgeClientConnectionPhase nextPhase() {
|
||||||
|
return IN_PROGRESS;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
IN_PROGRESS {
|
||||||
|
|
||||||
VelocityLoginPayloadManager payloadManager;
|
},
|
||||||
public VelocityForgeClientConnectionPhase.ClientPhase clientPhase = ClientPhase.HANDSHAKE;
|
COMPLETE {
|
||||||
|
|
||||||
public ServerConnection internalServerConnection;
|
@Override
|
||||||
public RegisteredServer forced;
|
public void resetConnectionPhase(ConnectedPlayer player) {
|
||||||
|
MinecraftConnection connection = player.getConnection();
|
||||||
|
|
||||||
protected VelocityForgeClientConnectionPhase(ClientPhase clientPhase, VelocityLoginPayloadManager payloadManager) {
|
|
||||||
this.clientPhase = clientPhase;
|
|
||||||
this.payloadManager = payloadManager;
|
|
||||||
}
|
|
||||||
protected VelocityForgeClientConnectionPhase() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public RegisteredServer chooseServer(ConnectedPlayer player) {
|
//We unregister so no plugin sees this client while the client is being reset.
|
||||||
return null;
|
((VelocityServer) Ambassador.getInstance().server).unregisterConnection(player);
|
||||||
}
|
|
||||||
|
connection.getChannel().pipeline().addBefore(Connections.MINECRAFT_DECODER, ForgeConstants.RESET_LISTENER,new FML2CRPMResetCompleteDecoder());
|
||||||
|
connection.getChannel().pipeline().addLast(ForgeConstants.FORGE_HANDSHAKE_HOLDER,new OutboundForgeHandshakeHolder());
|
||||||
|
|
||||||
|
connection.write(new PluginMessage("fml:handshake", Unpooled.wrappedBuffer(ForgeHandshakeUtils.generatePluginResetPacket())));
|
||||||
|
|
||||||
|
player.setPhase(WAITING_RESET);
|
||||||
|
WAITING_RESET.onTransitionToNewPhase(player);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
WAITING_RESET {
|
||||||
|
|
||||||
|
ScheduledFuture<?> scheduledFuture;
|
||||||
|
@Override
|
||||||
|
void onTransitionToNewPhase(ConnectedPlayer player) {
|
||||||
|
scheduledFuture = player.getConnection().eventLoop().schedule(()-> {
|
||||||
|
player.getConnection().getChannel().pipeline().remove(ForgeConstants.RESET_LISTENER);
|
||||||
|
Ambassador.getTemporaryForced().put(player.getUsername(), player.getConnectionInFlight().getServer(),
|
||||||
|
Ambassador.getInstance().config.getServerSwitchCancellationTime(), TimeUnit.SECONDS);
|
||||||
|
//Disconnect - Reset Timeout
|
||||||
|
player.disconnect(Component.text(Ambassador.getInstance().config.getDisconnectResetMessage()));
|
||||||
|
}, Ambassador.getInstance().config.getResetTimeout(), TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean handle(ConnectedPlayer player, LoginPluginResponse response, VelocityServerConnection server) {
|
||||||
|
if (response.getId() == 98) {
|
||||||
|
if (scheduledFuture.cancel(false)) {
|
||||||
|
player.getConnection().getChannel().pipeline().remove(ForgeConstants.RESET_LISTENER);
|
||||||
|
player.getConnection().setState(StateRegistry.LOGIN);
|
||||||
|
player.setPhase(NOT_STARTED);
|
||||||
|
//Send all held messages
|
||||||
|
player.getConnection().getChannel().pipeline().remove(ForgeConstants.FORGE_HANDSHAKE_HOLDER);
|
||||||
|
|
||||||
|
player.getConnection().setSessionHandler(new VelocityForgeHandshakeSessionHandler(player.getConnection().getSessionHandler(),player));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public CompletableFuture<Boolean> reset(RegisteredServer server, ConnectedPlayer player) {
|
|
||||||
return CompletableFuture.completedFuture(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
final void onFirstLogin(ConnectedPlayer player, VelocityServer server) throws InterruptedException, InvocationTargetException, IllegalAccessException {
|
public ServerConnection internalServerConnection;
|
||||||
}
|
|
||||||
|
|
||||||
public void handleForward(VelocityServerConnection serverConnection, LoginPluginMessage payload) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public final VelocityLoginPayloadManager getPayloadManager() {
|
|
||||||
return payloadManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean handle(ConnectedPlayer player, LoginPluginResponse response, VelocityServerConnection server) {
|
public boolean handle(ConnectedPlayer player, LoginPluginResponse response, VelocityServerConnection server) {
|
||||||
server.getConnection().write(response.retain());
|
player.setPhase(nextPhase());
|
||||||
|
|
||||||
|
player.getConnectionInFlight().getConnection().write(response.retain());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ClientPhase {
|
private RegisteredServer lastKnownWorking;
|
||||||
VANILLA,
|
|
||||||
HANDSHAKE,
|
void onTransitionToNewPhase(ConnectedPlayer player) {
|
||||||
MODLIST,
|
|
||||||
MODDED
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VelocityForgeClientConnectionPhase nextPhase() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public void handleKick(KickedFromServerEvent event) {
|
||||||
|
//If kicked before the client has entered PLAY and has been reset.
|
||||||
|
if (lastKnownWorking != null && !(event.getResult() instanceof KickedFromServerEvent.RedirectPlayer)) {
|
||||||
|
net.kyori.adventure.text.Component reason = event.getServerKickReason().orElse(null);
|
||||||
|
event.setResult(KickedFromServerEvent.RedirectPlayer.create(lastKnownWorking,reason));
|
||||||
|
lastKnownWorking = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
package org.adde0109.ambassador.velocity;
|
|
||||||
|
|
||||||
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
|
||||||
import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage;
|
|
||||||
import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
public class VelocityLoginPayloadManager {
|
|
||||||
private final HashMap<Integer, CompletableFuture<ByteBuf>> listenerList = new HashMap<>();
|
|
||||||
private int counter = 0;
|
|
||||||
private final MinecraftConnection connection;
|
|
||||||
|
|
||||||
public VelocityLoginPayloadManager(MinecraftConnection connection) {
|
|
||||||
this.connection = connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompletableFuture<ByteBuf> sendPayload(String channel, ByteBuf data) {
|
|
||||||
connection.write(new LoginPluginMessage(counter,channel,data));
|
|
||||||
CompletableFuture<ByteBuf> future = listenFor(counter);
|
|
||||||
counter++;
|
|
||||||
return future;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompletableFuture<ByteBuf> sendPayloads(String channel, List<ByteBuf> dataList) {
|
|
||||||
final CompletableFuture<ByteBuf> callback = new CompletableFuture<>();
|
|
||||||
for (ByteBuf data : dataList) {
|
|
||||||
connection.delayedWrite(new LoginPluginMessage(counter, channel, data));
|
|
||||||
listenerList.put(counter,callback);
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
connection.flush();
|
|
||||||
return callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompletableFuture<ByteBuf> listenFor(int id) {
|
|
||||||
CompletableFuture<ByteBuf> value = listenerList.get(id);
|
|
||||||
if (value == null) {
|
|
||||||
CompletableFuture<ByteBuf> callback = new CompletableFuture<>();
|
|
||||||
listenerList.put(id,callback);
|
|
||||||
return callback;
|
|
||||||
} else {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean handlePayload(LoginPluginResponse response) {
|
|
||||||
final CompletableFuture<ByteBuf> callback = listenerList.get(response.getId());
|
|
||||||
if (callback != null) {
|
|
||||||
listenerList.remove(response.getId());
|
|
||||||
if (!listenerList.containsValue(callback)) {
|
|
||||||
callback.complete(response.content());
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -4,26 +4,19 @@ 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.BackendConnectionPhases;
|
||||||
import com.velocitypowered.proxy.connection.backend.LoginSessionHandler;
|
import com.velocitypowered.proxy.connection.backend.LoginSessionHandler;
|
||||||
|
import com.velocitypowered.proxy.connection.backend.TransitionSessionHandler;
|
||||||
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;
|
||||||
import com.velocitypowered.proxy.protocol.packet.Disconnect;
|
|
||||||
import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage;
|
import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage;
|
||||||
import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess;
|
import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess;
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
|
||||||
import net.kyori.adventure.text.format.TextColor;
|
|
||||||
import org.adde0109.ambassador.forge.ForgeConstants;
|
|
||||||
import org.adde0109.ambassador.forge.ForgeFMLConnectionType;
|
|
||||||
import org.adde0109.ambassador.velocity.VelocityForgeClientConnectionPhase;
|
|
||||||
|
|
||||||
public class ForgeHandshakeSessionHandler implements MinecraftSessionHandler {
|
public class ForgeLoginSessionHandler implements MinecraftSessionHandler {
|
||||||
|
|
||||||
private final LoginSessionHandler original;
|
private final LoginSessionHandler original;
|
||||||
private final VelocityServerConnection serverConnection;
|
private final VelocityServerConnection serverConnection;
|
||||||
private final VelocityServer server;
|
private final VelocityServer server;
|
||||||
|
|
||||||
public ForgeHandshakeSessionHandler(LoginSessionHandler original, VelocityServerConnection serverConnection, VelocityServer server) {
|
public ForgeLoginSessionHandler(LoginSessionHandler original, VelocityServerConnection serverConnection, VelocityServer server) {
|
||||||
this.original = original;
|
this.original = original;
|
||||||
this.serverConnection = serverConnection;
|
this.serverConnection = serverConnection;
|
||||||
this.server = server;
|
this.server = server;
|
||||||
|
|
@ -47,7 +40,11 @@ public class ForgeHandshakeSessionHandler implements MinecraftSessionHandler {
|
||||||
if ((serverConnection.getPhase() instanceof VelocityForgeBackendConnectionPhase phase)) {
|
if ((serverConnection.getPhase() instanceof VelocityForgeBackendConnectionPhase phase)) {
|
||||||
phase.onLoginSuccess(serverConnection,serverConnection.getPlayer());
|
phase.onLoginSuccess(serverConnection,serverConnection.getPlayer());
|
||||||
}
|
}
|
||||||
return original.handle(packet);
|
original.handle(packet);
|
||||||
|
serverConnection.getConnection().setSessionHandler(
|
||||||
|
new ForgePlaySessionHandler((TransitionSessionHandler) serverConnection
|
||||||
|
.getConnection().getSessionHandler(),serverConnection));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package org.adde0109.ambassador.velocity.backend;
|
||||||
|
|
||||||
|
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
|
||||||
|
import com.velocitypowered.proxy.connection.backend.TransitionSessionHandler;
|
||||||
|
import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
|
||||||
|
import com.velocitypowered.proxy.protocol.MinecraftPacket;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.JoinGame;
|
||||||
|
import org.adde0109.ambassador.velocity.VelocityForgeClientConnectionPhase;
|
||||||
|
|
||||||
|
public class ForgePlaySessionHandler implements MinecraftSessionHandler {
|
||||||
|
|
||||||
|
private final TransitionSessionHandler original;
|
||||||
|
private final VelocityServerConnection serverConnection;
|
||||||
|
|
||||||
|
public ForgePlaySessionHandler(TransitionSessionHandler original, VelocityServerConnection serverConnection) {
|
||||||
|
this.original = original;
|
||||||
|
this.serverConnection = serverConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(JoinGame packet) {
|
||||||
|
if (serverConnection.getPlayer().getPhase() instanceof VelocityForgeClientConnectionPhase clientPhase) {
|
||||||
|
serverConnection.getPlayer().setPhase(VelocityForgeClientConnectionPhase.COMPLETE);
|
||||||
|
}
|
||||||
|
return MinecraftSessionHandler.super.handle(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disconnected() {
|
||||||
|
original.disconnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleGeneric(MinecraftPacket packet) {
|
||||||
|
if (!packet.handle(original))
|
||||||
|
original.handleGeneric(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MinecraftSessionHandler getOriginal() {
|
||||||
|
return this.original;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,9 +3,11 @@ package org.adde0109.ambassador.velocity.backend;
|
||||||
import com.velocitypowered.proxy.connection.MinecraftConnection;
|
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.ClientConnectionPhase;
|
||||||
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.StateRegistry;
|
||||||
import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage;
|
import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage;
|
||||||
|
import io.netty.channel.PendingWriteQueue;
|
||||||
import org.adde0109.ambassador.forge.ForgeConstants;
|
import org.adde0109.ambassador.forge.ForgeConstants;
|
||||||
import org.adde0109.ambassador.velocity.VelocityForgeClientConnectionPhase;
|
import org.adde0109.ambassador.velocity.VelocityForgeClientConnectionPhase;
|
||||||
|
|
||||||
|
|
@ -34,34 +36,21 @@ public enum VelocityForgeBackendConnectionPhase implements BackendConnectionPhas
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
VelocityForgeBackendConnectionPhase() {
|
VelocityForgeBackendConnectionPhase() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handle(VelocityServerConnection server, ConnectedPlayer player, LoginPluginMessage message) {
|
public void handle(VelocityServerConnection server, ConnectedPlayer player, LoginPluginMessage message) {
|
||||||
|
|
||||||
|
|
||||||
VelocityForgeBackendConnectionPhase newPhase = nextPhase();
|
VelocityForgeBackendConnectionPhase newPhase = nextPhase();
|
||||||
|
|
||||||
server.setConnectionPhase(newPhase);
|
server.setConnectionPhase(newPhase);
|
||||||
|
|
||||||
VelocityForgeClientConnectionPhase clientPhase = ((VelocityForgeClientConnectionPhase) player.getPhase());
|
//Reset client if not ready to receive new handshake
|
||||||
if (player.getConnection().getState() != StateRegistry.LOGIN) {
|
VelocityForgeClientConnectionPhase clientPhase = (VelocityForgeClientConnectionPhase) player.getPhase();
|
||||||
final LoginPluginMessage msg = message;
|
clientPhase.resetConnectionPhase(player);
|
||||||
|
player.getConnection().write(message.retain());
|
||||||
msg.content().retain().discardSomeReadBytes();
|
|
||||||
|
|
||||||
server.getConnection().getChannel().config().setAutoRead(false);
|
|
||||||
clientPhase.reset(server.getServer(),player).thenAccept((success) -> {
|
|
||||||
if (success) {
|
|
||||||
player.getConnection().write(msg);
|
|
||||||
server.getConnection().getChannel().config().setAutoRead(true);
|
|
||||||
} else {
|
|
||||||
msg.release();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
player.getConnection().write(message.retain());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onLoginSuccess(VelocityServerConnection serverCon, ConnectedPlayer player) {
|
public void onLoginSuccess(VelocityServerConnection serverCon, ConnectedPlayer player) {
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ public class VelocityForgeBackendHandshakeHandler extends ChannelInboundHandlerA
|
||||||
ctx.pipeline().remove(this);
|
ctx.pipeline().remove(this);
|
||||||
|
|
||||||
if (serverConnection.getPlayer().getConnection().getType() instanceof ForgeFMLConnectionType) {
|
if (serverConnection.getPlayer().getConnection().getType() instanceof ForgeFMLConnectionType) {
|
||||||
connection.setSessionHandler(new ForgeHandshakeSessionHandler((LoginSessionHandler) connection.getSessionHandler(),serverConnection,server));
|
connection.setSessionHandler(new ForgeLoginSessionHandler((LoginSessionHandler) connection.getSessionHandler(),serverConnection,server));
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.pipeline().fireChannelActive();
|
ctx.pipeline().fireChannelActive();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
package org.adde0109.ambassador.velocity.client;
|
||||||
|
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage;
|
||||||
|
import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess;
|
||||||
|
import io.netty.channel.*;
|
||||||
|
|
||||||
|
public class OutboundForgeHandshakeHolder extends ChannelOutboundHandlerAdapter {
|
||||||
|
|
||||||
|
PendingWriteQueue writeQueue;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
writeQueue = new PendingWriteQueue(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||||
|
if ((msg instanceof LoginPluginMessage packet)) {
|
||||||
|
writeQueue.add(msg, promise);
|
||||||
|
} else {
|
||||||
|
ctx.write(msg, promise);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
|
||||||
|
if (ctx.channel().isActive()) {
|
||||||
|
writeQueue.removeAndWriteAll();
|
||||||
|
ctx.flush();
|
||||||
|
} else {
|
||||||
|
writeQueue.removeAndFailAll(new ChannelException());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user