Complete all serverbound packets

This commit is contained in:
2026-09-06 14:51:32 +08:00
parent 84014a406e
commit 0bf3270be3
43 files changed
+1002 -100

No files matched your search

@@ -73,6 +73,22 @@ public fun BytesBuffer.writePrefixedByteArray(data: ByteArray) {
this.writeBytes(data) this.writeBytes(data)
} }
public fun BytesBuffer.readOptionalPrefixedByteArray(): ByteArray? {
val isPresent = this.readBoolean()
return if (isPresent) {
val length = this.readVarInt()
this.readBytes(length)
} else null
}
public fun BytesBuffer.writeOptionalPrefixedByteArray(data: ByteArray?) {
if (data != null) {
this.writeBoolean(true)
this.writeVarInt(data.size)
this.writeBytes(data)
} else this.writeBoolean(false)
}
public fun BytesBuffer.readPrefixedVarIntArray(): List<Int> { public fun BytesBuffer.readPrefixedVarIntArray(): List<Int> {
val length = readVarInt() val length = readVarInt()
val list = ArrayList<Int>(length) val list = ArrayList<Int>(length)
@@ -75,3 +75,24 @@ public object McStringCodec : PacketCodec<String> {
return bytes.decodeToString() 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)
}
@@ -7,6 +7,7 @@
package cn.rtast.libmc.protocol.client package cn.rtast.libmc.protocol.client
import cn.rtast.libmc.common.LibMCContext import cn.rtast.libmc.common.LibMCContext
import cn.rtast.libmc.protocol.event.InternalPacketDispatcher
import cn.rtast.libmc.protocol.event.PacketEventDispatcher import cn.rtast.libmc.protocol.event.PacketEventDispatcher
import cn.rtast.libmc.protocol.network.NetworkChannel import cn.rtast.libmc.protocol.network.NetworkChannel
import cn.rtast.libmc.protocol.packet.handshake.ServerboundHandshakePacket import cn.rtast.libmc.protocol.packet.handshake.ServerboundHandshakePacket
@@ -5,41 +5,18 @@
*/ */
package cn.rtast.libmc.protocol.client package cn.rtast.libmc.protocol.event
import cn.rtast.libmc.common.packet.MinecraftPacket import cn.rtast.libmc.common.packet.MinecraftPacket
import cn.rtast.libmc.protocol.packet.configuration.clientbound.ClientboundConfigurationPacket import cn.rtast.libmc.protocol.client.MinecraftClient
import cn.rtast.libmc.protocol.packet.configuration.clientbound.ClientboundCookieRequestPacket import cn.rtast.libmc.protocol.packet.configuration.clientbound.*
import cn.rtast.libmc.protocol.packet.configuration.clientbound.ClientboundCustomPayloadPacket
import cn.rtast.libmc.protocol.packet.configuration.clientbound.ClientboundDisconnectConfigurationPacket
import cn.rtast.libmc.protocol.packet.configuration.clientbound.ClientboundFinishConfigurationPacket
import cn.rtast.libmc.protocol.packet.configuration.clientbound.ClientboundKeepAliveConfigurationPacket
import cn.rtast.libmc.protocol.packet.configuration.clientbound.ClientboundPingConfigurationPacket
import cn.rtast.libmc.protocol.packet.configuration.clientbound.ClientboundSelectKnownPacksPacket
import cn.rtast.libmc.protocol.packet.configuration.serverbound.ServerboundAckFinishConfigurationPacket import cn.rtast.libmc.protocol.packet.configuration.serverbound.ServerboundAckFinishConfigurationPacket
import cn.rtast.libmc.protocol.packet.configuration.serverbound.ServerboundKeepAliveConfigurationPacket import cn.rtast.libmc.protocol.packet.configuration.serverbound.ServerboundKeepAliveConfigurationPacket
import cn.rtast.libmc.protocol.packet.configuration.serverbound.ServerboundPongConfigurationPacket import cn.rtast.libmc.protocol.packet.configuration.serverbound.ServerboundPongConfigurationPacket
import cn.rtast.libmc.protocol.packet.configuration.serverbound.ServerboundSelectKnownPacksPacket import cn.rtast.libmc.protocol.packet.configuration.serverbound.ServerboundSelectKnownPacksPacket
import cn.rtast.libmc.protocol.packet.login.clientbound.ClientboundDisconnectLoginPacket import cn.rtast.libmc.protocol.packet.login.clientbound.*
import cn.rtast.libmc.protocol.packet.login.clientbound.ClientboundLoginPacket
import cn.rtast.libmc.protocol.packet.login.clientbound.ClientboundLoginSuccessPacket
import cn.rtast.libmc.protocol.packet.login.clientbound.ClientboundSetCompressionPacket
import cn.rtast.libmc.protocol.packet.login.serverbound.ServerboundLoginAcknowledgedPacket import cn.rtast.libmc.protocol.packet.login.serverbound.ServerboundLoginAcknowledgedPacket
import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundAcknowledgeBlockChangePacket import cn.rtast.libmc.protocol.packet.play.clientbound.*
import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundAwardStatisticsPacket
import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundBlockDestructionPacket
import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundBlockEntityDataPacket
import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundDelimiterPacket
import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundDisconnectPlayPacket
import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundEntityAnimationPacket
import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundKeepAlivePlayPacket
import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundLoginPlayPacket
import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundPingPlayPacket
import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundPlayPacket
import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundPlayerChatMessagePacket
import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundSpawnEntityPacket
import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundStartConfigurationPacket
import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundSystemChatMessagePacket
import cn.rtast.libmc.protocol.packet.play.serverbound.ServerboundConfigurationAcknowledgedPacket import cn.rtast.libmc.protocol.packet.play.serverbound.ServerboundConfigurationAcknowledgedPacket
import cn.rtast.libmc.protocol.packet.play.serverbound.ServerboundKeepAlivePlayPacket import cn.rtast.libmc.protocol.packet.play.serverbound.ServerboundKeepAlivePlayPacket
import cn.rtast.libmc.protocol.packet.play.serverbound.ServerboundPongPlayPacket import cn.rtast.libmc.protocol.packet.play.serverbound.ServerboundPongPlayPacket
@@ -69,6 +46,9 @@ internal class InternalPacketDispatcher(private val client: MinecraftClient) {
client.networkChannel.sendPacket(ServerboundLoginAcknowledgedPacket) client.networkChannel.sendPacket(ServerboundLoginAcknowledgedPacket)
client.stateMachine.transitionTo(ProtocolState.CONFIGURATION) client.stateMachine.transitionTo(ProtocolState.CONFIGURATION)
} }
is ClientboundCustomQueryPacket -> {}
is ClientboundHelloPacket -> {}
} }
} }
@@ -102,6 +82,20 @@ internal class InternalPacketDispatcher(private val client: MinecraftClient) {
is ClientboundSelectKnownPacksPacket -> { is ClientboundSelectKnownPacksPacket -> {
client.networkChannel.sendPacket(ServerboundSelectKnownPacksPacket(emptyList())) // TODO empty resource packs list client.networkChannel.sendPacket(ServerboundSelectKnownPacksPacket(emptyList())) // TODO empty resource packs list
} }
is ClientboundAddResourcePackPacket -> {}
ClientboundClearDialogPacket -> {}
is ClientboundCodeOfConductPacket -> {}
is ClientboundConfigurationShowDialogPacket -> {}
is ClientboundCustomReportDetailsPacket -> {}
is ClientboundRegistryDataPacket -> {}
is ClientboundRemoveResourcePackPacket -> {}
ClientboundResetChatPacket -> {}
is ClientboundServerLinksPacket -> {}
is ClientboundStoreCookiePacket -> {}
is ClientboundTransferPacket -> {}
is ClientboundUpdateEnabledFeaturesPacket -> {}
is ClientboundUpdateTagsPacket -> {}
} }
} }
@@ -110,7 +104,7 @@ internal class InternalPacketDispatcher(private val client: MinecraftClient) {
is ClientboundDisconnectPlayPacket -> client.close() is ClientboundDisconnectPlayPacket -> client.close()
is ClientboundKeepAlivePlayPacket -> client.networkChannel.sendPacket(ServerboundKeepAlivePlayPacket(id = packet.id)) is ClientboundKeepAlivePlayPacket -> client.networkChannel.sendPacket(ServerboundKeepAlivePlayPacket(id = packet.id))
is ClientboundLoginPlayPacket -> println("Successfully joined world Entity ID: ${packet.entityId}") is ClientboundLoginPlayPacket -> println("Successfully joined world Entity ID: ${packet.entityId}")
is ClientboundPingPlayPacket -> client.networkChannel.sendPacket(ServerboundPongPlayPacket(packet.id)) is ClientboundPingPacket -> client.networkChannel.sendPacket(ServerboundPongPlayPacket(packet.id))
is ClientboundPlayerChatMessagePacket -> { is ClientboundPlayerChatMessagePacket -> {
println("Received player chat message $packet") println("Received player chat message $packet")
// TODO // TODO
@@ -129,6 +123,7 @@ internal class InternalPacketDispatcher(private val client: MinecraftClient) {
ClientboundDelimiterPacket -> {} ClientboundDelimiterPacket -> {}
is ClientboundEntityAnimationPacket -> {} is ClientboundEntityAnimationPacket -> {}
is ClientboundSpawnEntityPacket -> {} is ClientboundSpawnEntityPacket -> {}
is ClientboundShowDialogPacket -> {}
} }
} }
} }
@@ -0,0 +1,34 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
package cn.rtast.libmc.protocol.packet.configuration.clientbound
import cn.rtast.libmc.common.*
import cn.rtast.libmc.nbt.NBTCompound
import cn.rtast.libmc.protocol.protocol.util.readNetworkNBTCompound
import kotlin.uuid.Uuid
public data class ClientboundAddResourcePackPacket(
val uuid: Uuid,
val url: String,
val hash: String,
val forced: Boolean,
val prompt: NBTCompound,
) : ClientboundConfigurationPacket {
public companion object Codec : PacketCodec<ClientboundAddResourcePackPacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundAddResourcePackPacket) {}
override fun decode(buffer: BytesBuffer): ClientboundAddResourcePackPacket {
val uuid = buffer.readUuid()
val url = buffer.readMcString()
val hash = buffer.readMcString()
val forced = buffer.readBoolean()
buffer.readVarInt() // ?
val prompt = buffer.readNetworkNBTCompound() // ?
return ClientboundAddResourcePackPacket(uuid, url, hash, forced, prompt)
}
}
}
@@ -0,0 +1,17 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
package cn.rtast.libmc.protocol.packet.configuration.clientbound
import cn.rtast.libmc.common.BytesBuffer
import cn.rtast.libmc.common.PacketCodec
public data object ClientboundClearDialogPacket : ClientboundConfigurationPacket,
PacketCodec<ClientboundClearDialogPacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundClearDialogPacket) {}
override fun decode(buffer: BytesBuffer): ClientboundClearDialogPacket = ClientboundClearDialogPacket
}
@@ -0,0 +1,21 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
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
public data class ClientboundCodeOfConductPacket(val codeOfConduct: String) : ClientboundConfigurationPacket {
public companion object Codec : PacketCodec<ClientboundCodeOfConductPacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundCodeOfConductPacket) {}
override fun decode(buffer: BytesBuffer): ClientboundCodeOfConductPacket {
return ClientboundCodeOfConductPacket(buffer.readMcString())
}
}
}
@@ -0,0 +1,22 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
package cn.rtast.libmc.protocol.packet.configuration.clientbound
import cn.rtast.libmc.common.BytesBuffer
import cn.rtast.libmc.common.PacketCodec
import cn.rtast.libmc.nbt.NBTCompound
import cn.rtast.libmc.protocol.protocol.util.readNetworkNBTCompound
public data class ClientboundConfigurationShowDialogPacket(val dialog: NBTCompound) : ClientboundConfigurationPacket {
public companion object Codec : PacketCodec<ClientboundConfigurationShowDialogPacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundConfigurationShowDialogPacket) {}
override fun decode(buffer: BytesBuffer): ClientboundConfigurationShowDialogPacket {
return ClientboundConfigurationShowDialogPacket(buffer.readNetworkNBTCompound())
}
}
}
@@ -11,14 +11,10 @@ import cn.rtast.libmc.common.BytesBuffer
import cn.rtast.libmc.common.PacketCodec import cn.rtast.libmc.common.PacketCodec
import cn.rtast.libmc.protocol.protocol.game.Identifier import cn.rtast.libmc.protocol.protocol.game.Identifier
import cn.rtast.libmc.protocol.protocol.game.readIdentifier import cn.rtast.libmc.protocol.protocol.game.readIdentifier
import cn.rtast.libmc.protocol.protocol.game.writeIdentifier
public data class ClientboundCookieRequestPacket(val key: Identifier) : ClientboundConfigurationPacket { public data class ClientboundCookieRequestPacket(val key: Identifier) : ClientboundConfigurationPacket {
public companion object Codec : PacketCodec<ClientboundCookieRequestPacket> { public companion object Codec : PacketCodec<ClientboundCookieRequestPacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundCookieRequestPacket) { override fun encode(buffer: BytesBuffer, value: ClientboundCookieRequestPacket) {}
buffer.writeIdentifier(value.key)
}
override fun decode(buffer: BytesBuffer): ClientboundCookieRequestPacket { override fun decode(buffer: BytesBuffer): ClientboundCookieRequestPacket {
return ClientboundCookieRequestPacket(key = buffer.readIdentifier()) return ClientboundCookieRequestPacket(key = buffer.readIdentifier())
} }
@@ -1,7 +1,7 @@
/* /*
* Copyright © 2026 RTAkland * Copyright © 2026 RTAkland
* Author: RTAkland * Author: RTAkland
* Date: 2026/9/5 * Date: 2026/9/6
*/ */
@@ -11,19 +11,16 @@ import cn.rtast.libmc.common.BytesBuffer
import cn.rtast.libmc.common.PacketCodec import cn.rtast.libmc.common.PacketCodec
import cn.rtast.libmc.protocol.protocol.game.Identifier import cn.rtast.libmc.protocol.protocol.game.Identifier
import cn.rtast.libmc.protocol.protocol.game.readIdentifier import cn.rtast.libmc.protocol.protocol.game.readIdentifier
import cn.rtast.libmc.protocol.protocol.game.writeIdentifier
public data class ClientboundCustomPayloadPacket(val channel: Identifier, val data: ByteArray) : public data class ClientboundCustomPayloadPacket(
ClientboundConfigurationPacket { val channel: Identifier,
val data: ByteArray,
) : ClientboundConfigurationPacket {
public companion object Codec : PacketCodec<ClientboundCustomPayloadPacket> { public companion object Codec : PacketCodec<ClientboundCustomPayloadPacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundCustomPayloadPacket) { override fun encode(buffer: BytesBuffer, value: ClientboundCustomPayloadPacket) {}
buffer.writeIdentifier(value.channel)
buffer.writeBytes(value.data)
}
override fun decode(buffer: BytesBuffer): ClientboundCustomPayloadPacket { override fun decode(buffer: BytesBuffer): ClientboundCustomPayloadPacket {
val channel = buffer.readIdentifier() val channel = buffer.readIdentifier()
val data = buffer.readBytes(buffer.remaining.toInt()) val data = buffer.readRemainingBytes()
return ClientboundCustomPayloadPacket(channel, data) return ClientboundCustomPayloadPacket(channel, data)
} }
} }
@@ -0,0 +1,40 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
package cn.rtast.libmc.protocol.packet.configuration.clientbound
import cn.rtast.libmc.common.*
import kotlinx.serialization.Serializable
public data class ClientboundCustomReportDetailsPacket(val details: List<ReportDetail>) :
ClientboundConfigurationPacket {
@Serializable
public data class ReportDetail(val title: String, val description: String) {
public companion object Codec : PacketCodec<ReportDetail> {
override fun encode(buffer: BytesBuffer, value: ReportDetail) {
buffer.writeMcString(value.title)
buffer.writeMcString(value.description)
}
override fun decode(buffer: BytesBuffer): ReportDetail {
val title = buffer.readMcString()
val description = buffer.readMcString()
return ReportDetail(title, description)
}
}
}
public companion object Codec : PacketCodec<ClientboundCustomReportDetailsPacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundCustomReportDetailsPacket) {}
override fun decode(buffer: BytesBuffer): ClientboundCustomReportDetailsPacket {
val detailCount = buffer.readVarInt()
val details = ArrayList<ReportDetail>(detailCount)
repeat(detailCount) { details.add(ReportDetail.decode(buffer)) }
return ClientboundCustomReportDetailsPacket(details)
}
}
}
@@ -12,10 +12,7 @@ import cn.rtast.libmc.common.PacketCodec
public data class ClientboundKeepAliveConfigurationPacket(val id: Long) : ClientboundConfigurationPacket { public data class ClientboundKeepAliveConfigurationPacket(val id: Long) : ClientboundConfigurationPacket {
public companion object Codec : PacketCodec<ClientboundKeepAliveConfigurationPacket> { public companion object Codec : PacketCodec<ClientboundKeepAliveConfigurationPacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundKeepAliveConfigurationPacket) { override fun encode(buffer: BytesBuffer, value: ClientboundKeepAliveConfigurationPacket) {}
buffer.writeLong(value.id)
}
override fun decode(buffer: BytesBuffer): ClientboundKeepAliveConfigurationPacket { override fun decode(buffer: BytesBuffer): ClientboundKeepAliveConfigurationPacket {
return ClientboundKeepAliveConfigurationPacket(buffer.readLong()) return ClientboundKeepAliveConfigurationPacket(buffer.readLong())
} }
@@ -1,7 +1,7 @@
/* /*
* Copyright © 2026 RTAkland * Copyright © 2026 RTAkland
* Author: RTAkland * Author: RTAkland
* Date: 2026/9/4 * Date: 2026/9/6
*/ */
@@ -12,10 +12,9 @@ import cn.rtast.libmc.common.PacketCodec
public data class ClientboundPingConfigurationPacket(val id: Int) : ClientboundConfigurationPacket { public data class ClientboundPingConfigurationPacket(val id: Int) : ClientboundConfigurationPacket {
public companion object Codec : PacketCodec<ClientboundPingConfigurationPacket> { public companion object Codec : PacketCodec<ClientboundPingConfigurationPacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundPingConfigurationPacket) { override fun encode(buffer: BytesBuffer, value: ClientboundPingConfigurationPacket) {}
buffer.writeInt(value.id) override fun decode(buffer: BytesBuffer): ClientboundPingConfigurationPacket {
return ClientboundPingConfigurationPacket(id = buffer.readInt())
} }
override fun decode(buffer: BytesBuffer): ClientboundPingConfigurationPacket = ClientboundPingConfigurationPacket(buffer.readInt())
} }
} }
@@ -0,0 +1,34 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
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.protocol.protocol.game.Identifier
import cn.rtast.libmc.protocol.protocol.game.readIdentifier
import cn.rtast.libmc.protocol.protocol.game.registry.RegistryEntry
public data class ClientboundRegistryDataPacket(
/**
* Name of the registry, such as minecraft:dimension_type.
*/
val registryId: Identifier,
val entries: List<RegistryEntry>,
) : ClientboundConfigurationPacket {
public companion object Codec : PacketCodec<ClientboundRegistryDataPacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundRegistryDataPacket) {}
override fun decode(buffer: BytesBuffer): ClientboundRegistryDataPacket {
val id = buffer.readIdentifier()
val entryCount = buffer.readVarInt()
val entries = ArrayList<RegistryEntry>(entryCount)
(0 until entryCount).forEach { _ -> entries.add(RegistryEntry.decode(buffer)) }
return ClientboundRegistryDataPacket(id, entries)
}
}
}
@@ -0,0 +1,22 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
package cn.rtast.libmc.protocol.packet.configuration.clientbound
import cn.rtast.libmc.common.*
import cn.rtast.libmc.protocol.protocol.util.readNetworkNBTCompound
import kotlin.uuid.Uuid
public data class ClientboundRemoveResourcePackPacket(val uuid: Uuid) : ClientboundConfigurationPacket {
public companion object Codec : PacketCodec<ClientboundRemoveResourcePackPacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundRemoveResourcePackPacket) {}
override fun decode(buffer: BytesBuffer): ClientboundRemoveResourcePackPacket {
val uuid = buffer.readUuid()
return ClientboundRemoveResourcePackPacket(uuid)
}
}
}
@@ -0,0 +1,17 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
package cn.rtast.libmc.protocol.packet.configuration.clientbound
import cn.rtast.libmc.common.BytesBuffer
import cn.rtast.libmc.common.PacketCodec
public data object ClientboundResetChatPacket : ClientboundConfigurationPacket,
PacketCodec<ClientboundResetChatPacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundResetChatPacket) {}
override fun decode(buffer: BytesBuffer): ClientboundResetChatPacket = ClientboundResetChatPacket
}
@@ -10,16 +10,11 @@ package cn.rtast.libmc.protocol.packet.configuration.clientbound
import cn.rtast.libmc.common.BytesBuffer import cn.rtast.libmc.common.BytesBuffer
import cn.rtast.libmc.common.PacketCodec import cn.rtast.libmc.common.PacketCodec
import cn.rtast.libmc.common.readVarInt import cn.rtast.libmc.common.readVarInt
import cn.rtast.libmc.common.writeVarInt
import cn.rtast.libmc.protocol.packet.configuration.KnownPacks 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>) : ClientboundConfigurationPacket {
public companion object Codec : PacketCodec<ClientboundSelectKnownPacksPacket> { public companion object Codec : PacketCodec<ClientboundSelectKnownPacksPacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundSelectKnownPacksPacket) { override fun encode(buffer: BytesBuffer, value: ClientboundSelectKnownPacksPacket) {}
buffer.writeVarInt(value.knownPacks.size)
value.knownPacks.forEach { KnownPacks.encode(buffer, it) }
}
override fun decode(buffer: BytesBuffer): ClientboundSelectKnownPacksPacket { override fun decode(buffer: BytesBuffer): ClientboundSelectKnownPacksPacket {
val packsCount = buffer.readVarInt() val packsCount = buffer.readVarInt()
val packs = List(packsCount) { KnownPacks.decode(buffer) } val packs = List(packsCount) { KnownPacks.decode(buffer) }
@@ -0,0 +1,25 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
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.protocol.registry.report.ServerLink
public data class ClientboundServerLinksPacket(val links: List<ServerLink>) : ClientboundConfigurationPacket {
public companion object Codec : PacketCodec<ClientboundServerLinksPacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundServerLinksPacket) {}
override fun decode(buffer: BytesBuffer): ClientboundServerLinksPacket {
val count = buffer.readVarInt()
val links = ArrayList<ServerLink>(count)
repeat(count) { links.add(ServerLink.decode(buffer)) }
return ClientboundServerLinksPacket(links)
}
}
}
@@ -0,0 +1,49 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
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.protocol.protocol.game.Identifier
import cn.rtast.libmc.protocol.protocol.game.readIdentifier
public data class ClientboundStoreCookiePacket(
val key: Identifier,
/**
* cookie
*/
val payload: ByteArray,
) : ClientboundConfigurationPacket {
public companion object Codec : PacketCodec<ClientboundStoreCookiePacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundStoreCookiePacket) {}
override fun decode(buffer: BytesBuffer): ClientboundStoreCookiePacket {
val key = buffer.readIdentifier()
val payload = buffer.readPrefixedByteArray()
return ClientboundStoreCookiePacket(key, payload)
}
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as ClientboundStoreCookiePacket
if (key != other.key) return false
if (!payload.contentEquals(other.payload)) return false
return true
}
override fun hashCode(): Int {
var result = key.hashCode()
result = 31 * result + payload.contentHashCode()
return result
}
}
@@ -0,0 +1,24 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
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
public data class ClientboundTransferPacket(val host: String, val port: Int) : ClientboundConfigurationPacket {
public companion object Codec : PacketCodec<ClientboundTransferPacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundTransferPacket) {}
override fun decode(buffer: BytesBuffer): ClientboundTransferPacket {
val host = buffer.readMcString()
val port = buffer.readVarInt()
return ClientboundTransferPacket(host, port)
}
}
}
@@ -0,0 +1,27 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
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.protocol.protocol.game.Identifier
import cn.rtast.libmc.protocol.protocol.game.readIdentifier
public data class ClientboundUpdateEnabledFeaturesPacket(val features: List<Identifier>) :
ClientboundConfigurationPacket {
public companion object Codec : PacketCodec<ClientboundUpdateEnabledFeaturesPacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundUpdateEnabledFeaturesPacket) {}
override fun decode(buffer: BytesBuffer): ClientboundUpdateEnabledFeaturesPacket {
val featureCount = buffer.readVarInt()
val features = ArrayList<Identifier>(featureCount)
repeat(featureCount) { features.add(buffer.readIdentifier()) }
return ClientboundUpdateEnabledFeaturesPacket(features)
}
}
}
@@ -0,0 +1,82 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
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.protocol.protocol.game.Identifier
import cn.rtast.libmc.protocol.protocol.game.readIdentifier
import cn.rtast.libmc.protocol.protocol.game.writeIdentifier
import kotlinx.serialization.Serializable
public data class ClientboundUpdateTagsPacket(val registries: List<TaggedRegistry>) : ClientboundConfigurationPacket {
@Serializable
public data class TaggedRegistry(val registryId: Identifier, val tags: List<Tag>) {
public companion object Codec : PacketCodec<TaggedRegistry> {
override 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 {
val id = buffer.readIdentifier()
val tagCount = buffer.readVarInt()
val tags = ArrayList<Tag>(tagCount)
repeat(tagCount) { tags.add(Tag.decode(buffer)) }
return TaggedRegistry(id, tags)
}
}
}
@Serializable
public data class Tag(val name: Identifier, val entries: IntArray) {
public companion object Codec : PacketCodec<Tag> {
override 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 {
val name = buffer.readIdentifier()
val entrySize = buffer.readVarInt()
val entries = ArrayList<Int>(entrySize)
repeat(entrySize) { entries.add(buffer.readVarInt()) }
return Tag(name, entries.toIntArray())
}
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as Tag
if (name != other.name) return false
if (!entries.contentEquals(other.entries)) return false
return true
}
override fun hashCode(): Int {
var result = name.hashCode()
result = 31 * result + entries.contentHashCode()
return result
}
}
public companion object Codec : PacketCodec<ClientboundUpdateTagsPacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundUpdateTagsPacket) {}
override fun decode(buffer: BytesBuffer): ClientboundUpdateTagsPacket {
val registryCount = buffer.readVarInt()
val registries = ArrayList<TaggedRegistry>(registryCount)
repeat(registryCount) { registries.add(TaggedRegistry.decode(buffer)) }
return ClientboundUpdateTagsPacket(registries)
}
}
}
@@ -0,0 +1,19 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
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.packet.MinecraftPacket
public data object ServerboundAcceptCodeOfConductPacket : MinecraftPacket,
PacketCodec<ServerboundAcceptCodeOfConductPacket> {
override fun encode(buffer: BytesBuffer, value: ServerboundAcceptCodeOfConductPacket) {}
override fun decode(buffer: BytesBuffer): ServerboundAcceptCodeOfConductPacket =
ServerboundAcceptCodeOfConductPacket
}
@@ -14,7 +14,6 @@ import cn.rtast.libmc.common.packet.MinecraftPacket
public data object ServerboundAckFinishConfigurationPacket : MinecraftPacket, public data object ServerboundAckFinishConfigurationPacket : MinecraftPacket,
PacketCodec<ServerboundAckFinishConfigurationPacket> { PacketCodec<ServerboundAckFinishConfigurationPacket> {
override fun encode(buffer: BytesBuffer, value: ServerboundAckFinishConfigurationPacket) {} override fun encode(buffer: BytesBuffer, value: ServerboundAckFinishConfigurationPacket) {}
override fun decode(buffer: BytesBuffer): ServerboundAckFinishConfigurationPacket = override fun decode(buffer: BytesBuffer): ServerboundAckFinishConfigurationPacket =
ServerboundAckFinishConfigurationPacket throw UnsupportedOperationException()
} }
@@ -17,8 +17,7 @@ public data class ServerboundKeepAliveConfigurationPacket(val id: Long) : Minecr
buffer.writeLong(value.id) buffer.writeLong(value.id)
} }
override fun decode(buffer: BytesBuffer): ServerboundKeepAliveConfigurationPacket { override fun decode(buffer: BytesBuffer): ServerboundKeepAliveConfigurationPacket =
return ServerboundKeepAliveConfigurationPacket(buffer.readLong()) throw UnsupportedOperationException()
}
} }
} }
@@ -17,6 +17,7 @@ public data class ServerboundPongConfigurationPacket(val id: Int) : MinecraftPac
buffer.writeInt(value.id) buffer.writeInt(value.id)
} }
override fun decode(buffer: BytesBuffer): ServerboundPongConfigurationPacket = ServerboundPongConfigurationPacket(buffer.readInt()) override fun decode(buffer: BytesBuffer): ServerboundPongConfigurationPacket =
throw UnsupportedOperationException()
} }
} }
@@ -7,10 +7,9 @@
package cn.rtast.libmc.protocol.packet.configuration.serverbound package cn.rtast.libmc.protocol.packet.configuration.serverbound
import cn.rtast.libmc.common.PacketCodec
import cn.rtast.libmc.common.BytesBuffer import cn.rtast.libmc.common.BytesBuffer
import cn.rtast.libmc.common.PacketCodec
import cn.rtast.libmc.common.packet.MinecraftPacket import cn.rtast.libmc.common.packet.MinecraftPacket
import cn.rtast.libmc.common.readVarInt
import cn.rtast.libmc.common.writeVarInt import cn.rtast.libmc.common.writeVarInt
import cn.rtast.libmc.protocol.packet.configuration.KnownPacks import cn.rtast.libmc.protocol.packet.configuration.KnownPacks
@@ -21,10 +20,7 @@ public data class ServerboundSelectKnownPacksPacket(val knownPacks: List<KnownPa
value.knownPacks.forEach { KnownPacks.encode(buffer, it) } value.knownPacks.forEach { KnownPacks.encode(buffer, it) }
} }
override fun decode(buffer: BytesBuffer): ServerboundSelectKnownPacksPacket { override fun decode(buffer: BytesBuffer): ServerboundSelectKnownPacksPacket =
val packsCount = buffer.readVarInt() throw UnsupportedOperationException()
val packs = List(packsCount) { KnownPacks.decode(buffer) }
return ServerboundSelectKnownPacksPacket(packs)
}
} }
} }
@@ -0,0 +1,48 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/5
*/
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.protocol.protocol.game.Identifier
import cn.rtast.libmc.protocol.protocol.game.readIdentifier
public data class ClientboundCustomQueryPacket(
val messageId: Int,
val channel: Identifier,
val data: ByteArray,
) : ClientboundLoginPacket {
public companion object Codec : PacketCodec<ClientboundCustomQueryPacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundCustomQueryPacket) {}
override fun decode(buffer: BytesBuffer): ClientboundCustomQueryPacket {
val messageId = buffer.readVarInt()
val channel = buffer.readIdentifier()
val data = buffer.readBytes(buffer.remaining.toInt())
return ClientboundCustomQueryPacket(messageId, channel, data)
}
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as ClientboundCustomQueryPacket
if (channel != other.channel) return false
if (!data.contentEquals(other.data)) return false
return true
}
override fun hashCode(): Int {
var result = channel.hashCode()
result = 31 * result + data.contentHashCode()
return result
}
}
@@ -0,0 +1,60 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
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
/**
* ref: https://minecraft.wiki/w/Java_Edition_protocol/Packets#Encryption_Request
*/
public data class ClientboundHelloPacket(
val serverId: String,
val publicKey: ByteArray,
val verifyToken: ByteArray,
/**
* Whether the client should attempt to authenticate through mojang servers.
* ref: https://minecraft.wiki/w/Java_Edition_protocol/Encryption#Authentication
*/
val shouldAuthenticate: Boolean,
) : ClientboundLoginPacket {
public companion object Codec : PacketCodec<ClientboundHelloPacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundHelloPacket) {}
override fun decode(buffer: BytesBuffer): ClientboundHelloPacket {
val serverId = buffer.readMcString()
val publicKey = buffer.readPrefixedByteArray()
val verifyToken = buffer.readPrefixedByteArray()
val shouldAuthenticate = buffer.readBoolean()
return ClientboundHelloPacket(serverId, publicKey, verifyToken, shouldAuthenticate)
}
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as ClientboundHelloPacket
if (shouldAuthenticate != other.shouldAuthenticate) return false
if (serverId != other.serverId) return false
if (!publicKey.contentEquals(other.publicKey)) return false
if (!verifyToken.contentEquals(other.verifyToken)) return false
return true
}
override fun hashCode(): Int {
var result = shouldAuthenticate.hashCode()
result = 31 * result + serverId.hashCode()
result = 31 * result + publicKey.contentHashCode()
result = 31 * result + verifyToken.contentHashCode()
return result
}
}
@@ -0,0 +1,45 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
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.packet.MinecraftPacket
import cn.rtast.libmc.common.writeOptionalPrefixedByteArray
import cn.rtast.libmc.common.writeVarInt
public data class ServerboundCustomQueryAnswerPacket(val messageId: Int, val data: ByteArray?) : MinecraftPacket {
public companion object Codec : PacketCodec<ServerboundCustomQueryAnswerPacket> {
override fun encode(buffer: BytesBuffer, value: ServerboundCustomQueryAnswerPacket) {
buffer.writeVarInt(value.messageId)
buffer.writeOptionalPrefixedByteArray(value.data)
}
override fun decode(buffer: BytesBuffer): ServerboundCustomQueryAnswerPacket =
throw UnsupportedOperationException()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as ServerboundCustomQueryAnswerPacket
if (messageId != other.messageId) return false
if (!data.contentEquals(other.data)) return false
return true
}
override fun hashCode(): Int {
var result = messageId
result = 31 * result + (data?.contentHashCode() ?: 0)
return result
}
}
@@ -0,0 +1,46 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
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.packet.MinecraftPacket
import cn.rtast.libmc.common.writePrefixedByteArray
/**
* ref: https://minecraft.wiki/w/Java_Edition_protocol/Encryption
*/
public data class ServerboundKeyPacket(val sharedSecret: ByteArray, val verifyToken: ByteArray) : MinecraftPacket {
public companion object Codec : PacketCodec<ServerboundKeyPacket> {
override fun encode(buffer: BytesBuffer, value: ServerboundKeyPacket) {
buffer.writePrefixedByteArray(value.sharedSecret)
buffer.writePrefixedByteArray(value.verifyToken)
}
override fun decode(buffer: BytesBuffer): ServerboundKeyPacket =
throw UnsupportedOperationException()
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as ServerboundKeyPacket
if (!sharedSecret.contentEquals(other.sharedSecret)) return false
if (!verifyToken.contentEquals(other.verifyToken)) return false
return true
}
override fun hashCode(): Int {
var result = sharedSecret.contentHashCode()
result = 31 * result + verifyToken.contentHashCode()
return result
}
}
@@ -10,14 +10,11 @@ package cn.rtast.libmc.protocol.packet.play.clientbound
import cn.rtast.libmc.common.BytesBuffer import cn.rtast.libmc.common.BytesBuffer
import cn.rtast.libmc.common.PacketCodec import cn.rtast.libmc.common.PacketCodec
public data class ClientboundPingPlayPacket(val id: Int) : ClientboundPlayPacket { public data class ClientboundPingPacket(val id: Int) : ClientboundPlayPacket {
public companion object Codec : PacketCodec<ClientboundPingPlayPacket> { public companion object Codec : PacketCodec<ClientboundPingPacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundPingPlayPacket) { override fun encode(buffer: BytesBuffer, value: ClientboundPingPacket) {}
buffer.writeInt(value.id) override fun decode(buffer: BytesBuffer): ClientboundPingPacket {
} return ClientboundPingPacket(id = buffer.readInt())
override fun decode(buffer: BytesBuffer): ClientboundPingPlayPacket {
return ClientboundPingPlayPacket(id = buffer.readInt())
} }
} }
} }
@@ -0,0 +1,24 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
package cn.rtast.libmc.protocol.packet.play.clientbound
import cn.rtast.libmc.common.BytesBuffer
import cn.rtast.libmc.common.IdOrX
import cn.rtast.libmc.common.PacketCodec
import cn.rtast.libmc.common.readIdOrX
import cn.rtast.libmc.nbt.NBTCompound
import cn.rtast.libmc.protocol.protocol.util.readNetworkNBTCompound
public data class ClientboundShowDialogPacket(val dialog: IdOrX<NBTCompound>) : ClientboundPlayPacket {
public companion object Codec : PacketCodec<ClientboundShowDialogPacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundShowDialogPacket) {}
override fun decode(buffer: BytesBuffer): ClientboundShowDialogPacket {
return ClientboundShowDialogPacket(buffer.readIdOrX { this.readNetworkNBTCompound() })
}
}
}
@@ -0,0 +1,20 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
package cn.rtast.libmc.protocol.packet.status.clientbound
import cn.rtast.libmc.common.BytesBuffer
import cn.rtast.libmc.common.PacketCodec
public data class ClientboundPongResponsePacket(val timestamp: Long) : ClientboundStatusPacket {
public companion object Codec : PacketCodec<ClientboundPongResponsePacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundPongResponsePacket) {}
override fun decode(buffer: BytesBuffer): ClientboundPongResponsePacket {
return ClientboundPongResponsePacket(buffer.readLong())
}
}
}
@@ -0,0 +1,12 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
package cn.rtast.libmc.protocol.packet.status.clientbound
import cn.rtast.libmc.common.packet.MinecraftPacket
public sealed interface ClientboundStatusPacket : MinecraftPacket
@@ -0,0 +1,20 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
package cn.rtast.libmc.protocol.packet.status.clientbound
import cn.rtast.libmc.common.BytesBuffer
import cn.rtast.libmc.common.PacketCodec
import cn.rtast.libmc.common.readMcString
public data class ClientboundStatusResponsePacket(val jsonResponse: String) : ClientboundStatusPacket {
public companion object Codec : PacketCodec<ClientboundStatusResponsePacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundStatusResponsePacket) {}
override fun decode(buffer: BytesBuffer): ClientboundStatusResponsePacket =
ClientboundStatusResponsePacket(buffer.readMcString())
}
}
@@ -11,13 +11,13 @@ import cn.rtast.libmc.common.BytesBuffer
import cn.rtast.libmc.common.PacketCodec import cn.rtast.libmc.common.PacketCodec
import cn.rtast.libmc.common.packet.MinecraftPacket import cn.rtast.libmc.common.packet.MinecraftPacket
public data class ServerboundPingRequest(val timestamp: Long) : MinecraftPacket { public data class ServerboundPingRequestPacket(val timestamp: Long) : MinecraftPacket {
public companion object Codec : PacketCodec<ServerboundPingRequest> { public companion object Codec : PacketCodec<ServerboundPingRequestPacket> {
override fun encode(buffer: BytesBuffer, value: ServerboundPingRequest) { override fun encode(buffer: BytesBuffer, value: ServerboundPingRequestPacket) {
buffer.writeLong(value.timestamp) buffer.writeLong(value.timestamp)
} }
override fun decode(buffer: BytesBuffer): ServerboundPingRequest = override fun decode(buffer: BytesBuffer): ServerboundPingRequestPacket =
throw UnsupportedOperationException() throw UnsupportedOperationException()
} }
} }
@@ -0,0 +1,18 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
package cn.rtast.libmc.protocol.packet.status.serverbound
import cn.rtast.libmc.common.BytesBuffer
import cn.rtast.libmc.common.PacketCodec
import cn.rtast.libmc.common.packet.MinecraftPacket
public data object ServerboundStatusRequestPacket : MinecraftPacket, PacketCodec<ServerboundStatusRequestPacket> {
override fun encode(buffer: BytesBuffer, value: ServerboundStatusRequestPacket) {}
override fun decode(buffer: BytesBuffer): ServerboundStatusRequestPacket =
throw UnsupportedOperationException()
}
@@ -9,19 +9,34 @@ package cn.rtast.libmc.protocol.protocol
import cn.rtast.libmc.protocol.packet.configuration.clientbound.* import cn.rtast.libmc.protocol.packet.configuration.clientbound.*
import cn.rtast.libmc.protocol.packet.configuration.serverbound.* import cn.rtast.libmc.protocol.packet.configuration.serverbound.*
import cn.rtast.libmc.protocol.packet.handshake.ServerboundHandshakePacket import cn.rtast.libmc.protocol.packet.handshake.ServerboundHandshakePacket
import cn.rtast.libmc.protocol.packet.login.clientbound.ClientboundDisconnectLoginPacket import cn.rtast.libmc.protocol.packet.login.clientbound.*
import cn.rtast.libmc.protocol.packet.login.clientbound.ClientboundLoginSuccessPacket import cn.rtast.libmc.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket
import cn.rtast.libmc.protocol.packet.login.clientbound.ClientboundSetCompressionPacket import cn.rtast.libmc.protocol.packet.login.serverbound.ServerboundKeyPacket
import cn.rtast.libmc.protocol.packet.login.serverbound.ServerboundLoginAcknowledgedPacket import cn.rtast.libmc.protocol.packet.login.serverbound.ServerboundLoginAcknowledgedPacket
import cn.rtast.libmc.protocol.packet.login.serverbound.ServerboundLoginStartPacket import cn.rtast.libmc.protocol.packet.login.serverbound.ServerboundLoginStartPacket
import cn.rtast.libmc.protocol.packet.play.clientbound.* import cn.rtast.libmc.protocol.packet.play.clientbound.*
import cn.rtast.libmc.protocol.packet.play.serverbound.* import cn.rtast.libmc.protocol.packet.play.serverbound.*
import cn.rtast.libmc.protocol.packet.status.serverbound.ServerboundPingRequest import cn.rtast.libmc.protocol.packet.status.clientbound.ClientboundPongResponsePacket
import cn.rtast.libmc.protocol.packet.status.clientbound.ClientboundStatusResponsePacket
import cn.rtast.libmc.protocol.packet.status.serverbound.ServerboundPingRequestPacket
import cn.rtast.libmc.protocol.packet.status.serverbound.ServerboundStatusRequestPacket
import cn.rtast.libmc.protocol.protocol.state.ProtocolState import cn.rtast.libmc.protocol.protocol.state.ProtocolState
import cn.rtast.libmc.protocol.protocol.state.ProtocolStateRegistry import cn.rtast.libmc.protocol.protocol.state.ProtocolStateRegistry
internal object GameProtocols { internal object GameProtocols {
val clientboundGameProtocols = ProtocolStateRegistry().apply { val clientboundGameProtocols = ProtocolStateRegistry().apply {
register(ProtocolState.STATUS) {
register(0x00, ClientboundStatusResponsePacket)
register(0x01, ClientboundPongResponsePacket)
}
register(ProtocolState.LOGIN) {
register(0x00, ClientboundDisconnectLoginPacket)
register(0x01, ClientboundHelloPacket)
register(0x02, ClientboundLoginSuccessPacket)
register(0x03, ClientboundSetCompressionPacket)
register(0x04, ClientboundCustomQueryPacket)
register(0x05, ClientboundCookieRequestPacket)
}
register(ProtocolState.CONFIGURATION) { register(ProtocolState.CONFIGURATION) {
register(0x00, ClientboundCookieRequestPacket) register(0x00, ClientboundCookieRequestPacket)
register(0x01, ClientboundCustomPayloadPacket) register(0x01, ClientboundCustomPayloadPacket)
@@ -29,12 +44,20 @@ internal object GameProtocols {
register(0x03, ClientboundFinishConfigurationPacket) register(0x03, ClientboundFinishConfigurationPacket)
register(0x04, ClientboundKeepAliveConfigurationPacket) register(0x04, ClientboundKeepAliveConfigurationPacket)
register(0x05, ClientboundPingConfigurationPacket) register(0x05, ClientboundPingConfigurationPacket)
register(0x06, ClientboundResetChatPacket)
register(0x07, ClientboundRegistryDataPacket)
register(0x08, ClientboundRemoveResourcePackPacket)
register(0x09, ClientboundAddResourcePackPacket)
register(0x0a, ClientboundStoreCookiePacket)
register(0x0b, ClientboundTransferPacket)
register(0x0c, ClientboundUpdateEnabledFeaturesPacket)
register(0x0d, ClientboundUpdateTagsPacket)
register(0x0e, ClientboundSelectKnownPacksPacket) register(0x0e, ClientboundSelectKnownPacksPacket)
} register(0x0f, ClientboundCustomReportDetailsPacket)
register(ProtocolState.LOGIN) { register(0x10, ClientboundServerLinksPacket)
register(0x00, ClientboundDisconnectLoginPacket) register(0x11, ClientboundClearDialogPacket)
register(0x02, ClientboundLoginSuccessPacket) register(0x12, ClientboundConfigurationShowDialogPacket)
register(0x03, ClientboundSetCompressionPacket) register(0x13, ClientboundCodeOfConductPacket)
} }
register(ProtocolState.PLAY) { register(ProtocolState.PLAY) {
register(0x00, ClientboundDelimiterPacket) register(0x00, ClientboundDelimiterPacket)
@@ -45,13 +68,29 @@ internal object GameProtocols {
register(0x05, ClientboundBlockDestructionPacket) register(0x05, ClientboundBlockDestructionPacket)
register(0x06, ClientboundBlockEntityDataPacket) register(0x06, ClientboundBlockEntityDataPacket)
register(0x15, ClientboundCookieRequestPacket)
register(0x20, ClientboundDisconnectPlayPacket) register(0x20, ClientboundDisconnectPlayPacket)
register(0x24, ClientboundCustomPayloadPacket)
register(0x2c, ClientboundKeepAlivePlayPacket) register(0x2c, ClientboundKeepAlivePlayPacket)
register(0x31, ClientboundLoginPlayPacket) register(0x31, ClientboundLoginPlayPacket)
register(0x3d, ClientboundPingPlayPacket) register(0x3d, ClientboundPingPacket)
register(0x41, ClientboundPlayerChatMessagePacket) register(0x41, ClientboundPlayerChatMessagePacket)
register(0x50, ClientboundRemoveResourcePackPacket)
register(0x51, ClientboundAddResourcePackPacket)
register(0x76, ClientboundStartConfigurationPacket) register(0x76, ClientboundStartConfigurationPacket)
register(0x78, ClientboundStoreCookiePacket)
register(0x79, ClientboundSystemChatMessagePacket) register(0x79, ClientboundSystemChatMessagePacket)
register(0x81, ClientboundTransferPacket)
register(0x86, ClientboundUpdateTagsPacket)
register(0x88, ClientboundCustomReportDetailsPacket)
register(0x89, ClientboundServerLinksPacket)
register(0x8b, ClientboundClearDialogPacket)
register(0x8c, ClientboundShowDialogPacket)
} }
} }
@@ -59,17 +98,27 @@ internal object GameProtocols {
register(ProtocolState.HANDSHAKE) { register(ProtocolState.HANDSHAKE) {
register(0x00, ServerboundHandshakePacket) register(0x00, ServerboundHandshakePacket)
} }
register(ProtocolState.STATUS) {
register(0x00, ServerboundStatusRequestPacket)
register(0x01, ServerboundPingRequestPacket)
}
register(ProtocolState.LOGIN) {
register(0x00, ServerboundLoginStartPacket)
register(0x01, ServerboundKeyPacket)
register(0x02, ServerboundCustomQueryAnswerPacket)
register(0x03, ServerboundLoginAcknowledgedPacket)
register(0x04, ServerboundCookieResponsePacket)
}
register(ProtocolState.CONFIGURATION) { register(ProtocolState.CONFIGURATION) {
register(0x00, ServerboundCookieResponsePacket) register(0x00, ServerboundCookieResponsePacket)
register(0x01, ServerboundCookieResponsePacket)
register(0x02, ServerboundCustomPayloadPacket) register(0x02, ServerboundCustomPayloadPacket)
register(0x03, ServerboundAckFinishConfigurationPacket) register(0x03, ServerboundAckFinishConfigurationPacket)
register(0x04, ServerboundKeepAliveConfigurationPacket) register(0x04, ServerboundKeepAliveConfigurationPacket)
register(0x05, ServerboundPongConfigurationPacket) register(0x05, ServerboundPongConfigurationPacket)
register(0x07, ServerboundSelectKnownPacksPacket) register(0x07, ServerboundSelectKnownPacksPacket)
} register(0x08, ServerboundCustomClickActionPacket)
register(ProtocolState.LOGIN) { register(0x09, ServerboundAcceptCodeOfConductPacket)
register(0x00, ServerboundLoginStartPacket)
register(0x03, ServerboundLoginAcknowledgedPacket)
} }
register(ProtocolState.PLAY) { register(ProtocolState.PLAY) {
register(0x00, ServerboundAcceptTeleportationPacket) register(0x00, ServerboundAcceptTeleportationPacket)
@@ -110,7 +159,7 @@ internal object GameProtocols {
register(0x23, ServerboundPaddleBoatPacket) register(0x23, ServerboundPaddleBoatPacket)
register(0x24, ServerboundPickItemFromBlockPacket) register(0x24, ServerboundPickItemFromBlockPacket)
register(0x25, ServerboundPickItemFromEntityPacket) register(0x25, ServerboundPickItemFromEntityPacket)
register(0x26, ServerboundPingRequest) register(0x26, ServerboundPingRequestPacket)
register(0x27, ServerboundPlaceRecipePacket) register(0x27, ServerboundPlaceRecipePacket)
register(0x28, ServerboundPlayerAbilitiesPacket) register(0x28, ServerboundPlayerAbilitiesPacket)
register(0x29, ServerboundPlayerActionPacket) register(0x29, ServerboundPlayerActionPacket)
@@ -0,0 +1,43 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
package cn.rtast.libmc.protocol.protocol.game.registry
import cn.rtast.libmc.common.BytesBuffer
import cn.rtast.libmc.common.PacketCodec
import cn.rtast.libmc.nbt.NBTCompound
import cn.rtast.libmc.protocol.protocol.game.Identifier
import cn.rtast.libmc.protocol.protocol.game.readIdentifier
import cn.rtast.libmc.protocol.protocol.game.writeIdentifier
import cn.rtast.libmc.protocol.protocol.util.readNetworkNBTCompound
import cn.rtast.libmc.protocol.protocol.util.writeNetworkNBTCompound
public data class RegistryEntry(
/**
* Name of the entry, such as minecraft:overworld.
*/
val id: Identifier,
/**
* Entry data. If omitted, sourced from the selected known packs.
*/
val data: NBTCompound?,
) {
public companion object Codec : PacketCodec<RegistryEntry> {
override fun encode(buffer: BytesBuffer, value: RegistryEntry) {
buffer.writeIdentifier(value.id)
buffer.writeBoolean(value.data != null)
if (value.data != null) buffer.writeNetworkNBTCompound(value.data)
}
override fun decode(buffer: BytesBuffer): RegistryEntry {
val id = buffer.readIdentifier()
val hasData = buffer.readBoolean()
val data = if (hasData) buffer.readNetworkNBTCompound() else null
return RegistryEntry(id, data)
}
}
}
@@ -12,5 +12,10 @@ public enum class ProtocolState {
LOGIN, LOGIN,
CONFIGURATION, CONFIGURATION,
PLAY, PLAY,
DISCONNECTED STATUS,
/**
* reserved
*/
DISCONNECTED,
} }
@@ -0,0 +1,25 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
package cn.rtast.libmc.protocol.registry.report
public enum class BuiltinServerLinkType(public val id: Int) {
BUG_REPORT(0),
COMMUNITY_GUIDELINES(1),
SUPPORT(2),
STATUS(3),
FEEDBACK(4),
COMMUNITY(5),
WEBSITE(6),
FORUMS(7),
NEWS(8),
ANNOUNCEMENTS(9);
public companion object {
public fun fromID(id: Int): BuiltinServerLinkType = entries.first { it.id == id }
}
}
@@ -0,0 +1,45 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/6
*/
package cn.rtast.libmc.protocol.registry.report
import cn.rtast.libmc.common.*
import cn.rtast.libmc.nbt.NBTCompound
import cn.rtast.libmc.protocol.protocol.util.readNetworkNBTCompound
import cn.rtast.libmc.protocol.protocol.util.writeNetworkNBTCompound
public data class ServerLink(val label: ServerLinkLabel, val url: String) {
public companion object Codec : PacketCodec<ServerLink> {
override fun encode(buffer: BytesBuffer, value: ServerLink) {
when (value.label) {
is ServerLinkLabel.Builtin -> {
buffer.writeBoolean(true)
buffer.writeVarInt(value.label.type.id)
}
is ServerLinkLabel.Custom -> {
buffer.writeBoolean(false)
buffer.writeNetworkNBTCompound(value.label.text)
}
}
buffer.writeMcString(value.url)
}
override fun decode(buffer: BytesBuffer): ServerLink {
val isBuiltin = buffer.readBoolean()
val label = if (isBuiltin) ServerLinkLabel.Builtin(BuiltinServerLinkType.fromID(buffer.readVarInt()))
else ServerLinkLabel.Custom(buffer.readNetworkNBTCompound())
val url = buffer.readMcString()
return ServerLink(label, url)
}
}
}
public sealed interface ServerLinkLabel {
public data class Builtin(val type: BuiltinServerLinkType) : ServerLinkLabel
public data class Custom(val text: NBTCompound) : ServerLinkLabel
}