Add packet codecs across Handshake, Login, Configuration, and Play stages

This commit is contained in:
2026-09-06 21:42:13 +08:00
parent 4a9f35ffdd
commit a88888ba4d
261 files changed
+4387 -343

No files matched your search

@@ -21,6 +21,7 @@ public expect class BytesBuffer {
public fun writeBoolean(value: Boolean)
public fun readByte(): Byte
public fun readUByte(): UByte
public fun readShort(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Short
public fun readInt(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Int
public fun readLong(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Long
@@ -9,18 +9,10 @@ package cn.rtast.libmc.common
public interface Encoder<in T> {
public fun encode(buffer: BytesBuffer, value: T)
public fun encodeToByteArray(value: T): ByteArray {
val buf = BytesBuffer()
encode(buf, value)
return buf.toByteArray()
}
}
public interface Decoder<out T> {
public fun decode(buffer: BytesBuffer): T
public fun decodeFromByteArray(bytes: ByteArray): T = decode(bytes.wrap())
}
public interface PacketCodec<T> : Encoder<T>, Decoder<T>
@@ -130,14 +130,6 @@ public fun BytesBuffer.writePrefixedByteArray(data: ByteArray) {
this.writeBytes(data)
}
public fun BytesBuffer.readOptionalPrefixedByteArray(): ByteArray? {
val isPresent = this.readBoolean()
return if (isPresent) {
val length = this.readVarInt()
this.readBytes(length)
} else null
}
public fun BytesBuffer.writeOptionalPrefixedByteArray(data: ByteArray?) {
if (data != null) {
this.writeBoolean(true)
@@ -146,18 +138,6 @@ public fun BytesBuffer.writeOptionalPrefixedByteArray(data: ByteArray?) {
} else this.writeBoolean(false)
}
public fun BytesBuffer.readPrefixedVarIntArray(): List<Int> {
val length = readVarInt()
val list = ArrayList<Int>(length)
repeat(length) { list.add(readVarInt()) }
return list
}
public fun BytesBuffer.writePrefixedVarIntArray(value: List<Int>) {
writeVarInt(value.size)
for (item in value) writeVarInt(item)
}
public fun BytesBuffer.readPrefixedStringArray(): List<String> {
val length = readVarInt()
val list = ArrayList<String>(length)
@@ -170,7 +150,83 @@ public fun BytesBuffer.writePrefixedStringArray(value: List<String>) {
for (item in value) writeMcString(item)
}
public inline fun <T> BytesBuffer.writePrefixedArray(value: List<T>, writeItem: BytesBuffer.(T) -> Unit) {
writeVarInt(value.size)
for (item in value) writeItem(item)
public inline fun <T> BytesBuffer.readOptional(block: BytesBuffer.() -> T): T? {
val hasData = this.readBoolean()
return if (hasData) block.invoke(this) else null
}
/**
* buffer.writeOptional(value.someValue) { writeBlockPos(it) }
*/
public inline fun <T> BytesBuffer.writeOptional(value: T?, block: BytesBuffer.(T) -> Unit) {
if (value != null) {
this.writeBoolean(true)
block.invoke(this, value)
} else this.writeBoolean(false)
}
public inline fun <T> BytesBuffer.readPrefixed(reader: BytesBuffer.() -> T): List<T> {
val count = this.readVarInt()
val list = ArrayList<T>(count)
repeat(count) { _ -> list.add(this.reader()) }
return list
}
public inline fun <T> BytesBuffer.writePrefixed(list: List<T>, writer: BytesBuffer.(T) -> Unit) {
this.writeVarInt(list.size)
for (item in list) this.writer(item)
}
public fun BytesBuffer.readBitSet(): LongArray {
val count = this.readVarInt()
return LongArray(count) { this.readLong() }
}
public fun BytesBuffer.writeBitSet(data: LongArray) {
this.writeVarInt(data.size)
for (i in data.indices) this.writeLong(data[i])
}
public fun LongArray.countSetBits(): Int {
var count = 0
for (i in indices) count += this[i].countOneBits()
return count
}
public fun LongArray.getBit(bitIndex: Int): Boolean {
val longIndex = bitIndex shr 6
if (longIndex !in this.indices) return false
val bitOffset = bitIndex and 63
return (this[longIndex] and (1L shl bitOffset)) != 0L
}
public sealed interface IdSet {
public data class Tag(val tagName: String) : IdSet
public data class Entries(val ids: List<Int>) : IdSet
}
public fun BytesBuffer.readIdSet(): IdSet {
val type = this.readVarInt()
return if (type == 0) {
IdSet.Tag(tagName = this.readMcString())
} else {
val count = type - 1
val ids = ArrayList<Int>(count)
(0 until count).forEach { _ -> ids.add(this.readVarInt()) }
IdSet.Entries(ids)
}
}
public fun BytesBuffer.writeIdSet(idSet: IdSet) {
when (idSet) {
is IdSet.Tag -> {
this.writeVarInt(0)
this.writeMcString(idSet.tagName)
}
is IdSet.Entries -> {
this.writeVarInt(idSet.ids.size + 1)
for (id in idSet.ids) this.writeVarInt(id)
}
}
}
@@ -90,6 +90,7 @@ public actual class BytesBuffer {
return array[readOffset++]
}
public actual fun readUByte(): UByte = this.readByte().toUByte()
public actual fun readShort(endian: ByteOrder): Short = readBytes(2).toShort(endian)
public actual fun readInt(endian: ByteOrder): Int = readBytes(4).toInt(endian)
public actual fun readLong(endian: ByteOrder): Long = readBytes(8).toLong(endian)
@@ -47,6 +47,7 @@ public actual class BytesBuffer {
public actual fun writeBoolean(value: Boolean): Unit = _delegateBuf.writeByte(if (value) 0x01 else 0x00)
public actual fun readByte(): Byte = _delegateBuf.readByte()
public actual fun readUByte(): UByte = this.readByte().toUByte()
public actual fun readShort(endian: ByteOrder): Short =
if (endian == ByteOrder.BIG_ENDIAN) _delegateBuf.readShort() else _delegateBuf.readShortLe()