Update all codec to suspend; added a default ProtocolCryptoContext implementation
This commit is contained in:
296 files changed
+2199
-1818
No files matched your search
@@ -48,3 +48,4 @@ bin/
|
||||
.kotlin/
|
||||
**/build/*
|
||||
/libmc-protocol/src/jvmTest/resources/accessToken.txt
|
||||
/libmc-protocol-encrypt/src/commonTest/resources/accessToken.txt
|
||||
@@ -3,24 +3,27 @@ kotlin = "2.4.10"
|
||||
kotlinx-io = "0.9.1"
|
||||
ktor-network = "3.5.2"
|
||||
coroutines-test = "1.11.0"
|
||||
#kotlinx-serialization = "1.11.0"
|
||||
kotlinx-coroutines = "1.11.0"
|
||||
ktor-core = "3.5.2"
|
||||
cryptography-core = "0.6.0"
|
||||
#kotlinx-serialization = "1.11.0"
|
||||
|
||||
[libraries]
|
||||
kotlinx-io = { module = "org.jetbrains.kotlinx:kotlinx-io-core", version.ref = "kotlinx-io" }
|
||||
ktor-network = { module = "io.ktor:ktor-network", version.ref = "ktor-network" }
|
||||
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines-test" }
|
||||
kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
|
||||
cryptography-provider-optimal = { module = "dev.whyoleg.cryptography:cryptography-provider-optimal", version.ref = "cryptography-core" }
|
||||
cryptography-core = { module = "dev.whyoleg.cryptography:cryptography-core", version.ref = "cryptography-core" }
|
||||
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor-core" }
|
||||
ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor-core" }
|
||||
ktor-client-winhttp = { module = "io.ktor:ktor-client-winhttp", version.ref = "ktor-core" }
|
||||
ktor-client-curl = { module = "io.ktor:ktor-client-curl", version.ref = "ktor-core" }
|
||||
ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor-core" }
|
||||
#kotlinx-serialization-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "kotlinx-serialization" }
|
||||
#kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" }
|
||||
kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
|
||||
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor-core" }
|
||||
#ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor-core" }
|
||||
#ktor-client-winhttp = { module = "io.ktor:ktor-client-winhttp", version.ref = "ktor-core" }
|
||||
#ktor-client-curl = { module = "io.ktor:ktor-client-curl", version.ref = "ktor-core" }
|
||||
ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor-core" }
|
||||
|
||||
[plugins]
|
||||
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
|
||||
kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
||||
maven-publish = { id = "maven-publish" }
|
||||
#kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
||||
@@ -11,10 +11,10 @@ kotlin {
|
||||
jvm { compilerOptions.jvmTarget = JvmTarget.JVM_1_8 }
|
||||
|
||||
sourceSets {
|
||||
jvmMain.dependencies {
|
||||
// no dependencies needed
|
||||
commonMain.dependencies {
|
||||
api(libs.kotlinx.coroutines)
|
||||
}
|
||||
|
||||
jvmMain.dependencies {}
|
||||
nativeMain.dependencies {
|
||||
implementation(libs.ktor.network)
|
||||
implementation(libs.kotlinx.io)
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/3
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.common
|
||||
|
||||
public expect class BytesBuffer {
|
||||
public constructor()
|
||||
public constructor(bytes: ByteArray)
|
||||
|
||||
public fun writeByte(value: Byte)
|
||||
public fun writeShort(value: Short, endian: ByteOrder = ByteOrder.BIG_ENDIAN)
|
||||
public fun writeInt(value: Int, endian: ByteOrder = ByteOrder.BIG_ENDIAN)
|
||||
public fun writeLong(value: Long, endian: ByteOrder = ByteOrder.BIG_ENDIAN)
|
||||
public fun writeDouble(value: Double, endian: ByteOrder = ByteOrder.BIG_ENDIAN)
|
||||
public fun writeFloat(value: Float, endian: ByteOrder = ByteOrder.BIG_ENDIAN)
|
||||
public fun writeBytes(bytes: ByteArray)
|
||||
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
|
||||
public fun readDouble(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Double
|
||||
public fun readFloat(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Float
|
||||
public fun readBytes(length: Int): ByteArray
|
||||
public fun readBoolean(): Boolean
|
||||
public fun readRemainingBytes(): ByteArray
|
||||
|
||||
public fun toByteArray(): ByteArray
|
||||
public fun hasRemaining(): Boolean
|
||||
public fun close()
|
||||
public val size: Int
|
||||
public val remaining: Long
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ByteArray.wrap(): BytesBuffer = BytesBuffer(this)
|
||||
|
||||
public fun ReadChannel.readPacketFrame(): BytesBuffer {
|
||||
val length = this.readVarInt()
|
||||
return this.readBytes(length).wrap()
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/3
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.common
|
||||
|
||||
public expect open class ReadChannel() {
|
||||
public open fun readByte(): Byte
|
||||
public open fun readShort(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Short
|
||||
public open fun readInt(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Int
|
||||
public open fun readLong(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Long
|
||||
public open fun readBytes(length: Int): ByteArray
|
||||
public open fun readFully(out: ByteArray, start: Int = 0, end: Int = out.size)
|
||||
}
|
||||
|
||||
public expect open class WriteChannel() {
|
||||
public open fun writeFully(value: ByteArray, startIndex: Int = 0, endIndex: Int = value.size)
|
||||
public open fun flush()
|
||||
}
|
||||
|
||||
public fun ReadChannel.readVarInt(): Int {
|
||||
var numRead = 0
|
||||
var result = 0
|
||||
var read: Byte
|
||||
do {
|
||||
read = this.readByte()
|
||||
val value = (read.toInt() and 0x7F)
|
||||
result = result or (value shl (7 * numRead))
|
||||
numRead++
|
||||
if (numRead > 5) throw IllegalArgumentException("VarInt is too big")
|
||||
} while ((read.toInt() and 0x80) != 0)
|
||||
return result
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/4
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.common
|
||||
|
||||
public interface Encoder<in T> {
|
||||
public fun encode(buffer: BytesBuffer, value: T)
|
||||
}
|
||||
|
||||
public interface Decoder<out T> {
|
||||
public fun decode(buffer: BytesBuffer): T
|
||||
}
|
||||
|
||||
public interface PacketCodec<T> : Encoder<T>, Decoder<T>
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun <T> BytesBuffer.write(value: T, encoder: Encoder<T>): Unit = encoder.encode(this, value)
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun <T> BytesBuffer.read(decoder: Decoder<T>): T = decoder.decode(this)
|
||||
|
||||
public fun BytesBuffer.writeBuffer(source: BytesBuffer, length: Long = source.remaining) {
|
||||
if (length <= 0) return
|
||||
val bytes = source.readBytes(length.toInt())
|
||||
this.writeBytes(bytes)
|
||||
}
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.protocol.session
|
||||
package cn.rtast.libmc.common.crypto
|
||||
|
||||
public fun interface AuthenticationProvider {
|
||||
public suspend fun joinServer(url: String, accessToken: String, uuid: String, serverIdHash: String)
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/7
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.common.crypto
|
||||
|
||||
public interface NetworkCipher {
|
||||
public suspend fun encrypt(buffer: ByteArray, offset: Int, length: Int)
|
||||
public suspend fun decrypt(buffer: ByteArray, offset: Int, length: Int)
|
||||
}
|
||||
+7
-9
@@ -5,9 +5,7 @@
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.protocol.crypto
|
||||
|
||||
import cn.rtast.libmc.protocol.session.AuthenticationProvider
|
||||
package cn.rtast.libmc.common.crypto
|
||||
|
||||
public data class ProtocolContext(
|
||||
val rsaEncryptor: RSA1024Encryptor,
|
||||
@@ -16,25 +14,25 @@ public data class ProtocolContext(
|
||||
val authProvider: AuthenticationProvider,
|
||||
)
|
||||
|
||||
public class ProtocolContextBuilder internal constructor(private val onlineMode: Boolean) {
|
||||
public class ProtocolContextBuilder(private val onlineMode: Boolean) {
|
||||
public lateinit var rsaEncryptor: RSA1024Encryptor
|
||||
public lateinit var sha1Hasher: Sha1Hasher
|
||||
public lateinit var cipherFactory: (sharedKey: ByteArray) -> NetworkCipher
|
||||
public lateinit var authProvider: AuthenticationProvider
|
||||
|
||||
internal fun build(): ProtocolContext = ProtocolContext(
|
||||
public fun build(): ProtocolContext = ProtocolContext(
|
||||
rsaEncryptor = if (::rsaEncryptor.isInitialized) rsaEncryptor else error("rsaEncryptor is required"),
|
||||
sha1Hasher = if (::sha1Hasher.isInitialized) sha1Hasher else error("sha1Hasher is required"),
|
||||
cipherFactory = if (::cipherFactory.isInitialized) cipherFactory else error("cipherFactory is required"),
|
||||
authProvider = if (::authProvider.isInitialized && !onlineMode) authProvider else error("authProvider is required")
|
||||
authProvider = if (::authProvider.isInitialized) if (onlineMode) authProvider
|
||||
else error("authProvider is required") else error("authProvider is required")
|
||||
)
|
||||
}
|
||||
|
||||
public fun interface RSA1024Encryptor {
|
||||
public fun encrypt(key: ByteArray, data: ByteArray): ByteArray
|
||||
public suspend fun encrypt(key: ByteArray, data: ByteArray): ByteArray
|
||||
}
|
||||
|
||||
|
||||
public fun interface Sha1Hasher {
|
||||
public fun hash(serverId: String, secretKey: ByteArray, publicKey: ByteArray): String
|
||||
public suspend fun hash(serverId: String, secretKey: ByteArray, publicKey: ByteArray): String
|
||||
}
|
||||
@@ -1,232 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/3
|
||||
*/
|
||||
|
||||
package cn.rtast.libmc.common
|
||||
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
public object VarIntCodec : PacketCodec<Int> {
|
||||
override fun encode(buffer: BytesBuffer, value: Int) {
|
||||
var v = value
|
||||
while (true) {
|
||||
if ((v and 0x7F.inv()) == 0) {
|
||||
buffer.writeByte(v.toByte())
|
||||
return
|
||||
}
|
||||
buffer.writeByte(((v and 0x7F) or 0x80).toByte())
|
||||
v = v ushr 7
|
||||
}
|
||||
}
|
||||
|
||||
override fun decode(buffer: BytesBuffer): Int {
|
||||
var numRead = 0
|
||||
var result = 0
|
||||
var read: Byte
|
||||
do {
|
||||
read = buffer.readByte()
|
||||
val value = (read.toInt() and 0x7F)
|
||||
result = result or (value shl (7 * numRead))
|
||||
numRead++
|
||||
if (numRead > 5) throw IllegalArgumentException("VarInt is too big")
|
||||
} while ((read.toInt() and 0x80) != 0)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
public object VarLongCodec : PacketCodec<Long> {
|
||||
override fun encode(buffer: BytesBuffer, value: Long) {
|
||||
var v = value
|
||||
while (true) {
|
||||
if ((v and 0x7FL.inv()) == 0L) {
|
||||
buffer.writeByte(v.toByte())
|
||||
return
|
||||
}
|
||||
buffer.writeByte(((v and 0x7F) or 0x80).toByte())
|
||||
v = v ushr 7
|
||||
}
|
||||
}
|
||||
|
||||
override fun decode(buffer: BytesBuffer): Long {
|
||||
var numRead = 0
|
||||
var result = 0L
|
||||
var read: Byte
|
||||
do {
|
||||
read = buffer.readByte()
|
||||
val value = (read.toLong() and 0x7F)
|
||||
result = result or (value shl (7 * numRead))
|
||||
numRead++
|
||||
if (numRead > 10) throw IllegalArgumentException("VarLong is too big")
|
||||
} while ((read.toInt() and 0x80) != 0)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
public object McStringCodec : PacketCodec<String> {
|
||||
override fun encode(buffer: BytesBuffer, value: String) {
|
||||
val bytes = value.encodeToByteArray()
|
||||
VarIntCodec.encode(buffer, bytes.size)
|
||||
buffer.writeBytes(bytes)
|
||||
}
|
||||
|
||||
override fun decode(buffer: BytesBuffer): String {
|
||||
val length = VarIntCodec.decode(buffer)
|
||||
val bytes = buffer.readBytes(length)
|
||||
return bytes.decodeToString()
|
||||
}
|
||||
}
|
||||
|
||||
public sealed interface IdOrX<out T> {
|
||||
public data class Inline<T>(val value: T) : IdOrX<T>
|
||||
public data class Reference(val registryId: Int) : IdOrX<Nothing>
|
||||
}
|
||||
|
||||
public inline fun <T> BytesBuffer.writeIdOrX(value: IdOrX<T>, writeX: BytesBuffer.(T) -> Unit) {
|
||||
when (value) {
|
||||
is IdOrX.Inline -> {
|
||||
this.writeVarInt(0)
|
||||
this.writeX(value.value)
|
||||
}
|
||||
|
||||
is IdOrX.Reference -> this.writeVarInt(value.registryId + 1)
|
||||
}
|
||||
}
|
||||
|
||||
public inline fun <T> BytesBuffer.readIdOrX(readX: BytesBuffer.() -> T): IdOrX<T> {
|
||||
val id = this.readVarInt()
|
||||
return if (id == 0) IdOrX.Inline(this.readX()) else IdOrX.Reference(id - 1)
|
||||
}
|
||||
|
||||
public fun BytesBuffer.writeUuid(uuid: Uuid): Unit = uuid.toLongs { mostSignificantBits, leastSignificantBits ->
|
||||
this.writeLong(mostSignificantBits)
|
||||
this.writeLong(leastSignificantBits)
|
||||
}
|
||||
|
||||
public fun BytesBuffer.readUuid(): Uuid {
|
||||
val most = this.readLong()
|
||||
val least = this.readLong()
|
||||
return Uuid.fromLongs(most, least)
|
||||
}
|
||||
|
||||
public fun BytesBuffer.writeVarInt(value: Int): Unit = VarIntCodec.encode(this, value)
|
||||
public fun BytesBuffer.readVarInt(): Int = VarIntCodec.decode(this)
|
||||
|
||||
public fun BytesBuffer.writeVarLong(value: Long): Unit = VarLongCodec.encode(this, value)
|
||||
public fun BytesBuffer.readVarLong(): Long = VarLongCodec.decode(this)
|
||||
|
||||
public fun BytesBuffer.writeMcString(value: String): Unit = McStringCodec.encode(this, value)
|
||||
public fun BytesBuffer.readMcString(): String = McStringCodec.decode(this)
|
||||
|
||||
public fun BytesBuffer.readPrefixedByteArray(): ByteArray {
|
||||
val length = this.readVarInt()
|
||||
val data = this.readBytes(length)
|
||||
return data
|
||||
}
|
||||
|
||||
public fun BytesBuffer.writePrefixedByteArray(data: ByteArray) {
|
||||
this.writeVarInt(data.size)
|
||||
this.writeBytes(data)
|
||||
}
|
||||
|
||||
public fun BytesBuffer.writeOptionalPrefixedByteArray(data: ByteArray?) {
|
||||
if (data != null) {
|
||||
this.writeBoolean(true)
|
||||
this.writeVarInt(data.size)
|
||||
this.writeBytes(data)
|
||||
} else this.writeBoolean(false)
|
||||
}
|
||||
|
||||
public fun BytesBuffer.readPrefixedStringArray(): List<String> {
|
||||
val length = readVarInt()
|
||||
val list = ArrayList<String>(length)
|
||||
repeat(length) { list.add(readMcString()) }
|
||||
return list
|
||||
}
|
||||
|
||||
public fun BytesBuffer.writePrefixedStringArray(value: List<String>) {
|
||||
writeVarInt(value.size)
|
||||
for (item in value) writeMcString(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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/4
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.common.packet
|
||||
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
|
||||
public interface Encoder<in T> {
|
||||
public suspend fun encode(buffer: BytesBuffer, value: T)
|
||||
}
|
||||
|
||||
public interface Decoder<out T> {
|
||||
public suspend fun decode(buffer: BytesBuffer): T
|
||||
}
|
||||
|
||||
public interface PacketCodec<T> : Encoder<T>, Decoder<T>
|
||||
|
||||
public suspend fun BytesBuffer.writeBuffer(source: BytesBuffer, length: Long = source.remaining) {
|
||||
if (length <= 0) return
|
||||
val bytes = source.readBytes(length.toInt())
|
||||
this.writeBytes(bytes)
|
||||
}
|
||||
@@ -7,9 +7,8 @@
|
||||
|
||||
package cn.rtast.libmc.common.packet
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.writeVarInt
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.primitives.writeVarInt
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
public class PacketRegistry {
|
||||
@@ -29,10 +28,10 @@ public class PacketRegistry {
|
||||
register(id, T::class, codec)
|
||||
}
|
||||
|
||||
public fun decodePacket(packetId: Int, buffer: BytesBuffer): MinecraftPacket =
|
||||
public suspend fun decodePacket(packetId: Int, buffer: BytesBuffer): MinecraftPacket =
|
||||
idToCodec[packetId]?.decode(buffer) ?: UnknownPacket(packetId, buffer.readBytes(buffer.remaining.toInt()))
|
||||
|
||||
public fun <T : MinecraftPacket> encodePacket(buffer: BytesBuffer, packet: T) {
|
||||
public suspend fun <T : MinecraftPacket> encodePacket(buffer: BytesBuffer, packet: T) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val info = requireNotNull(classToInfo[packet::class]) {
|
||||
"Unregistered Packet ${packet::class.simpleName}"
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/7
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.common.primitives
|
||||
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
|
||||
public suspend fun BytesBuffer.readBitSet(): LongArray {
|
||||
val count = this.readVarInt()
|
||||
return LongArray(count) { this.readLong() }
|
||||
}
|
||||
|
||||
public suspend 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
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/7
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.common.primitives
|
||||
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
|
||||
public sealed interface IdOrX<out T> {
|
||||
public data class Inline<T>(val value: T) : IdOrX<T>
|
||||
public data class Reference(val registryId: Int) : IdOrX<Nothing>
|
||||
}
|
||||
|
||||
public suspend inline fun <T> BytesBuffer.writeIdOrX(value: IdOrX<T>, writeX: BytesBuffer.(T) -> Unit) {
|
||||
when (value) {
|
||||
is IdOrX.Inline -> {
|
||||
this.writeVarInt(0)
|
||||
this.writeX(value.value)
|
||||
}
|
||||
|
||||
is IdOrX.Reference -> this.writeVarInt(value.registryId + 1)
|
||||
}
|
||||
}
|
||||
|
||||
public suspend inline fun <T> BytesBuffer.readIdOrX(readX: BytesBuffer.() -> T): IdOrX<T> {
|
||||
val id = this.readVarInt()
|
||||
return if (id == 0) IdOrX.Inline(this.readX()) else IdOrX.Reference(id - 1)
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/7
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.common.primitives
|
||||
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
|
||||
public sealed interface IdSet {
|
||||
public data class Tag(val tagName: String) : IdSet
|
||||
public data class Entries(val ids: List<Int>) : IdSet
|
||||
}
|
||||
|
||||
public suspend 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 suspend 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/7
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.common.primitives
|
||||
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
|
||||
public object McStringCodec : PacketCodec<String> {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: String) {
|
||||
val bytes = value.encodeToByteArray()
|
||||
VarIntCodec.encode(buffer, bytes.size)
|
||||
buffer.writeBytes(bytes)
|
||||
}
|
||||
|
||||
override suspend fun decode(buffer: BytesBuffer): String {
|
||||
val length = VarIntCodec.decode(buffer)
|
||||
val bytes = buffer.readBytes(length)
|
||||
return bytes.decodeToString()
|
||||
}
|
||||
}
|
||||
|
||||
public suspend fun BytesBuffer.writeMcString(value: String): Unit = McStringCodec.encode(this, value)
|
||||
public suspend fun BytesBuffer.readMcString(): String = McStringCodec.decode(this)
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/7
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.common.primitives
|
||||
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
|
||||
public suspend 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 suspend 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)
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/7
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.common.primitives
|
||||
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
|
||||
|
||||
public suspend fun BytesBuffer.readPrefixedByteArray(): ByteArray {
|
||||
val length = this.readVarInt()
|
||||
val data = this.readBytes(length)
|
||||
return data
|
||||
}
|
||||
|
||||
public suspend fun BytesBuffer.writePrefixedByteArray(data: ByteArray) {
|
||||
this.writeVarInt(data.size)
|
||||
this.writeBytes(data)
|
||||
}
|
||||
|
||||
public suspend fun BytesBuffer.writeOptionalPrefixedByteArray(data: ByteArray?) {
|
||||
if (data != null) {
|
||||
this.writeBoolean(true)
|
||||
this.writeVarInt(data.size)
|
||||
this.writeBytes(data)
|
||||
} else this.writeBoolean(false)
|
||||
}
|
||||
|
||||
public suspend fun BytesBuffer.readPrefixedStringArray(): List<String> {
|
||||
val length = readVarInt()
|
||||
val list = ArrayList<String>(length)
|
||||
repeat(length) { list.add(readMcString()) }
|
||||
return list
|
||||
}
|
||||
|
||||
public suspend fun BytesBuffer.writePrefixedStringArray(value: List<String>) {
|
||||
writeVarInt(value.size)
|
||||
for (item in value) writeMcString(item)
|
||||
}
|
||||
|
||||
|
||||
|
||||
public suspend 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 suspend inline fun <T> BytesBuffer.writePrefixed(list: List<T>, writer: BytesBuffer.(T) -> Unit) {
|
||||
this.writeVarInt(list.size)
|
||||
for (item in list) this.writer(item)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/7
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.common.primitives
|
||||
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
public suspend fun BytesBuffer.writeUuid(uuid: Uuid): Unit = uuid.toLongs { mostSignificantBits, leastSignificantBits ->
|
||||
this.writeLong(mostSignificantBits)
|
||||
this.writeLong(leastSignificantBits)
|
||||
}
|
||||
|
||||
public suspend fun BytesBuffer.readUuid(): Uuid {
|
||||
val most = this.readLong()
|
||||
val least = this.readLong()
|
||||
return Uuid.fromLongs(most, least)
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/7
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.common.primitives
|
||||
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
|
||||
public object VarIntCodec : PacketCodec<Int> {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: Int) {
|
||||
var v = value
|
||||
while (true) {
|
||||
if ((v and 0x7F.inv()) == 0) {
|
||||
buffer.writeByte(v.toByte())
|
||||
return
|
||||
}
|
||||
buffer.writeByte(((v and 0x7F) or 0x80).toByte())
|
||||
v = v ushr 7
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun decode(buffer: BytesBuffer): Int {
|
||||
var numRead = 0
|
||||
var result = 0
|
||||
var read: Byte
|
||||
do {
|
||||
read = buffer.readByte()
|
||||
val value = (read.toInt() and 0x7F)
|
||||
result = result or (value shl (7 * numRead))
|
||||
numRead++
|
||||
if (numRead > 5) throw IllegalArgumentException("VarInt is too big")
|
||||
} while ((read.toInt() and 0x80) != 0)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
public suspend fun BytesBuffer.writeVarInt(value: Int): Unit = VarIntCodec.encode(this, value)
|
||||
public suspend fun BytesBuffer.readVarInt(): Int = VarIntCodec.decode(this)
|
||||
|
||||
public suspend fun BytesBuffer.writeVarLong(value: Long): Unit = VarLongCodec.encode(this, value)
|
||||
public suspend fun BytesBuffer.readVarLong(): Long = VarLongCodec.decode(this)
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/7
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.common.primitives
|
||||
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
|
||||
public object VarLongCodec : PacketCodec<Long> {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: Long) {
|
||||
var v = value
|
||||
while (true) {
|
||||
if ((v and 0x7FL.inv()) == 0L) {
|
||||
buffer.writeByte(v.toByte())
|
||||
return
|
||||
}
|
||||
buffer.writeByte(((v and 0x7F) or 0x80).toByte())
|
||||
v = v ushr 7
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun decode(buffer: BytesBuffer): Long {
|
||||
var numRead = 0
|
||||
var result = 0L
|
||||
var read: Byte
|
||||
do {
|
||||
read = buffer.readByte()
|
||||
val value = (read.toLong() and 0x7F)
|
||||
result = result or (value shl (7 * numRead))
|
||||
numRead++
|
||||
if (numRead > 10) throw IllegalArgumentException("VarLong is too big")
|
||||
} while ((read.toInt() and 0x80) != 0)
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/3
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.common.stream
|
||||
|
||||
public expect class BytesBuffer {
|
||||
public constructor()
|
||||
public constructor(bytes: ByteArray)
|
||||
|
||||
public suspend fun writeByte(value: Byte)
|
||||
public suspend fun writeShort(value: Short, endian: ByteOrder = ByteOrder.BIG_ENDIAN)
|
||||
public suspend fun writeInt(value: Int, endian: ByteOrder = ByteOrder.BIG_ENDIAN)
|
||||
public suspend fun writeLong(value: Long, endian: ByteOrder = ByteOrder.BIG_ENDIAN)
|
||||
public suspend fun writeDouble(value: Double, endian: ByteOrder = ByteOrder.BIG_ENDIAN)
|
||||
public suspend fun writeFloat(value: Float, endian: ByteOrder = ByteOrder.BIG_ENDIAN)
|
||||
public suspend fun writeBytes(bytes: ByteArray)
|
||||
public suspend fun writeBoolean(value: Boolean)
|
||||
|
||||
public suspend fun readByte(): Byte
|
||||
public suspend fun readUByte(): UByte
|
||||
public suspend fun readShort(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Short
|
||||
public suspend fun readInt(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Int
|
||||
public suspend fun readLong(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Long
|
||||
public suspend fun readDouble(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Double
|
||||
public suspend fun readFloat(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Float
|
||||
public suspend fun readBytes(length: Int): ByteArray
|
||||
public suspend fun readBoolean(): Boolean
|
||||
public suspend fun readRemainingBytes(): ByteArray
|
||||
|
||||
public suspend fun toByteArray(): ByteArray
|
||||
public suspend fun hasRemaining(): Boolean
|
||||
public suspend fun close()
|
||||
public val size: Int
|
||||
public val remaining: Long
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
public inline fun ByteArray.wrap(): BytesBuffer = BytesBuffer(this)
|
||||
|
||||
public suspend fun ReadChannel.readPacketFrame(): BytesBuffer {
|
||||
val length = this.readVarInt()
|
||||
return this.readBytes(length).wrap()
|
||||
}
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.common
|
||||
package cn.rtast.libmc.common.stream
|
||||
|
||||
public enum class ByteOrder {
|
||||
BIG_ENDIAN, LITTLE_ENDIAN
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/3
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.common.stream
|
||||
|
||||
public expect open class ReadChannel() {
|
||||
public open suspend fun readByte(): Byte
|
||||
public open suspend fun readShort(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Short
|
||||
public open suspend fun readInt(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Int
|
||||
public open suspend fun readLong(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Long
|
||||
public open suspend fun readBytes(length: Int): ByteArray
|
||||
public open suspend fun readFully(out: ByteArray, start: Int = 0, end: Int = out.size)
|
||||
}
|
||||
|
||||
public expect open class WriteChannel() {
|
||||
public open suspend fun writeFully(value: ByteArray, startIndex: Int = 0, endIndex: Int = value.size)
|
||||
public open suspend fun flush()
|
||||
}
|
||||
|
||||
public suspend fun ReadChannel.readVarInt(): Int {
|
||||
var numRead = 0
|
||||
var result = 0
|
||||
var read: Byte
|
||||
do {
|
||||
read = this.readByte()
|
||||
val value = (read.toInt() and 0x7F)
|
||||
result = result or (value shl (7 * numRead))
|
||||
numRead++
|
||||
if (numRead > 5) throw IllegalArgumentException("VarInt is too big")
|
||||
} while ((read.toInt() and 0x80) != 0)
|
||||
return result
|
||||
}
|
||||
+4
-2
@@ -5,7 +5,9 @@
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.common
|
||||
package cn.rtast.libmc.common.stream
|
||||
|
||||
import cn.rtast.libmc.common.LibMCContext
|
||||
|
||||
public expect class Socket public constructor(host: String, port: Int, context: LibMCContext) {
|
||||
public fun openReadChannel(): ReadChannel
|
||||
@@ -14,6 +16,6 @@ public expect class Socket public constructor(host: String, port: Int, context:
|
||||
}
|
||||
|
||||
public expect class UdpSocket public constructor(host: String, port: Int, context: LibMCContext) {
|
||||
public fun sendAndReceive(data: ByteArray): ByteArray
|
||||
public suspend fun sendAndReceive(data: ByteArray): ByteArray
|
||||
public fun close()
|
||||
}
|
||||
+26
-24
@@ -4,8 +4,10 @@
|
||||
* Date: 2026/9/3
|
||||
*/
|
||||
|
||||
package cn.rtast.libmc.common
|
||||
package cn.rtast.libmc.common.stream
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
public actual class BytesBuffer {
|
||||
@@ -19,12 +21,12 @@ public actual class BytesBuffer {
|
||||
outStream.write(bytes)
|
||||
}
|
||||
|
||||
public actual fun writeByte(value: Byte) {
|
||||
public actual suspend fun writeByte(value: Byte) {
|
||||
readBuffer = null
|
||||
outStream.write(value.toInt())
|
||||
}
|
||||
|
||||
public actual fun writeShort(value: Short, endian: ByteOrder) {
|
||||
public actual suspend fun writeShort(value: Short, endian: ByteOrder) {
|
||||
readBuffer = null
|
||||
val v = value.toInt()
|
||||
if (endian == ByteOrder.BIG_ENDIAN) {
|
||||
@@ -36,7 +38,7 @@ public actual class BytesBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
public actual fun writeInt(value: Int, endian: ByteOrder) {
|
||||
public actual suspend fun writeInt(value: Int, endian: ByteOrder) {
|
||||
readBuffer = null
|
||||
if (endian == ByteOrder.BIG_ENDIAN) {
|
||||
outStream.write(value shr 24)
|
||||
@@ -51,7 +53,7 @@ public actual class BytesBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
public actual fun writeLong(value: Long, endian: ByteOrder) {
|
||||
public actual suspend fun writeLong(value: Long, endian: ByteOrder) {
|
||||
readBuffer = null
|
||||
if (endian == ByteOrder.BIG_ENDIAN) {
|
||||
for (i in 56 downTo 0 step 8) outStream.write((value shr i).toInt())
|
||||
@@ -60,22 +62,22 @@ public actual class BytesBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
public actual fun writeDouble(value: Double, endian: ByteOrder) {
|
||||
public actual suspend fun writeDouble(value: Double, endian: ByteOrder) {
|
||||
writeLong(value.toRawBits(), endian)
|
||||
}
|
||||
|
||||
public actual fun writeFloat(value: Float, endian: ByteOrder) {
|
||||
public actual suspend fun writeFloat(value: Float, endian: ByteOrder) {
|
||||
writeInt(value.toRawBits(), endian)
|
||||
}
|
||||
|
||||
public actual fun writeBytes(bytes: ByteArray) {
|
||||
public actual suspend fun writeBytes(bytes: ByteArray) {
|
||||
readBuffer = null
|
||||
outStream.write(bytes)
|
||||
withContext(Dispatchers.IO) { outStream.write(bytes) }
|
||||
}
|
||||
|
||||
public actual fun writeBoolean(value: Boolean): Unit = writeByte(if (value) 0x01 else 0x00)
|
||||
public actual suspend fun writeBoolean(value: Boolean): Unit = writeByte(if (value) 0x01 else 0x00)
|
||||
|
||||
private fun ensureReadArray(): ByteArray {
|
||||
private suspend fun ensureReadArray(): ByteArray {
|
||||
var buf = readBuffer
|
||||
if (buf == null) {
|
||||
buf = outStream.toByteArray()
|
||||
@@ -84,26 +86,26 @@ public actual class BytesBuffer {
|
||||
return buf
|
||||
}
|
||||
|
||||
public actual fun readByte(): Byte {
|
||||
public actual suspend fun readByte(): Byte {
|
||||
val array = ensureReadArray()
|
||||
if (readOffset >= array.size) throw IndexOutOfBoundsException("Buffer underflow")
|
||||
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)
|
||||
public actual suspend fun readUByte(): UByte = this.readByte().toUByte()
|
||||
public actual suspend fun readShort(endian: ByteOrder): Short = readBytes(2).toShort(endian)
|
||||
public actual suspend fun readInt(endian: ByteOrder): Int = readBytes(4).toInt(endian)
|
||||
public actual suspend fun readLong(endian: ByteOrder): Long = readBytes(8).toLong(endian)
|
||||
|
||||
public actual fun readDouble(endian: ByteOrder): Double {
|
||||
public actual suspend fun readDouble(endian: ByteOrder): Double {
|
||||
return Double.fromBits(readLong(endian))
|
||||
}
|
||||
|
||||
public actual fun readFloat(endian: ByteOrder): Float {
|
||||
public actual suspend fun readFloat(endian: ByteOrder): Float {
|
||||
return Float.fromBits(readInt(endian))
|
||||
}
|
||||
|
||||
public actual fun readBytes(length: Int): ByteArray {
|
||||
public actual suspend fun readBytes(length: Int): ByteArray {
|
||||
val array = ensureReadArray()
|
||||
if (readOffset + length > array.size) throw IndexOutOfBoundsException("Buffer underflow")
|
||||
val result = array.copyOfRange(readOffset, readOffset + length)
|
||||
@@ -111,9 +113,9 @@ public actual class BytesBuffer {
|
||||
return result
|
||||
}
|
||||
|
||||
public actual fun readBoolean(): Boolean = this.readByte() != 0x00.toByte()
|
||||
public actual suspend fun readBoolean(): Boolean = this.readByte() != 0x00.toByte()
|
||||
|
||||
public actual fun readRemainingBytes(): ByteArray {
|
||||
public actual suspend fun readRemainingBytes(): ByteArray {
|
||||
val array = ensureReadArray()
|
||||
if (readOffset >= array.size) return byteArrayOf()
|
||||
val result = array.copyOfRange(readOffset, array.size)
|
||||
@@ -121,10 +123,10 @@ public actual class BytesBuffer {
|
||||
return result
|
||||
}
|
||||
|
||||
public actual fun toByteArray(): ByteArray = outStream.toByteArray()
|
||||
public actual fun hasRemaining(): Boolean = readOffset < ensureReadArray().size
|
||||
public actual suspend fun toByteArray(): ByteArray = outStream.toByteArray()
|
||||
public actual suspend fun hasRemaining(): Boolean = readOffset < ensureReadArray().size
|
||||
|
||||
public actual fun close(): Unit = outStream.close()
|
||||
public actual suspend fun close(): Unit = withContext(Dispatchers.IO) { outStream.close() }
|
||||
public actual val size: Int get() = outStream.size()
|
||||
public actual val remaining: Long get() = (outStream.size() - readOffset).coerceAtLeast(0).toLong()
|
||||
}
|
||||
+9
-9
@@ -4,7 +4,7 @@
|
||||
* Date: 2026/9/3
|
||||
*/
|
||||
|
||||
package cn.rtast.libmc.common
|
||||
package cn.rtast.libmc.common.stream
|
||||
|
||||
import java.io.EOFException
|
||||
import java.io.InputStream
|
||||
@@ -17,7 +17,7 @@ public actual open class ReadChannel public actual constructor() {
|
||||
this._inputStream = inputStream
|
||||
}
|
||||
|
||||
public actual open fun readFully(out: ByteArray, start: Int, end: Int) {
|
||||
public actual open suspend fun readFully(out: ByteArray, start: Int, end: Int) {
|
||||
var bytesRead = 0
|
||||
val length = end - start
|
||||
while (bytesRead < length) {
|
||||
@@ -27,21 +27,21 @@ public actual open class ReadChannel public actual constructor() {
|
||||
}
|
||||
}
|
||||
|
||||
public actual open fun readByte(): Byte {
|
||||
public actual open suspend fun readByte(): Byte {
|
||||
val buf = ByteArray(1)
|
||||
readFully(buf, 0, 1)
|
||||
return buf[0]
|
||||
}
|
||||
|
||||
public actual open fun readBytes(length: Int): ByteArray {
|
||||
public actual open suspend fun readBytes(length: Int): ByteArray {
|
||||
val bytes = ByteArray(length)
|
||||
readFully(bytes, 0, length)
|
||||
return bytes
|
||||
}
|
||||
|
||||
public actual open fun readShort(endian: ByteOrder): Short = readBytes(2).toShort(endian)
|
||||
public actual open fun readInt(endian: ByteOrder): Int = readBytes(4).toInt(endian)
|
||||
public actual open fun readLong(endian: ByteOrder): Long = readBytes(8).toLong(endian)
|
||||
public actual open suspend fun readShort(endian: ByteOrder): Short = readBytes(2).toShort(endian)
|
||||
public actual open suspend fun readInt(endian: ByteOrder): Int = readBytes(4).toInt(endian)
|
||||
public actual open suspend fun readLong(endian: ByteOrder): Long = readBytes(8).toLong(endian)
|
||||
}
|
||||
|
||||
public actual open class WriteChannel public actual constructor() {
|
||||
@@ -51,8 +51,8 @@ public actual open class WriteChannel public actual constructor() {
|
||||
_outputStream = outputStream
|
||||
}
|
||||
|
||||
public actual open fun writeFully(value: ByteArray, startIndex: Int, endIndex: Int): Unit =
|
||||
public actual open suspend fun writeFully(value: ByteArray, startIndex: Int, endIndex: Int): Unit =
|
||||
_outputStream.write(value, startIndex, endIndex - startIndex)
|
||||
|
||||
public actual open fun flush(): Unit = _outputStream.flush()
|
||||
public actual open suspend fun flush(): Unit = _outputStream.flush()
|
||||
}
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.common
|
||||
package cn.rtast.libmc.common.stream
|
||||
|
||||
internal fun ByteArray.toShort(endian: ByteOrder = ByteOrder.BIG_ENDIAN): Short {
|
||||
val b1 = this[0].toInt() and 0xFF
|
||||
+6
-4
@@ -4,8 +4,11 @@
|
||||
* Date: 2026/9/3
|
||||
*/
|
||||
|
||||
package cn.rtast.libmc.common
|
||||
package cn.rtast.libmc.common.stream
|
||||
|
||||
import cn.rtast.libmc.common.LibMCContext
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.net.DatagramPacket
|
||||
import java.net.DatagramSocket
|
||||
import java.net.InetSocketAddress
|
||||
@@ -25,13 +28,12 @@ public actual class UdpSocket public actual constructor(host: String, port: Int,
|
||||
connect(InetSocketAddress(host, port))
|
||||
}
|
||||
|
||||
public actual fun sendAndReceive(data: ByteArray): ByteArray {
|
||||
public actual suspend fun sendAndReceive(data: ByteArray): ByteArray = withContext(Dispatchers.IO) {
|
||||
socket.send(DatagramPacket(data, data.size))
|
||||
|
||||
val buf = ByteArray(2048)
|
||||
val receivePacket = DatagramPacket(buf, buf.size)
|
||||
socket.receive(receivePacket)
|
||||
return buf.copyOf(receivePacket.length)
|
||||
return@withContext buf.copyOf(receivePacket.length)
|
||||
}
|
||||
|
||||
public actual fun close(): Unit = socket.close()
|
||||
+22
-22
@@ -4,7 +4,7 @@
|
||||
* Date: 2026/9/3
|
||||
*/
|
||||
|
||||
package cn.rtast.libmc.common
|
||||
package cn.rtast.libmc.common.stream
|
||||
|
||||
import io.ktor.utils.io.core.*
|
||||
import kotlinx.io.*
|
||||
@@ -21,53 +21,53 @@ public actual class BytesBuffer {
|
||||
_delegateBuf = Buffer().apply { write(bytes) }
|
||||
}
|
||||
|
||||
public actual fun writeByte(value: Byte): Unit = _delegateBuf.writeByte(value)
|
||||
public actual fun writeShort(value: Short, endian: ByteOrder) {
|
||||
public actual suspend fun writeByte(value: Byte): Unit = _delegateBuf.writeByte(value)
|
||||
public actual suspend fun writeShort(value: Short, endian: ByteOrder) {
|
||||
if (endian == ByteOrder.BIG_ENDIAN) _delegateBuf.writeShort(value)
|
||||
else _delegateBuf.writeShortLe(value)
|
||||
}
|
||||
|
||||
public actual fun writeInt(value: Int, endian: ByteOrder) {
|
||||
public actual suspend fun writeInt(value: Int, endian: ByteOrder) {
|
||||
if (endian == ByteOrder.BIG_ENDIAN) _delegateBuf.writeInt(value)
|
||||
else _delegateBuf.writeIntLe(value)
|
||||
}
|
||||
|
||||
public actual fun writeLong(value: Long, endian: ByteOrder) {
|
||||
public actual suspend fun writeLong(value: Long, endian: ByteOrder) {
|
||||
if (endian == ByteOrder.BIG_ENDIAN) _delegateBuf.writeLong(value)
|
||||
else _delegateBuf.writeLongLe(value)
|
||||
}
|
||||
|
||||
public actual fun writeDouble(value: Double, endian: ByteOrder): Unit =
|
||||
public actual suspend fun writeDouble(value: Double, endian: ByteOrder): Unit =
|
||||
if (endian == ByteOrder.BIG_ENDIAN) _delegateBuf.writeDouble(value) else _delegateBuf.writeDoubleLe(value)
|
||||
|
||||
public actual fun writeFloat(value: Float, endian: ByteOrder): Unit =
|
||||
public actual suspend fun writeFloat(value: Float, endian: ByteOrder): Unit =
|
||||
if (endian == ByteOrder.BIG_ENDIAN) _delegateBuf.writeFloat(value) else _delegateBuf.writeFloatLe(value)
|
||||
|
||||
public actual fun writeBytes(bytes: ByteArray): Unit = _delegateBuf.write(bytes)
|
||||
public actual fun writeBoolean(value: Boolean): Unit = _delegateBuf.writeByte(if (value) 0x01 else 0x00)
|
||||
public actual suspend fun writeBytes(bytes: ByteArray): Unit = _delegateBuf.write(bytes)
|
||||
public actual suspend 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 =
|
||||
public actual suspend fun readByte(): Byte = _delegateBuf.readByte()
|
||||
public actual suspend fun readUByte(): UByte = this.readByte().toUByte()
|
||||
public actual suspend fun readShort(endian: ByteOrder): Short =
|
||||
if (endian == ByteOrder.BIG_ENDIAN) _delegateBuf.readShort() else _delegateBuf.readShortLe()
|
||||
|
||||
public actual fun readInt(endian: ByteOrder): Int =
|
||||
public actual suspend fun readInt(endian: ByteOrder): Int =
|
||||
if (endian == ByteOrder.BIG_ENDIAN) _delegateBuf.readInt() else _delegateBuf.readIntLe()
|
||||
|
||||
public actual fun readLong(endian: ByteOrder): Long =
|
||||
public actual suspend fun readLong(endian: ByteOrder): Long =
|
||||
if (endian == ByteOrder.BIG_ENDIAN) _delegateBuf.readLong() else _delegateBuf.readLongLe()
|
||||
|
||||
public actual fun readDouble(endian: ByteOrder): Double =
|
||||
public actual suspend fun readDouble(endian: ByteOrder): Double =
|
||||
if (endian == ByteOrder.BIG_ENDIAN) _delegateBuf.readDouble() else _delegateBuf.readDoubleLe()
|
||||
|
||||
public actual fun readFloat(endian: ByteOrder): Float =
|
||||
public actual suspend fun readFloat(endian: ByteOrder): Float =
|
||||
if (endian == ByteOrder.BIG_ENDIAN) _delegateBuf.readFloat() else _delegateBuf.readFloatLe()
|
||||
|
||||
public actual fun readBytes(length: Int): ByteArray = _delegateBuf.readByteArray(length)
|
||||
public actual fun readBoolean(): Boolean = _delegateBuf.readByte() != 0x00.toByte()
|
||||
public actual fun readRemainingBytes(): ByteArray = this.toByteArray()
|
||||
public actual suspend fun readBytes(length: Int): ByteArray = _delegateBuf.readByteArray(length)
|
||||
public actual suspend fun readBoolean(): Boolean = _delegateBuf.readByte() != 0x00.toByte()
|
||||
public actual suspend fun readRemainingBytes(): ByteArray = this.toByteArray()
|
||||
|
||||
public actual fun toByteArray(): ByteArray {
|
||||
public actual suspend fun toByteArray(): ByteArray {
|
||||
val copy = _delegateBuf.peek()
|
||||
return try {
|
||||
copy.readByteArray()
|
||||
@@ -76,8 +76,8 @@ public actual class BytesBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
public actual fun hasRemaining(): Boolean = !_delegateBuf.exhausted()
|
||||
public actual fun close(): Unit = _delegateBuf.close()
|
||||
public actual suspend fun hasRemaining(): Boolean = !_delegateBuf.exhausted()
|
||||
public actual suspend fun close(): Unit = _delegateBuf.close()
|
||||
|
||||
public actual val size: Int get() = _delegateBuf.size.toInt()
|
||||
public actual val remaining: Long get() = _delegateBuf.remaining
|
||||
+11
-12
@@ -4,11 +4,10 @@
|
||||
* Date: 2026/9/3
|
||||
*/
|
||||
|
||||
package cn.rtast.libmc.common
|
||||
package cn.rtast.libmc.common.stream
|
||||
|
||||
import io.ktor.utils.io.*
|
||||
import io.ktor.utils.io.bits.*
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
public actual open class ReadChannel public actual constructor() {
|
||||
|
||||
@@ -18,18 +17,18 @@ public actual open class ReadChannel public actual constructor() {
|
||||
this._readChannel = readChannel
|
||||
}
|
||||
|
||||
public actual open fun readByte(): Byte = runBlocking { _readChannel.readByte() }
|
||||
public actual open fun readBytes(length: Int): ByteArray = runBlocking { _readChannel.readByteArray(length) }
|
||||
public actual open fun readFully(out: ByteArray, start: Int, end: Int): Unit =
|
||||
runBlocking { _readChannel.readFully(out, start, end) }
|
||||
public actual open suspend fun readByte(): Byte = _readChannel.readByte()
|
||||
public actual open suspend fun readBytes(length: Int): ByteArray = _readChannel.readByteArray(length)
|
||||
public actual open suspend fun readFully(out: ByteArray, start: Int, end: Int): Unit =
|
||||
_readChannel.readFully(out, start, end)
|
||||
|
||||
public actual open fun readShort(endian: ByteOrder): Short {
|
||||
public actual open suspend fun readShort(endian: ByteOrder): Short {
|
||||
val bytes = readBytes(2)
|
||||
val v = ((bytes[0].toInt() and 0xFF shl 8) or (bytes[1].toInt() and 0xFF)).toShort()
|
||||
return if (endian == ByteOrder.BIG_ENDIAN) v else v.reverseByteOrder()
|
||||
}
|
||||
|
||||
public actual open fun readInt(endian: ByteOrder): Int {
|
||||
public actual open suspend fun readInt(endian: ByteOrder): Int {
|
||||
val bytes = readBytes(4)
|
||||
val v = (bytes[0].toInt() and 0xFF shl 24) or
|
||||
(bytes[1].toInt() and 0xFF shl 16) or
|
||||
@@ -38,7 +37,7 @@ public actual open class ReadChannel public actual constructor() {
|
||||
return if (endian == ByteOrder.BIG_ENDIAN) v else v.reverseByteOrder()
|
||||
}
|
||||
|
||||
public actual open fun readLong(endian: ByteOrder): Long {
|
||||
public actual open suspend fun readLong(endian: ByteOrder): Long {
|
||||
val bytes = readBytes(8)
|
||||
var v = 0L
|
||||
for (i in 0 until 8) {
|
||||
@@ -55,8 +54,8 @@ public actual open class WriteChannel public actual constructor() {
|
||||
_writeChannel = writeChannel
|
||||
}
|
||||
|
||||
public actual open fun writeFully(value: ByteArray, startIndex: Int, endIndex: Int): Unit =
|
||||
runBlocking { _writeChannel.writeFully(value, startIndex, endIndex) }
|
||||
public actual open suspend fun writeFully(value: ByteArray, startIndex: Int, endIndex: Int): Unit =
|
||||
_writeChannel.writeFully(value, startIndex, endIndex)
|
||||
|
||||
public actual open fun flush(): Unit = runBlocking { _writeChannel.flush() }
|
||||
public actual open suspend fun flush(): Unit = _writeChannel.flush()
|
||||
}
|
||||
+4
-3
@@ -4,8 +4,9 @@
|
||||
* Date: 2026/9/3
|
||||
*/
|
||||
|
||||
package cn.rtast.libmc.common
|
||||
package cn.rtast.libmc.common.stream
|
||||
|
||||
import cn.rtast.libmc.common.LibMCContext
|
||||
import io.ktor.network.sockets.*
|
||||
import io.ktor.utils.io.core.*
|
||||
import kotlinx.coroutines.runBlocking
|
||||
@@ -32,10 +33,10 @@ public actual class UdpSocket public actual constructor(host: String, port: Int,
|
||||
private val socket = runBlocking { aSocket(ctx._selectorManager).udp().bind() }
|
||||
private val remoteAddress = InetSocketAddress(host, port)
|
||||
|
||||
public actual fun sendAndReceive(data: ByteArray): ByteArray = runBlocking {
|
||||
public actual suspend fun sendAndReceive(data: ByteArray): ByteArray {
|
||||
val packet = buildPacket { writeFully(data) }
|
||||
socket.send(Datagram(packet, remoteAddress))
|
||||
socket.receive().packet.readByteArray()
|
||||
return socket.receive().packet.readByteArray()
|
||||
}
|
||||
|
||||
public actual fun close() {
|
||||
@@ -7,8 +7,8 @@
|
||||
|
||||
package cn.rtast.libmc.mcping.bedrock
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import kotlin.random.Random
|
||||
|
||||
private val RAKNET_MAGIC = byteArrayOf(
|
||||
@@ -33,14 +33,14 @@ internal data class BedrockRequestPacket(
|
||||
override val packetId: Byte = 0x01
|
||||
|
||||
companion object Codec : PacketCodec<BedrockRequestPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: BedrockRequestPacket) {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: BedrockRequestPacket) {
|
||||
buffer.writeByte(value.packetId)
|
||||
buffer.writeLong(value.time)
|
||||
buffer.writeBytes(value.magic)
|
||||
buffer.writeLong(value.guid)
|
||||
}
|
||||
|
||||
override fun decode(buffer: BytesBuffer): BedrockRequestPacket = throw UnsupportedOperationException()
|
||||
override suspend fun decode(buffer: BytesBuffer): BedrockRequestPacket = throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
@@ -72,8 +72,8 @@ internal data class BedrockResponsePacket(
|
||||
) : MinecraftBedrockPacket {
|
||||
|
||||
companion object Codec : PacketCodec<BedrockResponsePacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: BedrockResponsePacket) = throw UnsupportedOperationException()
|
||||
override fun decode(buffer: BytesBuffer): BedrockResponsePacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: BedrockResponsePacket) = throw UnsupportedOperationException()
|
||||
override suspend fun decode(buffer: BytesBuffer): BedrockResponsePacket {
|
||||
val packetId = buffer.readByte()
|
||||
if (packetId != 0x1C.toByte()) throw IllegalStateException("Expected pong id 0x1C, got $packetId")
|
||||
val time = buffer.readLong()
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
|
||||
package cn.rtast.libmc.mcping.bedrock
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.UdpSocket
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.UdpSocket
|
||||
|
||||
|
||||
internal fun <T : MinecraftBedrockPacket> UdpSocket.sendPacket(packet: T, codec: PacketCodec<T>): ByteArray {
|
||||
internal suspend fun <T : MinecraftBedrockPacket> UdpSocket.sendPacket(packet: T, codec: PacketCodec<T>): ByteArray {
|
||||
val buf = BytesBuffer()
|
||||
codec.encode(buf, packet)
|
||||
return sendAndReceive(buf.toByteArray())
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
package cn.rtast.libmc.mcping.bedrock
|
||||
|
||||
import cn.rtast.libmc.common.LibMCContext
|
||||
import cn.rtast.libmc.common.UdpSocket
|
||||
import cn.rtast.libmc.common.wrap
|
||||
import cn.rtast.libmc.common.stream.UdpSocket
|
||||
import cn.rtast.libmc.common.stream.wrap
|
||||
import cn.rtast.libmc.mcping.PingResponse
|
||||
import kotlin.time.Clock
|
||||
|
||||
internal fun pingBedrockServer(host: String, port: Int, context: LibMCContext): PingResponse {
|
||||
internal suspend fun pingBedrockServer(host: String, port: Int, context: LibMCContext): PingResponse {
|
||||
val socket = UdpSocket(host, port, context)
|
||||
return try {
|
||||
val sendTime = Clock.System.now().toEpochMilliseconds()
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
|
||||
package cn.rtast.libmc.mcping.java
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.McStringCodec
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.VarIntCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.primitives.McStringCodec
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.primitives.VarIntCodec
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
|
||||
// ref https://minecraft.wiki/w/Java_Edition_protocol/Packets#Handshake
|
||||
@@ -22,30 +22,30 @@ internal data class HandshakePacket(
|
||||
val nextState: Int,
|
||||
) : MinecraftPacket {
|
||||
companion object Codec : PacketCodec<HandshakePacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: HandshakePacket) {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: HandshakePacket) {
|
||||
VarIntCodec.encode(buffer, value.protocolVersion)
|
||||
McStringCodec.encode(buffer, value.serverAddress)
|
||||
buffer.writeShort(value.serverPort.toShort())
|
||||
VarIntCodec.encode(buffer, value.nextState)
|
||||
}
|
||||
|
||||
override fun decode(buffer: BytesBuffer): HandshakePacket = throw UnsupportedOperationException()
|
||||
override suspend fun decode(buffer: BytesBuffer): HandshakePacket = throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
|
||||
// ref https://minecraft.wiki/w/Java_Edition_protocol/Packets#Status
|
||||
internal data object StatusRequestPacket : MinecraftPacket, PacketCodec<StatusRequestPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: StatusRequestPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): StatusRequestPacket = throw UnsupportedOperationException()
|
||||
override suspend fun encode(buffer: BytesBuffer, value: StatusRequestPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): StatusRequestPacket = throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
internal data class PingPacket(val currentTime: Long) : MinecraftPacket {
|
||||
companion object : PacketCodec<PingPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: PingPacket) {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: PingPacket) {
|
||||
buffer.writeLong(value.currentTime)
|
||||
}
|
||||
|
||||
override fun decode(buffer: BytesBuffer): PingPacket {
|
||||
override suspend fun decode(buffer: BytesBuffer): PingPacket {
|
||||
return PingPacket(buffer.readLong())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,11 +8,15 @@
|
||||
package cn.rtast.libmc.mcping.java
|
||||
|
||||
import cn.rtast.libmc.common.*
|
||||
import cn.rtast.libmc.common.primitives.McStringCodec
|
||||
import cn.rtast.libmc.common.primitives.VarIntCodec
|
||||
import cn.rtast.libmc.common.stream.Socket
|
||||
import cn.rtast.libmc.common.stream.readPacketFrame
|
||||
import cn.rtast.libmc.mcping.PingResponse
|
||||
import cn.rtast.libmc.mcping.sendPacket
|
||||
import kotlin.time.Clock
|
||||
|
||||
internal fun pingJavaServer(host: String, port: Int, context: LibMCContext): PingResponse {
|
||||
internal suspend fun pingJavaServer(host: String, port: Int, context: LibMCContext): PingResponse {
|
||||
val socket = Socket(host, port, context)
|
||||
val receiveChannel = socket.openReadChannel()
|
||||
val sendChannel = socket.openWriteChannel()
|
||||
|
||||
@@ -16,7 +16,7 @@ import kotlin.jvm.JvmName
|
||||
import kotlin.jvm.JvmOverloads
|
||||
|
||||
@JvmOverloads
|
||||
public fun mcping(
|
||||
public suspend fun mcping(
|
||||
host: String,
|
||||
port: Int,
|
||||
type: ServerType = ServerType.Java,
|
||||
|
||||
@@ -7,15 +7,19 @@
|
||||
|
||||
package cn.rtast.libmc.mcping
|
||||
|
||||
import cn.rtast.libmc.common.*
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.primitives.VarIntCodec
|
||||
import cn.rtast.libmc.common.stream.WriteChannel
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.packet.writeBuffer
|
||||
|
||||
public fun <T : MinecraftPacket> WriteChannel.sendPacket(packet: T, packetId: Int, codec: PacketCodec<T>) {
|
||||
public suspend fun <T : MinecraftPacket> WriteChannel.sendPacket(packet: T, packetId: Int, codec: PacketCodec<T>) {
|
||||
val bodyBuffer = BytesBuffer()
|
||||
bodyBuffer.write(packetId, VarIntCodec)
|
||||
VarIntCodec.encode(bodyBuffer, packetId)
|
||||
codec.encode(bodyBuffer, packet)
|
||||
val frameBuffer = BytesBuffer()
|
||||
frameBuffer.write(bodyBuffer.size, VarIntCodec)
|
||||
VarIntCodec.encode(bodyBuffer, bodyBuffer.size)
|
||||
frameBuffer.writeBuffer(bodyBuffer)
|
||||
val bytes = frameBuffer.toByteArray()
|
||||
this.writeFully(bytes, 0, bytes.size)
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
|
||||
package cn.rtast.libmc.nbt
|
||||
|
||||
import cn.rtast.libmc.common.ByteOrder
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.stream.ByteOrder
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
|
||||
public class BytesBufferNBTInput(override val order: ByteOrder, private val buffer: BytesBuffer) : NBTInput {
|
||||
override fun readByte(): Byte = buffer.readByte()
|
||||
override fun readBytes(count: Int): ByteArray = buffer.readBytes(count)
|
||||
override suspend fun readByte(): Byte = buffer.readByte()
|
||||
override suspend fun readBytes(count: Int): ByteArray = buffer.readBytes(count)
|
||||
}
|
||||
|
||||
public fun BytesBuffer.toNBTInput(order: ByteOrder = ByteOrder.BIG_ENDIAN): BytesBufferNBTInput =
|
||||
|
||||
@@ -7,17 +7,17 @@
|
||||
|
||||
package cn.rtast.libmc.nbt
|
||||
|
||||
import cn.rtast.libmc.common.ByteOrder
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.stream.ByteOrder
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
|
||||
public class BytesBufferNBTOutput(
|
||||
override val order: ByteOrder,
|
||||
override val root: NBTTag.CompoundTag,
|
||||
private val buffer: BytesBuffer,
|
||||
) : NBTOutput {
|
||||
override fun writeByte(value: Byte): Unit = buffer.writeByte(value)
|
||||
override fun writeBytes(value: ByteArray): Unit = buffer.writeBytes(value)
|
||||
override fun toByteArray(): ByteArray = buffer.toByteArray()
|
||||
override suspend fun writeByte(value: Byte): Unit = buffer.writeByte(value)
|
||||
override suspend fun writeBytes(value: ByteArray): Unit = buffer.writeBytes(value)
|
||||
override suspend fun toByteArray(): ByteArray = buffer.toByteArray()
|
||||
}
|
||||
|
||||
public fun BytesBuffer.toNBTOutput(
|
||||
|
||||
@@ -7,33 +7,33 @@
|
||||
|
||||
package cn.rtast.libmc.nbt
|
||||
|
||||
import cn.rtast.libmc.common.ByteOrder
|
||||
import cn.rtast.libmc.common.stream.ByteOrder
|
||||
|
||||
public interface NBTInput {
|
||||
public val order: ByteOrder
|
||||
|
||||
public fun readByte(): Byte
|
||||
public fun readBytes(count: Int): ByteArray
|
||||
public suspend fun readByte(): Byte
|
||||
public suspend fun readBytes(count: Int): ByteArray
|
||||
|
||||
public fun readLong(): Long = if (order == ByteOrder.BIG_ENDIAN) readLongBE() else readLongLE()
|
||||
public fun readFloat(): Float = if (order == ByteOrder.BIG_ENDIAN) readFloatBE() else readFloatLE()
|
||||
public fun readDouble(): Double = if (order == ByteOrder.BIG_ENDIAN) readDoubleBE() else readDoubleLE()
|
||||
public fun readShort(): Short = if (order == ByteOrder.BIG_ENDIAN) readShortBE() else readShortLE()
|
||||
public fun readInt(): Int = if (order == ByteOrder.BIG_ENDIAN) readIntBE() else readIntLE()
|
||||
public suspend fun readLong(): Long = if (order == ByteOrder.BIG_ENDIAN) readLongBE() else readLongLE()
|
||||
public suspend fun readFloat(): Float = if (order == ByteOrder.BIG_ENDIAN) readFloatBE() else readFloatLE()
|
||||
public suspend fun readDouble(): Double = if (order == ByteOrder.BIG_ENDIAN) readDoubleBE() else readDoubleLE()
|
||||
public suspend fun readShort(): Short = if (order == ByteOrder.BIG_ENDIAN) readShortBE() else readShortLE()
|
||||
public suspend fun readInt(): Int = if (order == ByteOrder.BIG_ENDIAN) readIntBE() else readIntLE()
|
||||
|
||||
// big endian
|
||||
public fun readLongBE(): Long =
|
||||
public suspend fun readLongBE(): Long =
|
||||
(readIntBE().toLong() shl 32) or (readIntBE().toLong() and 0xFFFFFFFFL)
|
||||
|
||||
public fun readFloatBE(): Float = Float.fromBits(readIntBE())
|
||||
public fun readDoubleBE(): Double = Double.fromBits(readLongBE())
|
||||
public fun readShortBE(): Short {
|
||||
public suspend fun readFloatBE(): Float = Float.fromBits(readIntBE())
|
||||
public suspend fun readDoubleBE(): Double = Double.fromBits(readLongBE())
|
||||
public suspend fun readShortBE(): Short {
|
||||
val b1 = readByte().toInt() and 0xFF
|
||||
val b2 = readByte().toInt() and 0xFF
|
||||
return ((b1 shl 8) or b2).toShort()
|
||||
}
|
||||
|
||||
public fun readIntBE(): Int {
|
||||
public suspend fun readIntBE(): Int {
|
||||
return ((readByte().toInt() and 0xFF) shl 24) or
|
||||
((readByte().toInt() and 0xFF) shl 16) or
|
||||
((readByte().toInt() and 0xFF) shl 8) or
|
||||
@@ -41,7 +41,7 @@ public interface NBTInput {
|
||||
}
|
||||
|
||||
// little endian
|
||||
public fun readLongLE(): Long {
|
||||
public suspend fun readLongLE(): Long {
|
||||
return ((readByte().toInt() and 0xFF).toLong() shl 0) or
|
||||
((readByte().toInt() and 0xFF).toLong() shl 8) or
|
||||
((readByte().toInt() and 0xFF).toLong() shl 16) or
|
||||
@@ -52,14 +52,14 @@ public interface NBTInput {
|
||||
(readByte().toInt() and 0xFF).toLong()
|
||||
}
|
||||
|
||||
public fun readFloatLE(): Float = Float.fromBits(readIntLE())
|
||||
public suspend fun readFloatLE(): Float = Float.fromBits(readIntLE())
|
||||
|
||||
public fun readDoubleLE(): Double = Double.fromBits(readLongLE())
|
||||
public suspend fun readDoubleLE(): Double = Double.fromBits(readLongLE())
|
||||
|
||||
public fun readShortLE(): Short =
|
||||
public suspend fun readShortLE(): Short =
|
||||
((readByte().toInt() and 0xFF) or (readByte().toInt() and 0xFF shl 8)).toShort()
|
||||
|
||||
public fun readIntLE(): Int =
|
||||
public suspend fun readIntLE(): Int =
|
||||
((readByte().toInt() and 0xFF)) or
|
||||
((readByte().toInt() and 0xFF) shl 8) or
|
||||
((readByte().toInt() and 0xFF) shl 16) or
|
||||
|
||||
@@ -7,44 +7,44 @@
|
||||
|
||||
package cn.rtast.libmc.nbt
|
||||
|
||||
import cn.rtast.libmc.common.ByteOrder
|
||||
import cn.rtast.libmc.common.stream.ByteOrder
|
||||
|
||||
public interface NBTOutput {
|
||||
public val order: ByteOrder
|
||||
public val root: NBTTag.CompoundTag
|
||||
|
||||
public fun writeByte(value: Byte)
|
||||
public fun writeBytes(value: ByteArray)
|
||||
public suspend fun writeByte(value: Byte)
|
||||
public suspend fun writeBytes(value: ByteArray)
|
||||
|
||||
public fun writeShort(value: Short): Unit =
|
||||
public suspend fun writeShort(value: Short): Unit =
|
||||
if (order == ByteOrder.BIG_ENDIAN) writeShortBE(value) else writeShortLE(value)
|
||||
|
||||
public fun writeInt(value: Int): Unit =
|
||||
public suspend fun writeInt(value: Int): Unit =
|
||||
if (order == ByteOrder.BIG_ENDIAN) writeIntBE(value) else writeIntLE(value)
|
||||
|
||||
public fun writeLong(value: Long): Unit =
|
||||
public suspend fun writeLong(value: Long): Unit =
|
||||
if (order == ByteOrder.BIG_ENDIAN) writeLongBE(value) else writeLongLE(value)
|
||||
|
||||
public fun writeFloat(value: Float): Unit =
|
||||
public suspend fun writeFloat(value: Float): Unit =
|
||||
if (order == ByteOrder.BIG_ENDIAN) writeFloatBE(value) else writeFloatLE(value)
|
||||
|
||||
public fun writeDouble(value: Double): Unit =
|
||||
public suspend fun writeDouble(value: Double): Unit =
|
||||
if (order == ByteOrder.BIG_ENDIAN) writeDoubleBE(value) else writeDoubleLE(value)
|
||||
|
||||
// big endian
|
||||
public fun writeShortBE(value: Short) {
|
||||
public suspend fun writeShortBE(value: Short) {
|
||||
writeByte(((value.toInt() shr 8) and 0xFF).toByte())
|
||||
writeByte((value.toInt() and 0xFF).toByte())
|
||||
}
|
||||
|
||||
public fun writeIntBE(value: Int) {
|
||||
public suspend fun writeIntBE(value: Int) {
|
||||
writeByte(((value shr 24) and 0xFF).toByte())
|
||||
writeByte(((value shr 16) and 0xFF).toByte())
|
||||
writeByte(((value shr 8) and 0xFF).toByte())
|
||||
writeByte((value and 0xFF).toByte())
|
||||
}
|
||||
|
||||
public fun writeLongBE(value: Long) {
|
||||
public suspend fun writeLongBE(value: Long) {
|
||||
writeByte(((value shr 56).toInt() and 0xFF).toByte())
|
||||
writeByte(((value shr 48).toInt() and 0xFF).toByte())
|
||||
writeByte(((value shr 40).toInt() and 0xFF).toByte())
|
||||
@@ -55,28 +55,28 @@ public interface NBTOutput {
|
||||
writeByte((value.toInt() and 0xFF).toByte())
|
||||
}
|
||||
|
||||
public fun writeFloatBE(value: Float) {
|
||||
public suspend fun writeFloatBE(value: Float) {
|
||||
writeIntBE(value.toBits())
|
||||
}
|
||||
|
||||
public fun writeDoubleBE(value: Double) {
|
||||
public suspend fun writeDoubleBE(value: Double) {
|
||||
writeLongBE(value.toBits())
|
||||
}
|
||||
|
||||
// Little Endian
|
||||
public fun writeShortLE(value: Short) {
|
||||
public suspend fun writeShortLE(value: Short) {
|
||||
writeByte((value.toInt() and 0xFF).toByte())
|
||||
writeByte(((value.toInt() shr 8) and 0xFF).toByte())
|
||||
}
|
||||
|
||||
public fun writeIntLE(value: Int) {
|
||||
public suspend fun writeIntLE(value: Int) {
|
||||
writeByte((value and 0xFF).toByte())
|
||||
writeByte(((value shr 8) and 0xFF).toByte())
|
||||
writeByte(((value shr 16) and 0xFF).toByte())
|
||||
writeByte(((value shr 24) and 0xFF).toByte())
|
||||
}
|
||||
|
||||
public fun writeLongLE(value: Long) {
|
||||
public suspend fun writeLongLE(value: Long) {
|
||||
writeByte(((value and 0xFF).toInt()).toByte())
|
||||
writeByte((((value shr 8) and 0xFF).toInt()).toByte())
|
||||
writeByte((((value shr 16) and 0xFF).toInt()).toByte())
|
||||
@@ -87,10 +87,7 @@ public interface NBTOutput {
|
||||
writeByte((((value shr 56) and 0xFF).toInt()).toByte())
|
||||
}
|
||||
|
||||
public fun writeFloatLE(value: Float): Unit = writeIntLE(value.toBits())
|
||||
|
||||
public fun writeDoubleLE(value: Double): Unit = writeLongLE(value.toBits())
|
||||
|
||||
|
||||
public fun toByteArray(): ByteArray
|
||||
public suspend fun writeFloatLE(value: Float): Unit = writeIntLE(value.toBits())
|
||||
public suspend fun writeDoubleLE(value: Double): Unit = writeLongLE(value.toBits())
|
||||
public suspend fun toByteArray(): ByteArray
|
||||
}
|
||||
@@ -7,13 +7,13 @@
|
||||
|
||||
package cn.rtast.libmc.nbt
|
||||
|
||||
public fun NBTInput.readStringTag(): String {
|
||||
public suspend fun NBTInput.readStringTag(): String {
|
||||
val length = readShort().toInt() and 0xFFFF
|
||||
val bytes = readBytes(length)
|
||||
return bytes.decodeToString()
|
||||
}
|
||||
|
||||
public fun NBTInput.readListTag(): NBTTag.ListTag {
|
||||
public suspend fun NBTInput.readListTag(): NBTTag.ListTag {
|
||||
val elementTypeId = readByte().toInt() and 0xFF
|
||||
val elementType = NBTType.fromID(elementTypeId)
|
||||
val length = readInt()
|
||||
@@ -22,7 +22,7 @@ public fun NBTInput.readListTag(): NBTTag.ListTag {
|
||||
return NBTTag.ListTag(elementType, list)
|
||||
}
|
||||
|
||||
public fun NBTInput.readCompoundTag(): NBTTag.CompoundTag {
|
||||
public suspend fun NBTInput.readCompoundTag(): NBTTag.CompoundTag {
|
||||
val map = LinkedHashMap<String, NBTTag>()
|
||||
while (true) {
|
||||
val typeId = readByte().toInt() and 0xFF
|
||||
@@ -35,7 +35,7 @@ public fun NBTInput.readCompoundTag(): NBTTag.CompoundTag {
|
||||
return NBTTag.CompoundTag(map)
|
||||
}
|
||||
|
||||
public fun NBTInput.readTagPayload(type: NBTType): NBTTag =
|
||||
public suspend fun NBTInput.readTagPayload(type: NBTType): NBTTag =
|
||||
when (type) {
|
||||
NBTType.Byte -> NBTTag.ByteTag(readByte())
|
||||
NBTType.Short -> NBTTag.ShortTag(readShort())
|
||||
@@ -52,7 +52,7 @@ public fun NBTInput.readTagPayload(type: NBTType): NBTTag =
|
||||
NBTType.End -> error("TAG_End no payload")
|
||||
}
|
||||
|
||||
public fun NBTInput.readCompound(): NBTTag {
|
||||
public suspend fun NBTInput.readCompound(): NBTTag {
|
||||
val map = LinkedHashMap<String, NBTTag>()
|
||||
while (true) {
|
||||
val typeId = readByte().toInt()
|
||||
@@ -67,7 +67,7 @@ public fun NBTInput.readCompound(): NBTTag {
|
||||
return NBTTag.ListTag(NBTType.Compound, map.values.toMutableList())
|
||||
}
|
||||
|
||||
public fun NBTInput.readRootCompound(): NBTCompound {
|
||||
public suspend fun NBTInput.readRootCompound(): NBTCompound {
|
||||
val rootType = NBTType.fromID(readByte().toInt())
|
||||
require(rootType == NBTType.Compound) { "Root tag must be TAG_Compound" }
|
||||
val nameLen = readShort().toInt() and 0xFFFF
|
||||
@@ -76,7 +76,7 @@ public fun NBTInput.readRootCompound(): NBTCompound {
|
||||
return NBTCompound(name, root)
|
||||
}
|
||||
|
||||
public fun NBTInput.readNetworkCompound(): NBTCompound {
|
||||
public suspend fun NBTInput.readNetworkCompound(): NBTCompound {
|
||||
return when (val type = NBTType.fromID(readByte().toInt() and 0xFF)) {
|
||||
NBTType.Compound -> NBTCompound("", readCompoundTag())
|
||||
NBTType.String -> NBTCompound("", NBTTag.CompoundTag(linkedMapOf("text" to NBTTag.StringTag(readStringTag()))))
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
package cn.rtast.libmc.nbt
|
||||
|
||||
|
||||
public fun NBTOutput.writeStringTag(value: String) {
|
||||
public suspend fun NBTOutput.writeStringTag(value: String) {
|
||||
val bytes = value.encodeToByteArray()
|
||||
writeShort(bytes.size.toShort())
|
||||
writeBytes(bytes)
|
||||
}
|
||||
|
||||
public fun NBTOutput.writeTagPayload(tag: NBTTag) {
|
||||
public suspend fun NBTOutput.writeTagPayload(tag: NBTTag) {
|
||||
when (tag) {
|
||||
is NBTTag.ByteTag -> writeByte(tag.value)
|
||||
is NBTTag.ShortTag -> writeShort(tag.value)
|
||||
@@ -56,14 +56,14 @@ public fun NBTOutput.writeTagPayload(tag: NBTTag) {
|
||||
}
|
||||
}
|
||||
|
||||
public fun NBTOutput.writeRootNBTCompound(name: String = ""): ByteArray {
|
||||
public suspend fun NBTOutput.writeRootNBTCompound(name: String = ""): ByteArray {
|
||||
writeByte(NBTType.Compound.id)
|
||||
writeStringTag(name)
|
||||
writeTagPayload(root)
|
||||
return toByteArray()
|
||||
}
|
||||
|
||||
public fun NBTOutput.writeNetworkCompound(compound: NBTCompound) {
|
||||
public suspend fun NBTOutput.writeNetworkCompound(compound: NBTCompound) {
|
||||
val compoundTag = compound.element as? NBTTag.CompoundTag
|
||||
?: throw IllegalArgumentException("NBTCompound element must be an NBTTag.CompoundTag")
|
||||
writeByte(NBTType.Compound.id)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
package test
|
||||
|
||||
import cn.rtast.libmc.common.wrap
|
||||
import cn.rtast.libmc.common.stream.wrap
|
||||
import cn.rtast.libmc.nbt.NbtReader
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# libmc-protocol-encrypt
|
||||
|
||||
This module implemented `ProtocolCryptoContext` and provided a `DefaultProtocolCryptoContext`.
|
||||
|
||||
## Get started
|
||||
|
||||
> `Sha1`, `RSA1024`, `AES-128-CFB8` from `cryptography-kotlin`(and its based provider).
|
||||
> `HTTP Client` from `ktor-client`
|
||||
|
||||
> Before start, you need to add a `ktor client engine` for your platform. For JVM, `ktor-client-okhttp`(JVM 1.8+)
|
||||
> or `ktor-client-java`(JVM 11+), for Linux, use `ktor-client-curl`, for Windows, use `ktor-client-winhttp`,
|
||||
> for Apple, use `ktor-client-darwin`
|
||||
|
||||
```kotlin
|
||||
fun main() {
|
||||
val cli = createMinecraftClient(
|
||||
// ... other paramater
|
||||
crypto = DefaultProtocolCryptoContext
|
||||
)
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,43 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
kotlin {
|
||||
explicitApi()
|
||||
withSourcesJar()
|
||||
|
||||
linuxX64()
|
||||
linuxArm64()
|
||||
macosArm64()
|
||||
mingwX64()
|
||||
jvm { compilerOptions.jvmTarget = JvmTarget.JVM_1_8 }
|
||||
|
||||
sourceSets {
|
||||
commonMain.dependencies {
|
||||
api(project(":common"))
|
||||
implementation(libs.cryptography.core)
|
||||
implementation(libs.cryptography.provider.optimal)
|
||||
implementation(libs.ktor.client.core)
|
||||
}
|
||||
|
||||
jvmTest.dependencies {
|
||||
implementation(libs.ktor.client.okhttp)
|
||||
}
|
||||
|
||||
linuxTest.dependencies {
|
||||
implementation(libs.ktor.client.curl)
|
||||
}
|
||||
|
||||
mingwTest.dependencies {
|
||||
implementation(libs.ktor.client.winhttp)
|
||||
}
|
||||
|
||||
appleTest.dependencies {
|
||||
implementation(libs.ktor.client.darwin)
|
||||
}
|
||||
|
||||
commonTest.dependencies {
|
||||
implementation(kotlin("test"))
|
||||
implementation(project(":protocol"))
|
||||
implementation(libs.kotlinx.coroutines.test)
|
||||
}
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/7
|
||||
*/
|
||||
|
||||
|
||||
@file:OptIn(DelicateCryptographyApi::class)
|
||||
|
||||
package cn.rtast.libmc.protocol.crypto
|
||||
|
||||
import cn.rtast.libmc.common.crypto.NetworkCipher
|
||||
import dev.whyoleg.cryptography.DelicateCryptographyApi
|
||||
import dev.whyoleg.cryptography.algorithms.AES
|
||||
|
||||
public class AesCFB8Cipher(sharedKey: ByteArray) : NetworkCipher {
|
||||
private val encryptIv = sharedKey.copyOf()
|
||||
private val decryptIv = sharedKey.copyOf()
|
||||
|
||||
private val cipher = provider.get(AES.CFB8)
|
||||
.keyDecoder()
|
||||
.decodeFromByteArrayBlocking(AES.Key.Format.RAW, sharedKey)
|
||||
.cipher()
|
||||
|
||||
override suspend fun encrypt(buffer: ByteArray, offset: Int, length: Int) {
|
||||
val plaintext = buffer.copyOfRange(offset, offset + length)
|
||||
val ciphertext = cipher.encryptWithIvBlocking(encryptIv, plaintext)
|
||||
ciphertext.copyInto(buffer, destinationOffset = offset)
|
||||
updateIv(encryptIv, ciphertext)
|
||||
}
|
||||
|
||||
override suspend fun decrypt(buffer: ByteArray, offset: Int, length: Int) {
|
||||
val ciphertext = buffer.copyOfRange(offset, offset + length)
|
||||
val plaintext = cipher.decryptWithIvBlocking(decryptIv, ciphertext)
|
||||
plaintext.copyInto(buffer, destinationOffset = offset)
|
||||
updateIv(decryptIv, ciphertext)
|
||||
}
|
||||
|
||||
private fun updateIv(iv: ByteArray, ciphertext: ByteArray) {
|
||||
val len = ciphertext.size
|
||||
if (len >= iv.size) {
|
||||
ciphertext.copyInto(iv, destinationOffset = 0, startIndex = len - iv.size, endIndex = len)
|
||||
} else {
|
||||
iv.copyInto(iv, destinationOffset = 0, startIndex = len, endIndex = iv.size)
|
||||
ciphertext.copyInto(iv, destinationOffset = iv.size - len)
|
||||
}
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/7
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.protocol.crypto
|
||||
|
||||
import cn.rtast.libmc.common.crypto.AuthenticationProvider
|
||||
import cn.rtast.libmc.common.crypto.ProtocolContextBuilder
|
||||
import cn.rtast.libmc.common.crypto.RSA1024Encryptor
|
||||
import cn.rtast.libmc.common.crypto.Sha1Hasher
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.http.*
|
||||
|
||||
private val httpClient = HttpClient()
|
||||
|
||||
public val DefaultProtocolCryptoContext: ProtocolContextBuilder.() -> Unit = {
|
||||
rsaEncryptor = RSA1024Encryptor { key, data -> rsaEncrypt(key, data) }
|
||||
sha1Hasher = Sha1Hasher { serverId, secretKey, publicKey -> minecraftServerIdHash(serverId, secretKey, publicKey) }
|
||||
cipherFactory = { key -> AesCFB8Cipher(key) }
|
||||
authProvider = AuthenticationProvider { url, accessToken, uuid, serverIdHash ->
|
||||
val status = httpClient.post(url) {
|
||||
headers { header("Content-Type", "application/json") }
|
||||
setBody("{\"accessToken\":\"$accessToken\", \"selectedProfile\":\"$uuid\", \"serverId\":\"$serverIdHash\"}")
|
||||
}.status
|
||||
require(status == HttpStatusCode.NoContent)
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/7
|
||||
*/
|
||||
|
||||
|
||||
@file:OptIn(DelicateCryptographyApi::class)
|
||||
|
||||
package cn.rtast.libmc.protocol.crypto
|
||||
|
||||
import dev.whyoleg.cryptography.CryptographyProvider
|
||||
import dev.whyoleg.cryptography.DelicateCryptographyApi
|
||||
import dev.whyoleg.cryptography.algorithms.RSA
|
||||
import dev.whyoleg.cryptography.algorithms.SHA1
|
||||
|
||||
internal val provider = CryptographyProvider.Default
|
||||
|
||||
public suspend fun rsaEncrypt(publicKeyBytes: ByteArray, data: ByteArray): ByteArray {
|
||||
val provider = CryptographyProvider.Default
|
||||
val rsa = provider.get(RSA.PKCS1)
|
||||
val publicKey = rsa.publicKeyDecoder(SHA1).decodeFromByteArray(RSA.PublicKey.Format.DER, publicKeyBytes)
|
||||
return publicKey.encryptor().encrypt(data)
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/7
|
||||
*/
|
||||
|
||||
|
||||
@file:OptIn(DelicateCryptographyApi::class)
|
||||
|
||||
package cn.rtast.libmc.protocol.crypto
|
||||
|
||||
import dev.whyoleg.cryptography.DelicateCryptographyApi
|
||||
import dev.whyoleg.cryptography.algorithms.SHA1
|
||||
|
||||
public suspend fun minecraftServerIdHash(serverId: String, secretKey: ByteArray, publicKey: ByteArray): String {
|
||||
val serverIdBytes = serverId.encodeToByteArray()
|
||||
for (b in serverIdBytes) require((b.toInt() and 0xFF) <= 0x7F) { "serverId contains non-US-ASCII character" }
|
||||
val data = serverIdBytes + secretKey + publicKey
|
||||
val hash = provider.get(SHA1).hasher().hash(data)
|
||||
return mcDigestToString(hash)
|
||||
}
|
||||
|
||||
private fun mcDigestToString(digest: ByteArray): String {
|
||||
val isNegative = (digest[0].toInt() and 0x80) != 0
|
||||
val bytes = if (isNegative) twosComplement(digest) else digest
|
||||
var hex = bytes.joinToString("") { (it.toInt() and 0xFF).toString(16).padStart(2, '0') }
|
||||
hex = hex.trimStart('0')
|
||||
if (hex.isEmpty()) hex = "0"
|
||||
return if (isNegative) "-$hex" else hex
|
||||
}
|
||||
|
||||
private fun twosComplement(bytes: ByteArray): ByteArray {
|
||||
val result = ByteArray(bytes.size)
|
||||
var carry = 1
|
||||
for (i in bytes.size - 1 downTo 0) {
|
||||
val inverted = (bytes[i].toInt().inv() and 0xFF) + carry
|
||||
result[i] = (inverted and 0xFF).toByte()
|
||||
carry = inverted ushr 8
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/7
|
||||
*/
|
||||
|
||||
package test
|
||||
|
||||
import cn.rtast.libmc.protocol.client.createMinecraftClient
|
||||
import cn.rtast.libmc.protocol.crypto.DefaultProtocolCryptoContext
|
||||
import cn.rtast.libmc.protocol.packet.login.clientbound.ClientboundLoginSuccessPacket
|
||||
import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundSystemChatMessagePacket
|
||||
import kotlinx.coroutines.launch
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
|
||||
class TestJvmClient {
|
||||
|
||||
val accessToken = File("src/commonTest/resources/accessToken.txt").readText()
|
||||
|
||||
@Test
|
||||
fun `test default protocol context`() {
|
||||
val cli = createMinecraftClient(
|
||||
"127.0.0.1",
|
||||
25565,
|
||||
"RTAkland",
|
||||
// generateOfflineUuid("RTAkland"),
|
||||
Uuid.parse("bb033844-e68e-4909-a636-1a5d1821ddc4"),
|
||||
// null,
|
||||
accessToken,
|
||||
crypto = DefaultProtocolCryptoContext
|
||||
)
|
||||
cli.on<ClientboundSystemChatMessagePacket> { println(it) }
|
||||
cli.on<ClientboundLoginSuccessPacket> { println(it) }
|
||||
cli.launch { cli.connect() }
|
||||
while (true) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,6 @@ kotlin {
|
||||
commonMain.dependencies {
|
||||
api(project(":common"))
|
||||
api(project(":nbt"))
|
||||
api(libs.kotlinx.coroutines)
|
||||
}
|
||||
|
||||
jvmMain.dependencies {
|
||||
@@ -27,8 +26,7 @@ kotlin {
|
||||
}
|
||||
|
||||
jvmTest.dependencies {
|
||||
implementation(libs.ktor.client.core)
|
||||
implementation(libs.ktor.client.okhttp)
|
||||
implementation(project(":protocol-encrypt"))
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -7,8 +7,8 @@
|
||||
package cn.rtast.libmc.protocol.client
|
||||
|
||||
import cn.rtast.libmc.common.LibMCContext
|
||||
import cn.rtast.libmc.protocol.crypto.ProtocolContext
|
||||
import cn.rtast.libmc.protocol.crypto.ProtocolContextBuilder
|
||||
import cn.rtast.libmc.common.crypto.ProtocolContext
|
||||
import cn.rtast.libmc.common.crypto.ProtocolContextBuilder
|
||||
import cn.rtast.libmc.protocol.event.InternalPacketDispatcher
|
||||
import cn.rtast.libmc.protocol.event.PacketEventDispatcher
|
||||
import cn.rtast.libmc.protocol.network.NetworkChannel
|
||||
@@ -56,7 +56,7 @@ public class MinecraftClient internal constructor(
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = clientJob + ioDispatcher + CoroutineName("LibMC-MinecraftClient-$username")
|
||||
|
||||
public fun connect(protocolVersion: Int = 776) {
|
||||
public suspend fun connect(protocolVersion: Int = 776) {
|
||||
networkChannel.connect()
|
||||
startListening()
|
||||
networkChannel.sendPacket(
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/7
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.protocol.crypto
|
||||
|
||||
public interface NetworkCipher {
|
||||
public fun encrypt(buffer: ByteArray, offset: Int, length: Int)
|
||||
public fun decrypt(buffer: ByteArray, offset: Int, length: Int)
|
||||
}
|
||||
+6
-31
@@ -19,7 +19,7 @@ import cn.rtast.libmc.protocol.packet.play.serverbound.ServerboundConfigurationA
|
||||
import cn.rtast.libmc.protocol.packet.play.serverbound.ServerboundKeepAlivePlayPacket
|
||||
import cn.rtast.libmc.protocol.packet.play.serverbound.ServerboundPongPlayPacket
|
||||
import cn.rtast.libmc.protocol.protocol.state.ProtocolState
|
||||
import cn.rtast.libmc.protocol.session.AuthenticationProvider
|
||||
import cn.rtast.libmc.common.crypto.AuthenticationProvider
|
||||
import cn.rtast.libmc.protocol.util.generateRandom16Bytes
|
||||
|
||||
public class InternalPacketDispatcher(
|
||||
@@ -31,19 +31,8 @@ public class InternalPacketDispatcher(
|
||||
public suspend fun handleIncomingPackets(packet: MinecraftPacket) {
|
||||
this.dispatchEvent(packet)
|
||||
when (packet) {
|
||||
is ClientboundLoginPacket -> this.handleLoginPackets(packet)
|
||||
is ClientboundConfigurationPacket -> this.handleConfigurationPackets(packet)
|
||||
is ClientboundPlayPacket -> this.handlePlayPackets(packet)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun handleLoginPackets(packet: ClientboundLoginPacket) {
|
||||
when (packet) {
|
||||
is ClientboundDisconnectLoginPacket -> {
|
||||
println("Login denied: ${packet.reason}")
|
||||
client.close()
|
||||
}
|
||||
|
||||
// login
|
||||
is ClientboundDisconnectLoginPacket -> client.close()
|
||||
is ClientboundSetCompressionPacket -> client.networkChannel.setCompression(packet.threshold)
|
||||
is ClientboundLoginSuccessPacket -> {
|
||||
client.networkChannel.sendPacket(ServerboundLoginAcknowledgedPacket)
|
||||
@@ -67,13 +56,7 @@ public class InternalPacketDispatcher(
|
||||
client.session.enableEncryption(sharedSecret)
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleConfigurationPackets(packet: ClientboundConfigurationPacket) {
|
||||
when (packet) {
|
||||
is ClientboundDisconnectConfigurationPacket -> println("Configuration disconnected: ${packet.reason}")
|
||||
// configuration
|
||||
ClientboundFinishConfigurationPacket -> {
|
||||
client.networkChannel.sendPacket(ServerboundAckFinishConfigurationPacket)
|
||||
client.stateMachine.transitionTo(ProtocolState.PLAY)
|
||||
@@ -91,24 +74,16 @@ public class InternalPacketDispatcher(
|
||||
ServerboundSelectKnownPacksPacket(emptyList())
|
||||
) // TODO empty resource packs list
|
||||
is ClientboundCodeOfConductPacket -> client.networkChannel.sendPacket(ServerboundAcceptCodeOfConductPacket)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handlePlayPackets(packet: ClientboundPlayPacket) {
|
||||
when (packet) {
|
||||
// play
|
||||
is ClientboundDisconnectPlayPacket -> client.close()
|
||||
is ClientboundKeepAlivePlayPacket -> client.networkChannel.sendPacket(ServerboundKeepAlivePlayPacket(id = packet.id))
|
||||
is ClientboundLoginPlayPacket -> println("Successfully joined world Entity ID: ${packet.entityId}")
|
||||
is ClientboundPingPacket -> client.networkChannel.sendPacket(ServerboundPongPlayPacket(packet.id))
|
||||
is ClientboundPlayerChatMessagePacket -> println("[Player Chat Message] ${packet.message}")
|
||||
ClientboundStartConfigurationPacket -> {
|
||||
client.networkChannel.sendPacket(ServerboundConfigurationAcknowledgedPacket)
|
||||
client.stateMachine.transitionTo(ProtocolState.CONFIGURATION)
|
||||
}
|
||||
|
||||
is ClientboundSystemChatMessagePacket -> println("[System message] ${packet.content}")
|
||||
else -> println(packet)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-8
@@ -7,27 +7,27 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.network
|
||||
|
||||
import cn.rtast.libmc.common.ReadChannel
|
||||
import cn.rtast.libmc.common.WriteChannel
|
||||
import cn.rtast.libmc.protocol.crypto.NetworkCipher
|
||||
import cn.rtast.libmc.common.stream.ReadChannel
|
||||
import cn.rtast.libmc.common.stream.WriteChannel
|
||||
import cn.rtast.libmc.common.crypto.NetworkCipher
|
||||
|
||||
internal class CipherReadChannel(
|
||||
private val delegate: ReadChannel,
|
||||
private val crypto: NetworkCipher
|
||||
) : ReadChannel() {
|
||||
override fun readFully(out: ByteArray, start: Int, end: Int) {
|
||||
override suspend fun readFully(out: ByteArray, start: Int, end: Int) {
|
||||
delegate.readFully(out, start, end)
|
||||
val length = end - start
|
||||
if (length > 0) crypto.decrypt(out, start, length)
|
||||
}
|
||||
|
||||
override fun readByte(): Byte {
|
||||
override suspend fun readByte(): Byte {
|
||||
val buf = ByteArray(1)
|
||||
readFully(buf, 0, 1)
|
||||
return buf[0]
|
||||
}
|
||||
|
||||
override fun readBytes(length: Int): ByteArray {
|
||||
override suspend fun readBytes(length: Int): ByteArray {
|
||||
val bytes = ByteArray(length)
|
||||
readFully(bytes, 0, length)
|
||||
return bytes
|
||||
@@ -38,14 +38,14 @@ internal class CipherWriteChannel(
|
||||
private val delegate: WriteChannel,
|
||||
private val crypto: NetworkCipher
|
||||
) : WriteChannel() {
|
||||
override fun writeFully(value: ByteArray, startIndex: Int, endIndex: Int) {
|
||||
override suspend fun writeFully(value: ByteArray, startIndex: Int, endIndex: Int) {
|
||||
val length = endIndex - startIndex
|
||||
if (length <= 0) return
|
||||
val encrypted = value.copyOfRange(startIndex, endIndex)
|
||||
crypto.encrypt(encrypted, 0, length)
|
||||
delegate.writeFully(encrypted, 0, length)
|
||||
}
|
||||
override fun flush() {
|
||||
override suspend fun flush() {
|
||||
delegate.flush()
|
||||
}
|
||||
}
|
||||
+8
-3
@@ -7,9 +7,14 @@
|
||||
package cn.rtast.libmc.protocol.network
|
||||
|
||||
import cn.rtast.libmc.common.*
|
||||
import cn.rtast.libmc.common.crypto.NetworkCipher
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.writeBuffer
|
||||
import cn.rtast.libmc.common.primitives.readVarInt
|
||||
import cn.rtast.libmc.common.primitives.writeVarInt
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.stream.wrap
|
||||
import cn.rtast.libmc.protocol.client.ClientStateMachine
|
||||
import cn.rtast.libmc.protocol.crypto.NetworkCipher
|
||||
import cn.rtast.libmc.protocol.protocol.GameProtocols
|
||||
import kotlin.concurrent.Volatile
|
||||
|
||||
@@ -33,7 +38,7 @@ internal class NetworkChannel(
|
||||
this.threshold = threshold
|
||||
}
|
||||
|
||||
fun readNextPacket(): MinecraftPacket {
|
||||
suspend fun readNextPacket(): MinecraftPacket {
|
||||
val packetLength = session.readVarInt()
|
||||
val rawFrameBytes = session.readBytes(packetLength)
|
||||
val frameBuf = rawFrameBytes.wrap()
|
||||
@@ -49,7 +54,7 @@ internal class NetworkChannel(
|
||||
.decodePacket(packetId, payloadBuf)
|
||||
}
|
||||
|
||||
fun sendPacket(packet: MinecraftPacket) {
|
||||
suspend fun sendPacket(packet: MinecraftPacket) {
|
||||
val uncompressedBodyBuf = BytesBuffer()
|
||||
GameProtocols.serverboundGameProtocols
|
||||
.getRegistry(stateMachine.currentState)
|
||||
|
||||
+8
-8
@@ -7,10 +7,10 @@
|
||||
package cn.rtast.libmc.protocol.network
|
||||
|
||||
import cn.rtast.libmc.common.LibMCContext
|
||||
import cn.rtast.libmc.common.ReadChannel
|
||||
import cn.rtast.libmc.common.Socket
|
||||
import cn.rtast.libmc.common.WriteChannel
|
||||
import cn.rtast.libmc.protocol.crypto.NetworkCipher
|
||||
import cn.rtast.libmc.common.stream.ReadChannel
|
||||
import cn.rtast.libmc.common.stream.Socket
|
||||
import cn.rtast.libmc.common.stream.WriteChannel
|
||||
import cn.rtast.libmc.common.crypto.NetworkCipher
|
||||
|
||||
internal class NetworkSession(
|
||||
private val host: String,
|
||||
@@ -41,17 +41,17 @@ internal class NetworkSession(
|
||||
this.writeChannel = CipherWriteChannel(currentWrite, cipher)
|
||||
}
|
||||
|
||||
fun readByte(): Byte {
|
||||
suspend fun readByte(): Byte {
|
||||
val channel = requireNotNull(readChannel) { "ReadChannel not connected" }
|
||||
return channel.readByte()
|
||||
}
|
||||
|
||||
fun readBytes(length: Int): ByteArray {
|
||||
suspend fun readBytes(length: Int): ByteArray {
|
||||
val channel = requireNotNull(readChannel) { "ReadChannel not connected" }
|
||||
return channel.readBytes(length)
|
||||
}
|
||||
|
||||
fun readVarInt(): Int {
|
||||
suspend fun readVarInt(): Int {
|
||||
var numRead = 0
|
||||
var result = 0
|
||||
var read: Byte
|
||||
@@ -65,7 +65,7 @@ internal class NetworkSession(
|
||||
return result
|
||||
}
|
||||
|
||||
fun writeFully(data: ByteArray) {
|
||||
suspend fun writeFully(data: ByteArray) {
|
||||
val channel = requireNotNull(writeChannel) { "WriteChannel not connected" }
|
||||
channel.writeFully(data, 0, data.size)
|
||||
channel.flush()
|
||||
|
||||
+6
-6
@@ -7,20 +7,20 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.readMcString
|
||||
import cn.rtast.libmc.common.writeMcString
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.primitives.readMcString
|
||||
import cn.rtast.libmc.common.primitives.writeMcString
|
||||
|
||||
public data class KnownPacks(val namespace: String, val id: String, val version: String) {
|
||||
internal companion object Codec : PacketCodec<KnownPacks> {
|
||||
override fun encode(buffer: BytesBuffer, value: KnownPacks) {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: KnownPacks) {
|
||||
buffer.writeMcString(value.namespace)
|
||||
buffer.writeMcString(value.id)
|
||||
buffer.writeMcString(value.version)
|
||||
}
|
||||
|
||||
override fun decode(buffer: BytesBuffer): KnownPacks {
|
||||
override suspend fun decode(buffer: BytesBuffer): KnownPacks {
|
||||
val namespace = buffer.readMcString()
|
||||
val id = buffer.readMcString()
|
||||
val version = buffer.readMcString()
|
||||
|
||||
+9
-4
@@ -7,7 +7,12 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.*
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.primitives.readMcString
|
||||
import cn.rtast.libmc.common.primitives.readUuid
|
||||
import cn.rtast.libmc.common.primitives.readVarInt
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.nbt.NBTCompound
|
||||
import cn.rtast.libmc.protocol.protocol.util.readNetworkNBTCompound
|
||||
import kotlin.uuid.Uuid
|
||||
@@ -18,10 +23,10 @@ public data class ClientboundAddResourcePackPacket(
|
||||
val hash: String,
|
||||
val forced: Boolean,
|
||||
val prompt: NBTCompound,
|
||||
) : ClientboundConfigurationPacket {
|
||||
) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ClientboundAddResourcePackPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundAddResourcePackPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundAddResourcePackPacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundAddResourcePackPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundAddResourcePackPacket {
|
||||
val uuid = buffer.readUuid()
|
||||
val url = buffer.readMcString()
|
||||
val hash = buffer.readMcString()
|
||||
|
||||
+6
-5
@@ -7,11 +7,12 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
|
||||
public data object ClientboundClearDialogPacket : ClientboundConfigurationPacket,
|
||||
public data object ClientboundClearDialogPacket : MinecraftPacket,
|
||||
PacketCodec<ClientboundClearDialogPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundClearDialogPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundClearDialogPacket = ClientboundClearDialogPacket
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundClearDialogPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundClearDialogPacket = ClientboundClearDialogPacket
|
||||
}
|
||||
+7
-6
@@ -7,14 +7,15 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.readMcString
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.primitives.readMcString
|
||||
|
||||
public data class ClientboundCodeOfConductPacket(val codeOfConduct: String) : ClientboundConfigurationPacket {
|
||||
public data class ClientboundCodeOfConductPacket(val codeOfConduct: String) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ClientboundCodeOfConductPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundCodeOfConductPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundCodeOfConductPacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundCodeOfConductPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundCodeOfConductPacket {
|
||||
return ClientboundCodeOfConductPacket(buffer.readMcString())
|
||||
}
|
||||
}
|
||||
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/5
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
|
||||
public sealed interface ClientboundConfigurationPacket : MinecraftPacket
|
||||
+6
-5
@@ -7,15 +7,16 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.nbt.NBTCompound
|
||||
import cn.rtast.libmc.protocol.protocol.util.readNetworkNBTCompound
|
||||
|
||||
public data class ClientboundConfigurationShowDialogPacket(val dialog: NBTCompound) : ClientboundConfigurationPacket {
|
||||
public data class ClientboundConfigurationShowDialogPacket(val dialog: NBTCompound) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ClientboundConfigurationShowDialogPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundConfigurationShowDialogPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundConfigurationShowDialogPacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundConfigurationShowDialogPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundConfigurationShowDialogPacket {
|
||||
return ClientboundConfigurationShowDialogPacket(buffer.readNetworkNBTCompound())
|
||||
}
|
||||
}
|
||||
|
||||
+6
-5
@@ -7,15 +7,16 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.protocol.protocol.game.Identifier
|
||||
import cn.rtast.libmc.protocol.protocol.game.readIdentifier
|
||||
|
||||
public data class ClientboundCookieRequestPacket(val key: Identifier) : ClientboundConfigurationPacket {
|
||||
public data class ClientboundCookieRequestPacket(val key: Identifier) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ClientboundCookieRequestPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundCookieRequestPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundCookieRequestPacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundCookieRequestPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundCookieRequestPacket {
|
||||
return ClientboundCookieRequestPacket(key = buffer.readIdentifier())
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -7,9 +7,9 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.protocol.protocol.game.Identifier
|
||||
import cn.rtast.libmc.protocol.protocol.game.readIdentifier
|
||||
|
||||
@@ -18,8 +18,8 @@ public data class ClientboundCustomPayloadPacket(
|
||||
val data: ByteArray,
|
||||
) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ClientboundCustomPayloadPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundCustomPayloadPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundCustomPayloadPacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundCustomPayloadPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundCustomPayloadPacket {
|
||||
val channel = buffer.readIdentifier()
|
||||
val data = buffer.readRemainingBytes()
|
||||
return ClientboundCustomPayloadPacket(channel, data)
|
||||
|
||||
+11
-7
@@ -7,18 +7,22 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.*
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.primitives.readMcString
|
||||
import cn.rtast.libmc.common.primitives.readVarInt
|
||||
import cn.rtast.libmc.common.primitives.writeMcString
|
||||
|
||||
public data class ClientboundCustomReportDetailsPacket(val details: List<ReportDetail>) :
|
||||
ClientboundConfigurationPacket {
|
||||
public data class ClientboundCustomReportDetailsPacket(val details: List<ReportDetail>) : MinecraftPacket {
|
||||
public data class ReportDetail(val title: String, val description: String) {
|
||||
internal companion object Codec : PacketCodec<ReportDetail> {
|
||||
override fun encode(buffer: BytesBuffer, value: ReportDetail) {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ReportDetail) {
|
||||
buffer.writeMcString(value.title)
|
||||
buffer.writeMcString(value.description)
|
||||
}
|
||||
|
||||
override fun decode(buffer: BytesBuffer): ReportDetail {
|
||||
override suspend fun decode(buffer: BytesBuffer): ReportDetail {
|
||||
val title = buffer.readMcString()
|
||||
val description = buffer.readMcString()
|
||||
return ReportDetail(title, description)
|
||||
@@ -27,8 +31,8 @@ public data class ClientboundCustomReportDetailsPacket(val details: List<ReportD
|
||||
}
|
||||
|
||||
internal companion object Codec : PacketCodec<ClientboundCustomReportDetailsPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundCustomReportDetailsPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundCustomReportDetailsPacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundCustomReportDetailsPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundCustomReportDetailsPacket {
|
||||
val detailCount = buffer.readVarInt()
|
||||
val details = ArrayList<ReportDetail>(detailCount)
|
||||
repeat(detailCount) { details.add(ReportDetail.decode(buffer)) }
|
||||
|
||||
+6
-5
@@ -7,15 +7,16 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.nbt.NBTCompound
|
||||
import cn.rtast.libmc.protocol.protocol.util.readNetworkNBTCompound
|
||||
|
||||
public data class ClientboundDisconnectConfigurationPacket(val reason: NBTCompound) : ClientboundConfigurationPacket {
|
||||
public data class ClientboundDisconnectConfigurationPacket(val reason: NBTCompound) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ClientboundDisconnectConfigurationPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundDisconnectConfigurationPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundDisconnectConfigurationPacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundDisconnectConfigurationPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundDisconnectConfigurationPacket {
|
||||
return ClientboundDisconnectConfigurationPacket(reason = buffer.readNetworkNBTCompound())
|
||||
}
|
||||
}
|
||||
|
||||
+6
-5
@@ -7,13 +7,14 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
|
||||
public data object ClientboundFinishConfigurationPacket : ClientboundConfigurationPacket,
|
||||
public data object ClientboundFinishConfigurationPacket : MinecraftPacket,
|
||||
PacketCodec<ClientboundFinishConfigurationPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundFinishConfigurationPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundFinishConfigurationPacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundFinishConfigurationPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundFinishConfigurationPacket {
|
||||
return ClientboundFinishConfigurationPacket
|
||||
}
|
||||
}
|
||||
+6
-5
@@ -7,13 +7,14 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
|
||||
public data class ClientboundKeepAliveConfigurationPacket(val id: Long) : ClientboundConfigurationPacket {
|
||||
public data class ClientboundKeepAliveConfigurationPacket(val id: Long) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ClientboundKeepAliveConfigurationPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundKeepAliveConfigurationPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundKeepAliveConfigurationPacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundKeepAliveConfigurationPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundKeepAliveConfigurationPacket {
|
||||
return ClientboundKeepAliveConfigurationPacket(buffer.readLong())
|
||||
}
|
||||
}
|
||||
|
||||
+6
-5
@@ -7,13 +7,14 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
|
||||
public data class ClientboundPingConfigurationPacket(val id: Int) : ClientboundConfigurationPacket {
|
||||
public data class ClientboundPingConfigurationPacket(val id: Int) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ClientboundPingConfigurationPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundPingConfigurationPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundPingConfigurationPacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundPingConfigurationPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundPingConfigurationPacket {
|
||||
return ClientboundPingConfigurationPacket(id = buffer.readInt())
|
||||
}
|
||||
}
|
||||
|
||||
+7
-6
@@ -7,9 +7,10 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.readVarInt
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.primitives.readVarInt
|
||||
import cn.rtast.libmc.protocol.protocol.game.Identifier
|
||||
import cn.rtast.libmc.protocol.protocol.game.readIdentifier
|
||||
import cn.rtast.libmc.protocol.protocol.game.registry.RegistryEntry
|
||||
@@ -20,10 +21,10 @@ public data class ClientboundRegistryDataPacket(
|
||||
*/
|
||||
val registryId: Identifier,
|
||||
val entries: List<RegistryEntry>,
|
||||
) : ClientboundConfigurationPacket {
|
||||
) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ClientboundRegistryDataPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundRegistryDataPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundRegistryDataPacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundRegistryDataPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundRegistryDataPacket {
|
||||
val id = buffer.readIdentifier()
|
||||
val entryCount = buffer.readVarInt()
|
||||
val entries = ArrayList<RegistryEntry>(entryCount)
|
||||
|
||||
+7
-6
@@ -7,15 +7,16 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.readUuid
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.primitives.readUuid
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
public data class ClientboundRemoveResourcePackPacket(val uuid: Uuid) : ClientboundConfigurationPacket {
|
||||
public data class ClientboundRemoveResourcePackPacket(val uuid: Uuid) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ClientboundRemoveResourcePackPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundRemoveResourcePackPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundRemoveResourcePackPacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundRemoveResourcePackPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundRemoveResourcePackPacket {
|
||||
val uuid = buffer.readUuid()
|
||||
return ClientboundRemoveResourcePackPacket(uuid)
|
||||
}
|
||||
|
||||
+6
-5
@@ -7,11 +7,12 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
|
||||
public data object ClientboundResetChatPacket : ClientboundConfigurationPacket,
|
||||
public data object ClientboundResetChatPacket : MinecraftPacket,
|
||||
PacketCodec<ClientboundResetChatPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundResetChatPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundResetChatPacket = ClientboundResetChatPacket
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundResetChatPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundResetChatPacket = ClientboundResetChatPacket
|
||||
}
|
||||
+7
-6
@@ -7,15 +7,16 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.readVarInt
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.primitives.readVarInt
|
||||
import cn.rtast.libmc.protocol.packet.configuration.KnownPacks
|
||||
|
||||
public data class ClientboundSelectKnownPacksPacket(val knownPacks: List<KnownPacks>) : ClientboundConfigurationPacket {
|
||||
public data class ClientboundSelectKnownPacksPacket(val knownPacks: List<KnownPacks>) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ClientboundSelectKnownPacksPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundSelectKnownPacksPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundSelectKnownPacksPacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundSelectKnownPacksPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundSelectKnownPacksPacket {
|
||||
val packsCount = buffer.readVarInt()
|
||||
val packs = List(packsCount) { KnownPacks.decode(buffer) }
|
||||
return ClientboundSelectKnownPacksPacket(packs)
|
||||
|
||||
+7
-6
@@ -7,15 +7,16 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.readVarInt
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.primitives.readVarInt
|
||||
import cn.rtast.libmc.protocol.registry.report.ServerLink
|
||||
|
||||
public data class ClientboundServerLinksPacket(val links: List<ServerLink>) : ClientboundConfigurationPacket {
|
||||
public data class ClientboundServerLinksPacket(val links: List<ServerLink>) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ClientboundServerLinksPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundServerLinksPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundServerLinksPacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundServerLinksPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundServerLinksPacket {
|
||||
val count = buffer.readVarInt()
|
||||
val links = ArrayList<ServerLink>(count)
|
||||
repeat(count) { links.add(ServerLink.decode(buffer)) }
|
||||
|
||||
+7
-6
@@ -7,9 +7,10 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.readPrefixedByteArray
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.primitives.readPrefixedByteArray
|
||||
import cn.rtast.libmc.protocol.protocol.game.Identifier
|
||||
import cn.rtast.libmc.protocol.protocol.game.readIdentifier
|
||||
|
||||
@@ -19,10 +20,10 @@ public data class ClientboundStoreCookiePacket(
|
||||
* cookie
|
||||
*/
|
||||
val payload: ByteArray,
|
||||
) : ClientboundConfigurationPacket {
|
||||
) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ClientboundStoreCookiePacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundStoreCookiePacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundStoreCookiePacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundStoreCookiePacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundStoreCookiePacket {
|
||||
val key = buffer.readIdentifier()
|
||||
val payload = buffer.readPrefixedByteArray()
|
||||
return ClientboundStoreCookiePacket(key, payload)
|
||||
|
||||
+8
-7
@@ -7,15 +7,16 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.readMcString
|
||||
import cn.rtast.libmc.common.readVarInt
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.primitives.readMcString
|
||||
import cn.rtast.libmc.common.primitives.readVarInt
|
||||
|
||||
public data class ClientboundTransferPacket(val host: String, val port: Int) : ClientboundConfigurationPacket {
|
||||
public data class ClientboundTransferPacket(val host: String, val port: Int) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ClientboundTransferPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundTransferPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundTransferPacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundTransferPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundTransferPacket {
|
||||
val host = buffer.readMcString()
|
||||
val port = buffer.readVarInt()
|
||||
return ClientboundTransferPacket(host, port)
|
||||
|
||||
+7
-7
@@ -7,17 +7,17 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.readVarInt
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.primitives.readVarInt
|
||||
import cn.rtast.libmc.protocol.protocol.game.Identifier
|
||||
import cn.rtast.libmc.protocol.protocol.game.readIdentifier
|
||||
|
||||
public data class ClientboundUpdateEnabledFeaturesPacket(val features: List<Identifier>) :
|
||||
ClientboundConfigurationPacket {
|
||||
public data class ClientboundUpdateEnabledFeaturesPacket(val features: List<Identifier>) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ClientboundUpdateEnabledFeaturesPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundUpdateEnabledFeaturesPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundUpdateEnabledFeaturesPacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundUpdateEnabledFeaturesPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundUpdateEnabledFeaturesPacket {
|
||||
val featureCount = buffer.readVarInt()
|
||||
val features = ArrayList<Identifier>(featureCount)
|
||||
repeat(featureCount) { features.add(buffer.readIdentifier()) }
|
||||
|
||||
+12
-11
@@ -7,24 +7,25 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.readVarInt
|
||||
import cn.rtast.libmc.common.writeVarInt
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.primitives.readVarInt
|
||||
import cn.rtast.libmc.common.primitives.writeVarInt
|
||||
import cn.rtast.libmc.protocol.protocol.game.Identifier
|
||||
import cn.rtast.libmc.protocol.protocol.game.readIdentifier
|
||||
import cn.rtast.libmc.protocol.protocol.game.writeIdentifier
|
||||
|
||||
public data class ClientboundUpdateTagsPacket(val registries: List<TaggedRegistry>) : ClientboundConfigurationPacket {
|
||||
public data class ClientboundUpdateTagsPacket(val registries: List<TaggedRegistry>) : MinecraftPacket {
|
||||
public data class TaggedRegistry(val registryId: Identifier, val tags: List<Tag>) {
|
||||
internal companion object Codec : PacketCodec<TaggedRegistry> {
|
||||
override fun encode(buffer: BytesBuffer, value: TaggedRegistry) {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: TaggedRegistry) {
|
||||
buffer.writeIdentifier(value.registryId)
|
||||
buffer.writeVarInt(value.tags.size)
|
||||
value.tags.forEach { Tag.encode(buffer, it) }
|
||||
}
|
||||
|
||||
override fun decode(buffer: BytesBuffer): TaggedRegistry {
|
||||
override suspend fun decode(buffer: BytesBuffer): TaggedRegistry {
|
||||
val id = buffer.readIdentifier()
|
||||
val tagCount = buffer.readVarInt()
|
||||
val tags = ArrayList<Tag>(tagCount)
|
||||
@@ -36,13 +37,13 @@ public data class ClientboundUpdateTagsPacket(val registries: List<TaggedRegistr
|
||||
|
||||
public data class Tag(val name: Identifier, val entries: IntArray) {
|
||||
internal companion object Codec : PacketCodec<Tag> {
|
||||
override fun encode(buffer: BytesBuffer, value: Tag) {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: Tag) {
|
||||
buffer.writeIdentifier(value.name)
|
||||
buffer.writeVarInt(value.entries.size)
|
||||
value.entries.forEach { buffer.writeVarInt(it) }
|
||||
}
|
||||
|
||||
override fun decode(buffer: BytesBuffer): Tag {
|
||||
override suspend fun decode(buffer: BytesBuffer): Tag {
|
||||
val name = buffer.readIdentifier()
|
||||
val entrySize = buffer.readVarInt()
|
||||
val entries = ArrayList<Int>(entrySize)
|
||||
@@ -68,8 +69,8 @@ public data class ClientboundUpdateTagsPacket(val registries: List<TaggedRegistr
|
||||
}
|
||||
|
||||
internal companion object Codec : PacketCodec<ClientboundUpdateTagsPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundUpdateTagsPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundUpdateTagsPacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundUpdateTagsPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundUpdateTagsPacket {
|
||||
val registryCount = buffer.readVarInt()
|
||||
val registries = ArrayList<TaggedRegistry>(registryCount)
|
||||
repeat(registryCount) { registries.add(TaggedRegistry.decode(buffer)) }
|
||||
|
||||
+4
-4
@@ -7,13 +7,13 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.serverbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
|
||||
public data object ServerboundAcceptCodeOfConductPacket : MinecraftPacket,
|
||||
PacketCodec<ServerboundAcceptCodeOfConductPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ServerboundAcceptCodeOfConductPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ServerboundAcceptCodeOfConductPacket =
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ServerboundAcceptCodeOfConductPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ServerboundAcceptCodeOfConductPacket =
|
||||
ServerboundAcceptCodeOfConductPacket
|
||||
}
|
||||
+4
-4
@@ -7,13 +7,13 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.serverbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
|
||||
public data object ServerboundAckFinishConfigurationPacket : MinecraftPacket,
|
||||
PacketCodec<ServerboundAckFinishConfigurationPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ServerboundAckFinishConfigurationPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ServerboundAckFinishConfigurationPacket =
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ServerboundAckFinishConfigurationPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ServerboundAckFinishConfigurationPacket =
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
+5
-5
@@ -7,16 +7,16 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.serverbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.writeVarInt
|
||||
import cn.rtast.libmc.common.primitives.writeVarInt
|
||||
import cn.rtast.libmc.protocol.protocol.game.Identifier
|
||||
import cn.rtast.libmc.protocol.protocol.game.writeIdentifier
|
||||
|
||||
public data class ServerboundCookieResponsePacket(val key: Identifier, val payload: ByteArray?) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ServerboundCookieResponsePacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ServerboundCookieResponsePacket) {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ServerboundCookieResponsePacket) {
|
||||
buffer.writeIdentifier(value.key)
|
||||
if (value.payload != null) {
|
||||
buffer.writeBoolean(true)
|
||||
@@ -25,7 +25,7 @@ public data class ServerboundCookieResponsePacket(val key: Identifier, val paylo
|
||||
} else buffer.writeBoolean(false)
|
||||
}
|
||||
|
||||
override fun decode(buffer: BytesBuffer): ServerboundCookieResponsePacket =
|
||||
override suspend fun decode(buffer: BytesBuffer): ServerboundCookieResponsePacket =
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -7,17 +7,17 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.serverbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
|
||||
public data class ServerboundKeepAliveConfigurationPacket(val id: Long) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ServerboundKeepAliveConfigurationPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ServerboundKeepAliveConfigurationPacket) {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ServerboundKeepAliveConfigurationPacket) {
|
||||
buffer.writeLong(value.id)
|
||||
}
|
||||
|
||||
override fun decode(buffer: BytesBuffer): ServerboundKeepAliveConfigurationPacket =
|
||||
override suspend fun decode(buffer: BytesBuffer): ServerboundKeepAliveConfigurationPacket =
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -7,17 +7,17 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.serverbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
|
||||
public data class ServerboundPongConfigurationPacket(val id: Int) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ServerboundPongConfigurationPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ServerboundPongConfigurationPacket) {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ServerboundPongConfigurationPacket) {
|
||||
buffer.writeInt(value.id)
|
||||
}
|
||||
|
||||
override fun decode(buffer: BytesBuffer): ServerboundPongConfigurationPacket =
|
||||
override suspend fun decode(buffer: BytesBuffer): ServerboundPongConfigurationPacket =
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -7,20 +7,20 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.configuration.serverbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.writeVarInt
|
||||
import cn.rtast.libmc.common.primitives.writeVarInt
|
||||
import cn.rtast.libmc.protocol.packet.configuration.KnownPacks
|
||||
|
||||
public data class ServerboundSelectKnownPacksPacket(val knownPacks: List<KnownPacks>) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ServerboundSelectKnownPacksPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ServerboundSelectKnownPacksPacket) {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ServerboundSelectKnownPacksPacket) {
|
||||
buffer.writeVarInt(value.knownPacks.size)
|
||||
value.knownPacks.forEach { KnownPacks.encode(buffer, it) }
|
||||
}
|
||||
|
||||
override fun decode(buffer: BytesBuffer): ServerboundSelectKnownPacksPacket =
|
||||
override suspend fun decode(buffer: BytesBuffer): ServerboundSelectKnownPacksPacket =
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -7,11 +7,11 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.handshake
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.writeMcString
|
||||
import cn.rtast.libmc.common.writeVarInt
|
||||
import cn.rtast.libmc.common.primitives.writeMcString
|
||||
import cn.rtast.libmc.common.primitives.writeVarInt
|
||||
import cn.rtast.libmc.protocol.protocol.state.HandshakeIntent
|
||||
|
||||
public data class ServerboundHandshakePacket(
|
||||
@@ -21,13 +21,13 @@ public data class ServerboundHandshakePacket(
|
||||
val intent: HandshakeIntent,
|
||||
) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ServerboundHandshakePacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ServerboundHandshakePacket) {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ServerboundHandshakePacket) {
|
||||
buffer.writeVarInt(value.protocolVersion)
|
||||
buffer.writeMcString(value.serverAddress)
|
||||
buffer.writeShort(value.serverPort.toShort())
|
||||
buffer.writeVarInt(value.intent.intentID)
|
||||
}
|
||||
|
||||
override fun decode(buffer: BytesBuffer): ServerboundHandshakePacket = throw UnsupportedOperationException()
|
||||
override suspend fun decode(buffer: BytesBuffer): ServerboundHandshakePacket = throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
+7
-6
@@ -7,9 +7,10 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.login.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.readVarInt
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.primitives.readVarInt
|
||||
import cn.rtast.libmc.protocol.protocol.game.Identifier
|
||||
import cn.rtast.libmc.protocol.protocol.game.readIdentifier
|
||||
|
||||
@@ -17,10 +18,10 @@ public data class ClientboundCustomQueryPacket(
|
||||
val messageId: Int,
|
||||
val channel: Identifier,
|
||||
val data: ByteArray,
|
||||
) : ClientboundLoginPacket {
|
||||
) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ClientboundCustomQueryPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundCustomQueryPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundCustomQueryPacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundCustomQueryPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundCustomQueryPacket {
|
||||
val messageId = buffer.readVarInt()
|
||||
val channel = buffer.readIdentifier()
|
||||
val data = buffer.readBytes(buffer.remaining.toInt())
|
||||
|
||||
+6
-5
@@ -7,15 +7,16 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.login.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.nbt.NBTCompound
|
||||
import cn.rtast.libmc.protocol.protocol.util.readNetworkNBTCompound
|
||||
|
||||
public data class ClientboundDisconnectLoginPacket(val reason: NBTCompound) : ClientboundLoginPacket {
|
||||
public data class ClientboundDisconnectLoginPacket(val reason: NBTCompound) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ClientboundDisconnectLoginPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundDisconnectLoginPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundDisconnectLoginPacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundDisconnectLoginPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundDisconnectLoginPacket {
|
||||
return ClientboundDisconnectLoginPacket(reason = buffer.readNetworkNBTCompound())
|
||||
}
|
||||
}
|
||||
|
||||
+8
-7
@@ -7,10 +7,11 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.login.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.readMcString
|
||||
import cn.rtast.libmc.common.readPrefixedByteArray
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.primitives.readMcString
|
||||
import cn.rtast.libmc.common.primitives.readPrefixedByteArray
|
||||
|
||||
/**
|
||||
* ref: https://minecraft.wiki/w/Java_Edition_protocol/Packets#Encryption_Request
|
||||
@@ -24,10 +25,10 @@ public data class ClientboundHelloPacket(
|
||||
* ref: https://minecraft.wiki/w/Java_Edition_protocol/Encryption#Authentication
|
||||
*/
|
||||
val shouldAuthenticate: Boolean,
|
||||
) : ClientboundLoginPacket {
|
||||
) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ClientboundHelloPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundHelloPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundHelloPacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundHelloPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundHelloPacket {
|
||||
val serverId = buffer.readMcString()
|
||||
val publicKey = buffer.readPrefixedByteArray()
|
||||
val verifyToken = buffer.readPrefixedByteArray()
|
||||
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/5
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.login.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
|
||||
public sealed interface ClientboundLoginPacket : MinecraftPacket
|
||||
+7
-6
@@ -7,17 +7,18 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.login.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.readUuid
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.primitives.readUuid
|
||||
import cn.rtast.libmc.protocol.session.GameProfile
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
public data class ClientboundLoginSuccessPacket(val gameProfile: GameProfile, val sessionId: Uuid) :
|
||||
ClientboundLoginPacket {
|
||||
MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ClientboundLoginSuccessPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundLoginSuccessPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundLoginSuccessPacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundLoginSuccessPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundLoginSuccessPacket {
|
||||
val gameProfile = GameProfile.decode(buffer)
|
||||
val sessionId = buffer.readUuid()
|
||||
return ClientboundLoginSuccessPacket(gameProfile, sessionId)
|
||||
|
||||
+9
-8
@@ -7,18 +7,19 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.login.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.readVarInt
|
||||
import cn.rtast.libmc.common.writeVarInt
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.primitives.readVarInt
|
||||
import cn.rtast.libmc.common.primitives.writeVarInt
|
||||
|
||||
public data class ClientboundSetCompressionPacket(val threshold: Int) : ClientboundLoginPacket {
|
||||
public data class ClientboundSetCompressionPacket(val threshold: Int) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ClientboundSetCompressionPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundSetCompressionPacket) {
|
||||
buffer.writeVarInt(value.threshold)
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundSetCompressionPacket) {
|
||||
buffer.writeVarInt(value = value.threshold)
|
||||
}
|
||||
|
||||
override fun decode(buffer: BytesBuffer): ClientboundSetCompressionPacket {
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundSetCompressionPacket {
|
||||
return ClientboundSetCompressionPacket(buffer.readVarInt())
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -7,20 +7,20 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.login.serverbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.writeOptionalPrefixedByteArray
|
||||
import cn.rtast.libmc.common.writeVarInt
|
||||
import cn.rtast.libmc.common.primitives.writeOptionalPrefixedByteArray
|
||||
import cn.rtast.libmc.common.primitives.writeVarInt
|
||||
|
||||
public data class ServerboundCustomQueryAnswerPacket(val messageId: Int, val data: ByteArray?) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ServerboundCustomQueryAnswerPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ServerboundCustomQueryAnswerPacket) {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ServerboundCustomQueryAnswerPacket) {
|
||||
buffer.writeVarInt(value.messageId)
|
||||
buffer.writeOptionalPrefixedByteArray(value.data)
|
||||
}
|
||||
|
||||
override fun decode(buffer: BytesBuffer): ServerboundCustomQueryAnswerPacket =
|
||||
override suspend fun decode(buffer: BytesBuffer): ServerboundCustomQueryAnswerPacket =
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -7,22 +7,22 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.login.serverbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.writePrefixedByteArray
|
||||
import cn.rtast.libmc.common.primitives.writePrefixedByteArray
|
||||
|
||||
/**
|
||||
* ref: https://minecraft.wiki/w/Java_Edition_protocol/Encryption
|
||||
*/
|
||||
public data class ServerboundKeyPacket(val sharedSecret: ByteArray, val verifyToken: ByteArray) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ServerboundKeyPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ServerboundKeyPacket) {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ServerboundKeyPacket) {
|
||||
buffer.writePrefixedByteArray(value.sharedSecret)
|
||||
buffer.writePrefixedByteArray(value.verifyToken)
|
||||
}
|
||||
|
||||
override fun decode(buffer: BytesBuffer): ServerboundKeyPacket =
|
||||
override suspend fun decode(buffer: BytesBuffer): ServerboundKeyPacket =
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
|
||||
+5
-4
@@ -7,12 +7,13 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.login.serverbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
|
||||
public data object ServerboundLoginAcknowledgedPacket : MinecraftPacket,
|
||||
PacketCodec<ServerboundLoginAcknowledgedPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ServerboundLoginAcknowledgedPacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ServerboundLoginAcknowledgedPacket = throw UnsupportedOperationException()
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ServerboundLoginAcknowledgedPacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ServerboundLoginAcknowledgedPacket =
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
+7
-6
@@ -7,20 +7,21 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.login.serverbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.writeMcString
|
||||
import cn.rtast.libmc.common.writeUuid
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.primitives.writeMcString
|
||||
import cn.rtast.libmc.common.primitives.writeUuid
|
||||
import kotlin.uuid.Uuid
|
||||
|
||||
public data class ServerboundLoginStartPacket(val username: String, val playerUuid: Uuid) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ServerboundLoginStartPacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ServerboundLoginStartPacket) {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ServerboundLoginStartPacket) {
|
||||
buffer.writeMcString(value.username)
|
||||
buffer.writeUuid(value.playerUuid)
|
||||
}
|
||||
|
||||
override fun decode(buffer: BytesBuffer): ServerboundLoginStartPacket = throw UnsupportedOperationException()
|
||||
override suspend fun decode(buffer: BytesBuffer): ServerboundLoginStartPacket =
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
+7
-6
@@ -7,17 +7,18 @@
|
||||
|
||||
package cn.rtast.libmc.protocol.packet.play.clientbound
|
||||
|
||||
import cn.rtast.libmc.common.BytesBuffer
|
||||
import cn.rtast.libmc.common.PacketCodec
|
||||
import cn.rtast.libmc.common.readVarInt
|
||||
import cn.rtast.libmc.common.stream.BytesBuffer
|
||||
import cn.rtast.libmc.common.packet.MinecraftPacket
|
||||
import cn.rtast.libmc.common.packet.PacketCodec
|
||||
import cn.rtast.libmc.common.primitives.readVarInt
|
||||
|
||||
/**
|
||||
* ref: https://minecraft.wiki/w/Java_Edition_protocol/Packets#Acknowledge_Block_Change
|
||||
*/
|
||||
public data class ClientboundAcknowledgeBlockChangePacket(val sequenceId: Int) : ClientboundPlayPacket {
|
||||
public data class ClientboundAcknowledgeBlockChangePacket(val sequenceId: Int) : MinecraftPacket {
|
||||
internal companion object Codec : PacketCodec<ClientboundAcknowledgeBlockChangePacket> {
|
||||
override fun encode(buffer: BytesBuffer, value: ClientboundAcknowledgeBlockChangePacket) {}
|
||||
override fun decode(buffer: BytesBuffer): ClientboundAcknowledgeBlockChangePacket {
|
||||
override suspend fun encode(buffer: BytesBuffer, value: ClientboundAcknowledgeBlockChangePacket) {}
|
||||
override suspend fun decode(buffer: BytesBuffer): ClientboundAcknowledgeBlockChangePacket {
|
||||
return ClientboundAcknowledgeBlockChangePacket(buffer.readVarInt())
|
||||
}
|
||||
}
|
||||
|
||||
Loaded 100 of 296 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in New Issue
Block a user