diff --git a/libmc-common/src/commonMain/kotlin/cn/rtast/libmc/common/buffer.kt b/libmc-common/src/commonMain/kotlin/cn/rtast/libmc/common/buffer.kt index 8acf66e..14dcc8e 100644 --- a/libmc-common/src/commonMain/kotlin/cn/rtast/libmc/common/buffer.kt +++ b/libmc-common/src/commonMain/kotlin/cn/rtast/libmc/common/buffer.kt @@ -73,6 +73,22 @@ public fun BytesBuffer.writePrefixedByteArray(data: ByteArray) { this.writeBytes(data) } +public fun BytesBuffer.readOptionalPrefixedByteArray(): ByteArray? { + val isPresent = this.readBoolean() + return if (isPresent) { + val length = this.readVarInt() + this.readBytes(length) + } else null +} + +public fun BytesBuffer.writeOptionalPrefixedByteArray(data: ByteArray?) { + if (data != null) { + this.writeBoolean(true) + this.writeVarInt(data.size) + this.writeBytes(data) + } else this.writeBoolean(false) +} + public fun BytesBuffer.readPrefixedVarIntArray(): List { val length = readVarInt() val list = ArrayList(length) diff --git a/libmc-common/src/commonMain/kotlin/cn/rtast/libmc/common/mc_primitives.kt b/libmc-common/src/commonMain/kotlin/cn/rtast/libmc/common/mc_primitives.kt index 8b80092..899dbc9 100644 --- a/libmc-common/src/commonMain/kotlin/cn/rtast/libmc/common/mc_primitives.kt +++ b/libmc-common/src/commonMain/kotlin/cn/rtast/libmc/common/mc_primitives.kt @@ -74,4 +74,25 @@ public object McStringCodec : PacketCodec { val bytes = buffer.readBytes(length) return bytes.decodeToString() } +} + +public sealed interface IdOrX { + public data class Inline(val value: T) : IdOrX + public data class Reference(val registryId: Int) : IdOrX +} + +public inline fun BytesBuffer.writeIdOrX(value: IdOrX, 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 BytesBuffer.readIdOrX(readX: BytesBuffer.() -> T): IdOrX { + val id = this.readVarInt() + return if (id == 0) IdOrX.Inline(this.readX()) else IdOrX.Reference(id - 1) } \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/client/MinecraftClient.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/client/MinecraftClient.kt index 4625383..e1b39ec 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/client/MinecraftClient.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/client/MinecraftClient.kt @@ -7,6 +7,7 @@ package cn.rtast.libmc.protocol.client 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.network.NetworkChannel import cn.rtast.libmc.protocol.packet.handshake.ServerboundHandshakePacket diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/client/InternalPacketDispatcher.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/event/InternalPacketDispatcher.kt similarity index 64% rename from libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/client/InternalPacketDispatcher.kt rename to libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/event/InternalPacketDispatcher.kt index 05676e5..6f6664d 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/client/InternalPacketDispatcher.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/event/InternalPacketDispatcher.kt @@ -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.protocol.packet.configuration.clientbound.ClientboundConfigurationPacket -import cn.rtast.libmc.protocol.packet.configuration.clientbound.ClientboundCookieRequestPacket -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.client.MinecraftClient +import cn.rtast.libmc.protocol.packet.configuration.clientbound.* 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.ServerboundPongConfigurationPacket 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.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.clientbound.* 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.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.clientbound.* 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.ServerboundPongPlayPacket @@ -69,6 +46,9 @@ internal class InternalPacketDispatcher(private val client: MinecraftClient) { client.networkChannel.sendPacket(ServerboundLoginAcknowledgedPacket) client.stateMachine.transitionTo(ProtocolState.CONFIGURATION) } + + is ClientboundCustomQueryPacket -> {} + is ClientboundHelloPacket -> {} } } @@ -102,6 +82,20 @@ internal class InternalPacketDispatcher(private val client: MinecraftClient) { is ClientboundSelectKnownPacksPacket -> { 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 ClientboundKeepAlivePlayPacket -> client.networkChannel.sendPacket(ServerboundKeepAlivePlayPacket(id = packet.id)) 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 -> { println("Received player chat message $packet") // TODO @@ -129,6 +123,7 @@ internal class InternalPacketDispatcher(private val client: MinecraftClient) { ClientboundDelimiterPacket -> {} is ClientboundEntityAnimationPacket -> {} is ClientboundSpawnEntityPacket -> {} + is ClientboundShowDialogPacket -> {} } } } \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundAddResourcePackPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundAddResourcePackPacket.kt new file mode 100644 index 0000000..568ead6 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundAddResourcePackPacket.kt @@ -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 { + 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) + } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundClearDialogPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundClearDialogPacket.kt new file mode 100644 index 0000000..4a56f51 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundClearDialogPacket.kt @@ -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 { + override fun encode(buffer: BytesBuffer, value: ClientboundClearDialogPacket) {} + override fun decode(buffer: BytesBuffer): ClientboundClearDialogPacket = ClientboundClearDialogPacket +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundCodeOfConductPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundCodeOfConductPacket.kt new file mode 100644 index 0000000..5b15f9e --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundCodeOfConductPacket.kt @@ -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 { + override fun encode(buffer: BytesBuffer, value: ClientboundCodeOfConductPacket) {} + override fun decode(buffer: BytesBuffer): ClientboundCodeOfConductPacket { + return ClientboundCodeOfConductPacket(buffer.readMcString()) + } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundConfigurationShowDialogPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundConfigurationShowDialogPacket.kt new file mode 100644 index 0000000..5696a43 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundConfigurationShowDialogPacket.kt @@ -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 { + override fun encode(buffer: BytesBuffer, value: ClientboundConfigurationShowDialogPacket) {} + override fun decode(buffer: BytesBuffer): ClientboundConfigurationShowDialogPacket { + return ClientboundConfigurationShowDialogPacket(buffer.readNetworkNBTCompound()) + } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundCookieRequestPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundCookieRequestPacket.kt index ab71ce5..9ff7f3e 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundCookieRequestPacket.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundCookieRequestPacket.kt @@ -11,14 +11,10 @@ import cn.rtast.libmc.common.BytesBuffer import cn.rtast.libmc.common.PacketCodec 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 ClientboundCookieRequestPacket(val key: Identifier) : ClientboundConfigurationPacket { public companion object Codec : PacketCodec { - override fun encode(buffer: BytesBuffer, value: ClientboundCookieRequestPacket) { - buffer.writeIdentifier(value.key) - } - + override fun encode(buffer: BytesBuffer, value: ClientboundCookieRequestPacket) {} override fun decode(buffer: BytesBuffer): ClientboundCookieRequestPacket { return ClientboundCookieRequestPacket(key = buffer.readIdentifier()) } diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundCustomPayloadPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundCustomPayloadPacket.kt index 9a49844..9454ba1 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundCustomPayloadPacket.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundCustomPayloadPacket.kt @@ -1,7 +1,7 @@ /* * Copyright © 2026 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.protocol.protocol.game.Identifier 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) : - ClientboundConfigurationPacket { +public data class ClientboundCustomPayloadPacket( + val channel: Identifier, + val data: ByteArray, +) : ClientboundConfigurationPacket { public companion object Codec : PacketCodec { - override fun encode(buffer: BytesBuffer, value: ClientboundCustomPayloadPacket) { - buffer.writeIdentifier(value.channel) - buffer.writeBytes(value.data) - } - + override fun encode(buffer: BytesBuffer, value: ClientboundCustomPayloadPacket) {} override fun decode(buffer: BytesBuffer): ClientboundCustomPayloadPacket { val channel = buffer.readIdentifier() - val data = buffer.readBytes(buffer.remaining.toInt()) + val data = buffer.readRemainingBytes() return ClientboundCustomPayloadPacket(channel, data) } } diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundCustomReportDetailsPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundCustomReportDetailsPacket.kt new file mode 100644 index 0000000..a8b128b --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundCustomReportDetailsPacket.kt @@ -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) : + ClientboundConfigurationPacket { + @Serializable + public data class ReportDetail(val title: String, val description: String) { + public companion object Codec : PacketCodec { + 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 { + override fun encode(buffer: BytesBuffer, value: ClientboundCustomReportDetailsPacket) {} + override fun decode(buffer: BytesBuffer): ClientboundCustomReportDetailsPacket { + val detailCount = buffer.readVarInt() + val details = ArrayList(detailCount) + repeat(detailCount) { details.add(ReportDetail.decode(buffer)) } + return ClientboundCustomReportDetailsPacket(details) + } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundKeepAliveConfigurationPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundKeepAliveConfigurationPacket.kt index 1a7a85b..e98fd2c 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundKeepAliveConfigurationPacket.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundKeepAliveConfigurationPacket.kt @@ -12,10 +12,7 @@ import cn.rtast.libmc.common.PacketCodec public data class ClientboundKeepAliveConfigurationPacket(val id: Long) : ClientboundConfigurationPacket { public companion object Codec : PacketCodec { - override fun encode(buffer: BytesBuffer, value: ClientboundKeepAliveConfigurationPacket) { - buffer.writeLong(value.id) - } - + override fun encode(buffer: BytesBuffer, value: ClientboundKeepAliveConfigurationPacket) {} override fun decode(buffer: BytesBuffer): ClientboundKeepAliveConfigurationPacket { return ClientboundKeepAliveConfigurationPacket(buffer.readLong()) } diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundPingConfigurationPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundPingConfigurationPacket.kt index 7d075e6..0acf98f 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundPingConfigurationPacket.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundPingConfigurationPacket.kt @@ -1,7 +1,7 @@ /* * Copyright © 2026 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 companion object Codec : PacketCodec { - override fun encode(buffer: BytesBuffer, value: ClientboundPingConfigurationPacket) { - buffer.writeInt(value.id) + override fun encode(buffer: BytesBuffer, value: ClientboundPingConfigurationPacket) {} + override fun decode(buffer: BytesBuffer): ClientboundPingConfigurationPacket { + return ClientboundPingConfigurationPacket(id = buffer.readInt()) } - - override fun decode(buffer: BytesBuffer): ClientboundPingConfigurationPacket = ClientboundPingConfigurationPacket(buffer.readInt()) } } \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundRegistryDataPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundRegistryDataPacket.kt new file mode 100644 index 0000000..aa3f4ea --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundRegistryDataPacket.kt @@ -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, +) : ClientboundConfigurationPacket { + public companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ClientboundRegistryDataPacket) {} + override fun decode(buffer: BytesBuffer): ClientboundRegistryDataPacket { + val id = buffer.readIdentifier() + val entryCount = buffer.readVarInt() + val entries = ArrayList(entryCount) + (0 until entryCount).forEach { _ -> entries.add(RegistryEntry.decode(buffer)) } + return ClientboundRegistryDataPacket(id, entries) + } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundRemoveResourcePackPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundRemoveResourcePackPacket.kt new file mode 100644 index 0000000..201308d --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundRemoveResourcePackPacket.kt @@ -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 { + override fun encode(buffer: BytesBuffer, value: ClientboundRemoveResourcePackPacket) {} + override fun decode(buffer: BytesBuffer): ClientboundRemoveResourcePackPacket { + val uuid = buffer.readUuid() + return ClientboundRemoveResourcePackPacket(uuid) + } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundResetChatPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundResetChatPacket.kt new file mode 100644 index 0000000..f0e2e4a --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundResetChatPacket.kt @@ -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 { + override fun encode(buffer: BytesBuffer, value: ClientboundResetChatPacket) {} + override fun decode(buffer: BytesBuffer): ClientboundResetChatPacket = ClientboundResetChatPacket +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundSelectKnownPacksPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundSelectKnownPacksPacket.kt index 6f8caef..59a682a 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundSelectKnownPacksPacket.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundSelectKnownPacksPacket.kt @@ -10,16 +10,11 @@ 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.packet.configuration.KnownPacks public data class ClientboundSelectKnownPacksPacket(val knownPacks: List) : ClientboundConfigurationPacket { public companion object Codec : PacketCodec { - override fun encode(buffer: BytesBuffer, value: ClientboundSelectKnownPacksPacket) { - buffer.writeVarInt(value.knownPacks.size) - value.knownPacks.forEach { KnownPacks.encode(buffer, it) } - } - + override fun encode(buffer: BytesBuffer, value: ClientboundSelectKnownPacksPacket) {} override fun decode(buffer: BytesBuffer): ClientboundSelectKnownPacksPacket { val packsCount = buffer.readVarInt() val packs = List(packsCount) { KnownPacks.decode(buffer) } diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundServerLinksPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundServerLinksPacket.kt new file mode 100644 index 0000000..bad6dcd --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundServerLinksPacket.kt @@ -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) : ClientboundConfigurationPacket { + public companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ClientboundServerLinksPacket) {} + override fun decode(buffer: BytesBuffer): ClientboundServerLinksPacket { + val count = buffer.readVarInt() + val links = ArrayList(count) + repeat(count) { links.add(ServerLink.decode(buffer)) } + return ClientboundServerLinksPacket(links) + } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundStoreCookiePacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundStoreCookiePacket.kt new file mode 100644 index 0000000..c8ca865 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundStoreCookiePacket.kt @@ -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 { + 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 + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundTransferPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundTransferPacket.kt new file mode 100644 index 0000000..2bd8015 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundTransferPacket.kt @@ -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 { + 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) + } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundUpdateEnabledFeaturesPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundUpdateEnabledFeaturesPacket.kt new file mode 100644 index 0000000..cc48207 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundUpdateEnabledFeaturesPacket.kt @@ -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) : + ClientboundConfigurationPacket { + public companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ClientboundUpdateEnabledFeaturesPacket) {} + override fun decode(buffer: BytesBuffer): ClientboundUpdateEnabledFeaturesPacket { + val featureCount = buffer.readVarInt() + val features = ArrayList(featureCount) + repeat(featureCount) { features.add(buffer.readIdentifier()) } + return ClientboundUpdateEnabledFeaturesPacket(features) + } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundUpdateTagsPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundUpdateTagsPacket.kt new file mode 100644 index 0000000..e4b95e4 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/clientbound/ClientboundUpdateTagsPacket.kt @@ -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) : ClientboundConfigurationPacket { + @Serializable + public data class TaggedRegistry(val registryId: Identifier, val tags: List) { + public companion object Codec : PacketCodec { + 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(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 { + 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(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 { + override fun encode(buffer: BytesBuffer, value: ClientboundUpdateTagsPacket) {} + override fun decode(buffer: BytesBuffer): ClientboundUpdateTagsPacket { + val registryCount = buffer.readVarInt() + val registries = ArrayList(registryCount) + repeat(registryCount) { registries.add(TaggedRegistry.decode(buffer)) } + return ClientboundUpdateTagsPacket(registries) + } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/serverbound/ServerboundAcceptCodeOfConductPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/serverbound/ServerboundAcceptCodeOfConductPacket.kt new file mode 100644 index 0000000..b9ed74d --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/serverbound/ServerboundAcceptCodeOfConductPacket.kt @@ -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 { + override fun encode(buffer: BytesBuffer, value: ServerboundAcceptCodeOfConductPacket) {} + override fun decode(buffer: BytesBuffer): ServerboundAcceptCodeOfConductPacket = + ServerboundAcceptCodeOfConductPacket +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/serverbound/ServerboundAckFinishConfigurationPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/serverbound/ServerboundAckFinishConfigurationPacket.kt index b7494f9..72bc0df 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/serverbound/ServerboundAckFinishConfigurationPacket.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/serverbound/ServerboundAckFinishConfigurationPacket.kt @@ -14,7 +14,6 @@ import cn.rtast.libmc.common.packet.MinecraftPacket public data object ServerboundAckFinishConfigurationPacket : MinecraftPacket, PacketCodec { override fun encode(buffer: BytesBuffer, value: ServerboundAckFinishConfigurationPacket) {} - override fun decode(buffer: BytesBuffer): ServerboundAckFinishConfigurationPacket = - ServerboundAckFinishConfigurationPacket + throw UnsupportedOperationException() } \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/serverbound/ServerboundKeepAliveConfigurationPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/serverbound/ServerboundKeepAliveConfigurationPacket.kt index 5c9ed68..0db9c94 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/serverbound/ServerboundKeepAliveConfigurationPacket.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/serverbound/ServerboundKeepAliveConfigurationPacket.kt @@ -17,8 +17,7 @@ public data class ServerboundKeepAliveConfigurationPacket(val id: Long) : Minecr buffer.writeLong(value.id) } - override fun decode(buffer: BytesBuffer): ServerboundKeepAliveConfigurationPacket { - return ServerboundKeepAliveConfigurationPacket(buffer.readLong()) - } + override fun decode(buffer: BytesBuffer): ServerboundKeepAliveConfigurationPacket = + throw UnsupportedOperationException() } } \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/serverbound/ServerboundPongConfigurationPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/serverbound/ServerboundPongConfigurationPacket.kt index b925521..98c9eef 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/serverbound/ServerboundPongConfigurationPacket.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/serverbound/ServerboundPongConfigurationPacket.kt @@ -17,6 +17,7 @@ public data class ServerboundPongConfigurationPacket(val id: Int) : MinecraftPac buffer.writeInt(value.id) } - override fun decode(buffer: BytesBuffer): ServerboundPongConfigurationPacket = ServerboundPongConfigurationPacket(buffer.readInt()) + override fun decode(buffer: BytesBuffer): ServerboundPongConfigurationPacket = + throw UnsupportedOperationException() } } \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/serverbound/ServerboundSelectKnownPacksPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/serverbound/ServerboundSelectKnownPacksPacket.kt index 172cd11..f88d32f 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/serverbound/ServerboundSelectKnownPacksPacket.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/configuration/serverbound/ServerboundSelectKnownPacksPacket.kt @@ -7,10 +7,9 @@ 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.PacketCodec import cn.rtast.libmc.common.packet.MinecraftPacket -import cn.rtast.libmc.common.readVarInt import cn.rtast.libmc.common.writeVarInt import cn.rtast.libmc.protocol.packet.configuration.KnownPacks @@ -21,10 +20,7 @@ public data class ServerboundSelectKnownPacksPacket(val knownPacks: List { + 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 + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/login/clientbound/ClientboundHelloPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/login/clientbound/ClientboundHelloPacket.kt new file mode 100644 index 0000000..e24dfee --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/login/clientbound/ClientboundHelloPacket.kt @@ -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 { + 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 + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/login/serverbound/ServerboundCustomQueryAnswerPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/login/serverbound/ServerboundCustomQueryAnswerPacket.kt new file mode 100644 index 0000000..a4ea2e4 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/login/serverbound/ServerboundCustomQueryAnswerPacket.kt @@ -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 { + 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 + } + +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/login/serverbound/ServerboundKeyPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/login/serverbound/ServerboundKeyPacket.kt new file mode 100644 index 0000000..76ea1bb --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/login/serverbound/ServerboundKeyPacket.kt @@ -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 { + 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 + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundPingPlayPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundPingPacket.kt similarity index 63% rename from libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundPingPlayPacket.kt rename to libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundPingPacket.kt index a37d112..e9b31e8 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundPingPlayPacket.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundPingPacket.kt @@ -10,14 +10,11 @@ package cn.rtast.libmc.protocol.packet.play.clientbound import cn.rtast.libmc.common.BytesBuffer import cn.rtast.libmc.common.PacketCodec -public data class ClientboundPingPlayPacket(val id: Int) : ClientboundPlayPacket { - public companion object Codec : PacketCodec { - override fun encode(buffer: BytesBuffer, value: ClientboundPingPlayPacket) { - buffer.writeInt(value.id) - } - - override fun decode(buffer: BytesBuffer): ClientboundPingPlayPacket { - return ClientboundPingPlayPacket(id = buffer.readInt()) +public data class ClientboundPingPacket(val id: Int) : ClientboundPlayPacket { + public companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ClientboundPingPacket) {} + override fun decode(buffer: BytesBuffer): ClientboundPingPacket { + return ClientboundPingPacket(id = buffer.readInt()) } } } \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundShowDialogPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundShowDialogPacket.kt new file mode 100644 index 0000000..79bb094 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundShowDialogPacket.kt @@ -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) : ClientboundPlayPacket { + public companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ClientboundShowDialogPacket) {} + override fun decode(buffer: BytesBuffer): ClientboundShowDialogPacket { + return ClientboundShowDialogPacket(buffer.readIdOrX { this.readNetworkNBTCompound() }) + } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/status/clientbound/ClientboundPongResponsePacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/status/clientbound/ClientboundPongResponsePacket.kt new file mode 100644 index 0000000..388c73c --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/status/clientbound/ClientboundPongResponsePacket.kt @@ -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 { + override fun encode(buffer: BytesBuffer, value: ClientboundPongResponsePacket) {} + override fun decode(buffer: BytesBuffer): ClientboundPongResponsePacket { + return ClientboundPongResponsePacket(buffer.readLong()) + } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/status/clientbound/ClientboundStatusPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/status/clientbound/ClientboundStatusPacket.kt new file mode 100644 index 0000000..1d732f6 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/status/clientbound/ClientboundStatusPacket.kt @@ -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 \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/status/clientbound/ClientboundStatusResponsePacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/status/clientbound/ClientboundStatusResponsePacket.kt new file mode 100644 index 0000000..dc1dec6 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/status/clientbound/ClientboundStatusResponsePacket.kt @@ -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 { + override fun encode(buffer: BytesBuffer, value: ClientboundStatusResponsePacket) {} + override fun decode(buffer: BytesBuffer): ClientboundStatusResponsePacket = + ClientboundStatusResponsePacket(buffer.readMcString()) + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/status/serverbound/ServerboundPingRequest.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/status/serverbound/ServerboundPingRequestPacket.kt similarity index 79% rename from libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/status/serverbound/ServerboundPingRequest.kt rename to libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/status/serverbound/ServerboundPingRequestPacket.kt index 440ddc3..76cb90d 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/status/serverbound/ServerboundPingRequest.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/status/serverbound/ServerboundPingRequestPacket.kt @@ -11,13 +11,13 @@ import cn.rtast.libmc.common.BytesBuffer import cn.rtast.libmc.common.PacketCodec import cn.rtast.libmc.common.packet.MinecraftPacket -public data class ServerboundPingRequest(val timestamp: Long) : MinecraftPacket { - public companion object Codec : PacketCodec { - override fun encode(buffer: BytesBuffer, value: ServerboundPingRequest) { +public data class ServerboundPingRequestPacket(val timestamp: Long) : MinecraftPacket { + public companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ServerboundPingRequestPacket) { buffer.writeLong(value.timestamp) } - override fun decode(buffer: BytesBuffer): ServerboundPingRequest = + override fun decode(buffer: BytesBuffer): ServerboundPingRequestPacket = throw UnsupportedOperationException() } } \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/status/serverbound/ServerboundStatusRequestPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/status/serverbound/ServerboundStatusRequestPacket.kt new file mode 100644 index 0000000..c05b5b2 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/status/serverbound/ServerboundStatusRequestPacket.kt @@ -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 { + override fun encode(buffer: BytesBuffer, value: ServerboundStatusRequestPacket) {} + override fun decode(buffer: BytesBuffer): ServerboundStatusRequestPacket = + throw UnsupportedOperationException() +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/GameProtocols.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/GameProtocols.kt index c83f161..03a682c 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/GameProtocols.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/GameProtocols.kt @@ -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.serverbound.* 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.ClientboundLoginSuccessPacket -import cn.rtast.libmc.protocol.packet.login.clientbound.ClientboundSetCompressionPacket +import cn.rtast.libmc.protocol.packet.login.clientbound.* +import cn.rtast.libmc.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket +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.ServerboundLoginStartPacket import cn.rtast.libmc.protocol.packet.play.clientbound.* 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.ProtocolStateRegistry internal object GameProtocols { 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(0x00, ClientboundCookieRequestPacket) register(0x01, ClientboundCustomPayloadPacket) @@ -29,12 +44,20 @@ internal object GameProtocols { register(0x03, ClientboundFinishConfigurationPacket) register(0x04, ClientboundKeepAliveConfigurationPacket) 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(ProtocolState.LOGIN) { - register(0x00, ClientboundDisconnectLoginPacket) - register(0x02, ClientboundLoginSuccessPacket) - register(0x03, ClientboundSetCompressionPacket) + register(0x0f, ClientboundCustomReportDetailsPacket) + register(0x10, ClientboundServerLinksPacket) + register(0x11, ClientboundClearDialogPacket) + register(0x12, ClientboundConfigurationShowDialogPacket) + register(0x13, ClientboundCodeOfConductPacket) } register(ProtocolState.PLAY) { register(0x00, ClientboundDelimiterPacket) @@ -45,13 +68,29 @@ internal object GameProtocols { register(0x05, ClientboundBlockDestructionPacket) register(0x06, ClientboundBlockEntityDataPacket) + register(0x15, ClientboundCookieRequestPacket) + register(0x20, ClientboundDisconnectPlayPacket) + register(0x24, ClientboundCustomPayloadPacket) register(0x2c, ClientboundKeepAlivePlayPacket) register(0x31, ClientboundLoginPlayPacket) - register(0x3d, ClientboundPingPlayPacket) + register(0x3d, ClientboundPingPacket) register(0x41, ClientboundPlayerChatMessagePacket) + register(0x50, ClientboundRemoveResourcePackPacket) + register(0x51, ClientboundAddResourcePackPacket) register(0x76, ClientboundStartConfigurationPacket) + register(0x78, ClientboundStoreCookiePacket) 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(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(0x00, ServerboundCookieResponsePacket) + register(0x01, ServerboundCookieResponsePacket) register(0x02, ServerboundCustomPayloadPacket) register(0x03, ServerboundAckFinishConfigurationPacket) register(0x04, ServerboundKeepAliveConfigurationPacket) register(0x05, ServerboundPongConfigurationPacket) register(0x07, ServerboundSelectKnownPacksPacket) - } - register(ProtocolState.LOGIN) { - register(0x00, ServerboundLoginStartPacket) - register(0x03, ServerboundLoginAcknowledgedPacket) + register(0x08, ServerboundCustomClickActionPacket) + register(0x09, ServerboundAcceptCodeOfConductPacket) } register(ProtocolState.PLAY) { register(0x00, ServerboundAcceptTeleportationPacket) @@ -110,7 +159,7 @@ internal object GameProtocols { register(0x23, ServerboundPaddleBoatPacket) register(0x24, ServerboundPickItemFromBlockPacket) register(0x25, ServerboundPickItemFromEntityPacket) - register(0x26, ServerboundPingRequest) + register(0x26, ServerboundPingRequestPacket) register(0x27, ServerboundPlaceRecipePacket) register(0x28, ServerboundPlayerAbilitiesPacket) register(0x29, ServerboundPlayerActionPacket) diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/registry/RegistryEntry.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/registry/RegistryEntry.kt new file mode 100644 index 0000000..1a9ff1f --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/registry/RegistryEntry.kt @@ -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 { + 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) + } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/state/ProtocolState.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/state/ProtocolState.kt index f1e59fe..4296301 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/state/ProtocolState.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/state/ProtocolState.kt @@ -12,5 +12,10 @@ public enum class ProtocolState { LOGIN, CONFIGURATION, PLAY, - DISCONNECTED + STATUS, + + /** + * reserved + */ + DISCONNECTED, } \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/registry/report/BuiltinServerLinkType.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/registry/report/BuiltinServerLinkType.kt new file mode 100644 index 0000000..0a7395b --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/registry/report/BuiltinServerLinkType.kt @@ -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 } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/registry/report/ServerLink.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/registry/report/ServerLink.kt new file mode 100644 index 0000000..b18af1a --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/registry/report/ServerLink.kt @@ -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 { + 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 +} \ No newline at end of file