Open-source multiplayer game server compatible with the RuneScape client
https://www.openrs2.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
73 lines
2.2 KiB
73 lines
2.2 KiB
package org.openrs2.protocol
|
|
|
|
import com.github.michaelbull.logging.InlineLogger
|
|
import io.netty.buffer.ByteBuf
|
|
import io.netty.channel.ChannelHandlerContext
|
|
import io.netty.handler.codec.ByteToMessageDecoder
|
|
import io.netty.handler.codec.DecoderException
|
|
import org.openrs2.crypto.NopStreamCipher
|
|
import org.openrs2.crypto.StreamCipher
|
|
|
|
public class Rs2Decoder(public var protocol: Protocol) : ByteToMessageDecoder() {
|
|
private enum class State {
|
|
READ_OPCODE,
|
|
READ_LENGTH,
|
|
READ_PAYLOAD
|
|
}
|
|
|
|
public var cipher: StreamCipher = NopStreamCipher
|
|
private var state = State.READ_OPCODE
|
|
private lateinit var decoder: PacketCodec<*>
|
|
private var length = 0
|
|
|
|
init {
|
|
isSingleDecode = true
|
|
}
|
|
|
|
override fun decode(ctx: ChannelHandlerContext, input: ByteBuf, out: MutableList<Any>) {
|
|
if (state == State.READ_OPCODE) {
|
|
if (!input.isReadable) {
|
|
return
|
|
}
|
|
|
|
val opcode = (input.readUnsignedByte().toInt() - cipher.nextInt()) and 0xFF
|
|
decoder = protocol.getDecoder(opcode) ?: throw DecoderException("Unsupported opcode: $opcode")
|
|
|
|
state = State.READ_LENGTH
|
|
}
|
|
|
|
if (state == State.READ_LENGTH) {
|
|
if (!decoder.isLengthReadable(input)) {
|
|
return
|
|
}
|
|
|
|
length = decoder.readLength(input)
|
|
|
|
state = State.READ_PAYLOAD
|
|
}
|
|
|
|
if (state == State.READ_PAYLOAD) {
|
|
if (input.readableBytes() < length) {
|
|
return
|
|
}
|
|
|
|
val payload = input.readSlice(length)
|
|
out += try {
|
|
decoder.decode(payload, cipher)
|
|
} catch (ex: NotImplementedError) {
|
|
// TODO(gpe): remove this catch block when every packet is implemented
|
|
logger.warn { "Skipping unimplemented packet: ${decoder.javaClass}" }
|
|
}
|
|
|
|
if (payload.isReadable) {
|
|
throw DecoderException("Decoder didn't read entire payload: ${decoder.javaClass}")
|
|
}
|
|
|
|
state = State.READ_OPCODE
|
|
}
|
|
}
|
|
|
|
private companion object {
|
|
private val logger = InlineLogger()
|
|
}
|
|
}
|
|
|