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.
121 lines
3.2 KiB
121 lines
3.2 KiB
package org.openrs2.archive.cache.nxt
|
|
|
|
import io.netty.buffer.ByteBuf
|
|
import io.netty.channel.ChannelHandlerContext
|
|
import io.netty.handler.codec.ByteToMessageDecoder
|
|
import io.netty.handler.codec.DecoderException
|
|
import kotlin.math.min
|
|
|
|
public class Js5ResponseDecoder : ByteToMessageDecoder() {
|
|
private data class Request(val prefetch: Boolean, val archive: Int, val group: Int)
|
|
|
|
private enum class State {
|
|
READ_HEADER,
|
|
READ_LEN,
|
|
READ_DATA
|
|
}
|
|
|
|
private var state = State.READ_HEADER
|
|
private val buffers = mutableMapOf<Request, ByteBuf>()
|
|
private var request: Request? = null
|
|
|
|
override fun decode(ctx: ChannelHandlerContext, input: ByteBuf, out: MutableList<Any>) {
|
|
if (state == State.READ_HEADER) {
|
|
if (input.readableBytes() < 5) {
|
|
return
|
|
}
|
|
|
|
val prefetch: Boolean
|
|
val archive = input.readUnsignedByte().toInt()
|
|
var group = input.readInt()
|
|
|
|
if (group and 0x80000000.toInt() != 0) {
|
|
prefetch = true
|
|
group = group and 0x7FFFFFFF
|
|
} else {
|
|
prefetch = false
|
|
}
|
|
|
|
request = Request(prefetch, archive, group)
|
|
|
|
state = if (buffers.containsKey(request)) {
|
|
State.READ_DATA
|
|
} else {
|
|
State.READ_LEN
|
|
}
|
|
}
|
|
|
|
if (state == State.READ_LEN) {
|
|
if (input.readableBytes() < 5) {
|
|
return
|
|
}
|
|
|
|
val type = input.readUnsignedByte().toInt()
|
|
|
|
val len = input.readInt()
|
|
if (len < 0) {
|
|
throw DecoderException("Length is negative: $len")
|
|
}
|
|
|
|
val totalLen = if (type == 0) {
|
|
len + 5
|
|
} else {
|
|
len + 9
|
|
}
|
|
|
|
if (totalLen < 0) {
|
|
throw DecoderException("Total length exceeds maximum ByteBuf size")
|
|
}
|
|
|
|
val data = ctx.alloc().buffer(totalLen, totalLen)
|
|
data.writeByte(type)
|
|
data.writeInt(len)
|
|
|
|
buffers[request!!] = data
|
|
|
|
state = State.READ_DATA
|
|
}
|
|
|
|
if (state == State.READ_DATA) {
|
|
val data = buffers[request!!]!!
|
|
|
|
var blockLen = if (data.writerIndex() == 5) {
|
|
102400 - 10
|
|
} else {
|
|
102400 - 5
|
|
}
|
|
|
|
blockLen = min(blockLen, data.writableBytes())
|
|
|
|
if (input.readableBytes() < blockLen) {
|
|
return
|
|
}
|
|
|
|
data.writeBytes(input, blockLen)
|
|
|
|
if (!data.isWritable) {
|
|
out += Js5Response(request!!.prefetch, request!!.archive, request!!.group, data)
|
|
buffers.remove(request!!)
|
|
request = null
|
|
}
|
|
|
|
state = State.READ_HEADER
|
|
}
|
|
}
|
|
|
|
override fun channelInactive(ctx: ChannelHandlerContext) {
|
|
super.channelInactive(ctx)
|
|
reset()
|
|
}
|
|
|
|
override fun handlerRemoved0(ctx: ChannelHandlerContext?) {
|
|
reset()
|
|
}
|
|
|
|
private fun reset() {
|
|
buffers.values.forEach(ByteBuf::release)
|
|
buffers.clear()
|
|
|
|
state = State.READ_HEADER
|
|
}
|
|
}
|
|
|