WIP: Almost

This commit is contained in:
Adrian Bergqvist 2022-09-19 00:46:19 +02:00
parent e8f73d19b1
commit fea9082dd7
No known key found for this signature in database
GPG Key ID: FAE7D8EDE225E686
7 changed files with 130 additions and 29 deletions

View File

@ -1,11 +1,19 @@
package org.adde0109.ambassador.forge; package org.adde0109.ambassador.forge;
import com.velocitypowered.api.event.Continuation; import com.velocitypowered.api.event.Continuation;
import com.velocitypowered.api.util.UuidUtils;
import com.velocitypowered.proxy.Velocity;
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.MinecraftConnection;
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.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 com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil; import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
@ -14,7 +22,12 @@ import org.adde0109.ambassador.velocity.VelocityForgeHandshakeSessionHandler;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
public class ForgeFML2ClientConnectionPhase implements VelocityForgeClientConnectionPhase { public class ForgeFML2ClientConnectionPhase implements VelocityForgeClientConnectionPhase {
private boolean isResettable; private boolean isResettable;
@ -23,15 +36,15 @@ public class ForgeFML2ClientConnectionPhase implements VelocityForgeClientConnec
public byte[] modListData; public byte[] modListData;
private final ArrayList<Integer> listenerList = new ArrayList(); private final ArrayList<Integer> listenerList = new ArrayList();
private Continuation whenComplete; private Runnable whenComplete;
@Override @Override
public void handleLogin(ConnectedPlayer player,ForgeHandshakeUtils.CachedServerHandshake handshake, Continuation continuation) { public void handleLogin(ConnectedPlayer player,ForgeHandshakeUtils.CachedServerHandshake handshake, Continuation continuation) {
this.whenComplete = continuation; this.whenComplete = continuation::resume;
final MinecraftConnection connection = player.getConnection(); final MinecraftConnection connection = player.getConnection();
VelocityForgeHandshakeSessionHandler sessionHandler = new VelocityForgeHandshakeSessionHandler(connection.getSessionHandler(),player); VelocityForgeHandshakeSessionHandler sessionHandler = new VelocityForgeHandshakeSessionHandler(connection.getSessionHandler(),player);
if(handshake == null) { if(handshake == null) {
connection.delayedWrite(new LoginPluginMessage(98,"fml:loginwrapper", Unpooled.wrappedBuffer(ForgeHandshakeUtils.generateResetPacket()))); connection.delayedWrite(new LoginPluginMessage(1,"fml:loginwrapper", Unpooled.wrappedBuffer(ForgeHandshakeUtils.generateEmptyModlist())));
listenerList.add(98); listenerList.add(1);
} else { } else {
connection.delayedWrite(new LoginPluginMessage(1,"fml:loginwrapper", Unpooled.wrappedBuffer(handshake.modListPacket))); connection.delayedWrite(new LoginPluginMessage(1,"fml:loginwrapper", Unpooled.wrappedBuffer(handshake.modListPacket)));
listenerList.add(1); listenerList.add(1);
@ -59,9 +72,22 @@ public class ForgeFML2ClientConnectionPhase implements VelocityForgeClientConnec
} }
modListData = ByteBufUtil.getBytes(packet.content()); modListData = ByteBufUtil.getBytes(packet.content());
} }
if (listenerList.isEmpty()) { if (listenerList.isEmpty() && whenComplete != null) {
whenComplete.resume(); whenComplete.run();
whenComplete = null;
} }
return true; return true;
} }
public void reset(ConnectedPlayer player,MinecraftConnection connection, List<byte[]> messages, Runnable whenComplete) {
this.whenComplete = whenComplete;
connection.setSessionHandler(new VelocityForgeHandshakeSessionHandler(connection.getSessionHandler(),player));
connection.write(new PluginMessage("fml:handshake",Unpooled.wrappedBuffer(ForgeHandshakeUtils.generatePluginResetPacket())));
listenerList.add(98);
connection.setState(StateRegistry.LOGIN);
for (int i = 0;i<messages.size();i++) {
connection.delayedWrite(new LoginPluginMessage(i+2,"fml:loginwrapper", Unpooled.wrappedBuffer(messages.get(i))));
listenerList.add(i+2);
}
connection.flush();
}
} }

View File

@ -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.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.BackendConnectionPhases;
import com.velocitypowered.proxy.connection.client.ClientConnectionPhase; import com.velocitypowered.proxy.connection.client.ClientConnectionPhase;
import org.adde0109.ambassador.velocity.backend.VelocityForgeBackendConnectionPhase; import org.adde0109.ambassador.velocity.backend.VelocityForgeBackendConnectionPhase;
@ -17,7 +18,7 @@ public class ForgeFML2ConnectionType implements ConnectionType {
@Override @Override
public BackendConnectionPhase getInitialBackendPhase() { public BackendConnectionPhase getInitialBackendPhase() {
return new VelocityForgeBackendConnectionPhase(); return BackendConnectionPhases.UNKNOWN;
} }
@Override @Override

View File

@ -8,7 +8,16 @@ import com.velocitypowered.api.proxy.server.ServerPing;
import com.velocitypowered.api.util.ModInfo; import com.velocitypowered.api.util.ModInfo;
import java.util.*; import java.util.*;
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.protocol.StateRegistry;
import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import org.adde0109.ambassador.velocity.VelocityForgeHandshakeSessionHandler;
import org.slf4j.Logger; import org.slf4j.Logger;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -73,11 +82,46 @@ public class ForgeHandshakeUtils {
stream.write(dataAndPacketId); stream.write(dataAndPacketId);
return stream.toByteArray(); return stream.toByteArray();
} }
public static byte[] generatePluginResetPacket() {
ByteArrayDataOutput dataAndPacketIdStream = ByteStreams.newDataOutput();
writeVarInt(dataAndPacketIdStream,98);
return dataAndPacketIdStream.toByteArray();
}
public static byte[] generateEmptyModlist() {
ByteArrayDataOutput dataAndPacketIdStream = ByteStreams.newDataOutput();
writeVarInt(dataAndPacketIdStream,1);
writeVarInt(dataAndPacketIdStream,0);
writeVarInt(dataAndPacketIdStream,0);
writeVarInt(dataAndPacketIdStream,0);
ByteArrayDataOutput stream = ByteStreams.newDataOutput();
byte[] dataAndPacketId = dataAndPacketIdStream.toByteArray();
writeUtf(stream,"fml:handshake");
writeVarInt(stream,dataAndPacketId.length);
stream.write(dataAndPacketId);
return stream.toByteArray();
}
static 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);
connection.setState(StateRegistry.PLAY);
connection.setSessionHandler(((VelocityForgeHandshakeSessionHandler) connection.getSessionHandler()).getOriginal());
}
public static final byte[] ACKPacket = generateACKPacket(); public static final byte[] ACKPacket = generateACKPacket();
private static byte[] generateACKPacket() { private static byte[] generateACKPacket() {
ByteArrayDataOutput dataAndPacketIdStream = ByteStreams.newDataOutput(); ByteArrayDataOutput dataAndPacketIdStream = ByteStreams.newDataOutput();
writeVarInt(dataAndPacketIdStream,4); writeVarInt(dataAndPacketIdStream,99);
ByteArrayDataOutput stream = ByteStreams.newDataOutput(); ByteArrayDataOutput stream = ByteStreams.newDataOutput();
byte[] dataAndPacketId = dataAndPacketIdStream.toByteArray(); byte[] dataAndPacketId = dataAndPacketIdStream.toByteArray();

View File

@ -4,6 +4,7 @@ import com.velocitypowered.api.event.Continuation;
import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.permission.PermissionsSetupEvent; import com.velocitypowered.api.event.permission.PermissionsSetupEvent;
import com.velocitypowered.api.event.player.ServerLoginPluginMessageEvent; import com.velocitypowered.api.event.player.ServerLoginPluginMessageEvent;
import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.connection.ConnectionTypes; 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;
@ -11,6 +12,7 @@ import com.velocitypowered.proxy.connection.backend.BackendConnectionPhases;
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.LoginPluginMessage; import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import org.adde0109.ambassador.Ambassador; import org.adde0109.ambassador.Ambassador;
import org.adde0109.ambassador.forge.ForgeFML2ClientConnectionPhase; import org.adde0109.ambassador.forge.ForgeFML2ClientConnectionPhase;
@ -54,11 +56,14 @@ public class VelocityEventHandler {
continuation.resumeWithException(new NullPointerException()); continuation.resumeWithException(new NullPointerException());
return; return;
} }
serverCon.setConnectionPhase(new VelocityForgeBackendConnectionPhase()); connection.eventLoop().submit(() -> {
connection.setType(new ForgeFML2ConnectionType()); connection.setType(new ForgeFML2ConnectionType());
MinecraftSessionHandler sessionHandler = new VelocityForgeBackendHandshakeSessionHandler(connection.getSessionHandler(),serverCon); serverCon.setConnectionPhase(new VelocityForgeBackendConnectionPhase(ambassador));
connection.setSessionHandler(sessionHandler); byte[] response = ((VelocityForgeBackendConnectionPhase)serverCon.getPhase()).generateResponse(serverCon.getPlayer(), Unpooled.wrappedBuffer(event.getContents()));
sessionHandler.handle(new LoginPluginMessage(event.getSequenceId(),event.getIdentifier().getId(), Unpooled.wrappedBuffer(event.getContents()))); event.setResult(ServerLoginPluginMessageEvent.ResponseResult.reply(response));
continuation.resume(); continuation.resume();
MinecraftSessionHandler sessionHandler = new VelocityForgeBackendHandshakeSessionHandler(connection.getSessionHandler(),serverCon);
connection.setSessionHandler(sessionHandler);
});
} }
} }

View File

@ -15,6 +15,7 @@ import java.util.List;
public class VelocityForgeHandshakeSessionHandler implements MinecraftSessionHandler { public class VelocityForgeHandshakeSessionHandler implements MinecraftSessionHandler {
private final MinecraftSessionHandler original; private final MinecraftSessionHandler original;
private final ConnectedPlayer player; private final ConnectedPlayer player;
public VelocityForgeHandshakeSessionHandler(MinecraftSessionHandler original, ConnectedPlayer player) { public VelocityForgeHandshakeSessionHandler(MinecraftSessionHandler original, ConnectedPlayer player) {
this.original = original; this.original = original;
this.player = player; this.player = player;
@ -37,4 +38,8 @@ public class VelocityForgeHandshakeSessionHandler implements MinecraftSessionHan
public void disconnected() { public void disconnected() {
original.disconnected(); original.disconnected();
} }
}
public MinecraftSessionHandler getOriginal() {
return this.original;
}
}

View File

@ -1,34 +1,43 @@
package org.adde0109.ambassador.velocity.backend; package org.adde0109.ambassador.velocity.backend;
import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteArrayDataInput;
import com.velocitypowered.proxy.VelocityServer;
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.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.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 com.velocitypowered.proxy.protocol.packet.PluginMessage;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import org.adde0109.ambassador.Ambassador;
import org.adde0109.ambassador.forge.ForgeFML2ClientConnectionPhase; import org.adde0109.ambassador.forge.ForgeFML2ClientConnectionPhase;
import org.adde0109.ambassador.forge.ForgeHandshakeUtils; import org.adde0109.ambassador.forge.ForgeHandshakeUtils;
import org.adde0109.ambassador.velocity.VelocityForgeClientConnectionPhase; import org.adde0109.ambassador.velocity.VelocityForgeClientConnectionPhase;
import java.io.EOFException; import java.io.EOFException;
import java.util.ArrayList;
import java.util.List;
public class VelocityForgeBackendConnectionPhase implements BackendConnectionPhase { public class VelocityForgeBackendConnectionPhase implements BackendConnectionPhase {
public boolean handle(VelocityServerConnection server, ConnectedPlayer player, LoginPluginMessage message) { private final Ambassador ambassador;
if (!message.getChannel().equals("fml:loginwrapper") || !(player.getPhase() instanceof VelocityForgeClientConnectionPhase)) { private final List<byte[]> handshakeMessages = new ArrayList<>();
return false;
}
MinecraftConnection connection = server.getConnection();
if (connection == null) {
throw new NullPointerException();
}
ByteBuf content = message.content(); public VelocityForgeBackendConnectionPhase(Ambassador ambassador) {
this.ambassador = ambassador;
}
public void handleSuccess(VelocityServerConnection serverCon) {
((ForgeFML2ClientConnectionPhase) serverCon.getPlayer().getPhase()).reset(serverCon.getPlayer(),serverCon.getPlayer().getConnection(), handshakeMessages,
() -> ForgeHandshakeUtils.complete((VelocityServer) ambassador.server,serverCon.getPlayer(),serverCon.getPlayer().getConnection()));
}
public byte[] generateResponse(ConnectedPlayer player, ByteBuf content) {
content.readBytes(14); //Channel Identifier content.readBytes(14); //Channel Identifier
ProtocolUtils.readVarInt(content); //Length ProtocolUtils.readVarInt(content); //Length
int packetID = ProtocolUtils.readVarInt(content); int packetID = ProtocolUtils.readVarInt(content);
@ -38,14 +47,23 @@ public class VelocityForgeBackendConnectionPhase implements BackendConnectionPha
case 1: case 1:
final byte[] data = ((ForgeFML2ClientConnectionPhase) player.getPhase()).modListData; final byte[] data = ((ForgeFML2ClientConnectionPhase) player.getPhase()).modListData;
connection.write(new LoginPluginResponse(message.getId(),true, Unpooled.wrappedBuffer(data))); return data;
break;
default: default:
connection.write(new LoginPluginResponse(message.getId(),true,Unpooled.wrappedBuffer(ForgeHandshakeUtils.ACKPacket))); return ForgeHandshakeUtils.ACKPacket;
break;
} }
}
public boolean handle(VelocityServerConnection server, ConnectedPlayer player, LoginPluginMessage message) {
if (!message.getChannel().equals("fml:loginwrapper") || !(player.getPhase() instanceof VelocityForgeClientConnectionPhase)) {
return false;
}
MinecraftConnection connection = server.getConnection();
if (connection == null) {
throw new NullPointerException();
}
connection.write(new LoginPluginResponse(message.getId(),true, Unpooled.wrappedBuffer(generateResponse(player,message.content()))));
return true; return true;
} }
} }

View File

@ -37,6 +37,8 @@ public class VelocityForgeBackendHandshakeSessionHandler implements MinecraftSes
@Override @Override
public boolean handle(ServerLoginSuccess packet) { public boolean handle(ServerLoginSuccess packet) {
return original.handle(packet); original.handle(packet);
((VelocityForgeBackendConnectionPhase) serverCon.getPhase()).handleSuccess(serverCon);
return true;
} }
} }