package org.openrs2.protocol import io.netty.buffer.ByteBuf import io.netty.channel.ChannelHandlerContext import io.netty.handler.codec.EncoderException import io.netty.handler.codec.MessageToByteEncoder import org.openrs2.crypto.NopStreamCipher import org.openrs2.crypto.StreamCipher public class Rs2Encoder(public var protocol: Protocol) : MessageToByteEncoder(Packet::class.java) { public var cipher: StreamCipher = NopStreamCipher override fun encode(ctx: ChannelHandlerContext, msg: Packet, out: ByteBuf) { val encoder = protocol.getEncoder(msg.javaClass) ?: throw EncoderException("Unsupported packet type: ${msg.javaClass}") out.writeByte(encoder.opcode + cipher.nextInt()) val len = encoder.length val lenIndex = out.writerIndex() when (len) { PacketLength.VARIABLE_BYTE -> out.writeZero(1) PacketLength.VARIABLE_SHORT -> out.writeZero(2) } val payloadIndex = out.writerIndex() encoder.encode(msg, out) val written = out.writerIndex() - payloadIndex when (len) { PacketLength.VARIABLE_BYTE -> { if (written >= 256) { throw EncoderException("Variable byte payload too long: $written bytes") } out.setByte(lenIndex, written) } PacketLength.VARIABLE_SHORT -> { if (written >= 65536) { throw EncoderException("Variable short payload too long: $written bytes") } out.setShort(lenIndex, written) } else -> { if (written != len) { throw EncoderException("Fixed payload length mismatch (expected $len bytes, got $written bytes)") } } } } override fun allocateBuffer(ctx: ChannelHandlerContext, msg: Packet, preferDirect: Boolean): ByteBuf { val encoder = protocol.getEncoder(msg.javaClass) ?: throw EncoderException("Unsupported packet type: ${msg.javaClass}") return encoder.allocateBuffer(ctx.alloc(), msg, preferDirect) } }