Reworked packet decoding/encoding

This commit is contained in:
Adrian Bergqvist 2023-11-27 00:03:26 +01:00
parent 82f3e1ba5f
commit 57282b69ab
No known key found for this signature in database
GPG Key ID: FAE7D8EDE225E686
16 changed files with 143 additions and 98 deletions

View File

@ -3,13 +3,14 @@ package org.adde0109.ambassador.forge;
import org.adde0109.ambassador.forge.packet.ModListPacket;
import org.adde0109.ambassador.forge.packet.ModListReplyPacket;
import java.util.List;
public class ForgeHandshake {
private ModListPacket modListPacket;
private ModListReplyPacket modListReplyPacket;
public ForgeHandshake() {
}
public ModListPacket getModListPacket() {

View File

@ -6,13 +6,11 @@ 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.ProtocolUtils;
import com.velocitypowered.proxy.protocol.StateRegistry;
import com.velocitypowered.proxy.protocol.packet.AvailableCommands;
import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage;
import com.velocitypowered.proxy.protocol.packet.PluginMessage;
import io.netty.buffer.ByteBuf;
import org.adde0109.ambassador.forge.pipeline.CommandDecoderErrorCatcher;
import org.adde0109.ambassador.forge.pipeline.ForgeLoginWrapperDecoder;
import org.adde0109.ambassador.forge.pipeline.ForgeLoginWrapperCodec;
public enum VelocityForgeBackendConnectionPhase implements BackendConnectionPhase {
NOT_STARTED() {
@ -82,10 +80,6 @@ public enum VelocityForgeBackendConnectionPhase implements BackendConnectionPhas
//Forge server
//To avoid unnecessary resets, we wait until we get the handshake even if we know that we should
//reset because that the previous server was Forge.
ForgeLoginWrapperDecoder decoder = (ForgeLoginWrapperDecoder) player.getConnection()
.getChannel().pipeline().get(ForgeConstants.FORGE_HANDSHAKE_DECODER);
decoder.registerLoginWrapperID(message.getId());
}
public void onLoginSuccess(VelocityServerConnection serverCon, ConnectedPlayer player) {

View File

@ -14,12 +14,10 @@ import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage;
import com.velocitypowered.proxy.protocol.packet.PluginMessage;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.kyori.adventure.text.Component;
import org.adde0109.ambassador.Ambassador;
import org.adde0109.ambassador.forge.packet.Context;
import org.adde0109.ambassador.forge.packet.IForgeLoginWrapperPacket;
import org.adde0109.ambassador.forge.packet.ModListReplyPacket;
import org.adde0109.ambassador.forge.pipeline.ForgeLoginWrapperDecoder;
import org.adde0109.ambassador.velocity.client.FML2CRPMResetCompleteDecoder;
import org.adde0109.ambassador.velocity.client.OutboundSuccessHolder;
import org.adde0109.ambassador.velocity.client.ClientPacketQueue;
@ -170,16 +168,6 @@ public enum VelocityForgeClientConnectionPhase implements ClientConnectionPhase
return true;
}
public void sendVanillaModlist(ConnectedPlayer player) {
player.getConnection().write(new LoginPluginMessage(0, "fml:loginwrapper",
Unpooled.wrappedBuffer(player.getConnection().getType() == ForgeConstants.ForgeFML3 ?
ForgeHandshakeUtils.emptyModlistFML3 : ForgeHandshakeUtils.emptyModlistFML2)));
ForgeLoginWrapperDecoder decoder = (ForgeLoginWrapperDecoder) player.getConnection()
.getChannel().pipeline().get(ForgeConstants.FORGE_HANDSHAKE_DECODER);
decoder.registerLoginWrapperID(0);
}
public void complete(ConnectedPlayer player) {
complete(player, isResettable(player));
}

View File

@ -7,12 +7,8 @@ public class ACKPacket implements IForgeLoginWrapperPacket<Context.ClientContext
private final Context.ClientContext context;
ACKPacket(int msgID, boolean success) {
this.context = Context.createContext(msgID, success);
}
ACKPacket read(ByteBuf input, int msgID, boolean success) {
return new ACKPacket(msgID, success);
public ACKPacket(Context.ClientContext context) {
this.context = context;
}
@Override
public ByteBuf encode() {

View File

@ -2,12 +2,12 @@ package org.adde0109.ambassador.forge.packet;
import io.netty.buffer.ByteBuf;
public class configDataPacket implements IForgeLoginWrapperPacket<Context> {
public class ConfigDataPacket implements IForgeLoginWrapperPacket<Context> {
private final Context context;
public configDataPacket(int msgID) {
this.context = Context.createContext(msgID);
public ConfigDataPacket(Context context) {
this.context = context;
}
@Override

View File

@ -8,11 +8,11 @@ public class Context {
this.responseID = responseID;
}
static Context createContext(int responseID) {
public static Context createContext(int responseID) {
return new Context(responseID);
}
static ClientContext createContext(int responseID, boolean clientSuccess) {
public static ClientContext createContext(int responseID, boolean clientSuccess) {
return new ClientContext(responseID,clientSuccess);
}

View File

@ -13,12 +13,9 @@ public class GenericForgeLoginWrapperPacket<T extends Context> extends DeferredB
this.context = context;
}
static public GenericForgeLoginWrapperPacket<Context> create(ByteBuf input, int id) {
return new GenericForgeLoginWrapperPacket<>(input, Context.createContext(id));
}
static public GenericForgeLoginWrapperPacket<Context> create(ByteBuf input, int id, boolean success) {
return new GenericForgeLoginWrapperPacket<>(input, Context.createContext(id, success));
static public GenericForgeLoginWrapperPacket<Context> create(ByteBuf input, Context context) {
return new GenericForgeLoginWrapperPacket<>(input, context);
}
@Override

View File

@ -19,15 +19,15 @@ public class ModListPacket implements IForgeLoginWrapperPacket<Context> {
private final Context context;
private ModListPacket(List<String> mods, Map<ChannelIdentifier,
String> channels, List<String> registries, int id, List<String> dataPackRegistries) {
String> channels, List<String> registries, Context context, List<String> dataPackRegistries) {
this.mods = mods;
this.channels = channels;
this.registries = registries;
this.context = Context.createContext(id);
this.context = context;
this.dataPackRegistries = dataPackRegistries;
}
public static ModListPacket read(ByteBuf input, int msgID, boolean FML3) {
public static ModListPacket read(ByteBuf input, Context context) {
List<String> mods = new ArrayList<>();
int len = ProtocolUtils.readVarInt(input);
@ -46,13 +46,13 @@ public class ModListPacket implements IForgeLoginWrapperPacket<Context> {
registries.add(ProtocolUtils.readString(input, 32767));
List<String> dataPackRegistries = new ArrayList<>();
if (FML3) {
if (input.isReadable()) {
len = ProtocolUtils.readVarInt(input);
for (int x = 0; x < len; x++)
dataPackRegistries.add(ProtocolUtils.readString(input, 0x100));
}
return new ModListPacket(mods, channels, registries, msgID, dataPackRegistries);
return new ModListPacket(mods, channels, registries, context, dataPackRegistries);
}
@Override

View File

@ -20,14 +20,14 @@ public class ModListReplyPacket implements IForgeLoginWrapperPacket<Context.Clie
private final Context.ClientContext context;
private ModListReplyPacket(List<String> mods, Map<ChannelIdentifier,
String> channels, Map<String, String> registries, int id, boolean success) {
String> channels, Map<String, String> registries, Context.ClientContext context) {
this.mods = mods;
this.channels = channels;
this.registries = registries;
this.context = Context.createContext(id, success);
this.context = context;
}
public static ModListReplyPacket read(ByteBuf input, int msgID) {
public static ModListReplyPacket read(ByteBuf input, Context.ClientContext context) {
List<String> mods = new ArrayList<>();
int len = ProtocolUtils.readVarInt(input);
@ -45,7 +45,7 @@ public class ModListReplyPacket implements IForgeLoginWrapperPacket<Context.Clie
for (int x = 0; x < len; x++)
registries.put(ProtocolUtils.readString(input, 32767), ProtocolUtils.readString(input, 0x100));
return new ModListReplyPacket(mods, channels, registries, msgID, true);
return new ModListReplyPacket(mods, channels, registries, context);
}
@Override

View File

@ -0,0 +1,21 @@
package org.adde0109.ambassador.forge.packet;
import io.netty.buffer.ByteBuf;
public class RegistryPacket implements IForgeLoginWrapperPacket<Context> {
private final Context context;
public RegistryPacket(Context context) {
this.context = context;
}
@Override
public ByteBuf encode() {
return null;
}
@Override
public Context getContext() {
return context;
}
}

View File

@ -0,0 +1,82 @@
package org.adde0109.ambassador.forge.pipeline;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage;
import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse;
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.DecoderException;
import io.netty.handler.codec.MessageToMessageCodec;
import org.adde0109.ambassador.forge.packet.*;
import java.util.ArrayList;
import java.util.List;
public class ForgeLoginWrapperCodec extends MessageToMessageCodec<DeferredByteBufHolder, IForgeLoginWrapperPacket<?>> {
private final List<Integer> loginWrapperIDs = new ArrayList<>();
@Override
protected void decode(ChannelHandlerContext ctx, DeferredByteBufHolder in, List<Object> out) throws Exception {
ByteBuf buf = in.content();
Context context;
if (in instanceof LoginPluginMessage msg && msg.getChannel().equals("fml:loginwrapper")) {
context = Context.createContext(msg.getId());
} else if (in instanceof LoginPluginResponse msg && loginWrapperIDs.remove(msg.getId()) != null) {
context = Context.createContext(msg.getId(), msg.isSuccess());
} else {
return;
}
int originalReaderIndex = buf.readerIndex();
try {
String channel = ProtocolUtils.readString(buf);
if (!channel.equals("fml:handshake")) {
throw new DecoderException();
} else {
int length = ProtocolUtils.readVarInt(buf);
int packetID = ProtocolUtils.readVarInt(buf);
if (context instanceof Context.ClientContext clientContext) {
switch (packetID) {
case 2:
out.add(ModListReplyPacket.read(buf, clientContext));
break;
case 99:
out.add(new ACKPacket(clientContext));
default:
throw new DecoderException();
}
} else {
switch (packetID) {
case 1:
out.add(ModListPacket.read(buf, context));
break;
case 3:
out.add(new RegistryPacket(context));
break;
case 4:
out.add(new ConfigDataPacket(context));
break;
default:
throw new DecoderException();
}
}
}
} catch (DecoderException e) {
buf.readerIndex(originalReaderIndex);
out.add(GenericForgeLoginWrapperPacket.create(buf.retain(), context));
}
}
@Override
protected void encode(ChannelHandlerContext ctx, IForgeLoginWrapperPacket<?> msg, List<Object> out) throws Exception {
if (msg.getContext() instanceof Context.ClientContext clientContext) {
out.add(new LoginPluginResponse(clientContext.getResponseID(), clientContext.success(), msg.encode()));
} else {
out.add(new LoginPluginMessage(msg.getContext().getResponseID(), "fml:loginwrapper", msg.encode()));
this.loginWrapperIDs.add(msg.getContext().getResponseID());
}
}
}

View File

@ -1,45 +0,0 @@
package org.adde0109.ambassador.forge.pipeline;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import org.adde0109.ambassador.forge.packet.GenericForgeLoginWrapperPacket;
import org.adde0109.ambassador.forge.packet.ModListReplyPacket;
import java.util.ArrayList;
import java.util.List;
public class ForgeLoginWrapperDecoder extends MessageToMessageDecoder<LoginPluginResponse> {
private final List<Integer> loginWrapperIDs = new ArrayList<>();
@Override
protected void decode(ChannelHandlerContext ctx, LoginPluginResponse msg, List<Object> out) throws Exception {
ByteBuf buf = msg.content();
if (!loginWrapperIDs.remove((Integer) msg.getId())) {
out.add(msg.retain());
return;
}
int originalReaderIndex = msg.content().readerIndex();
String channel = ProtocolUtils.readString(buf);
if (!channel.equals("fml:handshake")) {
buf.readerIndex(originalReaderIndex);
out.add(GenericForgeLoginWrapperPacket.create(buf.retain(), msg.getId(), true));
return;
}
int length = ProtocolUtils.readVarInt(buf);
int packetID = ProtocolUtils.readVarInt(buf);
if (packetID == 2) {
out.add(ModListReplyPacket.read(msg.content(), msg.getId()));
} else {
buf.readerIndex(originalReaderIndex);
out.add(GenericForgeLoginWrapperPacket.create(buf.retain(), msg.getId(), true));
}
}
public void registerLoginWrapperID(int loginWrapperID) {
this.loginWrapperIDs.add(loginWrapperID);
}
}

View File

@ -3,7 +3,6 @@ package org.adde0109.ambassador.velocity;
import com.velocitypowered.api.event.Continuation;
import com.velocitypowered.api.event.PostOrder;
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.player.*;
import com.velocitypowered.api.proxy.server.RegisteredServer;
@ -12,12 +11,11 @@ import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.network.Connections;
import com.velocitypowered.proxy.protocol.StateRegistry;
import net.kyori.adventure.text.Component;
import org.adde0109.ambassador.Ambassador;
import org.adde0109.ambassador.forge.ForgeConstants;
import org.adde0109.ambassador.forge.ForgeFMLConnectionType;
import org.adde0109.ambassador.forge.VelocityForgeClientConnectionPhase;
import org.adde0109.ambassador.forge.pipeline.ForgeLoginWrapperDecoder;
import org.adde0109.ambassador.forge.pipeline.ForgeLoginWrapperCodec;
import org.adde0109.ambassador.forge.pipeline.ForgeLoginWrapperHandler;
public class VelocityEventHandler {
@ -39,7 +37,7 @@ public class VelocityEventHandler {
player.getConnection().getChannel().pipeline().addBefore(
Connections.HANDLER,
ForgeConstants.FORGE_HANDSHAKE_DECODER, new ForgeLoginWrapperDecoder());
ForgeConstants.FORGE_HANDSHAKE_DECODER, new ForgeLoginWrapperCodec());
player.getConnection().getChannel().pipeline().addAfter(
ForgeConstants.FORGE_HANDSHAKE_DECODER,
ForgeConstants.FORGE_HANDSHAKE_HANDLER, new ForgeLoginWrapperHandler(player));

View File

@ -51,7 +51,7 @@ public class ForgeLoginSessionHandler implements MinecraftSessionHandler {
if (!(serverConnection.getConnection().getType() instanceof ForgeFMLConnectionType)) {
if (player.getConnectedServer() == null ||
player.getConnectedServer().getConnection().getType() instanceof ForgeFMLConnectionType) {
//Initial Vanilla
//Initial Vanilla - test if the client can be reset
//Forge -> vanilla
player.getPhase().resetConnectionPhase(player);
player.getConnectionInFlight().getConnection().getChannel().config().setAutoRead(false);

View File

@ -4,10 +4,14 @@ import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.connection.MinecraftConnection;
import com.velocitypowered.proxy.connection.backend.LoginSessionHandler;
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 io.netty.channel.*;
import org.adde0109.ambassador.forge.ForgeConstants;
import org.adde0109.ambassador.forge.ForgeFMLConnectionType;
import org.adde0109.ambassador.forge.pipeline.ForgeLoginWrapperCodec;
import org.adde0109.ambassador.forge.pipeline.ForgeLoginWrapperHandler;
import org.jetbrains.annotations.NotNull;
public class VelocityForgeBackendHandshakeHandler extends ChannelInboundHandlerAdapter {
@ -25,9 +29,17 @@ public class VelocityForgeBackendHandshakeHandler extends ChannelInboundHandlerA
ctx.pipeline().remove(this);
if (serverConnection.getPlayer().getConnection().getType() instanceof ForgeFMLConnectionType) {
ConnectedPlayer player = serverConnection.getPlayer();
if (player.getConnection().getType() instanceof ForgeFMLConnectionType) {
ForgeLoginSessionHandler forgeLoginSessionHandler = new ForgeLoginSessionHandler((LoginSessionHandler) connection.getActiveSessionHandler(), serverConnection,server);
connection.setActiveSessionHandler(StateRegistry.LOGIN, forgeLoginSessionHandler);
player.getConnection().getChannel().pipeline().addBefore(
Connections.HANDLER,
ForgeConstants.FORGE_HANDSHAKE_DECODER, new ForgeLoginWrapperCodec());
player.getConnection().getChannel().pipeline().addAfter(
ForgeConstants.FORGE_HANDSHAKE_DECODER,
ForgeConstants.FORGE_HANDSHAKE_HANDLER, new ForgeLoginWrapperHandler(player));
}
ctx.pipeline().fireChannelActive();

View File

@ -5,6 +5,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.adde0109.ambassador.forge.packet.Context;
import org.adde0109.ambassador.forge.packet.GenericForgeLoginWrapperPacket;
import org.adde0109.ambassador.forge.packet.IForgeLoginWrapperPacket;
@ -26,8 +27,8 @@ public class FML2CRPMResetCompleteDecoder extends ChannelInboundHandlerAdapter {
boolean success = buf.readBoolean();
if (id == 98) {
try {
IForgeLoginWrapperPacket packet = GenericForgeLoginWrapperPacket.create(Unpooled.EMPTY_BUFFER, id, success);
ctx.fireChannelRead(packet);
ctx.fireChannelRead(GenericForgeLoginWrapperPacket.create(
Unpooled.EMPTY_BUFFER, Context.createContext(id, success)));
} finally {
buf.release();
}