Add easy option to cache encoded packets
This commit is contained in:
parent
75888e9bc0
commit
5aeea48516
4 changed files with 67 additions and 35 deletions
|
@ -1,6 +1,11 @@
|
|||
package space.blokk.net.packet
|
||||
|
||||
import com.google.common.cache.CacheBuilder
|
||||
import com.google.common.cache.CacheLoader
|
||||
import com.google.common.cache.LoadingCache
|
||||
import io.netty.buffer.ByteBuf
|
||||
import io.netty.buffer.Unpooled
|
||||
import java.time.Duration
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
abstract class PacketCodec<T : Packet>(val id: Int, val dataType: KClass<T>)
|
||||
|
@ -9,6 +14,37 @@ abstract class IncomingPacketCodec<T : IncomingPacket>(id: Int, dataType: KClass
|
|||
abstract fun decode(msg: ByteBuf): T
|
||||
}
|
||||
|
||||
abstract class OutgoingPacketCodec<T : OutgoingPacket>(id: Int, dataType: KClass<T>) : PacketCodec<T>(id, dataType) {
|
||||
abstract fun T.encode(dst: ByteBuf)
|
||||
abstract class OutgoingPacketCodec<T : OutgoingPacket>(
|
||||
id: Int,
|
||||
dataType: KClass<T>,
|
||||
cacheOptions: CacheOptions? = null
|
||||
) : PacketCodec<T>(id, dataType) {
|
||||
protected abstract fun T.encode(dst: ByteBuf)
|
||||
|
||||
private val cache: LoadingCache<T, ByteBuf>? = cacheOptions?.let { options ->
|
||||
CacheBuilder.newBuilder()
|
||||
.weakKeys()
|
||||
.maximumSize(options.limit)
|
||||
.expireAfterAccess(options.expirationDuration)
|
||||
.concurrencyLevel(2)
|
||||
.removalListener<T, ByteBuf> { it.value.release() }
|
||||
.build(object : CacheLoader<T, ByteBuf>() {
|
||||
override fun load(packet: T): ByteBuf {
|
||||
val dst = Unpooled.buffer()
|
||||
packet.encode(dst)
|
||||
return dst
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@JvmName("encodePacket")
|
||||
fun encode(packet: T, dst: ByteBuf) {
|
||||
if (cache == null) packet.encode(dst)
|
||||
else dst.writeBytes(cache.get(packet))
|
||||
}
|
||||
|
||||
data class CacheOptions(
|
||||
val limit: Long,
|
||||
val expirationDuration: Duration
|
||||
)
|
||||
}
|
||||
|
|
|
@ -31,6 +31,12 @@ dependencies {
|
|||
}
|
||||
|
||||
tasks {
|
||||
compileKotlin {
|
||||
kotlinOptions.freeCompilerArgs = listOf(
|
||||
"-Xopt-in=kotlin.time.ExperimentalTime"
|
||||
)
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
|
|
@ -1,44 +1,34 @@
|
|||
package space.blokk.net.packet.play
|
||||
|
||||
import com.google.common.cache.CacheBuilder
|
||||
import com.google.common.cache.CacheLoader
|
||||
import com.google.common.cache.LoadingCache
|
||||
import io.netty.buffer.ByteBuf
|
||||
import io.netty.buffer.Unpooled
|
||||
import space.blokk.net.MinecraftProtocolDataTypes.writeString
|
||||
import space.blokk.net.MinecraftProtocolDataTypes.writeVarInt
|
||||
import space.blokk.net.packet.OutgoingPacketCodec
|
||||
import space.blokk.tags.Tag
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.toJavaDuration
|
||||
|
||||
object TagsPacketCodec : OutgoingPacketCodec<TagsPacket>(0x5C, TagsPacket::class) {
|
||||
private val cache: LoadingCache<TagsPacket, ByteBuf> = CacheBuilder.newBuilder()
|
||||
.maximumSize(3)
|
||||
.weakKeys()
|
||||
.removalListener<TagsPacket, ByteBuf> { it.value.release() }
|
||||
.build(object : CacheLoader<TagsPacket, ByteBuf>() {
|
||||
override fun load(packet: TagsPacket): ByteBuf {
|
||||
val dst = Unpooled.buffer()
|
||||
|
||||
listOf(
|
||||
packet.tags.filter { it.type == Tag.Type.BLOCKS },
|
||||
packet.tags.filter { it.type == Tag.Type.ITEMS },
|
||||
packet.tags.filter { it.type == Tag.Type.FLUIDS },
|
||||
packet.tags.filter { it.type == Tag.Type.ENTITY_TYPES }
|
||||
).forEach { tags ->
|
||||
dst.writeVarInt(tags.size)
|
||||
|
||||
tags.forEach { tag ->
|
||||
dst.writeString(tag.name)
|
||||
dst.writeVarInt(tag.values.size)
|
||||
tag.numericIDs.forEach { dst.writeVarInt(it) }
|
||||
}
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
})
|
||||
object TagsPacketCodec :
|
||||
OutgoingPacketCodec<TagsPacket>(0x5C, TagsPacket::class, CacheOptions(3, Duration.INFINITE.toJavaDuration())) {
|
||||
private val ORDER = listOf(
|
||||
Tag.Type.BLOCKS,
|
||||
Tag.Type.ITEMS,
|
||||
Tag.Type.FLUIDS,
|
||||
Tag.Type.ENTITY_TYPES
|
||||
)
|
||||
|
||||
override fun TagsPacket.encode(dst: ByteBuf) {
|
||||
dst.writeBytes(cache.get(this))
|
||||
val tagsByType = tags.groupBy { it.type }
|
||||
|
||||
ORDER.forEach { type ->
|
||||
val tags = tagsByType[type] ?: emptyList()
|
||||
dst.writeVarInt(tags.size)
|
||||
|
||||
tags.forEach { tag ->
|
||||
dst.writeString(tag.name)
|
||||
dst.writeVarInt(tag.values.size)
|
||||
tag.numericIDs.forEach { dst.writeVarInt(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ abstract class PacketMessage<T : Packet>(val session: BlokkSession, val packet:
|
|||
class OutgoingPacketMessage<T : OutgoingPacket>(session: BlokkSession, packet: T) : PacketMessage<T>(session, packet) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val packetCodec = session.currentProtocol!!.getCodecByType(packet::class) as OutgoingPacketCodec<T>
|
||||
fun encodePacket(dst: ByteBuf) = with(packetCodec) { packet.encode(dst) }
|
||||
fun encodePacket(dst: ByteBuf) = packetCodec.encode(packet, dst)
|
||||
}
|
||||
|
||||
class IncomingPacketMessage<T : IncomingPacket>(session: BlokkSession, packet: T) : PacketMessage<T>(session, packet)
|
||||
|
|
Reference in a new issue