Auto-detect. Now works as expected

This commit is contained in:
Adrian Bergqvist 2022-10-20 22:52:26 +02:00
parent b021bed467
commit 772098772f
No known key found for this signature in database
GPG Key ID: FAE7D8EDE225E686
9 changed files with 137 additions and 70 deletions

View File

@ -4,7 +4,7 @@ plugins {
}
group 'org.adde0109'
version '1.0.6-alpha'
version '1.0.7-alpha'
repositories {
maven {

View File

@ -22,7 +22,7 @@ import org.slf4j.Logger;
import java.nio.file.Path;
@Plugin(id = "ambassador", name = "Ambassador", version = "1.0.6-alpha", authors = {"adde0109"})
@Plugin(id = "ambassador", name = "Ambassador", version = "1.0.7-alpha", authors = {"adde0109"})
public class Ambassador {
public ProxyServer server;

View File

@ -1,6 +1,5 @@
package org.adde0109.ambassador.forge;
import com.velocitypowered.api.event.Continuation;
import com.velocitypowered.api.event.player.KickedFromServerEvent;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.util.UuidUtils;
@ -12,23 +11,15 @@ import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
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.LoginPluginResponse;
import com.velocitypowered.proxy.protocol.packet.PluginMessage;
import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component;
import org.adde0109.ambassador.velocity.VelocityForgeClientConnectionPhase;
import org.adde0109.ambassador.velocity.VelocityForgeHandshakeSessionHandler;
import org.adde0109.ambassador.velocity.VelocityLoginPayloadManager;
import java.util.ArrayList;
import java.util.NoSuchElementException;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public class FML2CRPMClientConnectionPhase extends VelocityForgeClientConnectionPhase {
private static String OUTBOUND_CATCHER_NAME = "ambassador-catcher";
@ -36,18 +27,11 @@ public class FML2CRPMClientConnectionPhase extends VelocityForgeClientConnection
//TODO: Use modData inside ConnectedPlayer instead
public byte[] modListData;
private RegisteredServer backupServer;
@Override
public void handleLogin(ConnectedPlayer player, VelocityServer server, Continuation continuation) {
final MinecraftConnection connection = player.getConnection();
VelocityForgeHandshakeSessionHandler sessionHandler = new VelocityForgeHandshakeSessionHandler(connection.getSessionHandler(), player);
getPayloadManager().sendPayload("fml:loginwrapper",Unpooled.wrappedBuffer(ForgeHandshakeUtils.emptyModlist)).thenAccept((data) -> {
if (modListData == null)
modListData = ByteBufUtil.getBytes(data);
this.clientPhase = ClientPhase.MODDED;
continuation.resume();
});
connection.setSessionHandler(sessionHandler);
connection.flush();
public FML2CRPMClientConnectionPhase(VelocityForgeClientConnectionPhase.ClientPhase clientPhase, VelocityLoginPayloadManager payloadManager) {
super(clientPhase,payloadManager);
}
public FML2CRPMClientConnectionPhase() {
}
public void reset(VelocityServerConnection serverConnection, ConnectedPlayer player, Runnable whenComplete) {
@ -67,13 +51,18 @@ public class FML2CRPMClientConnectionPhase extends VelocityForgeClientConnection
connection.write(new PluginMessage("fml:handshake",Unpooled.wrappedBuffer(ForgeHandshakeUtils.generatePluginResetPacket())));
connection.setState(StateRegistry.LOGIN);
}
getPayloadManager().listenFor(98).thenAccept((ignored) -> {
getPayloadManager().listenFor(98).thenAccept((response) -> {
this.clientPhase = ClientPhase.HANDSHAKE;
whenComplete.run();
});
this.clientPhase = null;
connection.getChannel().pipeline().addBefore(Connections.HANDLER,OUTBOUND_CATCHER_NAME,new FML2CRPMOutgoingCatcher());
connection.getChannel().pipeline().addBefore(Connections.HANDLER,OUTBOUND_CATCHER_NAME,new FML2CRPMConnectionHandler(() -> {
connection.setState(StateRegistry.PLAY);
final FML2ClientConnectionPhase newPhase = new FML2ClientConnectionPhase(ClientPhase.HANDSHAKE,getPayloadManager());
player.setPhase(newPhase);
newPhase.reset(serverConnection,player,whenComplete);
}));
}
public void complete(VelocityServer server, ConnectedPlayer player, MinecraftConnection connection) {
VelocityConfiguration configuration = (VelocityConfiguration) server.getConfiguration();

View File

@ -1,16 +1,23 @@
package org.adde0109.ambassador.forge;
import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage;
import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse;
import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
import org.jetbrains.annotations.NotNull;
import java.util.*;
public class FML2CRPMOutgoingCatcher extends ChannelOutboundHandlerAdapter {
public class FML2CRPMConnectionHandler extends ChannelDuplexHandler {
private final Map<ChannelPromise, Object> catchedPackets = Collections.synchronizedMap(new LinkedHashMap<>());
private final Runnable abort;
public FML2CRPMConnectionHandler(Runnable abort) {
this.abort = abort;
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
@ -32,4 +39,15 @@ public class FML2CRPMOutgoingCatcher extends ChannelOutboundHandlerAdapter {
catchedPackets.put(promise,msg);
}
}
@Override
public void channelRead(@NotNull ChannelHandlerContext ctx, @NotNull Object msg) throws Exception {
if (!(msg instanceof LoginPluginResponse)) {
abort.run();
ctx.pipeline().remove(this);
ctx.pipeline().fireChannelRead(msg);
} else {
ctx.fireChannelRead(msg);
}
}
}

View File

@ -4,35 +4,40 @@ import com.velocitypowered.api.event.Continuation;
import com.velocitypowered.api.event.player.PlayerChooseInitialServerEvent;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerPing;
import com.velocitypowered.api.util.ModInfo;
import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.connection.MinecraftConnection;
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.LoginSessionHandler;
import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage;
import io.netty.buffer.ByteBuf;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.adde0109.ambassador.velocity.VelocityForgeClientConnectionPhase;
import org.adde0109.ambassador.velocity.VelocityLoginPayloadManager;
import org.apache.commons.collections4.map.PassiveExpiringMap;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
public class FML2ClientConnectionPhase extends VelocityForgeClientConnectionPhase {
private static String OUTBOUND_CATCHER_NAME = "ambassador-catcher";
private static final PassiveExpiringMap<String,RegisteredServer> TEMPORARY_FORCED = new PassiveExpiringMap<>(120, TimeUnit.SECONDS);
private Throwable throwable;
private RegisteredServer triedServer;
private Continuation continuation;
public FML2ClientConnectionPhase(VelocityForgeClientConnectionPhase.ClientPhase clientPhase, VelocityLoginPayloadManager payloadManager) {
super(clientPhase,payloadManager);
}
public FML2ClientConnectionPhase(){
super();
}
@Override
public void handleLogin(ConnectedPlayer player, VelocityServer server, Continuation continuation) {
@ -50,20 +55,8 @@ public class FML2ClientConnectionPhase extends VelocityForgeClientConnectionPhas
});
};
final RegisteredServer forced = TEMPORARY_FORCED.remove(player.getUsername());
if (forced != null) {
forced.ping().whenCompleteAsync((msg,ex) -> {
if (ex == null) {
if (throwable == null)
throwable = ex;
handlePingResponse(msg);
} else {
defaultTask.run();
}
},connection.eventLoop());
} else {
connection.eventLoop().submit(defaultTask);
}
forced = TEMPORARY_FORCED.remove(player.getUsername());
connection.eventLoop().submit(defaultTask);
}
@Override
@ -77,6 +70,14 @@ public class FML2ClientConnectionPhase extends VelocityForgeClientConnectionPhas
if (triedServer != null)
player.sendMessage(Component.translatable("velocity.error.connecting-server-error",
Component.text(triedServer.getServerInfo().getName())));
if (clientPhase == ClientPhase.VANILLA) {
player.setPhase(new FML2CRPMClientConnectionPhase(ClientPhase.VANILLA,getPayloadManager()));
} else if (clientPhase == ClientPhase.MODLIST) {
clientPhase = ClientPhase.MODDED;
internalServerConnection = player.getConnectionInFlight();
player.resetInFlightConnection();
continuation.resume();
}
}
private void tryServer(ConnectedPlayer player, RegisteredServer server) {
@ -89,21 +90,37 @@ public class FML2ClientConnectionPhase extends VelocityForgeClientConnectionPhas
if (ex != null) {
if (throwable == null)
throwable = ex;
tryServer(player,player.getNextServerToTry().orElse(null));
tryServer(player, player.getNextServerToTry().orElse(null));
} else {
handlePingResponse(msg);
handlePingResponse(player, server, msg);
}
}, player.getConnection().eventLoop());
}
private void handlePingResponse(ServerPing ping) {
if (ping.getModinfo().isEmpty() || !ping.getModinfo().get().getType().equals("Ambassador")) {
continuation.resume();
return;
@Override
public void forwardPayload(VelocityServerConnection serverConnection, LoginPluginMessage payload) {
ByteBuf buf = payload.content().copy();
String channel = ProtocolUtils.readString(buf);
int length = ProtocolUtils.readVarInt(buf);
int id = ProtocolUtils.readVarInt(buf);
if (id == 1) {
String[] mods = ProtocolUtils.readStringArray(buf);
if (Arrays.stream(mods).anyMatch(s -> s.equals("clientresetpacket"))) {
serverConnection.getPlayer().setPhase(new FML2CRPMClientConnectionPhase(ClientPhase.VANILLA,getPayloadManager()));
}
}
super.forwardPayload(serverConnection, payload);
}
private void handlePingResponse(ConnectedPlayer player, RegisteredServer server, ServerPing ping) {
if (ping.getModinfo().isEmpty()) {
clientPhase = ClientPhase.VANILLA;
continuation.resume();
} else {
player.createConnectionRequest(server).fireAndForget();
}
ModInfo.Mod mod = ping.getModinfo().get().getMods().get(0);
String data = mod.getId();
String markers = mod.getVersion();
}
}

View File

@ -2,11 +2,14 @@ package org.adde0109.ambassador.velocity;
import com.velocitypowered.api.event.Continuation;
import com.velocitypowered.api.event.PostOrder;
import com.velocitypowered.api.event.ResultedEvent;
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.permission.PermissionsSetupEvent;
import com.velocitypowered.api.event.player.KickedFromServerEvent;
import com.velocitypowered.api.event.player.PlayerChooseInitialServerEvent;
import com.velocitypowered.api.event.player.ServerPreConnectEvent;
import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import org.adde0109.ambassador.Ambassador;
@ -40,4 +43,32 @@ public class VelocityEventHandler {
}
continuation.resume();
}
@Subscribe(order = PostOrder.FIRST)
public void onServerPreConnectEvent(ServerPreConnectEvent event, Continuation continuation) {
ConnectedPlayer player = (ConnectedPlayer) event.getPlayer();
if (!(player.getPhase() instanceof VelocityForgeClientConnectionPhase phase)) {
continuation.resume();
return;
}
if (phase.internalServerConnection != null) {
event.setResult(ServerPreConnectEvent.ServerResult.denied());
phase.internalServerConnection = null;
}
continuation.resume();
}
@Subscribe(order = PostOrder.LAST)
public void onPlayerChooseInitialServerEvent(PlayerChooseInitialServerEvent event, Continuation continuation) {
ConnectedPlayer player = (ConnectedPlayer) event.getPlayer();
if (!(player.getPhase() instanceof VelocityForgeClientConnectionPhase phase)) {
continuation.resume();
return;
}
if (phase.forced != null)
event.setInitialServer(phase.forced);
if (event.getInitialServer().isEmpty())
event.setInitialServer(phase.internalServerConnection.getServer());
continuation.resume();
}
}

View File

@ -1,6 +1,8 @@
package org.adde0109.ambassador.velocity;
import com.velocitypowered.api.event.Continuation;
import com.velocitypowered.api.proxy.ServerConnection;
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;
@ -9,17 +11,24 @@ import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage;
import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse;
import org.adde0109.ambassador.forge.FML2CRPMClientConnectionPhase;
import org.adde0109.ambassador.forge.ForgeHandshakeUtils;
import javax.annotation.Nullable;
import java.util.ArrayList;
public abstract class VelocityForgeClientConnectionPhase implements ClientConnectionPhase {
//TODO:Make class when PCF is done
VelocityLoginPayloadManager payloadManager;
public FML2CRPMClientConnectionPhase.ClientPhase clientPhase = ClientPhase.HANDSHAKE;
public VelocityForgeClientConnectionPhase.ClientPhase clientPhase = ClientPhase.HANDSHAKE;
public ServerConnection internalServerConnection;
public RegisteredServer forced;
protected VelocityForgeClientConnectionPhase(ClientPhase clientPhase, VelocityLoginPayloadManager payloadManager) {
this.clientPhase = clientPhase;
this.payloadManager = payloadManager;
}
protected VelocityForgeClientConnectionPhase() {
}
public void handleLogin(ConnectedPlayer player, VelocityServer server, Continuation continuation) {
}
@ -34,6 +43,9 @@ public abstract class VelocityForgeClientConnectionPhase implements ClientConnec
final void fireLoginEvent(ConnectedPlayer player, VelocityServer server, Continuation continuation) {
payloadManager = new VelocityLoginPayloadManager(player.getConnection());
handleLogin(player,server,continuation);
VelocityForgeHandshakeSessionHandler sessionHandler = new VelocityForgeHandshakeSessionHandler(player.getConnection().getSessionHandler(), player);
player.getConnection().setSessionHandler(sessionHandler);
}
public void forwardPayload(VelocityServerConnection serverConnection, LoginPluginMessage payload) {
@ -44,6 +56,7 @@ public abstract class VelocityForgeClientConnectionPhase implements ClientConnec
//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() {

View File

@ -20,15 +20,13 @@ public class VelocityForgeBackendConnectionPhase implements BackendConnectionPha
public void handleSuccess(VelocityServerConnection serverCon, VelocityServer server) {
VelocityForgeClientConnectionPhase clientPhase = ((VelocityForgeClientConnectionPhase) serverCon.getPlayer().getPhase());
if (clientPhase.clientPhase == VelocityForgeClientConnectionPhase.ClientPhase.HANDSHAKE || clientPhase.clientPhase == VelocityForgeClientConnectionPhase.ClientPhase.MODLIST) {
clientPhase.complete((VelocityServer) server,serverCon.getPlayer(),serverCon.getPlayer().getConnection());
}
clientPhase.complete((VelocityServer) server,serverCon.getPlayer(),serverCon.getPlayer().getConnection());
}
public boolean handle(VelocityServerConnection server, ConnectedPlayer player, LoginPluginMessage message) throws Exception {
VelocityForgeClientConnectionPhase clientPhase = ((FML2CRPMClientConnectionPhase) player.getPhase());
VelocityForgeClientConnectionPhase clientPhase = ((VelocityForgeClientConnectionPhase) player.getPhase());
message.retain();
if (clientPhase.clientPhase == FML2CRPMClientConnectionPhase.ClientPhase.VANILLA) {
if (clientPhase.clientPhase == VelocityForgeClientConnectionPhase.ClientPhase.VANILLA) {
clientPhase.reset(server,player, () -> {
for (LoginPluginMessage msg: queuedHandshakePackets) {
clientPhase.forwardPayload(server,msg);

View File

@ -11,6 +11,7 @@ import io.netty.channel.*;
import io.netty.util.ReferenceCountUtil;
import org.adde0109.ambassador.forge.ForgeConstants;
import org.adde0109.ambassador.forge.FML2CRPMClientConnectionPhase;
import org.adde0109.ambassador.velocity.VelocityForgeClientConnectionPhase;
public class VelocityForgeBackendHandshakeHandler extends ChannelDuplexHandler {
@ -30,9 +31,9 @@ public class VelocityForgeBackendHandshakeHandler extends ChannelDuplexHandler {
ChannelHandler handler = ctx.pipeline().get(Connections.HANDLER);
if (handler instanceof MinecraftConnection connection) {
if (connection.getAssociation() instanceof VelocityServerConnection serverConnection) {
if (serverConnection.getPlayer().getPhase() instanceof FML2CRPMClientConnectionPhase phase) {
if (serverConnection.getPlayer().getPhase() instanceof VelocityForgeClientConnectionPhase phase) {
init(connection,serverConnection);
if (phase.clientPhase == FML2CRPMClientConnectionPhase.ClientPhase.MODDED) {
if (phase.clientPhase == VelocityForgeClientConnectionPhase.ClientPhase.MODDED) {
phase.reset(serverConnection ,serverConnection.getPlayer(), () -> {
ctx.flush();
});