From 59189d2fad470fe98bbfd267ee436085a0fe0fc0 Mon Sep 17 00:00:00 2001 From: RTAkland Date: Fri, 11 Sep 2026 01:19:59 +0800 Subject: [PATCH] Implemented 0x12-ClientboundContainerSetContentPacket, 0x14-ClientboundContainerSetSlotPacket, implemented slot data codec --- .../cn/rtast/libmc/primitives/Optional.kt | 17 +- .../cn/rtast/libmc/primitives/Prefixed.kt | 5 +- .../kotlin/cn/rtast/libmc/nbt/NBTReader.kt | 1 + .../protocol/client/ClientStateMachine.kt | 16 +- .../libmc/protocol/client/MinecraftClient.kt | 5 +- .../libmc/protocol/network/NetworkChannel.kt | 4 +- .../ClientboundContainerSetContentPacket.kt | 34 + .../ClientboundContainerSetSlotPacket.kt | 33 + .../ClientboundDeleteChatPacket.kt | 5 +- .../ClientboundDisguisedChatMessagePacket.kt | 6 +- .../ClientboundMapItemDataPacket.kt | 11 +- .../ClientboundPlayerInfoUpdatePacket.kt | 2 +- .../ClientboundResetScorePacket.kt | 7 +- .../clientbound/ClientboundRespawnPacket.kt | 6 +- .../ClientboundSelectAdvancementsTabPacket.kt | 6 +- .../ClientboundServerDataPacket.kt | 6 +- ...lientboundTestInstanceBlockStatusPacket.kt | 8 +- .../ClientboundUpdateScorePacket.kt | 8 +- .../clientbound/ClientboundWaypointPacket.kt | 2 +- .../protocol/game/block/BlockStateProperty.kt | 10 + .../protocol/protocol/game/color/DyeColor.kt | 31 + .../game/data/component/DataComponent.kt | 1673 +++++++++++++++++ .../attributes/AttributeModifierEntry.kt | 18 + .../attributes/AttributeOperation.kt | 17 + .../component/attributes/AttributeSlot.kt | 24 + .../component/attributes/BannerPattern.kt | 41 + .../data/component/attributes/BeeAttribute.kt | 17 + .../component/attributes/BlockPredicate.kt | 137 ++ .../component/attributes/DamageReduction.kt | 17 + .../component/attributes/EnchantmentEntry.kt | 10 + .../component/attributes/EquipmentSlot.kt | 22 + .../attributes/FireworkExplosionAttribute.kt | 47 + .../attributes/InstrumentAttribute.kt | 19 + .../data/component/attributes/ItemRarity.kt | 19 + .../data/component/attributes/JukeboxSong.kt | 19 + .../attributes/KineticWeaponCondition.kt | 31 + .../attributes/MapPostProcessingType.kt | 16 + .../component/attributes/StoredEnchantment.kt | 10 + .../attributes/SwingAnimationType.kt | 16 + .../data/component/attributes/ToolRule.kt | 16 + .../data/component/attributes/TrimMaterial.kt | 16 + .../attributes/TrimMaterialOverride.kt | 12 + .../data/component/attributes/TrimPattern.kt | 17 + .../data/component/attributes/WritablePage.kt | 10 + .../data/component/attributes/WrittenPage.kt | 12 + .../game/entity/AxolotlVariantType.kt | 16 + .../protocol/game/entity/FoxVariantType.kt | 16 + .../protocol/game/entity/HorseVariantType.kt | 16 + .../protocol/game/entity/LlamaVariantType.kt | 16 + .../game/entity/MooshroomVariantType.kt | 16 + .../protocol/game/entity/ParrotVariantType.kt | 16 + .../protocol/game/entity/RabbitVariantType.kt | 17 + .../protocol/game/entity/SalmonSizeType.kt | 16 + .../game/entity/TropicalFishPatternType.kt | 27 + .../protocol/game/item/ItemUseAnimation.kt | 25 + .../protocol/game/item/PaintingVariantType.kt | 43 + .../protocol/game/item/slot/HashedSlot.kt | 9 + .../protocol/protocol/game/item/slot/Slot.kt | 59 + .../game/player/skin/TextureModelType.kt | 16 + .../protocol/game/potion/ConsumeEffect.kt | 90 + .../protocol/game/potion/PotionEffect.kt | 45 + .../game/potion/SuspiciousStewEffect.kt | 28 + .../game/session/ResolvableProfile.kt | 69 + .../protocol/game/sound/SoundEvent.kt | 2 +- .../protocol/protocol/game/world/GlobalPos.kt | 13 + .../protocol/protocol/session/SessionEvent.kt | 8 + .../registry/DataComponentRegistry.kt | 171 ++ .../GamePacketsProtocolRegistry.kt} | 8 +- .../commonTest/kotlin/client/TestClient.kt | 12 +- 69 files changed, 3146 insertions(+), 67 deletions(-) create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundContainerSetContentPacket.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundContainerSetSlotPacket.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/block/BlockStateProperty.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/color/DyeColor.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/DataComponent.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/AttributeModifierEntry.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/AttributeOperation.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/AttributeSlot.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/BannerPattern.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/BeeAttribute.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/BlockPredicate.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/DamageReduction.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/EnchantmentEntry.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/EquipmentSlot.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/FireworkExplosionAttribute.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/InstrumentAttribute.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/ItemRarity.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/JukeboxSong.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/KineticWeaponCondition.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/MapPostProcessingType.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/StoredEnchantment.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/SwingAnimationType.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/ToolRule.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/TrimMaterial.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/TrimMaterialOverride.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/TrimPattern.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/WritablePage.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/WrittenPage.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/AxolotlVariantType.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/FoxVariantType.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/HorseVariantType.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/LlamaVariantType.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/MooshroomVariantType.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/ParrotVariantType.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/RabbitVariantType.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/SalmonSizeType.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/TropicalFishPatternType.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/item/ItemUseAnimation.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/item/PaintingVariantType.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/item/slot/HashedSlot.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/item/slot/Slot.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/player/skin/TextureModelType.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/potion/ConsumeEffect.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/potion/PotionEffect.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/potion/SuspiciousStewEffect.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/session/ResolvableProfile.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/world/GlobalPos.kt create mode 100644 libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/registry/DataComponentRegistry.kt rename libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/{protocol/GamePacketsProtocolCodec.kt => registry/GamePacketsProtocolRegistry.kt} (98%) diff --git a/libmc-common/src/commonMain/kotlin/cn/rtast/libmc/primitives/Optional.kt b/libmc-common/src/commonMain/kotlin/cn/rtast/libmc/primitives/Optional.kt index a3e309c..7742778 100644 --- a/libmc-common/src/commonMain/kotlin/cn/rtast/libmc/primitives/Optional.kt +++ b/libmc-common/src/commonMain/kotlin/cn/rtast/libmc/primitives/Optional.kt @@ -9,17 +9,8 @@ package cn.rtast.libmc.primitives import cn.rtast.libmc.network.BytesBuffer -public inline fun BytesBuffer.readOptional(block: BytesBuffer.() -> T): T? { - val hasData = this.readBoolean() - return if (hasData) block.invoke(this) else null -} +public inline fun BytesBuffer.readOptional(condition: Boolean, block: BytesBuffer.() -> T): T? = + if (condition) block() else null -/** - * buffer.writeOptional(value.someValue) { writeBlockPos(it) } - */ -public inline fun BytesBuffer.writeOptional(value: T?, block: BytesBuffer.(T) -> Unit) { - if (value != null) { - this.writeBoolean(true) - block.invoke(this, value) - } else this.writeBoolean(false) -} \ No newline at end of file +public inline fun BytesBuffer.writeOptional(value: T?, block: BytesBuffer.(T) -> Unit): Unit = + if (value != null) block.invoke(this, value) else Unit diff --git a/libmc-common/src/commonMain/kotlin/cn/rtast/libmc/primitives/Prefixed.kt b/libmc-common/src/commonMain/kotlin/cn/rtast/libmc/primitives/Prefixed.kt index f7a96f7..dd71e07 100644 --- a/libmc-common/src/commonMain/kotlin/cn/rtast/libmc/primitives/Prefixed.kt +++ b/libmc-common/src/commonMain/kotlin/cn/rtast/libmc/primitives/Prefixed.kt @@ -44,10 +44,7 @@ public fun BytesBuffer.writePrefixedStringArray(value: List) { public inline fun BytesBuffer.readPrefixed(reader: BytesBuffer.() -> T): List { val count = this.readVarInt() - require(count in 0..4096) { - "Prefixed array count $count is invalid (expected 0..4096). " + - "Stream offset is corrupted. Check Heightmaps/NBT encoding." - } + require(count in 0..4096) val list = ArrayList(count) repeat(count) { _ -> list.add(this.reader()) } return list diff --git a/libmc-nbt/src/commonMain/kotlin/cn/rtast/libmc/nbt/NBTReader.kt b/libmc-nbt/src/commonMain/kotlin/cn/rtast/libmc/nbt/NBTReader.kt index 1923dfc..f116d59 100644 --- a/libmc-nbt/src/commonMain/kotlin/cn/rtast/libmc/nbt/NBTReader.kt +++ b/libmc-nbt/src/commonMain/kotlin/cn/rtast/libmc/nbt/NBTReader.kt @@ -80,6 +80,7 @@ public fun NBTInput.readNetworkCompound(): NBTCompound { return when (val type = NBTType.fromID(readByte().toInt() and 0xFF)) { NBTType.Compound -> NBTCompound("", readCompoundTag()) NBTType.String -> NBTCompound("", NBTTag.CompoundTag(linkedMapOf("text" to NBTTag.StringTag(readStringTag())))) + NBTType.End -> NBTCompound("", NBTTag.CompoundTag(linkedMapOf())) else -> throw UnsupportedOperationException("Unsupported network nbt tag 0x${type.id.toString(16).uppercase()}") } } \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/client/ClientStateMachine.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/client/ClientStateMachine.kt index de9ab95..b02aeb1 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/client/ClientStateMachine.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/client/ClientStateMachine.kt @@ -7,16 +7,28 @@ package cn.rtast.libmc.protocol.client +import cn.rtast.libmc.protocol.protocol.session.Session +import cn.rtast.libmc.protocol.protocol.session.SessionEvent import cn.rtast.libmc.protocol.protocol.state.ProtocolState import kotlin.concurrent.Volatile -internal class ClientStateMachine { +internal class ClientStateMachine(private val session: Session) { @Volatile var currentState: ProtocolState = ProtocolState.HANDSHAKE private set - fun transitionTo(newState: ProtocolState) { + suspend fun transitionTo(newState: ProtocolState) { println("Changing State $currentState to $newState") currentState = newState + session.emitEvent( + when (newState) { + ProtocolState.HANDSHAKE -> SessionEvent.ChangedState.HANDSHAKE + ProtocolState.LOGIN -> SessionEvent.ChangedState.LOGIN + ProtocolState.CONFIGURATION -> SessionEvent.ChangedState.CONFIGURATION + ProtocolState.PLAY -> SessionEvent.ChangedState.PLAY + ProtocolState.STATUS -> SessionEvent.ChangedState.STATUS + ProtocolState.DISCONNECTED -> SessionEvent.ChangedState.DISCONNECTED + } + ) } } \ 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 7581955..465e833 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 @@ -30,7 +30,7 @@ public class MinecraftClient internal constructor( internal val protocolContext: ProtocolContext, public val session: SessionImpl = SessionImpl(), ) : PacketEventDispatcher(), CoroutineScope, Session by session { - internal val stateMachine = ClientStateMachine() + internal val stateMachine = ClientStateMachine(session) public val networkChannel: NetworkChannel = NetworkChannel(this) private val clientJob = SupervisorJob(parentJob) private var listenJob: Job? = null @@ -52,8 +52,9 @@ public class MinecraftClient internal constructor( try { while (isActive) networkChannel.readNextPacket() } catch (e: Throwable) { - if (e is CancellationException) return@launch + e.printStackTrace() println("Network read loop exception: ${e.message}") + if (e is CancellationException) return@launch } finally { networkChannel.close() } diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/network/NetworkChannel.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/network/NetworkChannel.kt index c19b6f3..0f54428 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/network/NetworkChannel.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/network/NetworkChannel.kt @@ -14,8 +14,8 @@ import cn.rtast.libmc.primitives.readVarInt import cn.rtast.libmc.primitives.writeVarInt import cn.rtast.libmc.protocol.client.MinecraftClient import cn.rtast.libmc.protocol.protocol.event.PacketEventDispatcher -import cn.rtast.libmc.protocol.protocol.GamePacketsProtocolCodec.clientboundGameProtocols -import cn.rtast.libmc.protocol.protocol.GamePacketsProtocolCodec.serverboundGameProtocols +import cn.rtast.libmc.protocol.registry.GamePacketsProtocolRegistry.clientboundGameProtocols +import cn.rtast.libmc.protocol.registry.GamePacketsProtocolRegistry.serverboundGameProtocols import cn.rtast.libmc.zlibCompress import cn.rtast.libmc.zlibDecompress import kotlin.concurrent.Volatile diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundContainerSetContentPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundContainerSetContentPacket.kt new file mode 100644 index 0000000..9ed66e3 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundContainerSetContentPacket.kt @@ -0,0 +1,34 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.packet.play.clientbound + +import cn.rtast.libmc.network.BytesBuffer +import cn.rtast.libmc.packet.MinecraftPacket +import cn.rtast.libmc.packet.PacketCodec +import cn.rtast.libmc.primitives.readPrefixed +import cn.rtast.libmc.primitives.readVarInt +import cn.rtast.libmc.protocol.protocol.game.item.slot.Slot +import cn.rtast.libmc.protocol.protocol.game.item.slot.readSlot + +public data class ClientboundContainerSetContentPacket( + val windowId: Int, + val stateId: Int, + val slotData: List, + val carriedItem: Slot?, +) : MinecraftPacket { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ClientboundContainerSetContentPacket) {} + override fun decode(buffer: BytesBuffer): ClientboundContainerSetContentPacket { + val windowId = buffer.readVarInt() + val stateId = buffer.readVarInt() + val slotData = buffer.readPrefixed { readSlot() } +// val carriedItem = buffer.readSlot() // TODO FIX ME + return ClientboundContainerSetContentPacket(windowId, stateId, slotData, null) + } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundContainerSetSlotPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundContainerSetSlotPacket.kt new file mode 100644 index 0000000..66bd160 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundContainerSetSlotPacket.kt @@ -0,0 +1,33 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/11 + */ + + +package cn.rtast.libmc.protocol.packet.play.clientbound + +import cn.rtast.libmc.network.BytesBuffer +import cn.rtast.libmc.packet.MinecraftPacket +import cn.rtast.libmc.packet.PacketCodec +import cn.rtast.libmc.primitives.readVarInt +import cn.rtast.libmc.protocol.protocol.game.item.slot.Slot +import cn.rtast.libmc.protocol.protocol.game.item.slot.readSlot + +public data class ClientboundContainerSetSlotPacket( + val windowId: Int, + val stateId: Int, + val slot: Short, + val slotData: Slot, +) : MinecraftPacket { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ClientboundContainerSetSlotPacket) {} + override fun decode(buffer: BytesBuffer): ClientboundContainerSetSlotPacket { + val windowId = buffer.readVarInt() + val stateId = buffer.readVarInt() + val slot = buffer.readShort() + val slotData = buffer.readSlot() + return ClientboundContainerSetSlotPacket(windowId, stateId, slot, slotData) + } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundDeleteChatPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundDeleteChatPacket.kt index 886b294..573458a 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundDeleteChatPacket.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundDeleteChatPacket.kt @@ -18,7 +18,7 @@ public data class ClientboundDeleteChatPacket(val messageId: Int, val signature: override fun encode(buffer: BytesBuffer, value: ClientboundDeleteChatPacket) {} override fun decode(buffer: BytesBuffer): ClientboundDeleteChatPacket { val messageId = buffer.readVarInt() - val signature = buffer.readOptional { buffer.readBytes(256) } + val signature = buffer.readOptional(messageId == 0) { buffer.readBytes(256) } return ClientboundDeleteChatPacket(messageId, signature) } } @@ -26,12 +26,9 @@ public data class ClientboundDeleteChatPacket(val messageId: Int, val signature: override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false - other as ClientboundDeleteChatPacket - if (messageId != other.messageId) return false if (!signature.contentEquals(other.signature)) return false - return true } diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundDisguisedChatMessagePacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundDisguisedChatMessagePacket.kt index 4c5414a..ddda39b 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundDisguisedChatMessagePacket.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundDisguisedChatMessagePacket.kt @@ -7,16 +7,16 @@ package cn.rtast.libmc.protocol.packet.play.clientbound +import cn.rtast.libmc.network.BytesBuffer import cn.rtast.libmc.packet.MinecraftPacket import cn.rtast.libmc.packet.PacketCodec import cn.rtast.libmc.primitives.IdOrX import cn.rtast.libmc.primitives.readIdOrX -import cn.rtast.libmc.primitives.readOptional +import cn.rtast.libmc.primitives.readPrefixOptional import cn.rtast.libmc.protocol.protocol.game.chat.InlineChatType import cn.rtast.libmc.protocol.protocol.game.chat.TextComponent import cn.rtast.libmc.protocol.protocol.game.chat.readInlineChatType import cn.rtast.libmc.protocol.protocol.game.chat.readTextComponent -import cn.rtast.libmc.network.BytesBuffer public data class ClientboundDisguisedChatMessagePacket( val message: TextComponent, @@ -30,7 +30,7 @@ public data class ClientboundDisguisedChatMessagePacket( val message = buffer.readTextComponent() val chatType = buffer.readIdOrX { readInlineChatType() } val senderName = buffer.readTextComponent() - val targetName = buffer.readOptional { readTextComponent() } + val targetName = buffer.readPrefixOptional { readTextComponent() } return ClientboundDisguisedChatMessagePacket(message, chatType, senderName, targetName) } } diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundMapItemDataPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundMapItemDataPacket.kt index f4aeff6..b076839 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundMapItemDataPacket.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundMapItemDataPacket.kt @@ -7,9 +7,11 @@ package cn.rtast.libmc.protocol.packet.play.clientbound +import cn.rtast.libmc.network.BytesBuffer import cn.rtast.libmc.packet.MinecraftPacket import cn.rtast.libmc.packet.PacketCodec import cn.rtast.libmc.primitives.readOptional +import cn.rtast.libmc.primitives.readPrefixOptional import cn.rtast.libmc.primitives.readPrefixed import cn.rtast.libmc.primitives.readPrefixedByteArray import cn.rtast.libmc.primitives.readVarInt @@ -17,7 +19,6 @@ import cn.rtast.libmc.protocol.protocol.game.chat.readTextComponent import cn.rtast.libmc.protocol.protocol.game.item.MapItemColorPatch import cn.rtast.libmc.protocol.protocol.game.item.MapItemIcon import cn.rtast.libmc.protocol.protocol.game.item.MapItemIconType -import cn.rtast.libmc.network.BytesBuffer public data class ClientboundMapItemDataPacket( val mapId: Int, @@ -32,24 +33,24 @@ public data class ClientboundMapItemDataPacket( val mapId = buffer.readVarInt() val scale = buffer.readByte() val locked = buffer.readBoolean() - val icons = buffer.readOptional { + val icons = buffer.readPrefixOptional { readPrefixed { val type = MapItemIconType.fromID(readVarInt()) val x = readByte() val z = readByte() val direction = readByte() - val displayName = readOptional { readTextComponent() } + val displayName = readPrefixOptional { readTextComponent() } MapItemIcon(type, x, z, direction, displayName) } } val columns = buffer.readUByte() - val colorPatch = if (columns > 0u) { + val colorPatch = buffer.readOptional(columns > 0u) { val rows = buffer.readUByte() val xOffset = buffer.readUByte() val zOffset = buffer.readUByte() val data = buffer.readPrefixedByteArray() MapItemColorPatch(columns, rows, xOffset, zOffset, data) - } else null + } return ClientboundMapItemDataPacket(mapId, scale, locked, icons, colorPatch) } } diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundPlayerInfoUpdatePacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundPlayerInfoUpdatePacket.kt index dfc9237..54c14c7 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundPlayerInfoUpdatePacket.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundPlayerInfoUpdatePacket.kt @@ -43,7 +43,7 @@ public data class ClientboundPlayerInfoUpdatePacket( } PlayerUpdateInfoAction.INITIALIZE_CHAT -> { - buffer.readOptional { + buffer.readPrefixOptional { SinglePlayerAction.InitializeChat( readUuid(), readLong(), readBytes(512), readBytes(4096) diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundResetScorePacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundResetScorePacket.kt index 99407f1..17d7ea4 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundResetScorePacket.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundResetScorePacket.kt @@ -7,19 +7,18 @@ package cn.rtast.libmc.protocol.packet.play.clientbound +import cn.rtast.libmc.network.BytesBuffer import cn.rtast.libmc.packet.MinecraftPacket import cn.rtast.libmc.packet.PacketCodec import cn.rtast.libmc.primitives.readMcString -import cn.rtast.libmc.primitives.readOptional -import cn.rtast.libmc.primitives.readPrefixed -import cn.rtast.libmc.network.BytesBuffer +import cn.rtast.libmc.primitives.readPrefixOptional public data class ClientboundResetScorePacket(val entityName: String, val objectiveName: String?) : MinecraftPacket { internal companion object Codec : PacketCodec { override fun encode(buffer: BytesBuffer, value: ClientboundResetScorePacket) {} override fun decode(buffer: BytesBuffer): ClientboundResetScorePacket { val entityName = buffer.readMcString() - val objectiveName = buffer.readPrefixed { readOptional { readMcString() } }.first() // ? + val objectiveName = buffer.readPrefixOptional { readMcString() } return ClientboundResetScorePacket(entityName, objectiveName) } } diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundRespawnPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundRespawnPacket.kt index d9ab436..0cc935e 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundRespawnPacket.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundRespawnPacket.kt @@ -8,8 +8,8 @@ package cn.rtast.libmc.protocol.packet.play.clientbound import cn.rtast.libmc.network.BytesBuffer -import cn.rtast.libmc.packet.PacketCodec import cn.rtast.libmc.packet.MinecraftPacket +import cn.rtast.libmc.packet.PacketCodec import cn.rtast.libmc.primitives.readOptional import cn.rtast.libmc.primitives.readVarInt import cn.rtast.libmc.protocol.protocol.game.GameMode @@ -45,8 +45,8 @@ public data class ClientboundRespawnPacket( val isDebug = buffer.readBoolean() val isFlat = buffer.readBoolean() val hasDeathLocation = buffer.readBoolean() - val deathDimensionName = buffer.readOptional { readIdentifier() } - val deathLocation = buffer.readOptional { readBlockPos() } + val deathDimensionName = buffer.readOptional(hasDeathLocation) { readIdentifier() } + val deathLocation = buffer.readOptional(hasDeathLocation) { readBlockPos() } val portalCooldown = buffer.readVarInt() val seaLevel = buffer.readVarInt() val dataKept = RespawnDataToKeep.fromByte(buffer.readByte()) diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundSelectAdvancementsTabPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundSelectAdvancementsTabPacket.kt index a969355..d40323e 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundSelectAdvancementsTabPacket.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundSelectAdvancementsTabPacket.kt @@ -8,9 +8,9 @@ package cn.rtast.libmc.protocol.packet.play.clientbound import cn.rtast.libmc.network.BytesBuffer -import cn.rtast.libmc.packet.PacketCodec import cn.rtast.libmc.packet.MinecraftPacket -import cn.rtast.libmc.primitives.readOptional +import cn.rtast.libmc.packet.PacketCodec +import cn.rtast.libmc.primitives.readPrefixOptional import cn.rtast.libmc.protocol.protocol.game.Identifier import cn.rtast.libmc.protocol.protocol.game.readIdentifier @@ -18,7 +18,7 @@ public data class ClientboundSelectAdvancementsTabPacket(val tabId: Identifier?) internal companion object Codec : PacketCodec { override fun encode(buffer: BytesBuffer, value: ClientboundSelectAdvancementsTabPacket) {} override fun decode(buffer: BytesBuffer): ClientboundSelectAdvancementsTabPacket { - return ClientboundSelectAdvancementsTabPacket(buffer.readOptional { readIdentifier() }) + return ClientboundSelectAdvancementsTabPacket(buffer.readPrefixOptional { readIdentifier() }) } } } \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundServerDataPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundServerDataPacket.kt index 9a3c865..973482a 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundServerDataPacket.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundServerDataPacket.kt @@ -7,20 +7,20 @@ package cn.rtast.libmc.protocol.packet.play.clientbound +import cn.rtast.libmc.network.BytesBuffer import cn.rtast.libmc.packet.MinecraftPacket import cn.rtast.libmc.packet.PacketCodec -import cn.rtast.libmc.primitives.readOptional +import cn.rtast.libmc.primitives.readPrefixOptional import cn.rtast.libmc.primitives.readVarInt import cn.rtast.libmc.protocol.protocol.game.chat.TextComponent import cn.rtast.libmc.protocol.protocol.game.chat.readTextComponent -import cn.rtast.libmc.network.BytesBuffer public data class ClientboundServerDataPacket(val motd: TextComponent, val icon: ByteArray?) : MinecraftPacket { internal companion object Codec : PacketCodec { override fun encode(buffer: BytesBuffer, value: ClientboundServerDataPacket) {} override fun decode(buffer: BytesBuffer): ClientboundServerDataPacket { val motd = buffer.readTextComponent() - val icon = buffer.readOptional { val length = readVarInt(); readBytes(length) } + val icon = buffer.readPrefixOptional { val length = readVarInt(); readBytes(length) } return ClientboundServerDataPacket(motd, icon) } } diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundTestInstanceBlockStatusPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundTestInstanceBlockStatusPacket.kt index 28814a7..d83da93 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundTestInstanceBlockStatusPacket.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundTestInstanceBlockStatusPacket.kt @@ -7,12 +7,12 @@ package cn.rtast.libmc.protocol.packet.play.clientbound +import cn.rtast.libmc.network.BytesBuffer import cn.rtast.libmc.packet.MinecraftPacket import cn.rtast.libmc.packet.PacketCodec import cn.rtast.libmc.primitives.readOptional import cn.rtast.libmc.protocol.protocol.game.chat.TextComponent import cn.rtast.libmc.protocol.protocol.game.chat.readTextComponent -import cn.rtast.libmc.network.BytesBuffer public data class ClientboundTestInstanceBlockStatusPacket( val status: TextComponent, @@ -26,9 +26,9 @@ public data class ClientboundTestInstanceBlockStatusPacket( override fun decode(buffer: BytesBuffer): ClientboundTestInstanceBlockStatusPacket { val status = buffer.readTextComponent() val hasSize = buffer.readBoolean() - val sizeX = buffer.readOptional { readDouble() } // ? - val sizeY = buffer.readOptional { readDouble() } // ? - val sizeZ = buffer.readOptional { readDouble() } // ? + val sizeX = buffer.readOptional(hasSize) { readDouble() } + val sizeY = buffer.readOptional(hasSize) { readDouble() } + val sizeZ = buffer.readOptional(hasSize) { readDouble() } return ClientboundTestInstanceBlockStatusPacket(status, hasSize, sizeX, sizeY, sizeZ) } } diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundUpdateScorePacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundUpdateScorePacket.kt index aab3e99..495a5df 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundUpdateScorePacket.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundUpdateScorePacket.kt @@ -8,16 +8,16 @@ package cn.rtast.libmc.protocol.packet.play.clientbound import cn.rtast.libmc.nbt.NBTTag +import cn.rtast.libmc.network.BytesBuffer import cn.rtast.libmc.packet.MinecraftPacket import cn.rtast.libmc.packet.PacketCodec import cn.rtast.libmc.primitives.readMcString -import cn.rtast.libmc.primitives.readOptional +import cn.rtast.libmc.primitives.readPrefixOptional import cn.rtast.libmc.primitives.readVarInt import cn.rtast.libmc.protocol.protocol.game.chat.TextComponent import cn.rtast.libmc.protocol.protocol.game.chat.readTextComponent import cn.rtast.libmc.protocol.protocol.game.scoreboard.ScoreNumberFormat import cn.rtast.libmc.protocol.protocol.util.readNetworkNBTCompound -import cn.rtast.libmc.network.BytesBuffer public data class ClientboundUpdateScorePacket( val entityName: String, @@ -32,8 +32,8 @@ public data class ClientboundUpdateScorePacket( val entityName = buffer.readMcString() val objectiveName = buffer.readMcString() val value = buffer.readVarInt() - val displayName = buffer.readOptional { readTextComponent() } - val numberFormat = buffer.readOptional { + val displayName = buffer.readPrefixOptional { readTextComponent() } + val numberFormat = buffer.readPrefixOptional { when (val type = readVarInt()) { 0 -> ScoreNumberFormat.Blank 1 -> ScoreNumberFormat.Styled(styling = readNetworkNBTCompound().element as NBTTag.CompoundTag) // fix me diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundWaypointPacket.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundWaypointPacket.kt index 2659384..17e68a8 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundWaypointPacket.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/packet/play/clientbound/ClientboundWaypointPacket.kt @@ -34,7 +34,7 @@ public data class ClientboundWaypointPacket( readRight = { readIdentifier() } ) val iconStyle = buffer.readIdentifier() - val color = buffer.readOptional { + val color = buffer.readPrefixOptional { val red = readUByte() val green = readUByte() val blue = readUByte() diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/block/BlockStateProperty.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/block/BlockStateProperty.kt new file mode 100644 index 0000000..7698d5a --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/block/BlockStateProperty.kt @@ -0,0 +1,10 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.block + +public data class BlockStateProperty(val name: String, val value: String) \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/color/DyeColor.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/color/DyeColor.kt new file mode 100644 index 0000000..8219761 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/color/DyeColor.kt @@ -0,0 +1,31 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.color + +public enum class DyeColor(public val id: Int) { + WHITE(0), + ORANGE(1), + MAGENTA(2), + LIGHT_BLUE(3), + YELLOW(4), + LIME(5), + PINK(6), + GRAY(7), + LIGHT_GRAY(8), + CYAN(9), + PURPLE(10), + BLUE(11), + BROWN(12), + GREEN(13), + RED(14), + BLACK(15); + + public companion object { + public fun fromID(id: Int): DyeColor = entries.first { it.id == id } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/DataComponent.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/DataComponent.kt new file mode 100644 index 0000000..d9edeb3 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/DataComponent.kt @@ -0,0 +1,1673 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.data.component + +import cn.rtast.libmc.nbt.NBTCompound +import cn.rtast.libmc.network.BytesBuffer +import cn.rtast.libmc.packet.PacketCodec +import cn.rtast.libmc.primitives.* +import cn.rtast.libmc.protocol.protocol.game.Identifier +import cn.rtast.libmc.protocol.protocol.game.block.BlockPos +import cn.rtast.libmc.protocol.protocol.game.block.BlockStateProperty +import cn.rtast.libmc.protocol.protocol.game.block.readBlockPos +import cn.rtast.libmc.protocol.protocol.game.block.writeBlockPos +import cn.rtast.libmc.protocol.protocol.game.chat.TextComponent +import cn.rtast.libmc.protocol.protocol.game.chat.readTextComponent +import cn.rtast.libmc.protocol.protocol.game.chat.writeTextComponent +import cn.rtast.libmc.protocol.protocol.game.color.DyeColor +import cn.rtast.libmc.protocol.protocol.game.data.component.attributes.* +import cn.rtast.libmc.protocol.protocol.game.entity.* +import cn.rtast.libmc.protocol.protocol.game.item.ItemUseAnimation +import cn.rtast.libmc.protocol.protocol.game.item.PaintingVariantType +import cn.rtast.libmc.protocol.protocol.game.item.readPaintingVariantType +import cn.rtast.libmc.protocol.protocol.game.item.slot.Slot +import cn.rtast.libmc.protocol.protocol.game.item.slot.readSlot +import cn.rtast.libmc.protocol.protocol.game.item.slot.writeSlot +import cn.rtast.libmc.protocol.protocol.game.item.writePaintingVariantType +import cn.rtast.libmc.protocol.protocol.game.potion.* +import cn.rtast.libmc.protocol.protocol.game.readIdentifier +import cn.rtast.libmc.protocol.protocol.game.session.ResolvableProfile +import cn.rtast.libmc.protocol.protocol.game.session.readResolvableProfile +import cn.rtast.libmc.protocol.protocol.game.session.writeResolvableProfile +import cn.rtast.libmc.protocol.protocol.game.sound.SoundEvent +import cn.rtast.libmc.protocol.protocol.game.sound.readSoundEvent +import cn.rtast.libmc.protocol.protocol.game.sound.writeSoundEvent +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 sealed interface DataComponent { + public data class CustomDataComponent(val nbt: NBTCompound) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: CustomDataComponent) { + buffer.writeNetworkNBTCompound(value.nbt) + } + + override fun decode(buffer: BytesBuffer): CustomDataComponent { + return CustomDataComponent(buffer.readNetworkNBTCompound()) + } + } + } + + public data class MaxStackSizeComponent(val size: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: MaxStackSizeComponent) { + require(value.size in 1..99) + buffer.writeVarInt(value.size) + } + + override fun decode(buffer: BytesBuffer): MaxStackSizeComponent = + MaxStackSizeComponent(buffer.readVarInt()) + } + } + + public data class MaxDamageComponent(val maxDamage: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: MaxDamageComponent) { + buffer.writeVarInt(value.maxDamage) + } + + override fun decode(buffer: BytesBuffer): MaxDamageComponent = + MaxDamageComponent(buffer.readVarInt()) + } + } + + public data class DamageComponent(val damage: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: DamageComponent) { + buffer.writeVarInt(value.damage) + } + + override fun decode(buffer: BytesBuffer): DamageComponent = + DamageComponent(buffer.readVarInt()) + } + } + + public data object UnbreakableComponent : DataComponent, PacketCodec { + override fun encode(buffer: BytesBuffer, value: UnbreakableComponent) {} + override fun decode(buffer: BytesBuffer): UnbreakableComponent = UnbreakableComponent + } + + public data class CustomNameComponent(val name: TextComponent) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: CustomNameComponent) { + buffer.writeTextComponent(value.name) + } + + override fun decode(buffer: BytesBuffer): CustomNameComponent = + CustomNameComponent(buffer.readTextComponent()) + } + } + + public data class ItemNameComponent(val name: TextComponent) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ItemNameComponent) { + buffer.writeTextComponent(value.name) + } + + override fun decode(buffer: BytesBuffer): ItemNameComponent = + ItemNameComponent(buffer.readTextComponent()) + } + } + + public data class ItemModelComponent(val model: Identifier) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ItemModelComponent) { + buffer.writeIdentifier(value.model) + } + + override fun decode(buffer: BytesBuffer): ItemModelComponent = + ItemModelComponent(buffer.readIdentifier()) + } + } + + public data class LoreComponent(val lines: List) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: LoreComponent) { + buffer.writePrefixed(value.lines) { writeTextComponent(it) } + } + + override fun decode(buffer: BytesBuffer): LoreComponent = + LoreComponent(buffer.readPrefixed { readTextComponent() }) + } + } + + public data class RarityComponent(val rarity: ItemRarity) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: RarityComponent) { + buffer.writeVarInt(value.rarity.id) + } + + override fun decode(buffer: BytesBuffer): RarityComponent = + RarityComponent(ItemRarity.fromID(buffer.readVarInt())) + } + } + + public data class EnchantmentsComponent(val enchantments: List) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: EnchantmentsComponent) { + buffer.writePrefixed(value.enchantments) { + writeVarInt(it.typeId) + writeVarInt(it.level) + } + } + + override fun decode(buffer: BytesBuffer): EnchantmentsComponent = + EnchantmentsComponent(buffer.readPrefixed { + val typeId = readVarInt() + val level = readVarInt() + EnchantmentEntry(typeId, level) + }) + } + } + + public data class CanPlaceOnComponent(val predicates: List) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: CanPlaceOnComponent) { + buffer.writePrefixed(value.predicates) { writeBlockPredicate(it) } + } + + override fun decode(buffer: BytesBuffer): CanPlaceOnComponent = + CanPlaceOnComponent(buffer.readPrefixed { readBlockPredicate() }) + } + } + + public data class CanBreakComponent(val predicates: List) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: CanBreakComponent) { + buffer.writePrefixed(value.predicates) { writeBlockPredicate(it) } + } + + override fun decode(buffer: BytesBuffer): CanBreakComponent = + CanBreakComponent(buffer.readPrefixed { readBlockPredicate() }) + } + } + + public data class AttributeModifiersComponent(val modifiers: List) : + DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: AttributeModifiersComponent) { + buffer.writePrefixed(value.modifiers) { entry -> + writeVarInt(entry.attributeId) + writeIdentifier(entry.modifierId) + writeDouble(entry.value) + writeVarInt(entry.operation.id) + writeVarInt(entry.slot.id) + } + } + + override fun decode(buffer: BytesBuffer): AttributeModifiersComponent = + AttributeModifiersComponent(buffer.readPrefixed { + val attributeId = readVarInt() + val modifierId = readIdentifier() + val value = readDouble() + val operation = AttributeOperation.fromID(readVarInt()) + val slot = AttributeSlot.fromID(readVarInt()) + AttributeModifierEntry(attributeId, modifierId, value, operation, slot) + }) + } + } + + public data class CustomModelDataComponent( + val floats: List, + val flags: List, + val strings: List, + val colors: List, + ) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: CustomModelDataComponent) { + buffer.writePrefixed(value.floats) { writeFloat(it) } + buffer.writePrefixed(value.flags) { writeBoolean(it) } + buffer.writePrefixed(value.strings) { writeMcString(it) } + buffer.writePrefixed(value.colors) { writeInt(it) } + } + + override fun decode(buffer: BytesBuffer): CustomModelDataComponent { + val floats = buffer.readPrefixed { readFloat() } + val flags = buffer.readPrefixed { readBoolean() } + val strings = buffer.readPrefixed { readMcString() } + val colors = buffer.readPrefixed { readInt() } + return CustomModelDataComponent(floats, flags, strings, colors) + } + } + } + + public data class TooltipDisplayComponent(val hideTooltip: Boolean, val hiddenComponents: List) : + DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: TooltipDisplayComponent) { + buffer.writeBoolean(value.hideTooltip) + buffer.writePrefixed(value.hiddenComponents) { writeVarInt(it) } + } + + override fun decode(buffer: BytesBuffer): TooltipDisplayComponent { + val hideTooltip = buffer.readBoolean() + val hiddenComponents = buffer.readPrefixed { readVarInt() } + return TooltipDisplayComponent(hideTooltip, hiddenComponents) + } + } + } + + public data class RepairCostComponent(val cost: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: RepairCostComponent) { + buffer.writeVarInt(value.cost) + } + + override fun decode(buffer: BytesBuffer): RepairCostComponent = RepairCostComponent(buffer.readVarInt()) + } + } + + public data object CreativeSlotLockComponent : DataComponent, PacketCodec { + override fun encode(buffer: BytesBuffer, value: CreativeSlotLockComponent) {} + override fun decode(buffer: BytesBuffer): CreativeSlotLockComponent = CreativeSlotLockComponent + } + + public data class EnchantmentGlintOverrideComponent(val hasGlint: Boolean) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: EnchantmentGlintOverrideComponent) { + buffer.writeBoolean(value.hasGlint) + } + + override fun decode(buffer: BytesBuffer): EnchantmentGlintOverrideComponent = + EnchantmentGlintOverrideComponent(buffer.readBoolean()) + } + } + + public data class IntangibleProjectileComponent(val empty: NBTCompound) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: IntangibleProjectileComponent) { + buffer.writeNetworkNBTCompound(value.empty) + } + + override fun decode(buffer: BytesBuffer): IntangibleProjectileComponent = + IntangibleProjectileComponent(buffer.readNetworkNBTCompound()) + } + } + + public data class FoodComponent(val nutrition: Int, val saturationModifier: Float, val canAlwaysEat: Boolean) : + DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: FoodComponent) { + buffer.writeVarInt(value.nutrition) + buffer.writeFloat(value.saturationModifier) + buffer.writeBoolean(value.canAlwaysEat) + } + + override fun decode(buffer: BytesBuffer): FoodComponent { + val nutrition = buffer.readVarInt() + val saturationModifier = buffer.readFloat() + val canAlwaysEat = buffer.readBoolean() + return FoodComponent(nutrition, saturationModifier, canAlwaysEat) + } + } + } + + public data class ConsumableComponent( + val consumeSeconds: Float, + val animation: ItemUseAnimation, + val sound: IdOrX, + val hasConsumeParticles: Boolean, + val effects: List, + ) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ConsumableComponent) { + buffer.writeFloat(value.consumeSeconds) + buffer.writeVarInt(value.animation.id) + buffer.writeIdOrX(value.sound) { writeSoundEvent(it) } + buffer.writeBoolean(value.hasConsumeParticles) + buffer.writeConsumeEffects(value.effects) + } + + override fun decode(buffer: BytesBuffer): ConsumableComponent { + val consumeSeconds = buffer.readFloat() + val animation = ItemUseAnimation.fromID(buffer.readVarInt()) + val sound = buffer.readIdOrX { readSoundEvent() } + val hasConsumeParticles = buffer.readBoolean() + val effects = buffer.readConsumeEffects() + return ConsumableComponent(consumeSeconds, animation, sound, hasConsumeParticles, effects) + } + } + } + + public data class UseRemainderComponent(val remainder: Slot) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: UseRemainderComponent) { + buffer.writeSlot(value.remainder) + } + + override fun decode(buffer: BytesBuffer): UseRemainderComponent = + UseRemainderComponent(buffer.readSlot()) + } + } + + public data class UseCooldownComponent(val seconds: Float, val cooldownGroup: Identifier?) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: UseCooldownComponent) { + buffer.writeFloat(value.seconds) + buffer.writePrefixedOptional(value.cooldownGroup) { writeIdentifier(it) } + } + + override fun decode(buffer: BytesBuffer): UseCooldownComponent { + val seconds = buffer.readFloat() + val cooldownGroup = buffer.readIdentifier() + return UseCooldownComponent(seconds, cooldownGroup) + } + } + } + + public data class UseEffectsComponent( + val canSprint: Boolean, + val interactVibrations: Boolean, + val speedMultiplier: Float, + ) : + DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: UseEffectsComponent) { + buffer.writeBoolean(value.canSprint) + buffer.writeBoolean(value.interactVibrations) + buffer.writeFloat(value.speedMultiplier) + } + + override fun decode(buffer: BytesBuffer): UseEffectsComponent { + val canSprint = buffer.readBoolean() + val interactVibrations = buffer.readBoolean() + val speedMultiplier = buffer.readFloat() + return UseEffectsComponent(canSprint, interactVibrations, speedMultiplier) + } + } + } + + public data class MinimumAttackChargeComponent(val minimumAttackChange: Float) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: MinimumAttackChargeComponent) { + buffer.writeFloat(value.minimumAttackChange) + } + + override fun decode(buffer: BytesBuffer): MinimumAttackChargeComponent = + MinimumAttackChargeComponent(buffer.readFloat()) + } + } + + public data class DamageTypeComponent(val type: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: DamageTypeComponent) { + buffer.writeVarInt(value.type) + } + + override fun decode(buffer: BytesBuffer): DamageTypeComponent = + DamageTypeComponent(buffer.readVarInt()) + } + } + + public data class DamageResistantComponent(val types: IdSet) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: DamageResistantComponent) { + buffer.writeIdSet(value.types) + } + + override fun decode(buffer: BytesBuffer): DamageResistantComponent = + DamageResistantComponent(buffer.readIdSet()) + } + } + + public data class AttackRangeComponent( + val minReach: Float, + val maxReach: Float, + val minCreativeReach: Float, + val maxCreativeReach: Float, + val hitBoxMargin: Float, + val mobFactor: Float, + ) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: AttackRangeComponent) { + buffer.writeFloat(value.minReach) + buffer.writeFloat(value.maxReach) + buffer.writeFloat(value.minCreativeReach) + buffer.writeFloat(value.maxCreativeReach) + buffer.writeFloat(value.hitBoxMargin) + buffer.writeFloat(value.mobFactor) + } + + override fun decode(buffer: BytesBuffer): AttackRangeComponent { + val minReach = buffer.readFloat() + val maxReach = buffer.readFloat() + val minCreativeReach = buffer.readFloat() + val maxCreativeReach = buffer.readFloat() + val hitBoxMargin = buffer.readFloat() + val mobFactor = buffer.readFloat() + return AttackRangeComponent( + minReach, + maxReach, + minCreativeReach, + maxCreativeReach, + hitBoxMargin, + mobFactor + ) + } + } + } + + public data class ToolComponent( + val rules: List, + val defaultMiningSpeed: Float, + val damagePerBlock: Int, + val canDestroyBlocksInCreative: Boolean, + ) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ToolComponent) { + buffer.writePrefixed(value.rules) { rule -> + writeIdSet(rule.blocks) + writePrefixedOptional(rule.speed) { writeFloat(it) } + writePrefixedOptional(rule.correctForDrops) { writeBoolean(it) } + } + buffer.writeFloat(value.defaultMiningSpeed) + buffer.writeVarInt(value.damagePerBlock) + buffer.writeBoolean(value.canDestroyBlocksInCreative) + } + + override fun decode(buffer: BytesBuffer): ToolComponent { + val rules = buffer.readPrefixed { + val blocks = readIdSet() + val speed = readPrefixOptional { readFloat() } + val correctForDrops = readPrefixOptional { readBoolean() } + ToolRule(blocks, speed, correctForDrops) + } + val defaultMiningSpeed = buffer.readFloat() + val damagePerBlock = buffer.readVarInt() + val canDestroyBlocksInCreative = buffer.readBoolean() + return ToolComponent(rules, defaultMiningSpeed, damagePerBlock, canDestroyBlocksInCreative) + } + } + } + + public data class WeaponComponent(val damagePerAttack: Int, val disableBlockingFor: Float) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: WeaponComponent) { + buffer.writeVarInt(value.damagePerAttack) + buffer.writeFloat(value.disableBlockingFor) + } + + override fun decode(buffer: BytesBuffer): WeaponComponent { + val damagePerAttack = buffer.readVarInt() + val disableBlockingFor = buffer.readFloat() + return WeaponComponent(damagePerAttack, disableBlockingFor) + } + } + } + + public data class EnchantableComponent(val value: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: EnchantableComponent) { + buffer.writeVarInt(value.value) + } + + override fun decode(buffer: BytesBuffer): EnchantableComponent = + EnchantableComponent(buffer.readVarInt()) + } + } + + public data class EquippableComponent( + val slot: EquipmentSlot, + val equipSound: IdOrX, + val model: Identifier?, + val cameraOverlay: Identifier?, + val allowedEntities: IdSet?, + val dispensable: Boolean, + val swappable: Boolean, + val damageOnHurt: Boolean, + val canBeSheared: Boolean, + val shearingSound: IdOrX, + ) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: EquippableComponent) { + buffer.writeVarInt(value.slot.id) + buffer.writeIdOrX(value.equipSound) { writeSoundEvent(it) } + buffer.writePrefixedOptional(value.model) { writeIdentifier(it) } + buffer.writePrefixedOptional(value.cameraOverlay) { writeIdentifier(it) } + buffer.writePrefixedOptional(value.allowedEntities) { writeIdSet(it) } + buffer.writeBoolean(value.dispensable) + buffer.writeBoolean(value.swappable) + buffer.writeBoolean(value.damageOnHurt) + buffer.writeBoolean(value.canBeSheared) + buffer.writeIdOrX(value.shearingSound) { writeSoundEvent(it) } + } + + override fun decode(buffer: BytesBuffer): EquippableComponent { + val slot = EquipmentSlot.fromID(buffer.readVarInt()) + val equipSound = buffer.readIdOrX { readSoundEvent() } + val model = buffer.readPrefixOptional { readIdentifier() } + val cameraOverlay = buffer.readPrefixOptional { readIdentifier() } + val allowedEntities = buffer.readPrefixOptional { readIdSet() } + val dispensable = buffer.readBoolean() + val swappable = buffer.readBoolean() + val damageOnHurt = buffer.readBoolean() + val canBeSheared = buffer.readBoolean() + val shearingSound = buffer.readIdOrX { readSoundEvent() } + return EquippableComponent( + slot, equipSound, model, cameraOverlay, allowedEntities, + dispensable, swappable, damageOnHurt, canBeSheared, shearingSound + ) + } + } + } + + public data class RepairableComponent(val items: IdSet) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: RepairableComponent) { + buffer.writeIdSet(value.items) + } + + override fun decode(buffer: BytesBuffer): RepairableComponent = + RepairableComponent(buffer.readIdSet()) + } + } + + public data object GliderComponent : DataComponent, PacketCodec { + override fun encode(buffer: BytesBuffer, value: GliderComponent) {} + override fun decode(buffer: BytesBuffer): GliderComponent = GliderComponent + } + + public data class TooltipStyleComponent(val style: Identifier) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: TooltipStyleComponent) { + buffer.writeIdentifier(value.style) + } + + override fun decode(buffer: BytesBuffer): TooltipStyleComponent = + TooltipStyleComponent(buffer.readIdentifier()) + } + } + + public data class DeathProtectionComponent(val effects: List) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: DeathProtectionComponent) { + buffer.writeConsumeEffects(value.effects) + } + + override fun decode(buffer: BytesBuffer): DeathProtectionComponent = + DeathProtectionComponent(buffer.readConsumeEffects()) + } + } + + public data class BlocksAttacksComponent( + val blockDelaySeconds: Float, + val disableCooldownScale: Float, + val damageReductions: List, + val itemDamageThreshold: Float, + val itemDamageBase: Float, + val itemDamageFactor: Float, + val bypassedBy: IdSet?, + val blockSound: IdOrX?, + val disableSound: IdOrX?, + ) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: BlocksAttacksComponent) { + buffer.writeFloat(value.blockDelaySeconds) + buffer.writeFloat(value.disableCooldownScale) + buffer.writePrefixed(value.damageReductions) { reduction -> + writeFloat(reduction.horizontalBlockingAngle) + writePrefixedOptional(reduction.type) { writeIdSet(it) } + writeFloat(reduction.base) + writeFloat(reduction.factor) + } + buffer.writeFloat(value.itemDamageThreshold) + buffer.writeFloat(value.itemDamageBase) + buffer.writeFloat(value.itemDamageFactor) + buffer.writePrefixedOptional(value.bypassedBy) { writeIdSet(it) } + buffer.writePrefixedOptional(value.blockSound) { writeIdOrX(it) { sound -> writeSoundEvent(sound) } } + buffer.writePrefixedOptional(value.disableSound) { writeIdOrX(it) { sound -> writeSoundEvent(sound) } } + } + + override fun decode(buffer: BytesBuffer): BlocksAttacksComponent { + val blockDelaySeconds = buffer.readFloat() + val disableCooldownScale = buffer.readFloat() + val damageReductions = buffer.readPrefixed { + val horizontalBlockingAngle = readFloat() + val type = readPrefixOptional { readIdSet() } + val base = readFloat() + val factor = readFloat() + DamageReduction(horizontalBlockingAngle, type, base, factor) + } + val itemDamageThreshold = buffer.readFloat() + val itemDamageBase = buffer.readFloat() + val itemDamageFactor = buffer.readFloat() + val bypassedBy = buffer.readPrefixOptional { readIdSet() } + val blockSound = buffer.readPrefixOptional { readIdOrX { readSoundEvent() } } + val disableSound = buffer.readPrefixOptional { readIdOrX { readSoundEvent() } } + return BlocksAttacksComponent( + blockDelaySeconds, disableCooldownScale, damageReductions, + itemDamageThreshold, itemDamageBase, itemDamageFactor, + bypassedBy, blockSound, disableSound + ) + } + } + } + + public data class StoredEnchantmentsComponent(val enchantments: List) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: StoredEnchantmentsComponent) { + buffer.writePrefixed(value.enchantments) { enchantment -> + writeVarInt(enchantment.enchantmentId) + writeVarInt(enchantment.level) + } + } + + override fun decode(buffer: BytesBuffer): StoredEnchantmentsComponent = + StoredEnchantmentsComponent(buffer.readPrefixed { + val enchantmentId = buffer.readVarInt() + val level = buffer.readVarInt() + StoredEnchantment(enchantmentId, level) + }) + } + } + + public data class DyedColorComponent(val color: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: DyedColorComponent) { + buffer.writeInt(value.color) + } + + override fun decode(buffer: BytesBuffer): DyedColorComponent = + DyedColorComponent(buffer.readInt()) + } + } + + public data class MapColorComponent(val color: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: MapColorComponent) { + buffer.writeInt(value.color) + } + + override fun decode(buffer: BytesBuffer): MapColorComponent = + MapColorComponent(buffer.readInt()) + } + } + + public data class MapIdComponent(val id: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: MapIdComponent) { + buffer.writeVarInt(value.id) + } + + override fun decode(buffer: BytesBuffer): MapIdComponent = + MapIdComponent(buffer.readVarInt()) + } + } + + public data class MapDecorationsComponent(val nbt: NBTCompound) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: MapDecorationsComponent) { + buffer.writeNetworkNBTCompound(value.nbt) + } + + override fun decode(buffer: BytesBuffer): MapDecorationsComponent = + MapDecorationsComponent(buffer.readNetworkNBTCompound()) + } + } + + public data class MapPostProcessingComponent(val type: MapPostProcessingType) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: MapPostProcessingComponent) { + buffer.writeVarInt(value.type.id) + } + + override fun decode(buffer: BytesBuffer): MapPostProcessingComponent = + MapPostProcessingComponent(MapPostProcessingType.fromID(buffer.readVarInt())) + } + } + + public data class ChargedProjectilesComponent(val projectiles: List) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ChargedProjectilesComponent) { + buffer.writePrefixed(value.projectiles) { writeSlot(it) } + } + + override fun decode(buffer: BytesBuffer): ChargedProjectilesComponent = + ChargedProjectilesComponent(buffer.readPrefixed { readSlot() }) + } + } + + public data class BundleContentsComponent(val items: List) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: BundleContentsComponent) { + buffer.writePrefixed(value.items) { writeSlot(it) } + } + + override fun decode(buffer: BytesBuffer): BundleContentsComponent = + BundleContentsComponent(buffer.readPrefixed { readSlot() }) + } + } + + public data class PotionContentsComponent( + val potionId: Int?, + val customColor: Int?, + val customEffects: List, + /** + * it will always be null ??? + * */ + val customName: String?, + ) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: PotionContentsComponent) { + buffer.writePrefixedOptional(value.potionId) { writeVarInt(it) } + buffer.writePrefixedOptional(value.customColor) { writeInt(it) } + buffer.writePrefixed(value.customEffects) { writePotionEffect(it) } +// buffer.writePrefixedOptional(value.customName) { writeMcString(it) } // ???? + } + + override fun decode(buffer: BytesBuffer): PotionContentsComponent { + val potionId = buffer.readPrefixOptional { readVarInt() } + val customColor = buffer.readPrefixOptional { readInt() } + val customEffects = buffer.readPrefixed { readPotionEffect() } +// val customName = buffer.readPrefixOptional { readMcString() } // ???? + return PotionContentsComponent(potionId, customColor, customEffects, null) + } + } + } + + public data class PotionDurationScaleComponent(val effectMultiplier: Float) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: PotionDurationScaleComponent) { + buffer.writeFloat(value.effectMultiplier) + } + + override fun decode(buffer: BytesBuffer): PotionDurationScaleComponent = + PotionDurationScaleComponent(buffer.readFloat()) + } + } + + public data class SuspiciousStewEffectsComponent(val effects: List) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: SuspiciousStewEffectsComponent) { + buffer.writePrefixed(value.effects) { + writeVarInt(it.effectId) + writeVarInt(it.duration) + } + } + + override fun decode(buffer: BytesBuffer): SuspiciousStewEffectsComponent = + SuspiciousStewEffectsComponent(buffer.readPrefixed { + val effectId = readVarInt() + val duration = readVarInt() + SuspiciousStewEffect(effectId, duration) + }) + } + } + + public data class WritableBookContentComponent(val pages: List) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: WritableBookContentComponent) { + buffer.writePrefixed(value.pages) { + writeMcString(it.rawContent) + writePrefixedOptional(it.filteredContent) { filtered -> writeMcString(filtered) } + } + } + + override fun decode(buffer: BytesBuffer): WritableBookContentComponent = + WritableBookContentComponent(buffer.readPrefixed { + val rawContent = readMcString() + val filtered = readPrefixOptional { readMcString() } + WritablePage(rawContent, filtered) + }) + } + } + + public data class WrittenBookContentComponent( + val rawTitle: String, + val filteredTitle: String?, + val author: String, + val generation: Int, + val pages: List, + val resolved: Boolean, + ) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: WrittenBookContentComponent) { + buffer.writeMcString(value.rawTitle) + buffer.writePrefixedOptional(value.filteredTitle) { writeMcString(it) } + buffer.writeMcString(value.author) + buffer.writeVarInt(value.generation) + buffer.writePrefixed(value.pages) { page -> + writeTextComponent(page.rawContent) + writePrefixedOptional(page.filteredContent) { filtered -> writeTextComponent(filtered) } + } + buffer.writeBoolean(value.resolved) + } + + override fun decode(buffer: BytesBuffer): WrittenBookContentComponent { + val rawTitle = buffer.readMcString() + val filteredTitle = buffer.readPrefixOptional { readMcString() } + val author = buffer.readMcString() + val generation = buffer.readVarInt() + val pages = buffer.readPrefixed { + val rawContent = readTextComponent() + val filtered = readPrefixOptional { readTextComponent() } + WrittenPage(rawContent, filtered) + } + val resolved = buffer.readBoolean() + return WrittenBookContentComponent(rawTitle, filteredTitle, author, generation, pages, resolved) + } + } + } + + public data class TrimComponent(val material: IdOrX, val pattern: IdOrX) : + DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: TrimComponent) { + buffer.writeIdOrX(value.material) { material -> + writeMcString(material.suffix) + writePrefixed(material.overrides) { + writeIdentifier(it.armorMaterialType) + writeMcString(it.overriddenAssetName) + } + writeTextComponent(material.description) + } + } + + override fun decode(buffer: BytesBuffer): TrimComponent { + val material = buffer.readIdOrX { + val suffix = readMcString() + val overrides = readPrefixed { + val armorMaterialType = readIdentifier() + val overriddenAssetName = readMcString() + TrimMaterialOverride(armorMaterialType, overriddenAssetName) + } + val description = readTextComponent() + TrimMaterial(suffix, overrides, description) + } + val pattern = buffer.readIdOrX { + val assetName = readMcString() + val templateItem = readVarInt() + val description = readTextComponent() + val decal = readBoolean() + TrimPattern(assetName, templateItem, description, decal) + } + return TrimComponent(material, pattern) + } + } + } + + public data class DebugStickStateComponent(val data: NBTCompound) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: DebugStickStateComponent) { + buffer.writeNetworkNBTCompound(value.data) + } + + override fun decode(buffer: BytesBuffer): DebugStickStateComponent = + DebugStickStateComponent(buffer.readNetworkNBTCompound()) + } + } + + public data class EntityDataComponent(val entityType: Int, val data: NBTCompound) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: EntityDataComponent) { + buffer.writeVarInt(value.entityType) + buffer.writeNetworkNBTCompound(value.data) + } + + override fun decode(buffer: BytesBuffer): EntityDataComponent { + val type = buffer.readVarInt() + val data = buffer.readNetworkNBTCompound() + return EntityDataComponent(type, data) + } + } + } + + public data class BucketEntityDataComponent(val data: NBTCompound) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: BucketEntityDataComponent) { + buffer.writeNetworkNBTCompound(value.data) + } + + override fun decode(buffer: BytesBuffer): BucketEntityDataComponent = + BucketEntityDataComponent(buffer.readNetworkNBTCompound()) + } + } + + public data class BlockEntityDataComponent(val type: Int, val data: NBTCompound) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: BlockEntityDataComponent) { + buffer.writeVarInt(value.type) + buffer.writeNetworkNBTCompound(value.data) + } + + override fun decode(buffer: BytesBuffer): BlockEntityDataComponent { + val type = buffer.readVarInt() + val data = buffer.readNetworkNBTCompound() + return BlockEntityDataComponent(type, data) + } + } + } + + public data class InstrumentComponent(val instrument: IdOrX) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: InstrumentComponent) { + buffer.writeIdOrX(value.instrument) { instrument -> + writeIdOrX(instrument.sound) { writeSoundEvent(it) } + writeFloat(instrument.useDuration) + writeFloat(instrument.range) + writeTextComponent(instrument.description) + } + } + + override fun decode(buffer: BytesBuffer): InstrumentComponent = + InstrumentComponent(buffer.readIdOrX { + val sound = readIdOrX { readSoundEvent() } + val duration = readFloat() + val range = readFloat() + val description = readTextComponent() + InstrumentAttribute(sound, duration, range, description) + }) + } + } + + public data class PiercingWeaponComponent( + val dealsKnockback: Boolean, + val dismounts: Boolean, + val sound: SoundEvent?, + val hitSound: SoundEvent?, + ) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: PiercingWeaponComponent) { + buffer.writeBoolean(value.dealsKnockback) + buffer.writeBoolean(value.dismounts) + buffer.writePrefixedOptional(value.sound) { writeSoundEvent(it) } + buffer.writePrefixedOptional(value.hitSound) { writeSoundEvent(it) } + } + + override fun decode(buffer: BytesBuffer): PiercingWeaponComponent { + val dealsKnockback = buffer.readBoolean() + val dismounts = buffer.readBoolean() + val soundEvent = buffer.readPrefixOptional { readSoundEvent() } + val hitSound = buffer.readPrefixOptional { readSoundEvent() } + return PiercingWeaponComponent(dealsKnockback, dismounts, soundEvent, hitSound) + } + } + } + + public data class KineticWeaponComponent( + val contactCooldownTicks: Int, + val delayTicks: Int, + val dismountConditions: KineticWeaponCondition?, + val knockbackConditions: KineticWeaponCondition?, + val damageConditions: KineticWeaponCondition?, + val forwardMovement: Float, + val damageMultiplier: Float, + val sound: SoundEvent?, + val hitSound: SoundEvent?, + ) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: KineticWeaponComponent) { + buffer.writeVarInt(value.contactCooldownTicks) + buffer.writeVarInt(value.delayTicks) + buffer.writePrefixedOptional(value.dismountConditions) { writeKineticWeaponCondition(it) } + buffer.writePrefixedOptional(value.knockbackConditions) { writeKineticWeaponCondition(it) } + buffer.writePrefixedOptional(value.damageConditions) { writeKineticWeaponCondition(it) } + buffer.writeFloat(value.forwardMovement) + buffer.writeFloat(value.damageMultiplier) + buffer.writePrefixedOptional(value.sound) { writeSoundEvent(it) } + buffer.writePrefixedOptional(value.hitSound) { writeSoundEvent(it) } + } + + override fun decode(buffer: BytesBuffer): KineticWeaponComponent { + val contactCooldownTicks = buffer.readVarInt() + val delayTicks = buffer.readVarInt() + val dismountConditions = buffer.readPrefixOptional { readKineticWeaponCondition() } + val knockbackConditions = buffer.readPrefixOptional { readKineticWeaponCondition() } + val damageConditions = buffer.readPrefixOptional { readKineticWeaponCondition() } + val forwardMovement = buffer.readFloat() + val damageMultiplier = buffer.readFloat() + val sound = buffer.readPrefixOptional { readSoundEvent() } + val hitSound = buffer.readPrefixOptional { readSoundEvent() } + return KineticWeaponComponent( + contactCooldownTicks, delayTicks, dismountConditions, + knockbackConditions, damageConditions, forwardMovement, + damageMultiplier, sound, hitSound + ) + } + } + } + + public data class SwingAnimationComponent(val type: SwingAnimationType, val duration: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: SwingAnimationComponent) { + buffer.writeVarInt(value.type.id) + } + + override fun decode(buffer: BytesBuffer): SwingAnimationComponent { + val type = SwingAnimationType.fromID(buffer.readVarInt()) + val duration = buffer.readVarInt() + return SwingAnimationComponent(type, duration) + } + } + } + + public data class AdditionalTradeCostComponent(val cost: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: AdditionalTradeCostComponent) { + buffer.writeVarInt(value.cost) + } + + override fun decode(buffer: BytesBuffer): AdditionalTradeCostComponent = + AdditionalTradeCostComponent(buffer.readVarInt()) + } + } + + public data class DyeComponent(val color: DyeColor) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: DyeComponent) { + buffer.writeVarInt(value.color.id) + } + + override fun decode(buffer: BytesBuffer): DyeComponent = + DyeComponent(DyeColor.fromID(buffer.readVarInt())) + } + } + + public data class ProvidesTrimMaterialComponent(val material: IdOrX) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ProvidesTrimMaterialComponent) { + buffer.writeIdOrX(value.material) { material -> + writeMcString(material.suffix) + writePrefixed(material.overrides) { override -> + writeIdentifier(override.armorMaterialType) + writeMcString(override.overriddenAssetName) + } + writeTextComponent(material.description) + } + } + + override fun decode(buffer: BytesBuffer): ProvidesTrimMaterialComponent = + ProvidesTrimMaterialComponent(buffer.readIdOrX { + val suffix = readMcString() + val overrides = readPrefixed { + val armorMaterialType = readIdentifier() + val overriddenAssetName = readMcString() + TrimMaterialOverride(armorMaterialType, overriddenAssetName) + } + val description = readTextComponent() + TrimMaterial(suffix, overrides, description) + }) + } + } + + public data class OminousBottleAmplifierComponent(val amplifier: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: OminousBottleAmplifierComponent) { + buffer.writeVarInt(value.amplifier) + } + + override fun decode(buffer: BytesBuffer): OminousBottleAmplifierComponent = + OminousBottleAmplifierComponent(buffer.readVarInt()) + } + } + + public data class JukeboxPlayableComponent(val jukeboxSong: IdOrX) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: JukeboxPlayableComponent) { + buffer.writeIdOrX(value.jukeboxSong) { song -> + writeIdOrX(song.sound) { writeSoundEvent(it) } + writeTextComponent(song.description) + writeFloat(song.duration) + writeVarInt(song.output) + } + } + + override fun decode(buffer: BytesBuffer): JukeboxPlayableComponent = + JukeboxPlayableComponent(buffer.readIdOrX { + val sound = buffer.readIdOrX { readSoundEvent() } + val description = buffer.readTextComponent() + val duration = buffer.readFloat() + val output = buffer.readVarInt() + JukeboxSong(sound, description, duration, output) + }) + } + } + + public data class ProvidesBannerPatternsComponent(val key: IdSet) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ProvidesBannerPatternsComponent) { + buffer.writeIdSet(value.key) + } + + override fun decode(buffer: BytesBuffer): ProvidesBannerPatternsComponent = + ProvidesBannerPatternsComponent(buffer.readIdSet()) + } + } + + public data class RecipesComponent(val data: NBTCompound) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: RecipesComponent) { + buffer.writeNetworkNBTCompound(value.data) + } + + override fun decode(buffer: BytesBuffer): RecipesComponent = + RecipesComponent(buffer.readNetworkNBTCompound()) + } + } + + public data class LodestoneTrackerComponent( + val hasGlobalPosition: Boolean, + val dimension: Identifier?, + val position: BlockPos?, + val tracked: Boolean, + ) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: LodestoneTrackerComponent) { + buffer.writeBoolean(value.hasGlobalPosition) + if (value.hasGlobalPosition) buffer.writeIdentifier(value.dimension!!) + if (value.hasGlobalPosition) buffer.writeBlockPos(value.position!!) + buffer.writeBoolean(value.tracked) + } + + override fun decode(buffer: BytesBuffer): LodestoneTrackerComponent { + val hasGlobalPosition = buffer.readBoolean() + val dimension = if (hasGlobalPosition) buffer.readIdentifier() else null + val position = if (hasGlobalPosition) buffer.readBlockPos() else null + val tracked = buffer.readBoolean() + return LodestoneTrackerComponent(hasGlobalPosition, dimension, position, tracked) + } + } + } + + public data class FireworkExplosionComponent(val explosion: FireworkExplosionAttribute) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: FireworkExplosionComponent) { + buffer.writeFireworkExplosion(value.explosion) + } + + override fun decode(buffer: BytesBuffer): FireworkExplosionComponent = + FireworkExplosionComponent(buffer.readFireworkExplosion()) + } + } + + public data class FireworksComponent(val flightDuration: Int, val explosions: List) : + DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: FireworksComponent) { + buffer.writeVarInt(value.flightDuration) + buffer.writePrefixed(value.explosions) { writeFireworkExplosion(it) } + } + + override fun decode(buffer: BytesBuffer): FireworksComponent { + val duration = buffer.readVarInt() + val explosions = buffer.readPrefixed { readFireworkExplosion() } + return FireworksComponent(duration, explosions) + } + } + } + + public data class ProfileComponent(val profile: ResolvableProfile) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ProfileComponent) { + buffer.writeResolvableProfile(value.profile) + } + + override fun decode(buffer: BytesBuffer): ProfileComponent = + ProfileComponent(buffer.readResolvableProfile()) + } + } + + public data class NoteBlockSoundComponent(val sound: Identifier) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: NoteBlockSoundComponent) { + buffer.writeIdentifier(value.sound) + } + + override fun decode(buffer: BytesBuffer): NoteBlockSoundComponent = + NoteBlockSoundComponent(buffer.readIdentifier()) + } + } + + public data class BannerPatternsComponent(val layers: List) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: BannerPatternsComponent) { + buffer.writePrefixed(value.layers) { writeBannerPatternLayer(it) } + } + + override fun decode(buffer: BytesBuffer): BannerPatternsComponent = + BannerPatternsComponent(buffer.readPrefixed { readBannerPatternLayer() }) + } + } + + public data class BaseColorComponent(val color: DyeColor) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: BaseColorComponent) { + buffer.writeVarInt(value.color.id) + } + + override fun decode(buffer: BytesBuffer): BaseColorComponent = + BaseColorComponent(DyeColor.fromID(buffer.readVarInt())) + } + } + + public data class PotDecorationsComponent(val decorations: List) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: PotDecorationsComponent) { + buffer.writePrefixed(value.decorations) { writeVarInt(it) } + } + + override fun decode(buffer: BytesBuffer): PotDecorationsComponent = + PotDecorationsComponent(buffer.readPrefixed { readVarInt() }) + } + } + + public data class ContainerComponent(val items: List) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ContainerComponent) { + buffer.writePrefixed(value.items) { writeSlot(it) } + } + + override fun decode(buffer: BytesBuffer): ContainerComponent { + return ContainerComponent(buffer.readPrefixed { readSlot() }) + } + } + } + + public data class BlockStateComponent(val properties: List) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: BlockStateComponent) { + buffer.writePrefixed(value.properties) { + writeMcString(it.name) + writeMcString(it.value) + } + } + + override fun decode(buffer: BytesBuffer): BlockStateComponent = BlockStateComponent(buffer.readPrefixed { + val name = readMcString() + val value = readMcString() + BlockStateProperty(name, value) + }) + } + } + + public data class BeesComponent(val bees: List) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: BeesComponent) { + buffer.writePrefixed(value.bees) { bee -> + writeVarInt(bee.entityType) + writeNetworkNBTCompound(bee.entityData) + writeVarInt(bee.ticksInHive) + writeVarInt(bee.minTicksInHive) + } + } + + override fun decode(buffer: BytesBuffer): BeesComponent = + BeesComponent(buffer.readPrefixed { + val entityType = readVarInt() + val entityData = readNetworkNBTCompound() + val ticksInHive = readVarInt() + val minTicksInHive = readVarInt() + BeeAttribute(entityType, entityData, ticksInHive, minTicksInHive) + }) + } + } + + public data class LockComponent(val key: NBTCompound) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: LockComponent) { + buffer.writeNetworkNBTCompound(value.key) + } + + override fun decode(buffer: BytesBuffer): LockComponent = + LockComponent(buffer.readNetworkNBTCompound()) + } + } + + public data class ContainerLootComponent(val data: NBTCompound) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ContainerLootComponent) { + buffer.writeNetworkNBTCompound(value.data) + } + + override fun decode(buffer: BytesBuffer): ContainerLootComponent = + ContainerLootComponent(buffer.readNetworkNBTCompound()) + } + } + + public data class BreakSoundComponent(val sound: IdOrX) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: BreakSoundComponent) { + buffer.writeIdOrX(value.sound) { writeSoundEvent(it) } + } + + override fun decode(buffer: BytesBuffer): BreakSoundComponent = + BreakSoundComponent(buffer.readIdOrX { readSoundEvent() }) + } + } + + public data class SulfurCubeContentComponent(val content: Slot) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: SulfurCubeContentComponent) { + buffer.writeSlot(value.content) + } + + override fun decode(buffer: BytesBuffer): SulfurCubeContentComponent = + SulfurCubeContentComponent(buffer.readSlot()) + } + } + + public data class VillagerVariantComponent(val variant: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: VillagerVariantComponent) { + buffer.writeVarInt(value.variant) + } + + override fun decode(buffer: BytesBuffer): VillagerVariantComponent = + VillagerVariantComponent(buffer.readVarInt()) + } + } + + public data class WolfVariantComponent(val variant: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: WolfVariantComponent) { + buffer.writeVarInt(value.variant) + } + + override fun decode(buffer: BytesBuffer): WolfVariantComponent = + WolfVariantComponent(buffer.readVarInt()) + } + } + + public data class WolfSoundVariantComponent(val variant: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: WolfSoundVariantComponent) { + buffer.writeVarInt(value.variant) + } + + override fun decode(buffer: BytesBuffer): WolfSoundVariantComponent = + WolfSoundVariantComponent(buffer.readVarInt()) + } + } + + public data class WolfCollarComponent(val color: DyeColor) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: WolfCollarComponent) { + buffer.writeVarInt(value.color.id) + } + + override fun decode(buffer: BytesBuffer): WolfCollarComponent = + WolfCollarComponent(DyeColor.fromID(buffer.readVarInt())) + } + } + + public data class FoxVariantComponent(val variant: FoxVariantType) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: FoxVariantComponent) { + buffer.writeVarInt(value.variant.id) + } + + override fun decode(buffer: BytesBuffer): FoxVariantComponent = + FoxVariantComponent(FoxVariantType.fromID(buffer.readVarInt())) + } + } + + public data class SalmonSizeComponent(val type: SalmonSizeType) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: SalmonSizeComponent) { + buffer.writeVarInt(value.type.id) + } + + override fun decode(buffer: BytesBuffer): SalmonSizeComponent = + SalmonSizeComponent(SalmonSizeType.fromID(buffer.readVarInt())) + } + } + + public data class ParrotVariantComponent(val variant: ParrotVariantType) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ParrotVariantComponent) { + buffer.writeVarInt(value.variant.id) + } + + override fun decode(buffer: BytesBuffer): ParrotVariantComponent = + ParrotVariantComponent(ParrotVariantType.fromID(buffer.readVarInt())) + } + } + + public data class TropicalFishPatternComponent(val pattern: TropicalFishPatternType) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: TropicalFishPatternComponent) { + buffer.writeVarInt(value.pattern.id) + } + + override fun decode(buffer: BytesBuffer): TropicalFishPatternComponent = + TropicalFishPatternComponent(TropicalFishPatternType.fromID(buffer.readVarInt())) + } + } + + public data class TropicalFishBaseColorComponent(val color: DyeColor) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: TropicalFishBaseColorComponent) { + buffer.writeVarInt(value.color.id) + } + + override fun decode(buffer: BytesBuffer): TropicalFishBaseColorComponent = + TropicalFishBaseColorComponent(DyeColor.fromID(buffer.readVarInt())) + } + } + + public data class TropicalFishPatternColorComponent(val color: DyeColor) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: TropicalFishPatternColorComponent) { + buffer.writeVarInt(value.color.id) + } + + override fun decode(buffer: BytesBuffer): TropicalFishPatternColorComponent = + TropicalFishPatternColorComponent(DyeColor.fromID(buffer.readVarInt())) + } + } + + public data class MooshroomVariantComponent(val variant: MooshroomVariantType) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: MooshroomVariantComponent) { + buffer.writeVarInt(value.variant.id) + } + + override fun decode(buffer: BytesBuffer): MooshroomVariantComponent = + MooshroomVariantComponent(MooshroomVariantType.fromID(buffer.readVarInt())) + } + } + + public data class RabbitVariantComponent(val variant: RabbitVariantType) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: RabbitVariantComponent) { + buffer.writeVarInt(value.variant.id) + } + + override fun decode(buffer: BytesBuffer): RabbitVariantComponent = + RabbitVariantComponent(RabbitVariantType.fromID(buffer.readVarInt())) + } + } + + public data class PigVariantComponent(val variant: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: PigVariantComponent) { + buffer.writeVarInt(value.variant) + } + + override fun decode(buffer: BytesBuffer): PigVariantComponent = + PigVariantComponent(buffer.readVarInt()) + } + } + + public data class PigSoundVariantComponent(val variant: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: PigSoundVariantComponent) { + buffer.writeVarInt(value.variant) + } + + override fun decode(buffer: BytesBuffer): PigSoundVariantComponent = + PigSoundVariantComponent(buffer.readVarInt()) + } + } + + public data class CowVariantComponent(val variant: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: CowVariantComponent) { + buffer.writeVarInt(value.variant) + } + + override fun decode(buffer: BytesBuffer): CowVariantComponent = + CowVariantComponent(buffer.readVarInt()) + } + } + + public data class CowSoundVariantComponent(val variant: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: CowSoundVariantComponent) { + buffer.writeVarInt(value.variant) + } + + override fun decode(buffer: BytesBuffer): CowSoundVariantComponent = + CowSoundVariantComponent(buffer.readVarInt()) + } + } + + public data class ChickenVariantComponent(val variant: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ChickenVariantComponent) { + buffer.writeVarInt(value.variant) + } + + override fun decode(buffer: BytesBuffer): ChickenVariantComponent = + ChickenVariantComponent(buffer.readVarInt()) + } + } + + public data class ChickenSoundVariantComponent(val variant: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ChickenSoundVariantComponent) { + buffer.writeVarInt(value.variant) + } + + override fun decode(buffer: BytesBuffer): ChickenSoundVariantComponent = + ChickenSoundVariantComponent(buffer.readVarInt()) + } + } + + public data class FrogVariantComponent(val variant: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: FrogVariantComponent) { + buffer.writeVarInt(value.variant) + } + + override fun decode(buffer: BytesBuffer): FrogVariantComponent = + FrogVariantComponent(buffer.readVarInt()) + } + } + + public data class HorseVariantComponent(val variant: HorseVariantType) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: HorseVariantComponent) { + buffer.writeVarInt(value.variant.id) + } + + override fun decode(buffer: BytesBuffer): HorseVariantComponent = + HorseVariantComponent(HorseVariantType.fromID(buffer.readVarInt())) + } + } + + public data class PaintingVariantComponent(val variant: PaintingVariantType) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: PaintingVariantComponent) { + buffer.writePaintingVariantType(value.variant) + } + + override fun decode(buffer: BytesBuffer): PaintingVariantComponent = + PaintingVariantComponent(buffer.readPaintingVariantType()) + } + } + + public data class LlamaVariantComponent(val variant: LlamaVariantType) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: LlamaVariantComponent) { + buffer.writeVarInt(value.variant.id) + } + + override fun decode(buffer: BytesBuffer): LlamaVariantComponent = + LlamaVariantComponent(LlamaVariantType.fromID(buffer.readVarInt())) + } + } + + public data class AxolotlVariantComponent(val variant: AxolotlVariantType) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: AxolotlVariantComponent) { + buffer.writeVarInt(value.variant.id) + } + + override fun decode(buffer: BytesBuffer): AxolotlVariantComponent = + AxolotlVariantComponent(AxolotlVariantType.fromID(buffer.readVarInt())) + } + } + + public data class ZombieNautilusVariantComponent(val variant: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ZombieNautilusVariantComponent) { + buffer.writeVarInt(value.variant) + } + + override fun decode(buffer: BytesBuffer): ZombieNautilusVariantComponent = + ZombieNautilusVariantComponent(buffer.readVarInt()) + } + } + + public data class CatVariantComponent(val variant: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: CatVariantComponent) { + buffer.writeVarInt(value.variant) + } + + override fun decode(buffer: BytesBuffer): CatVariantComponent = + CatVariantComponent(buffer.readVarInt()) + } + } + + public data class CatSoundVariantComponent(val variant: Int) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: CatSoundVariantComponent) { + buffer.writeVarInt(value.variant) + } + + override fun decode(buffer: BytesBuffer): CatSoundVariantComponent = + CatSoundVariantComponent(buffer.readVarInt()) + } + } + + public data class CatCollarComponent(val color: DyeColor) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: CatCollarComponent) { + buffer.writeVarInt(value.color.id) + } + + override fun decode(buffer: BytesBuffer): CatCollarComponent = + CatCollarComponent(DyeColor.fromID(buffer.readVarInt())) + } + } + + public data class SheepColorComponent(val color: DyeColor) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: SheepColorComponent) { + buffer.writeVarInt(value.color.id) + } + + override fun decode(buffer: BytesBuffer): SheepColorComponent = + SheepColorComponent(DyeColor.fromID(buffer.readVarInt())) + } + } + + public data class ShulkerColorComponent(val color: DyeColor) : DataComponent { + internal companion object Codec : PacketCodec { + override fun encode(buffer: BytesBuffer, value: ShulkerColorComponent) { + buffer.writeVarInt(value.color.id) + } + + override fun decode(buffer: BytesBuffer): ShulkerColorComponent = + ShulkerColorComponent(DyeColor.fromID(buffer.readVarInt())) + } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/AttributeModifierEntry.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/AttributeModifierEntry.kt new file mode 100644 index 0000000..36d1c9d --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/AttributeModifierEntry.kt @@ -0,0 +1,18 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +import cn.rtast.libmc.protocol.protocol.game.Identifier + +public data class AttributeModifierEntry( + val attributeId: Int, + val modifierId: Identifier, + val value: Double, + val operation: AttributeOperation, + val slot: AttributeSlot, +) diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/AttributeOperation.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/AttributeOperation.kt new file mode 100644 index 0000000..e537507 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/AttributeOperation.kt @@ -0,0 +1,17 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +public enum class AttributeOperation(public val id: Int) { + ADD(0), + MULTIPLY_BASE(1), + MULTIPLY_TOTAL(2); + + public companion object { + public fun fromID(id: Int): AttributeOperation = entries.first { it.id == id } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/AttributeSlot.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/AttributeSlot.kt new file mode 100644 index 0000000..fef1355 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/AttributeSlot.kt @@ -0,0 +1,24 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +public enum class AttributeSlot(public val id: Int) { + ANY(0), + MAINHAND(1), + OFFHAND(2), + HAND(3), + FEET(4), + LEGS(5), + CHEST(6), + HEAD(7), + ARMOR(8), + BODY(9); + + public companion object { + public fun fromID(id: Int): AttributeSlot = entries.first { it.id == id } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/BannerPattern.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/BannerPattern.kt new file mode 100644 index 0000000..0a2ae81 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/BannerPattern.kt @@ -0,0 +1,41 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +import cn.rtast.libmc.network.BytesBuffer +import cn.rtast.libmc.primitives.* +import cn.rtast.libmc.protocol.protocol.game.Identifier +import cn.rtast.libmc.protocol.protocol.game.color.DyeColor +import cn.rtast.libmc.protocol.protocol.game.readIdentifier +import cn.rtast.libmc.protocol.protocol.game.writeIdentifier + +public data class BannerPattern(val assetId: Identifier, val translationKey: String) + +public data class BannerPatternLayer(val pattern: IdOrX, val color: DyeColor) + +internal fun BytesBuffer.readBannerPatternLayer(): BannerPatternLayer { + val pattern = readIdOrX { readBannerPattern() } + val color = DyeColor.fromID(readVarInt()) + return BannerPatternLayer(pattern, color) +} + +internal fun BytesBuffer.writeBannerPatternLayer(layer: BannerPatternLayer) { + writeIdOrX(layer.pattern) { writeBannerPattern(it) } + writeVarInt(layer.color.id) +} + +internal fun BytesBuffer.readBannerPattern(): BannerPattern { + val assetId = readIdentifier() + val translationKey = readMcString() + return BannerPattern(assetId, translationKey) +} + +internal fun BytesBuffer.writeBannerPattern(pattern: BannerPattern) { + writeIdentifier(pattern.assetId) + writeMcString(pattern.translationKey) +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/BeeAttribute.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/BeeAttribute.kt new file mode 100644 index 0000000..16600ec --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/BeeAttribute.kt @@ -0,0 +1,17 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +import cn.rtast.libmc.nbt.NBTCompound + +public data class BeeAttribute( + val entityType: Int, + val entityData: NBTCompound, + val ticksInHive: Int, + val minTicksInHive: Int, +) \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/BlockPredicate.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/BlockPredicate.kt new file mode 100644 index 0000000..068879d --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/BlockPredicate.kt @@ -0,0 +1,137 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +import cn.rtast.libmc.nbt.NBTCompound +import cn.rtast.libmc.network.BytesBuffer +import cn.rtast.libmc.primitives.* +import cn.rtast.libmc.protocol.protocol.game.data.component.DataComponent +import cn.rtast.libmc.protocol.protocol.util.readNetworkNBTCompound +import cn.rtast.libmc.protocol.protocol.util.writeNetworkNBTCompound +import cn.rtast.libmc.protocol.registry.readDataComponent +import cn.rtast.libmc.protocol.registry.writeDataComponent + +public data class BlockPredicate( + val blocks: IdSet?, + val properties: List?, + val nbt: NBTCompound?, + val components: List, + val partialComponents: List, +) + +public sealed interface PropertyMatcher { + public val name: String + + public data class Exact(override val name: String, val value: String) : + PropertyMatcher + + public data class Ranged(override val name: String, val minValue: String?, val maxValue: String?) : + PropertyMatcher +} + +public data class ExactDataComponentMatcher(val typeId: Int, val value: DataComponent) + +public enum class PartialComponentPredicateType(public val id: Int) { + DAMAGE(0), + ENCHANTMENTS(1), + STORED_ENCHANTMENTS(2), + POTION_CONTENTS(3), + CUSTOM_DATA(4), + CONTAINER(5), + BUNDLE_CONTENTS(6), + FIREWORK_EXPLOSION(7), + FIREWORKS(8), + WRITABLE_BOOK_CONTENT(9), + WRITTEN_BOOK_CONTENT(10), + ATTRIBUTE_MODIFIERS(11), + TRIM(12), + JUKEBOX_PLAYABLE(13); + + public companion object { + public fun fromID(id: Int): PartialComponentPredicateType = entries.first { it.id == id } + } +} + +public data class PartialDataComponentMatcher(val type: PartialComponentPredicateType, val nbt: NBTCompound) + + +internal fun BytesBuffer.readBlockPredicate(): BlockPredicate { + val blocks = readPrefixOptional { readIdSet() } + val properties = readPrefixOptional { readPrefixed { readPropertyMatcher() } } + val nbt = readPrefixOptional { readNetworkNBTCompound() } + val components = readPrefixed { readExactDataComponentMatcher() } + val partialComponents = readPrefixed { readPartialDataComponentMatcher() } + + return BlockPredicate( + blocks = blocks, + properties = properties, + nbt = nbt, + components = components, + partialComponents = partialComponents + ) +} + +internal fun BytesBuffer.writeBlockPredicate(value: BlockPredicate) { + writePrefixedOptional(value.blocks) { writeIdSet(it) } + writePrefixedOptional(value.properties) { list -> + writePrefixed(list) { writePropertyMatcher(it) } + } + writePrefixedOptional(value.nbt) { writeNetworkNBTCompound(it) } + writePrefixed(value.components) { writeExactDataComponentMatcher(it) } + writePrefixed(value.partialComponents) { writePartialDataComponentMatcher(it) } +} + +internal fun BytesBuffer.readPropertyMatcher(): PropertyMatcher { + val name = readMcString() + val isExactMatch = readBoolean() + return if (isExactMatch) { + PropertyMatcher.Exact(name, readMcString()) + } else { + val minValue = readPrefixOptional { readMcString() } + val maxValue = readPrefixOptional { readMcString() } + PropertyMatcher.Ranged(name, minValue, maxValue) + } +} + +internal fun BytesBuffer.writePropertyMatcher(value: PropertyMatcher) { + writeMcString(value.name) + when (value) { + is PropertyMatcher.Exact -> { + writeBoolean(true) + writeMcString(value.value) + } + + is PropertyMatcher.Ranged -> { + writeBoolean(false) + writePrefixedOptional(value.minValue) { writeMcString(it) } + writePrefixedOptional(value.maxValue) { writeMcString(it) } + } + } +} + +internal fun BytesBuffer.readExactDataComponentMatcher(): ExactDataComponentMatcher { + val typeId = readVarInt() + val component = readDataComponent(typeId) + return ExactDataComponentMatcher(typeId, component) +} + +internal fun BytesBuffer.writeExactDataComponentMatcher(value: ExactDataComponentMatcher) { + writeVarInt(value.typeId) + writeDataComponent(value.value) +} + +internal fun BytesBuffer.readPartialDataComponentMatcher(): PartialDataComponentMatcher { + val typeId = readVarInt() + val predicateNbt = readNetworkNBTCompound() + return PartialDataComponentMatcher(PartialComponentPredicateType.fromID(typeId), predicateNbt) +} + +internal fun BytesBuffer.writePartialDataComponentMatcher(value: PartialDataComponentMatcher) { + writeVarInt(value.type.id) + writeNetworkNBTCompound(value.nbt) +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/DamageReduction.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/DamageReduction.kt new file mode 100644 index 0000000..58c901e --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/DamageReduction.kt @@ -0,0 +1,17 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +import cn.rtast.libmc.primitives.IdSet + +public data class DamageReduction( + val horizontalBlockingAngle: Float, + val type: IdSet?, + val base: Float, + val factor: Float, +) diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/EnchantmentEntry.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/EnchantmentEntry.kt new file mode 100644 index 0000000..f5e3e44 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/EnchantmentEntry.kt @@ -0,0 +1,10 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +public data class EnchantmentEntry(val typeId: Int, val level: Int) \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/EquipmentSlot.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/EquipmentSlot.kt new file mode 100644 index 0000000..8c8b1db --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/EquipmentSlot.kt @@ -0,0 +1,22 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +public enum class EquipmentSlot(public val id: Int) { + MAINHAND(0), + FEET(1), + LEGS(2), + CHEST(3), + HEAD(4), + OFFHAND(5), + BODY(6); + + public companion object { + public fun fromID(id: Int): EquipmentSlot = entries.first { it.id == id } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/FireworkExplosionAttribute.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/FireworkExplosionAttribute.kt new file mode 100644 index 0000000..70f8990 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/FireworkExplosionAttribute.kt @@ -0,0 +1,47 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +import cn.rtast.libmc.network.BytesBuffer +import cn.rtast.libmc.primitives.readPrefixed +import cn.rtast.libmc.primitives.readVarInt +import cn.rtast.libmc.primitives.writePrefixed +import cn.rtast.libmc.primitives.writeVarInt + +public data class FireworkExplosionAttribute( + val shape: FireworkExplosionShape, + val colors: List, + val fadeColors: List, + val hasTrail: Boolean, + val hasTwinkle: Boolean, +) + +public enum class FireworkExplosionShape(public val id: Int) { + SmallBall(0), LargeBall(1), Star(2), Creeper(3), Burst(4); + + public companion object { + public fun fromID(id: Int): FireworkExplosionShape = entries.first { it.id == id } + } +} + +internal fun BytesBuffer.readFireworkExplosion(): FireworkExplosionAttribute { + val shape = FireworkExplosionShape.Companion.fromID(readVarInt()) + val colors = readPrefixed { readInt() } + val fadeColors = readPrefixed { readInt() } + val hasTrail = readBoolean() + val hasTwinkle = readBoolean() + return FireworkExplosionAttribute(shape, colors, fadeColors, hasTrail, hasTwinkle) +} + +internal fun BytesBuffer.writeFireworkExplosion(explosion: FireworkExplosionAttribute) { + writeVarInt(explosion.shape.id) + writePrefixed(explosion.colors) { writeInt(it) } + writePrefixed(explosion.fadeColors) { writeInt(it) } + writeBoolean(explosion.hasTrail) + writeBoolean(explosion.hasTwinkle) +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/InstrumentAttribute.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/InstrumentAttribute.kt new file mode 100644 index 0000000..b78ddf4 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/InstrumentAttribute.kt @@ -0,0 +1,19 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +import cn.rtast.libmc.primitives.IdOrX +import cn.rtast.libmc.protocol.protocol.game.chat.TextComponent +import cn.rtast.libmc.protocol.protocol.game.sound.SoundEvent + +public data class InstrumentAttribute( + val sound: IdOrX, + val useDuration: Float, + val range: Float, + val description: TextComponent, +) diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/ItemRarity.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/ItemRarity.kt new file mode 100644 index 0000000..6e05ed2 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/ItemRarity.kt @@ -0,0 +1,19 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +public enum class ItemRarity(public val id: Int) { + COMMON(0), + UNCOMMON(1), + RARE(2), + EPIC(3); + + public companion object { + public fun fromID(id: Int): ItemRarity = entries.first { it.id == id } + } +} diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/JukeboxSong.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/JukeboxSong.kt new file mode 100644 index 0000000..f567c36 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/JukeboxSong.kt @@ -0,0 +1,19 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +import cn.rtast.libmc.primitives.IdOrX +import cn.rtast.libmc.protocol.protocol.game.chat.TextComponent +import cn.rtast.libmc.protocol.protocol.game.sound.SoundEvent + +public data class JukeboxSong( + val sound: IdOrX, + val description: TextComponent, + val duration: Float, + val output: Int, +) \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/KineticWeaponCondition.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/KineticWeaponCondition.kt new file mode 100644 index 0000000..a789484 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/KineticWeaponCondition.kt @@ -0,0 +1,31 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +import cn.rtast.libmc.network.BytesBuffer +import cn.rtast.libmc.primitives.readVarInt +import cn.rtast.libmc.primitives.writeVarInt + +public data class KineticWeaponCondition( + val maxDurationTicks: Int, + val minSpeed: Float, + val minRelativeSpeed: Float, +) + +internal fun BytesBuffer.readKineticWeaponCondition(): KineticWeaponCondition { + val duration = readVarInt() + val minSpeed = readFloat() + val minRelativeSpeed = readFloat() + return KineticWeaponCondition(duration, minSpeed, minRelativeSpeed) +} + +internal fun BytesBuffer.writeKineticWeaponCondition(condition: KineticWeaponCondition) { + writeVarInt(condition.maxDurationTicks) + writeFloat(condition.minSpeed) + writeFloat(condition.minRelativeSpeed) +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/MapPostProcessingType.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/MapPostProcessingType.kt new file mode 100644 index 0000000..d9f8133 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/MapPostProcessingType.kt @@ -0,0 +1,16 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +public enum class MapPostProcessingType(public val id: Int) { + LOCK(0), SCALE(1); + + public companion object { + public fun fromID(id: Int): MapPostProcessingType = entries.first { it.id == id } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/StoredEnchantment.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/StoredEnchantment.kt new file mode 100644 index 0000000..5c248f4 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/StoredEnchantment.kt @@ -0,0 +1,10 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +public data class StoredEnchantment(val enchantmentId: Int, val level: Int) \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/SwingAnimationType.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/SwingAnimationType.kt new file mode 100644 index 0000000..a678eec --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/SwingAnimationType.kt @@ -0,0 +1,16 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +public enum class SwingAnimationType(public val id: Int) { + NONE(0), WHACK(1), STAB(2); + + public companion object { + public fun fromID(id: Int): SwingAnimationType = entries.first { it.id == id } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/ToolRule.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/ToolRule.kt new file mode 100644 index 0000000..9294fea --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/ToolRule.kt @@ -0,0 +1,16 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +import cn.rtast.libmc.primitives.IdSet + +public data class ToolRule( + val blocks: IdSet, + val speed: Float?, + val correctForDrops: Boolean?, +) \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/TrimMaterial.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/TrimMaterial.kt new file mode 100644 index 0000000..e24253b --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/TrimMaterial.kt @@ -0,0 +1,16 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +import cn.rtast.libmc.protocol.protocol.game.chat.TextComponent + +public data class TrimMaterial( + val suffix: String, + val overrides: List, + val description: TextComponent, +) diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/TrimMaterialOverride.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/TrimMaterialOverride.kt new file mode 100644 index 0000000..de5cb3d --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/TrimMaterialOverride.kt @@ -0,0 +1,12 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +import cn.rtast.libmc.protocol.protocol.game.Identifier + +public data class TrimMaterialOverride(val armorMaterialType: Identifier, val overriddenAssetName: String) diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/TrimPattern.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/TrimPattern.kt new file mode 100644 index 0000000..1d9180c --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/TrimPattern.kt @@ -0,0 +1,17 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +import cn.rtast.libmc.protocol.protocol.game.chat.TextComponent + +public data class TrimPattern( + val assetName: String, + val templateItem: Int, + val description: TextComponent, + val decal: Boolean, +) \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/WritablePage.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/WritablePage.kt new file mode 100644 index 0000000..1955fb8 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/WritablePage.kt @@ -0,0 +1,10 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +public data class WritablePage(val rawContent: String, val filteredContent: String?) diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/WrittenPage.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/WrittenPage.kt new file mode 100644 index 0000000..fb01590 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/data/component/attributes/WrittenPage.kt @@ -0,0 +1,12 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.data.component.attributes + +import cn.rtast.libmc.protocol.protocol.game.chat.TextComponent + +public data class WrittenPage(val rawContent: TextComponent, val filteredContent: TextComponent?) diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/AxolotlVariantType.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/AxolotlVariantType.kt new file mode 100644 index 0000000..0b0a415 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/AxolotlVariantType.kt @@ -0,0 +1,16 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.entity + +public enum class AxolotlVariantType(public val id: Int) { + LUCY(0), WILD(1), GOLD(2), CYAN(3), BLUE(4); + + public companion object { + public fun fromID(id: Int): AxolotlVariantType = entries.first { it.id == id } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/FoxVariantType.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/FoxVariantType.kt new file mode 100644 index 0000000..ab7d9f1 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/FoxVariantType.kt @@ -0,0 +1,16 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.entity + +public enum class FoxVariantType(public val id: Int) { + RED(0), SNOW(1); + + public companion object { + public fun fromID(id: Int): FoxVariantType = entries.first { it.id == id } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/HorseVariantType.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/HorseVariantType.kt new file mode 100644 index 0000000..842309e --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/HorseVariantType.kt @@ -0,0 +1,16 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.entity + +public enum class HorseVariantType(public val id: Int) { + WHITE(0), CREAMY(1), CHESTNUT(2), BROWN(3), BLACK(4), GRAY(5), DARK_BROWN(6); + + public companion object { + public fun fromID(id: Int): HorseVariantType = entries.first { it.id == id } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/LlamaVariantType.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/LlamaVariantType.kt new file mode 100644 index 0000000..bb2257f --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/LlamaVariantType.kt @@ -0,0 +1,16 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.entity + +public enum class LlamaVariantType(public val id: Int) { + CREAMY(0), WHITE(1), BROWN(2), GRAY(3); + + public companion object { + public fun fromID(id: Int): LlamaVariantType = entries.first { it.id == id } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/MooshroomVariantType.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/MooshroomVariantType.kt new file mode 100644 index 0000000..01c2ad0 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/MooshroomVariantType.kt @@ -0,0 +1,16 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.entity + +public enum class MooshroomVariantType(public val id: Int) { + RED(0), BROWN(1); + + public companion object { + public fun fromID(id: Int): MooshroomVariantType = entries.first { it.id == id } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/ParrotVariantType.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/ParrotVariantType.kt new file mode 100644 index 0000000..33445a2 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/ParrotVariantType.kt @@ -0,0 +1,16 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.entity + +public enum class ParrotVariantType(public val id: Int) { + RED_BLUE(0), BLUE(1), GREEN(2), YELLOW_BLUE(3), GRAY(4); + + public companion object { + public fun fromID(id: Int): ParrotVariantType = entries.first { it.id == id } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/RabbitVariantType.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/RabbitVariantType.kt new file mode 100644 index 0000000..03809dc --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/RabbitVariantType.kt @@ -0,0 +1,17 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.entity + +public enum class RabbitVariantType(public val id: Int) { + BROWN(0), WHITE(1), BLACK(2), WHITE_SPLOTCHED(3), + GOLD(4), SALT(5), EVIL(6); + + public companion object { + public fun fromID(id: Int): RabbitVariantType = entries.first { it.id == id } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/SalmonSizeType.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/SalmonSizeType.kt new file mode 100644 index 0000000..8106f27 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/SalmonSizeType.kt @@ -0,0 +1,16 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.entity + +public enum class SalmonSizeType(public val id: Int) { + SMALL(0), MEDIUM(1), LARGE(2); + + public companion object { + public fun fromID(id: Int): SalmonSizeType = entries.first { it.id == id } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/TropicalFishPatternType.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/TropicalFishPatternType.kt new file mode 100644 index 0000000..2092851 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/entity/TropicalFishPatternType.kt @@ -0,0 +1,27 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.entity + +public enum class TropicalFishPatternType(public val id: Int) { + KOB(0), + SUNSTREAK(1), + SNOOPER(2), + DASHER(3), + BRINELY(4), + SPOTTY(5), + FLOPPER(6), + STRIPEY(7), + GLITTER(8), + BLOCKFISH(9), + BETTY(10), + CLAYFISH(11); + + public companion object { + public fun fromID(id: Int): TropicalFishPatternType = entries.first { it.id == id } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/item/ItemUseAnimation.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/item/ItemUseAnimation.kt new file mode 100644 index 0000000..74e6ffd --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/item/ItemUseAnimation.kt @@ -0,0 +1,25 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.item + +public enum class ItemUseAnimation(public val id: Int) { + NONE(0), + EAT(1), + DRINK(2), + BLOCK(3), + BOW(4), + SPEAR(5), + CROSSBOW(6), + SPYGLASS(7), + TOOT_HORN(8), + BRUSH(9); + + public companion object { + public fun fromID(id: Int): ItemUseAnimation = entries.first { it.id == id } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/item/PaintingVariantType.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/item/PaintingVariantType.kt new file mode 100644 index 0000000..31ad928 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/item/PaintingVariantType.kt @@ -0,0 +1,43 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.item + +import cn.rtast.libmc.network.BytesBuffer +import cn.rtast.libmc.primitives.readPrefixOptional +import cn.rtast.libmc.primitives.writePrefixedOptional +import cn.rtast.libmc.protocol.protocol.game.Identifier +import cn.rtast.libmc.protocol.protocol.game.chat.TextComponent +import cn.rtast.libmc.protocol.protocol.game.chat.readTextComponent +import cn.rtast.libmc.protocol.protocol.game.chat.writeTextComponent +import cn.rtast.libmc.protocol.protocol.game.readIdentifier +import cn.rtast.libmc.protocol.protocol.game.writeIdentifier + +public data class PaintingVariantType( + val width: Int, + val height: Int, + val assetId: Identifier, + val title: TextComponent?, + val author: TextComponent?, +) + +internal fun BytesBuffer.readPaintingVariantType(): PaintingVariantType { + val width = readInt() + val height = readInt() + val assetId = readIdentifier() + val title = readPrefixOptional { readTextComponent() } + val author = readPrefixOptional { readTextComponent() } + return PaintingVariantType(width, height, assetId, title, author) +} + +internal fun BytesBuffer.writePaintingVariantType(variant: PaintingVariantType) { + writeInt(variant.width) + writeInt(variant.height) + writeIdentifier(variant.assetId) + writePrefixedOptional(variant.title) { writeTextComponent(it) } + writePrefixedOptional(variant.author) { writeTextComponent(it) } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/item/slot/HashedSlot.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/item/slot/HashedSlot.kt new file mode 100644 index 0000000..e36751a --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/item/slot/HashedSlot.kt @@ -0,0 +1,9 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.item.slot + diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/item/slot/Slot.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/item/slot/Slot.kt new file mode 100644 index 0000000..d2a6b90 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/item/slot/Slot.kt @@ -0,0 +1,59 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.item.slot + +import cn.rtast.libmc.network.BytesBuffer +import cn.rtast.libmc.primitives.readVarInt +import cn.rtast.libmc.primitives.writeVarInt +import cn.rtast.libmc.protocol.protocol.game.data.component.DataComponent +import cn.rtast.libmc.protocol.registry.readDataComponent +import cn.rtast.libmc.protocol.registry.writeDataComponent + +public typealias ItemStack = Slot + +public data class Slot( + val count: Int, + val itemId: Int?, + val componentsToAdd: List, + val componentsToRemove: List, +) { + val isEmpty: Boolean get() = count <= 0 + + public companion object { + public val EMPTY: Slot = Slot(0, null, emptyList(), emptyList()) + } +} + +internal fun BytesBuffer.readSlot(): Slot { + val count = readVarInt() + if (count <= 0) return Slot.EMPTY + val itemId = readVarInt() + val addCount = readVarInt() + val removeCount = readVarInt() + val componentsToAdd = ArrayList(addCount) + repeat(addCount) { + val componentId = readVarInt() + componentsToAdd.add(readDataComponent(componentId)) + } + val componentsToRemove = ArrayList(removeCount) + repeat(removeCount) { componentsToRemove.add(readVarInt()) } + return Slot(count, itemId, componentsToAdd, componentsToRemove) +} + +internal fun BytesBuffer.writeSlot(slot: Slot) { + if (slot.isEmpty || slot.itemId == null) { + writeVarInt(0) + return + } + writeVarInt(slot.count) + writeVarInt(slot.itemId) + writeVarInt(slot.componentsToAdd.size) + writeVarInt(slot.componentsToRemove.size) + for (component in slot.componentsToAdd) writeDataComponent(component) + for (typeId in slot.componentsToRemove) writeVarInt(typeId) +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/player/skin/TextureModelType.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/player/skin/TextureModelType.kt new file mode 100644 index 0000000..b7e64a4 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/player/skin/TextureModelType.kt @@ -0,0 +1,16 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.player.skin + +public enum class TextureModelType(public val id: Int) { + WIDE(0), SLIM(1); + + public companion object { + public fun fromID(id: Int): TextureModelType = entries.first { it.id == id } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/potion/ConsumeEffect.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/potion/ConsumeEffect.kt new file mode 100644 index 0000000..2267c8c --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/potion/ConsumeEffect.kt @@ -0,0 +1,90 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.potion + +import cn.rtast.libmc.network.BytesBuffer +import cn.rtast.libmc.primitives.IdSet +import cn.rtast.libmc.primitives.readIdSet +import cn.rtast.libmc.primitives.readPrefixed +import cn.rtast.libmc.primitives.readVarInt +import cn.rtast.libmc.primitives.writeIdSet +import cn.rtast.libmc.primitives.writePrefixed +import cn.rtast.libmc.primitives.writeVarInt +import cn.rtast.libmc.protocol.protocol.game.sound.SoundEvent +import cn.rtast.libmc.protocol.protocol.game.sound.readSoundEvent +import cn.rtast.libmc.protocol.protocol.game.sound.writeSoundEvent + +public sealed interface ConsumeEffect { + public data class ApplyEffects(val effects: List, val probability: Float) : ConsumeEffect + public data class RemoveEffects(val effects: IdSet) : ConsumeEffect + public data object ClearAllEffects : ConsumeEffect + public data class TeleportRandomly(val diameter: Float) : ConsumeEffect + public data class PlaySound(val sound: SoundEvent) : ConsumeEffect +} + + +internal fun BytesBuffer.readConsumeEffects(): List { + return readPrefixed { + when (val typeId = readVarInt()) { + 0 -> { + val effects = readPrefixed { readPotionEffect() } + val probability = readFloat() + ConsumeEffect.ApplyEffects(effects, probability) + } + + 1 -> { + val effects = readIdSet() + ConsumeEffect.RemoveEffects(effects) + } + + 2 -> ConsumeEffect.ClearAllEffects + 3 -> { + val diameter = readFloat() + ConsumeEffect.TeleportRandomly(diameter) + } + + 4 -> { + val sound = readSoundEvent() + ConsumeEffect.PlaySound(sound) + } + + else -> throw IllegalArgumentException("Unknown ConsumeEffect type ID: $typeId") + } + } +} + +internal fun BytesBuffer.writeConsumeEffects(effects: List) { + writePrefixed(effects) { effect -> + when (effect) { + is ConsumeEffect.ApplyEffects -> { + writeVarInt(0) + writePrefixed(effect.effects) { writePotionEffect(it) } + writeFloat(effect.probability) + } + + is ConsumeEffect.RemoveEffects -> { + writeVarInt(1) + writeIdSet(effect.effects) + } + + is ConsumeEffect.ClearAllEffects -> { + writeVarInt(2) + } + + is ConsumeEffect.TeleportRandomly -> { + writeVarInt(3) + writeFloat(effect.diameter) + } + + is ConsumeEffect.PlaySound -> { + writeVarInt(4) + writeSoundEvent(effect.sound) + } + } + } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/potion/PotionEffect.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/potion/PotionEffect.kt new file mode 100644 index 0000000..2c24652 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/potion/PotionEffect.kt @@ -0,0 +1,45 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.potion + +import cn.rtast.libmc.network.BytesBuffer +import cn.rtast.libmc.primitives.readPrefixOptional +import cn.rtast.libmc.primitives.readVarInt +import cn.rtast.libmc.primitives.writePrefixedOptional +import cn.rtast.libmc.primitives.writeVarInt + +public data class PotionEffect( + val effectId: Int, + val amplifier: Int, + val duration: Int, + val ambient: Boolean, + val showParticles: Boolean, + val showIcon: Boolean, + val hideEffect: PotionEffect?, +) + +internal fun BytesBuffer.readPotionEffect(): PotionEffect { + val effectId = readVarInt() + val amplifier = readVarInt() + val duration = readVarInt() + val ambient = readBoolean() + val showParticles = readBoolean() + val showIcon = readBoolean() + val hideEffect = readPrefixOptional { readPotionEffect() } + return PotionEffect(effectId, amplifier, duration, ambient, showParticles, showIcon, hideEffect) +} + +internal fun BytesBuffer.writePotionEffect(effect: PotionEffect) { + writeVarInt(effect.effectId) + writeVarInt(effect.amplifier) + writeVarInt(effect.duration) + writeBoolean(effect.ambient) + writeBoolean(effect.showParticles) + writeBoolean(effect.showIcon) + writePrefixedOptional(effect.hideEffect) { writePotionEffect(it) } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/potion/SuspiciousStewEffect.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/potion/SuspiciousStewEffect.kt new file mode 100644 index 0000000..09d121c --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/potion/SuspiciousStewEffect.kt @@ -0,0 +1,28 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.potion + +import cn.rtast.libmc.network.BytesBuffer +import cn.rtast.libmc.primitives.readVarInt +import cn.rtast.libmc.primitives.writeVarInt + +public data class SuspiciousStewEffect(val effectId: Int, val duration: Int) + +internal fun BytesBuffer.readSuspiciousStewEffect(): SuspiciousStewEffect { + val effectId = readVarInt() + val duration = readVarInt() + return SuspiciousStewEffect( + effectId = effectId, + duration = duration + ) +} + +internal fun BytesBuffer.writeSuspiciousStewEffect(effect: SuspiciousStewEffect) { + writeVarInt(effect.effectId) + writeVarInt(effect.duration) +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/session/ResolvableProfile.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/session/ResolvableProfile.kt new file mode 100644 index 0000000..2450cc6 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/session/ResolvableProfile.kt @@ -0,0 +1,69 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.session + +import cn.rtast.libmc.network.BytesBuffer +import cn.rtast.libmc.primitives.* +import cn.rtast.libmc.protocol.protocol.game.Identifier +import cn.rtast.libmc.protocol.protocol.game.player.skin.TextureModelType +import cn.rtast.libmc.protocol.protocol.game.readIdentifier +import cn.rtast.libmc.protocol.protocol.game.writeIdentifier +import kotlin.uuid.Uuid + +public data class ResolvableProfile( + val profile: UnpackedProfile, + val body: Identifier?, + val cape: Identifier?, + val elytra: Identifier?, + val model: TextureModelType?, +) { + public sealed interface UnpackedProfile { + public data class PartialProfile( + val username: String?, + val uuid: Uuid?, + val properties: List, + ) : UnpackedProfile + + public data class CompleteProfile(val profile: GameProfile) : UnpackedProfile + } +} + +internal fun BytesBuffer.readResolvableProfile(): ResolvableProfile { + val kind = readVarInt() + val profile = if (kind == 0) { + val username = readPrefixOptional { readMcString() } + val uuid = readPrefixOptional { readUuid() } + val properties = readPrefixed { GameProfile.Property.decode(this) } + ResolvableProfile.UnpackedProfile.PartialProfile(username, uuid, properties) + } else ResolvableProfile.UnpackedProfile.CompleteProfile(GameProfile.decode(this)) + val body = readPrefixOptional { readIdentifier() } + val cape = readPrefixOptional { readIdentifier() } + val elytra = readPrefixOptional { readIdentifier() } + val model = readPrefixOptional { TextureModelType.fromID(readVarInt()) } + return ResolvableProfile(profile, body, cape, elytra, model) +} + +internal fun BytesBuffer.writeResolvableProfile(profile: ResolvableProfile) { + when (profile.profile) { + is ResolvableProfile.UnpackedProfile.CompleteProfile -> { + writeVarInt(1) + GameProfile.encode(this, profile.profile.profile) + } + + is ResolvableProfile.UnpackedProfile.PartialProfile -> { + writeVarInt(0) + writePrefixedOptional(profile.profile.username) { writeMcString(it) } + writePrefixedOptional(profile.profile.uuid) { writeUuid(it) } + writePrefixed(profile.profile.properties) { GameProfile.Property.encode(this, it) } + } + } + writePrefixedOptional(profile.body) { writeIdentifier(it) } + writePrefixedOptional(profile.cape) { writeIdentifier(it) } + writePrefixedOptional(profile.elytra) { writeIdentifier(it) } + writePrefixedOptional(profile.model) { writeVarInt(it.id) } +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/sound/SoundEvent.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/sound/SoundEvent.kt index 442375c..74f9964 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/sound/SoundEvent.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/sound/SoundEvent.kt @@ -19,7 +19,7 @@ public data class SoundEvent(val name: Identifier, val hasFixedRange: Boolean, v internal fun BytesBuffer.readSoundEvent(): SoundEvent { val name = readIdentifier() val hasFixedRange = readBoolean() - val fixedRange = readOptional { readFloat() } + val fixedRange = readOptional(hasFixedRange) { readFloat() } return SoundEvent(name, hasFixedRange, fixedRange) } diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/world/GlobalPos.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/world/GlobalPos.kt new file mode 100644 index 0000000..4e96738 --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/game/world/GlobalPos.kt @@ -0,0 +1,13 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + + +package cn.rtast.libmc.protocol.protocol.game.world + +import cn.rtast.libmc.protocol.protocol.game.Identifier +import cn.rtast.libmc.protocol.protocol.game.block.BlockPos + +public data class GlobalPos(val dimension: Identifier, val pos: BlockPos) \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/session/SessionEvent.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/session/SessionEvent.kt index dd7da1b..39a65c1 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/session/SessionEvent.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/session/SessionEvent.kt @@ -13,4 +13,12 @@ import cn.rtast.libmc.protocol.protocol.state.ProtocolState public sealed interface SessionEvent { public data class DisconnectedEvent(val reason: TextComponent, val state: ProtocolState) : SessionEvent public object ConnectedEvent : SessionEvent + public sealed interface ChangedState : SessionEvent { + public data object STATUS : ChangedState + public data object HANDSHAKE : ChangedState + public data object LOGIN : ChangedState + public data object CONFIGURATION : ChangedState + public data object PLAY : ChangedState + public data object DISCONNECTED : ChangedState + } } \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/registry/DataComponentRegistry.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/registry/DataComponentRegistry.kt new file mode 100644 index 0000000..71bc30d --- /dev/null +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/registry/DataComponentRegistry.kt @@ -0,0 +1,171 @@ +/* + * Copyright © 2026 RTAkland + * Author: RTAkland + * Date: 2026/9/10 + */ + +package cn.rtast.libmc.protocol.registry + +import cn.rtast.libmc.network.BytesBuffer +import cn.rtast.libmc.packet.PacketCodec +import cn.rtast.libmc.primitives.writeVarInt +import cn.rtast.libmc.protocol.protocol.game.data.component.DataComponent +import kotlin.reflect.KClass + +internal object DataComponentRegistry { + private val codecMap = mutableMapOf>() + private val classToIdMap = mutableMapOf, Int>() + private lateinit var codecArray: Array> + + private fun register(kClass: KClass, codec: PacketCodec) { + val id = codecMap.size + codecMap[id] = codec + classToIdMap[kClass] = id + } + + inline fun register(codec: PacketCodec) = register(T::class, codec) + + fun freeze() { + val maxId = codecMap.keys.maxOrNull() ?: -1 + codecArray = Array(maxId + 1) { index -> + @Suppress("UNCHECKED_CAST") + codecMap[index] as? PacketCodec ?: error("Missing component codec for $index") + } + codecMap.clear() + } + + internal fun read(typeId: Int, buffer: BytesBuffer): DataComponent { + val codec = codecArray.getOrNull(typeId) ?: error("Unknown DataComponent ID: $typeId") + return codec.decode(buffer) + } + + internal fun write(buffer: BytesBuffer, component: DataComponent) { + val typeId = classToIdMap[component::class] ?: error("Unregistered DataComponent class: ${component::class}") + val codec = codecArray[typeId] + buffer.writeVarInt(typeId) + codec.encode(buffer, component) + } + + init { + register(DataComponent.CustomDataComponent) + register(DataComponent.MaxStackSizeComponent) + register(DataComponent.MaxDamageComponent) + register(DataComponent.DamageComponent) + register(DataComponent.UnbreakableComponent) + register(DataComponent.UseEffectsComponent) + register(DataComponent.CustomNameComponent) + register(DataComponent.MinimumAttackChargeComponent) + register(DataComponent.DamageTypeComponent) + register(DataComponent.ItemNameComponent) + register(DataComponent.ItemModelComponent) + register(DataComponent.LoreComponent) + register(DataComponent.RarityComponent) + register(DataComponent.EnchantmentsComponent) + register(DataComponent.CanPlaceOnComponent) + register(DataComponent.CanBreakComponent) + register(DataComponent.AttributeModifiersComponent) + register(DataComponent.CustomModelDataComponent) + register(DataComponent.TooltipDisplayComponent) + register(DataComponent.RepairCostComponent) + register(DataComponent.CreativeSlotLockComponent) + register(DataComponent.EnchantmentGlintOverrideComponent) + register(DataComponent.IntangibleProjectileComponent) + register(DataComponent.FoodComponent) + register(DataComponent.ConsumableComponent) + register(DataComponent.UseRemainderComponent) + register(DataComponent.UseCooldownComponent) + register(DataComponent.DamageResistantComponent) + register(DataComponent.ToolComponent) + register(DataComponent.WeaponComponent) + register(DataComponent.AttackRangeComponent) + register(DataComponent.EnchantableComponent) + register(DataComponent.EquippableComponent) + register(DataComponent.RepairableComponent) + register(DataComponent.GliderComponent) + register(DataComponent.TooltipStyleComponent) + register(DataComponent.DeathProtectionComponent) + register(DataComponent.BlocksAttacksComponent) + register(DataComponent.PiercingWeaponComponent) + register(DataComponent.KineticWeaponComponent) + register(DataComponent.SwingAnimationComponent) + register(DataComponent.AdditionalTradeCostComponent) + register(DataComponent.StoredEnchantmentsComponent) + register(DataComponent.DyeComponent) + register(DataComponent.DyedColorComponent) + register(DataComponent.MapColorComponent) + register(DataComponent.MapIdComponent) + register(DataComponent.MapDecorationsComponent) + register(DataComponent.MapPostProcessingComponent) + register(DataComponent.ChargedProjectilesComponent) + register(DataComponent.BundleContentsComponent) + register(DataComponent.PotionContentsComponent) + register(DataComponent.PotionDurationScaleComponent) + register(DataComponent.SuspiciousStewEffectsComponent) + register(DataComponent.WritableBookContentComponent) + register(DataComponent.WrittenBookContentComponent) + register(DataComponent.TrimComponent) + register(DataComponent.DebugStickStateComponent) + register(DataComponent.EntityDataComponent) + register(DataComponent.BucketEntityDataComponent) + register(DataComponent.BlockEntityDataComponent) + register(DataComponent.InstrumentComponent) + register(DataComponent.ProvidesTrimMaterialComponent) + register(DataComponent.OminousBottleAmplifierComponent) + register(DataComponent.JukeboxPlayableComponent) + register(DataComponent.ProvidesBannerPatternsComponent) + register(DataComponent.RecipesComponent) + register(DataComponent.LodestoneTrackerComponent) + register(DataComponent.FireworkExplosionComponent) + register(DataComponent.FireworksComponent) + register(DataComponent.ProfileComponent) + register(DataComponent.NoteBlockSoundComponent) + register(DataComponent.BannerPatternsComponent) + register(DataComponent.BaseColorComponent) + register(DataComponent.PotDecorationsComponent) + register(DataComponent.ContainerComponent) + register(DataComponent.BlockStateComponent) + register(DataComponent.BeesComponent) + register(DataComponent.SulfurCubeContentComponent) + register(DataComponent.LockComponent) + register(DataComponent.ContainerLootComponent) + register(DataComponent.BreakSoundComponent) + register(DataComponent.VillagerVariantComponent) + register(DataComponent.WolfVariantComponent) + register(DataComponent.WolfSoundVariantComponent) + register(DataComponent.WolfCollarComponent) + register(DataComponent.FoxVariantComponent) + register(DataComponent.SalmonSizeComponent) + register(DataComponent.ParrotVariantComponent) + register(DataComponent.TropicalFishPatternComponent) + register(DataComponent.TropicalFishBaseColorComponent) + register(DataComponent.TropicalFishPatternColorComponent) + register(DataComponent.MooshroomVariantComponent) + register(DataComponent.RabbitVariantComponent) + register(DataComponent.PigVariantComponent) + register(DataComponent.PigSoundVariantComponent) + register(DataComponent.CowVariantComponent) + register(DataComponent.CowSoundVariantComponent) + register(DataComponent.ChickenVariantComponent) + register(DataComponent.ChickenSoundVariantComponent) + register(DataComponent.ZombieNautilusVariantComponent) + register(DataComponent.FrogVariantComponent) + register(DataComponent.HorseVariantComponent) + register(DataComponent.PaintingVariantComponent) + register(DataComponent.LlamaVariantComponent) + register(DataComponent.AxolotlVariantComponent) + register(DataComponent.CatVariantComponent) + register(DataComponent.CatSoundVariantComponent) + register(DataComponent.CatCollarComponent) + register(DataComponent.SheepColorComponent) + register(DataComponent.ShulkerColorComponent) + + freeze() + } +} + +internal fun BytesBuffer.readDataComponent(typeId: Int): DataComponent = + DataComponentRegistry.read(typeId, this) + +internal fun BytesBuffer.writeDataComponent(component: DataComponent) { + DataComponentRegistry.write(this, component) +} \ No newline at end of file diff --git a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/GamePacketsProtocolCodec.kt b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/registry/GamePacketsProtocolRegistry.kt similarity index 98% rename from libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/GamePacketsProtocolCodec.kt rename to libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/registry/GamePacketsProtocolRegistry.kt index ac9252d..6363452 100644 --- a/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/protocol/GamePacketsProtocolCodec.kt +++ b/libmc-protocol/src/commonMain/kotlin/cn/rtast/libmc/protocol/registry/GamePacketsProtocolRegistry.kt @@ -4,7 +4,7 @@ * Date: 2026/9/5 */ -package cn.rtast.libmc.protocol.protocol +package cn.rtast.libmc.protocol.registry import cn.rtast.libmc.protocol.packet.configuration.clientbound.* import cn.rtast.libmc.protocol.packet.configuration.serverbound.* @@ -23,7 +23,7 @@ import cn.rtast.libmc.protocol.packet.status.serverbound.ServerboundStatusReques import cn.rtast.libmc.protocol.protocol.state.ProtocolState import cn.rtast.libmc.protocol.protocol.state.ProtocolStateRegistry -internal object GamePacketsProtocolCodec { +internal object GamePacketsProtocolRegistry { val clientboundGameProtocols = ProtocolStateRegistry().apply { register(ProtocolState.STATUS) { register(0x00, ClientboundStatusResponsePacket) @@ -78,9 +78,9 @@ internal object GamePacketsProtocolCodec { register(0x0F, ClientboundCommandSuggestionsPacket) register(0x10, ClientboundCommandsPacket) register(0x11, ClientboundContainerClosePacket) -// register(0x12, ClientboundContainerSetContentPacket) + register(0x12, ClientboundContainerSetContentPacket) register(0x13, ClientboundContainerSetDataPacket) -// register(0x14, ClientboundContainerSetSlotPacket) + register(0x14, ClientboundContainerSetSlotPacket) register(0x15, ClientboundCookieRequestPacket) register(0x16, ClientboundCooldownPacket) register(0x17, ClientboundCustomChatCompletionsPacket) diff --git a/libmc-protocol/src/commonTest/kotlin/client/TestClient.kt b/libmc-protocol/src/commonTest/kotlin/client/TestClient.kt index a6d9c11..e97c875 100644 --- a/libmc-protocol/src/commonTest/kotlin/client/TestClient.kt +++ b/libmc-protocol/src/commonTest/kotlin/client/TestClient.kt @@ -9,7 +9,10 @@ package client import cn.rtast.libmc.crypto.AuthenticationProvider import cn.rtast.libmc.protocol.client.createMinecraftClient +import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundContainerSetContentPacket +import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundContainerSetSlotPacket import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundPlayerChatMessagePacket +import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundServerDataPacket import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundStepTickPacket import cn.rtast.libmc.protocol.protocol.session.SessionEvent import cn.rtast.libmc.protocol.protocol.session.onEvent @@ -95,13 +98,14 @@ class TestClient { login() // disconnect() } - cli.onEvent { - println(it.reason.toJsonString()) + cli.onEvent { + println(it) } cli.onPacket { chatTracker.onReceivePlayerChat(it.messageSignature) } - cli.onPacket { println(it) } - cli.on { packet, direction -> println("$direction -> $packet") } + cli.onPacket { println(it) } +// cli.on { packet, direction -> println("$direction -> $packet") } cli.connect() + // awaitCancellation() while (true) { }