diff --git a/build.gradle.kts b/build.gradle.kts index 95e2103..620cb13 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,7 +5,7 @@ plugins { } group = "org.adde0109" -version = "1.5.0" +version = "1.5.0-tst12" repositories { mavenCentral() diff --git a/src/main/java/org/adde0109/ambassador/forge/packet/ModDataPacket.java b/src/main/java/org/adde0109/ambassador/forge/packet/ModDataPacket.java index bfc6cf4..b048a10 100644 --- a/src/main/java/org/adde0109/ambassador/forge/packet/ModDataPacket.java +++ b/src/main/java/org/adde0109/ambassador/forge/packet/ModDataPacket.java @@ -1,10 +1,39 @@ package org.adde0109.ambassador.forge.packet; +import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; -public class ModDataPacket extends GenericForgeLoginWrapperPacket { +public class ModDataPacket implements IForgeLoginWrapperPacket { + private final byte[] content; + private final Context context; ModDataPacket(byte[] content, Context context) { - super(content, context); + this.content = content; + this.context = context; + } + + + static public ModDataPacket read(ByteBuf input, Context context) { + byte[] content = new byte[input.readableBytes()]; + input.readBytes(content); + return new ModDataPacket(content, context); + } + + @Override + public ByteBuf encode() { + ByteBuf buf = Unpooled.buffer(); + ProtocolUtils.writeVarInt(buf, 5); //PacketID + buf.writeBytes(content); + return buf; + } + + public byte[] getContent() { + return content; + } + + @Override + public Context getContext() { + return context; } } diff --git a/src/main/java/org/adde0109/ambassador/forge/pipeline/ForgeLoginWrapperCodec.java b/src/main/java/org/adde0109/ambassador/forge/pipeline/ForgeLoginWrapperCodec.java index 717487b..d0162eb 100644 --- a/src/main/java/org/adde0109/ambassador/forge/pipeline/ForgeLoginWrapperCodec.java +++ b/src/main/java/org/adde0109/ambassador/forge/pipeline/ForgeLoginWrapperCodec.java @@ -9,84 +9,108 @@ import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.DecoderException; import io.netty.handler.codec.MessageToMessageCodec; +import io.netty.util.ReferenceCountUtil; import org.adde0109.ambassador.Ambassador; import org.adde0109.ambassador.forge.packet.*; -import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class ForgeLoginWrapperCodec extends MessageToMessageCodec> { private final boolean FML3; - private final List loginWrapperIDs = new ArrayList<>(); + private final Map loginWrapperContexts = new HashMap<>(); public ForgeLoginWrapperCodec(boolean fml3) { FML3 = fml3; } + @Override + public boolean acceptInboundMessage(Object msg) throws Exception { + return (msg instanceof LoginPluginMessagePacket + && ((LoginPluginMessagePacket) msg).getChannel().equals("fml:loginwrapper")) + || (msg instanceof LoginPluginResponsePacket + && loginWrapperContexts.containsKey(((LoginPluginResponsePacket) msg).getId())); + } + @Override protected void decode(ChannelHandlerContext ctx, DeferredByteBufHolder in, List out) throws Exception { + ByteBuf buf = in.content(); + Context context; + if (in instanceof LoginPluginResponsePacket msg) { + //Continue from stored context + context = Context.fromContext( + loginWrapperContexts.remove(((LoginPluginResponsePacket) msg).getId()), msg.isSuccess()); + if (!msg.isSuccess()) { + //Nothing to read, just create an empty packet. + out.add(GenericForgeLoginWrapperPacket.read(buf, context)); + return; + } else { + String channel = ProtocolUtils.readString(buf); //Read the channel even though we know the channel by context. + Ambassador.getInstance(); + } + } else { + //New context. + LoginPluginMessagePacket msg = (LoginPluginMessagePacket) in; + String channel = ProtocolUtils.readString(buf); + + context = Context.createContext(msg.getId(), channel); + } + + //Decoding of data starts here - channel already read int originalReaderIndex = buf.readerIndex(); - String channel; - - try { - Context context; - if (in instanceof LoginPluginMessagePacket msg && msg.getChannel().equals("fml:loginwrapper")) { - channel = ProtocolUtils.readString(buf); - context = Context.createContext(msg.getId(), channel); - } else if (in instanceof LoginPluginResponsePacket msg && loginWrapperIDs.remove(Integer.valueOf(msg.getId()))) { - channel = ProtocolUtils.readString(buf); - context = Context.createClientContext(msg.getId(), msg.isSuccess(), channel); + if (!context.getChannelName().equals("fml:handshake")) { + out.add(GenericForgeLoginWrapperPacket.read(buf, context)); + } 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)); + break; + default: + //Undo decoding + buf.readerIndex(originalReaderIndex); + out.add(GenericForgeLoginWrapperPacket.read(buf, context)); + if (Ambassador.getInstance().config.isDebugMode()) { + Ambassador.getInstance().logger.warn( + "Unrecognised packet id received from client on fml:handshake: " + packetID); + } + } } else { - //Not a loginWrapperPacket - buf.readerIndex(originalReaderIndex); - ctx.fireChannelRead(in.retain()); - return; - } - - if (!channel.equals("fml:handshake")) { - out.add(GenericForgeLoginWrapperPacket.read(buf, context)); - } 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)); + switch (packetID) { + case 1: + out.add(ModListPacket.read(buf, context, FML3)); + break; + case 3: + out.add(RegistryPacket.read(buf, context, FML3)); + break; + case 4: + out.add(ConfigDataPacket.read(buf, context, FML3)); + break; + case 5: + if (FML3) { + out.add(ModDataPacket.read(buf, context)); break; - case 99: - out.add(new ACKPacket(clientContext)); - break; - default: - throw new DecoderException("Unrecognised packet ID: " + packetID); - } - } else { - switch (packetID) { - case 1: - out.add(ModListPacket.read(buf, context, FML3)); - break; - case 3: - out.add(RegistryPacket.read(buf, context, FML3)); - break; - case 4: - out.add(ConfigDataPacket.read(buf, context, FML3)); - break; - case 5: - if (FML3) { - buf.readerIndex(originalReaderIndex); - out.add(ModDataPacket.read(buf, context)); - break; - } - default: - throw new DecoderException("Unrecognised packet ID: " + packetID); - } + } + default: + //Undo decoding + buf.readerIndex(originalReaderIndex); + out.add(GenericForgeLoginWrapperPacket.read(buf, context)); + if (Ambassador.getInstance().config.isDebugMode()) { + Ambassador.getInstance().logger.warn( + "Unrecognised packet id received from server on fml:handshake: " + packetID); + } } } - } catch (DecoderException exception) { - Ambassador.getInstance().logger.error("Failed to decode a wrapped Forge login packet: ", exception); } } @@ -94,21 +118,28 @@ public class ForgeLoginWrapperCodec extends MessageToMessageCodec msg, List out) throws Exception { ByteBuf wrapped; + boolean data = !(msg.getContext() instanceof Context.ClientContext clientContext && !clientContext.success()); + + boolean includeLength = !(msg instanceof GenericForgeLoginWrapperPacket); + String channel = msg.getContext().getChannelName(); wrapped = Unpooled.buffer(); - ByteBuf encoded = msg.encode(); - ProtocolUtils.writeString(wrapped, channel); - ProtocolUtils.writeVarInt(wrapped, encoded.readableBytes()); - wrapped.writeBytes(encoded); - encoded.release(); + if (data) { + ByteBuf encoded = msg.encode(); + ProtocolUtils.writeString(wrapped, channel); + if (includeLength) + ProtocolUtils.writeVarInt(wrapped, encoded.readableBytes()); + wrapped.writeBytes(encoded); + encoded.release(); + } if (msg.getContext() instanceof Context.ClientContext clientContext) { out.add(new LoginPluginResponsePacket(clientContext.getResponseID(), clientContext.success(), wrapped)); } else { out.add(new LoginPluginMessagePacket(msg.getContext().getResponseID(), "fml:loginwrapper", wrapped)); if (!(msg instanceof ModDataPacket)) { //ModDataPacket doesn't require a response - this.loginWrapperIDs.add(msg.getContext().getResponseID()); + this.loginWrapperContexts.put(msg.getContext().getResponseID(), msg.getContext()); } } }