Implemented 0x12-ClientboundContainerSetContentPacket, 0x14-ClientboundContainerSetSlotPacket, implemented slot data codec
This commit is contained in:
69 files changed
+3146
-67
No files matched your search
@@ -9,17 +9,8 @@ package cn.rtast.libmc.primitives
|
|||||||
|
|
||||||
import cn.rtast.libmc.network.BytesBuffer
|
import cn.rtast.libmc.network.BytesBuffer
|
||||||
|
|
||||||
public inline fun <T> BytesBuffer.readOptional(block: BytesBuffer.() -> T): T? {
|
public inline fun <T> BytesBuffer.readOptional(condition: Boolean, block: BytesBuffer.() -> T): T? =
|
||||||
val hasData = this.readBoolean()
|
if (condition) block() else null
|
||||||
return if (hasData) block.invoke(this) else null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public inline fun <T> BytesBuffer.writeOptional(value: T?, block: BytesBuffer.(T) -> Unit): Unit =
|
||||||
* buffer.writeOptional(value.someValue) { writeBlockPos(it) }
|
if (value != null) block.invoke(this, value) else Unit
|
||||||
*/
|
|
||||||
public inline fun <T> BytesBuffer.writeOptional(value: T?, block: BytesBuffer.(T) -> Unit) {
|
|
||||||
if (value != null) {
|
|
||||||
this.writeBoolean(true)
|
|
||||||
block.invoke(this, value)
|
|
||||||
} else this.writeBoolean(false)
|
|
||||||
}
|
|
||||||
@@ -44,10 +44,7 @@ public fun BytesBuffer.writePrefixedStringArray(value: List<String>) {
|
|||||||
|
|
||||||
public inline fun <T> BytesBuffer.readPrefixed(reader: BytesBuffer.() -> T): List<T> {
|
public inline fun <T> BytesBuffer.readPrefixed(reader: BytesBuffer.() -> T): List<T> {
|
||||||
val count = this.readVarInt()
|
val count = this.readVarInt()
|
||||||
require(count in 0..4096) {
|
require(count in 0..4096)
|
||||||
"Prefixed array count $count is invalid (expected 0..4096). " +
|
|
||||||
"Stream offset is corrupted. Check Heightmaps/NBT encoding."
|
|
||||||
}
|
|
||||||
val list = ArrayList<T>(count)
|
val list = ArrayList<T>(count)
|
||||||
repeat(count) { _ -> list.add(this.reader()) }
|
repeat(count) { _ -> list.add(this.reader()) }
|
||||||
return list
|
return list
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ public fun NBTInput.readNetworkCompound(): NBTCompound {
|
|||||||
return when (val type = NBTType.fromID(readByte().toInt() and 0xFF)) {
|
return when (val type = NBTType.fromID(readByte().toInt() and 0xFF)) {
|
||||||
NBTType.Compound -> NBTCompound("", readCompoundTag())
|
NBTType.Compound -> NBTCompound("", readCompoundTag())
|
||||||
NBTType.String -> NBTCompound("", NBTTag.CompoundTag(linkedMapOf("text" to NBTTag.StringTag(readStringTag()))))
|
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()}")
|
else -> throw UnsupportedOperationException("Unsupported network nbt tag 0x${type.id.toString(16).uppercase()}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+14
-2
@@ -7,16 +7,28 @@
|
|||||||
|
|
||||||
package cn.rtast.libmc.protocol.client
|
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 cn.rtast.libmc.protocol.protocol.state.ProtocolState
|
||||||
import kotlin.concurrent.Volatile
|
import kotlin.concurrent.Volatile
|
||||||
|
|
||||||
internal class ClientStateMachine {
|
internal class ClientStateMachine(private val session: Session) {
|
||||||
@Volatile
|
@Volatile
|
||||||
var currentState: ProtocolState = ProtocolState.HANDSHAKE
|
var currentState: ProtocolState = ProtocolState.HANDSHAKE
|
||||||
private set
|
private set
|
||||||
|
|
||||||
fun transitionTo(newState: ProtocolState) {
|
suspend fun transitionTo(newState: ProtocolState) {
|
||||||
println("Changing State $currentState to $newState")
|
println("Changing State $currentState to $newState")
|
||||||
currentState = 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
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3
-2
@@ -30,7 +30,7 @@ public class MinecraftClient internal constructor(
|
|||||||
internal val protocolContext: ProtocolContext,
|
internal val protocolContext: ProtocolContext,
|
||||||
public val session: SessionImpl = SessionImpl(),
|
public val session: SessionImpl = SessionImpl(),
|
||||||
) : PacketEventDispatcher(), CoroutineScope, Session by session {
|
) : PacketEventDispatcher(), CoroutineScope, Session by session {
|
||||||
internal val stateMachine = ClientStateMachine()
|
internal val stateMachine = ClientStateMachine(session)
|
||||||
public val networkChannel: NetworkChannel = NetworkChannel(this)
|
public val networkChannel: NetworkChannel = NetworkChannel(this)
|
||||||
private val clientJob = SupervisorJob(parentJob)
|
private val clientJob = SupervisorJob(parentJob)
|
||||||
private var listenJob: Job? = null
|
private var listenJob: Job? = null
|
||||||
@@ -52,8 +52,9 @@ public class MinecraftClient internal constructor(
|
|||||||
try {
|
try {
|
||||||
while (isActive) networkChannel.readNextPacket()
|
while (isActive) networkChannel.readNextPacket()
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
if (e is CancellationException) return@launch
|
e.printStackTrace()
|
||||||
println("Network read loop exception: ${e.message}")
|
println("Network read loop exception: ${e.message}")
|
||||||
|
if (e is CancellationException) return@launch
|
||||||
} finally {
|
} finally {
|
||||||
networkChannel.close()
|
networkChannel.close()
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -14,8 +14,8 @@ import cn.rtast.libmc.primitives.readVarInt
|
|||||||
import cn.rtast.libmc.primitives.writeVarInt
|
import cn.rtast.libmc.primitives.writeVarInt
|
||||||
import cn.rtast.libmc.protocol.client.MinecraftClient
|
import cn.rtast.libmc.protocol.client.MinecraftClient
|
||||||
import cn.rtast.libmc.protocol.protocol.event.PacketEventDispatcher
|
import cn.rtast.libmc.protocol.protocol.event.PacketEventDispatcher
|
||||||
import cn.rtast.libmc.protocol.protocol.GamePacketsProtocolCodec.clientboundGameProtocols
|
import cn.rtast.libmc.protocol.registry.GamePacketsProtocolRegistry.clientboundGameProtocols
|
||||||
import cn.rtast.libmc.protocol.protocol.GamePacketsProtocolCodec.serverboundGameProtocols
|
import cn.rtast.libmc.protocol.registry.GamePacketsProtocolRegistry.serverboundGameProtocols
|
||||||
import cn.rtast.libmc.zlibCompress
|
import cn.rtast.libmc.zlibCompress
|
||||||
import cn.rtast.libmc.zlibDecompress
|
import cn.rtast.libmc.zlibDecompress
|
||||||
import kotlin.concurrent.Volatile
|
import kotlin.concurrent.Volatile
|
||||||
|
|||||||
+34
@@ -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<Slot>,
|
||||||
|
val carriedItem: Slot?,
|
||||||
|
) : MinecraftPacket {
|
||||||
|
internal companion object Codec : PacketCodec<ClientboundContainerSetContentPacket> {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+33
@@ -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<ClientboundContainerSetSlotPacket> {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-4
@@ -18,7 +18,7 @@ public data class ClientboundDeleteChatPacket(val messageId: Int, val signature:
|
|||||||
override fun encode(buffer: BytesBuffer, value: ClientboundDeleteChatPacket) {}
|
override fun encode(buffer: BytesBuffer, value: ClientboundDeleteChatPacket) {}
|
||||||
override fun decode(buffer: BytesBuffer): ClientboundDeleteChatPacket {
|
override fun decode(buffer: BytesBuffer): ClientboundDeleteChatPacket {
|
||||||
val messageId = buffer.readVarInt()
|
val messageId = buffer.readVarInt()
|
||||||
val signature = buffer.readOptional { buffer.readBytes(256) }
|
val signature = buffer.readOptional(messageId == 0) { buffer.readBytes(256) }
|
||||||
return ClientboundDeleteChatPacket(messageId, signature)
|
return ClientboundDeleteChatPacket(messageId, signature)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -26,12 +26,9 @@ public data class ClientboundDeleteChatPacket(val messageId: Int, val signature:
|
|||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (other == null || this::class != other::class) return false
|
if (other == null || this::class != other::class) return false
|
||||||
|
|
||||||
other as ClientboundDeleteChatPacket
|
other as ClientboundDeleteChatPacket
|
||||||
|
|
||||||
if (messageId != other.messageId) return false
|
if (messageId != other.messageId) return false
|
||||||
if (!signature.contentEquals(other.signature)) return false
|
if (!signature.contentEquals(other.signature)) return false
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -7,16 +7,16 @@
|
|||||||
|
|
||||||
package cn.rtast.libmc.protocol.packet.play.clientbound
|
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.MinecraftPacket
|
||||||
import cn.rtast.libmc.packet.PacketCodec
|
import cn.rtast.libmc.packet.PacketCodec
|
||||||
import cn.rtast.libmc.primitives.IdOrX
|
import cn.rtast.libmc.primitives.IdOrX
|
||||||
import cn.rtast.libmc.primitives.readIdOrX
|
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.InlineChatType
|
||||||
import cn.rtast.libmc.protocol.protocol.game.chat.TextComponent
|
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.readInlineChatType
|
||||||
import cn.rtast.libmc.protocol.protocol.game.chat.readTextComponent
|
import cn.rtast.libmc.protocol.protocol.game.chat.readTextComponent
|
||||||
import cn.rtast.libmc.network.BytesBuffer
|
|
||||||
|
|
||||||
public data class ClientboundDisguisedChatMessagePacket(
|
public data class ClientboundDisguisedChatMessagePacket(
|
||||||
val message: TextComponent,
|
val message: TextComponent,
|
||||||
@@ -30,7 +30,7 @@ public data class ClientboundDisguisedChatMessagePacket(
|
|||||||
val message = buffer.readTextComponent()
|
val message = buffer.readTextComponent()
|
||||||
val chatType = buffer.readIdOrX { readInlineChatType() }
|
val chatType = buffer.readIdOrX { readInlineChatType() }
|
||||||
val senderName = buffer.readTextComponent()
|
val senderName = buffer.readTextComponent()
|
||||||
val targetName = buffer.readOptional { readTextComponent() }
|
val targetName = buffer.readPrefixOptional { readTextComponent() }
|
||||||
return ClientboundDisguisedChatMessagePacket(message, chatType, senderName, targetName)
|
return ClientboundDisguisedChatMessagePacket(message, chatType, senderName, targetName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-5
@@ -7,9 +7,11 @@
|
|||||||
|
|
||||||
package cn.rtast.libmc.protocol.packet.play.clientbound
|
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.MinecraftPacket
|
||||||
import cn.rtast.libmc.packet.PacketCodec
|
import cn.rtast.libmc.packet.PacketCodec
|
||||||
import cn.rtast.libmc.primitives.readOptional
|
import cn.rtast.libmc.primitives.readOptional
|
||||||
|
import cn.rtast.libmc.primitives.readPrefixOptional
|
||||||
import cn.rtast.libmc.primitives.readPrefixed
|
import cn.rtast.libmc.primitives.readPrefixed
|
||||||
import cn.rtast.libmc.primitives.readPrefixedByteArray
|
import cn.rtast.libmc.primitives.readPrefixedByteArray
|
||||||
import cn.rtast.libmc.primitives.readVarInt
|
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.MapItemColorPatch
|
||||||
import cn.rtast.libmc.protocol.protocol.game.item.MapItemIcon
|
import cn.rtast.libmc.protocol.protocol.game.item.MapItemIcon
|
||||||
import cn.rtast.libmc.protocol.protocol.game.item.MapItemIconType
|
import cn.rtast.libmc.protocol.protocol.game.item.MapItemIconType
|
||||||
import cn.rtast.libmc.network.BytesBuffer
|
|
||||||
|
|
||||||
public data class ClientboundMapItemDataPacket(
|
public data class ClientboundMapItemDataPacket(
|
||||||
val mapId: Int,
|
val mapId: Int,
|
||||||
@@ -32,24 +33,24 @@ public data class ClientboundMapItemDataPacket(
|
|||||||
val mapId = buffer.readVarInt()
|
val mapId = buffer.readVarInt()
|
||||||
val scale = buffer.readByte()
|
val scale = buffer.readByte()
|
||||||
val locked = buffer.readBoolean()
|
val locked = buffer.readBoolean()
|
||||||
val icons = buffer.readOptional {
|
val icons = buffer.readPrefixOptional {
|
||||||
readPrefixed {
|
readPrefixed {
|
||||||
val type = MapItemIconType.fromID(readVarInt())
|
val type = MapItemIconType.fromID(readVarInt())
|
||||||
val x = readByte()
|
val x = readByte()
|
||||||
val z = readByte()
|
val z = readByte()
|
||||||
val direction = readByte()
|
val direction = readByte()
|
||||||
val displayName = readOptional { readTextComponent() }
|
val displayName = readPrefixOptional { readTextComponent() }
|
||||||
MapItemIcon(type, x, z, direction, displayName)
|
MapItemIcon(type, x, z, direction, displayName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val columns = buffer.readUByte()
|
val columns = buffer.readUByte()
|
||||||
val colorPatch = if (columns > 0u) {
|
val colorPatch = buffer.readOptional(columns > 0u) {
|
||||||
val rows = buffer.readUByte()
|
val rows = buffer.readUByte()
|
||||||
val xOffset = buffer.readUByte()
|
val xOffset = buffer.readUByte()
|
||||||
val zOffset = buffer.readUByte()
|
val zOffset = buffer.readUByte()
|
||||||
val data = buffer.readPrefixedByteArray()
|
val data = buffer.readPrefixedByteArray()
|
||||||
MapItemColorPatch(columns, rows, xOffset, zOffset, data)
|
MapItemColorPatch(columns, rows, xOffset, zOffset, data)
|
||||||
} else null
|
}
|
||||||
return ClientboundMapItemDataPacket(mapId, scale, locked, icons, colorPatch)
|
return ClientboundMapItemDataPacket(mapId, scale, locked, icons, colorPatch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -43,7 +43,7 @@ public data class ClientboundPlayerInfoUpdatePacket(
|
|||||||
}
|
}
|
||||||
|
|
||||||
PlayerUpdateInfoAction.INITIALIZE_CHAT -> {
|
PlayerUpdateInfoAction.INITIALIZE_CHAT -> {
|
||||||
buffer.readOptional {
|
buffer.readPrefixOptional {
|
||||||
SinglePlayerAction.InitializeChat(
|
SinglePlayerAction.InitializeChat(
|
||||||
readUuid(), readLong(),
|
readUuid(), readLong(),
|
||||||
readBytes(512), readBytes(4096)
|
readBytes(512), readBytes(4096)
|
||||||
|
|||||||
+3
-4
@@ -7,19 +7,18 @@
|
|||||||
|
|
||||||
package cn.rtast.libmc.protocol.packet.play.clientbound
|
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.MinecraftPacket
|
||||||
import cn.rtast.libmc.packet.PacketCodec
|
import cn.rtast.libmc.packet.PacketCodec
|
||||||
import cn.rtast.libmc.primitives.readMcString
|
import cn.rtast.libmc.primitives.readMcString
|
||||||
import cn.rtast.libmc.primitives.readOptional
|
import cn.rtast.libmc.primitives.readPrefixOptional
|
||||||
import cn.rtast.libmc.primitives.readPrefixed
|
|
||||||
import cn.rtast.libmc.network.BytesBuffer
|
|
||||||
|
|
||||||
public data class ClientboundResetScorePacket(val entityName: String, val objectiveName: String?) : MinecraftPacket {
|
public data class ClientboundResetScorePacket(val entityName: String, val objectiveName: String?) : MinecraftPacket {
|
||||||
internal companion object Codec : PacketCodec<ClientboundResetScorePacket> {
|
internal companion object Codec : PacketCodec<ClientboundResetScorePacket> {
|
||||||
override fun encode(buffer: BytesBuffer, value: ClientboundResetScorePacket) {}
|
override fun encode(buffer: BytesBuffer, value: ClientboundResetScorePacket) {}
|
||||||
override fun decode(buffer: BytesBuffer): ClientboundResetScorePacket {
|
override fun decode(buffer: BytesBuffer): ClientboundResetScorePacket {
|
||||||
val entityName = buffer.readMcString()
|
val entityName = buffer.readMcString()
|
||||||
val objectiveName = buffer.readPrefixed { readOptional { readMcString() } }.first() // ?
|
val objectiveName = buffer.readPrefixOptional { readMcString() }
|
||||||
return ClientboundResetScorePacket(entityName, objectiveName)
|
return ClientboundResetScorePacket(entityName, objectiveName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -8,8 +8,8 @@
|
|||||||
package cn.rtast.libmc.protocol.packet.play.clientbound
|
package cn.rtast.libmc.protocol.packet.play.clientbound
|
||||||
|
|
||||||
import cn.rtast.libmc.network.BytesBuffer
|
import cn.rtast.libmc.network.BytesBuffer
|
||||||
import cn.rtast.libmc.packet.PacketCodec
|
|
||||||
import cn.rtast.libmc.packet.MinecraftPacket
|
import cn.rtast.libmc.packet.MinecraftPacket
|
||||||
|
import cn.rtast.libmc.packet.PacketCodec
|
||||||
import cn.rtast.libmc.primitives.readOptional
|
import cn.rtast.libmc.primitives.readOptional
|
||||||
import cn.rtast.libmc.primitives.readVarInt
|
import cn.rtast.libmc.primitives.readVarInt
|
||||||
import cn.rtast.libmc.protocol.protocol.game.GameMode
|
import cn.rtast.libmc.protocol.protocol.game.GameMode
|
||||||
@@ -45,8 +45,8 @@ public data class ClientboundRespawnPacket(
|
|||||||
val isDebug = buffer.readBoolean()
|
val isDebug = buffer.readBoolean()
|
||||||
val isFlat = buffer.readBoolean()
|
val isFlat = buffer.readBoolean()
|
||||||
val hasDeathLocation = buffer.readBoolean()
|
val hasDeathLocation = buffer.readBoolean()
|
||||||
val deathDimensionName = buffer.readOptional { readIdentifier() }
|
val deathDimensionName = buffer.readOptional(hasDeathLocation) { readIdentifier() }
|
||||||
val deathLocation = buffer.readOptional { readBlockPos() }
|
val deathLocation = buffer.readOptional(hasDeathLocation) { readBlockPos() }
|
||||||
val portalCooldown = buffer.readVarInt()
|
val portalCooldown = buffer.readVarInt()
|
||||||
val seaLevel = buffer.readVarInt()
|
val seaLevel = buffer.readVarInt()
|
||||||
val dataKept = RespawnDataToKeep.fromByte(buffer.readByte())
|
val dataKept = RespawnDataToKeep.fromByte(buffer.readByte())
|
||||||
|
|||||||
+3
-3
@@ -8,9 +8,9 @@
|
|||||||
package cn.rtast.libmc.protocol.packet.play.clientbound
|
package cn.rtast.libmc.protocol.packet.play.clientbound
|
||||||
|
|
||||||
import cn.rtast.libmc.network.BytesBuffer
|
import cn.rtast.libmc.network.BytesBuffer
|
||||||
import cn.rtast.libmc.packet.PacketCodec
|
|
||||||
import cn.rtast.libmc.packet.MinecraftPacket
|
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.Identifier
|
||||||
import cn.rtast.libmc.protocol.protocol.game.readIdentifier
|
import cn.rtast.libmc.protocol.protocol.game.readIdentifier
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ public data class ClientboundSelectAdvancementsTabPacket(val tabId: Identifier?)
|
|||||||
internal companion object Codec : PacketCodec<ClientboundSelectAdvancementsTabPacket> {
|
internal companion object Codec : PacketCodec<ClientboundSelectAdvancementsTabPacket> {
|
||||||
override fun encode(buffer: BytesBuffer, value: ClientboundSelectAdvancementsTabPacket) {}
|
override fun encode(buffer: BytesBuffer, value: ClientboundSelectAdvancementsTabPacket) {}
|
||||||
override fun decode(buffer: BytesBuffer): ClientboundSelectAdvancementsTabPacket {
|
override fun decode(buffer: BytesBuffer): ClientboundSelectAdvancementsTabPacket {
|
||||||
return ClientboundSelectAdvancementsTabPacket(buffer.readOptional { readIdentifier() })
|
return ClientboundSelectAdvancementsTabPacket(buffer.readPrefixOptional { readIdentifier() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3
-3
@@ -7,20 +7,20 @@
|
|||||||
|
|
||||||
package cn.rtast.libmc.protocol.packet.play.clientbound
|
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.MinecraftPacket
|
||||||
import cn.rtast.libmc.packet.PacketCodec
|
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.primitives.readVarInt
|
||||||
import cn.rtast.libmc.protocol.protocol.game.chat.TextComponent
|
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.readTextComponent
|
||||||
import cn.rtast.libmc.network.BytesBuffer
|
|
||||||
|
|
||||||
public data class ClientboundServerDataPacket(val motd: TextComponent, val icon: ByteArray?) : MinecraftPacket {
|
public data class ClientboundServerDataPacket(val motd: TextComponent, val icon: ByteArray?) : MinecraftPacket {
|
||||||
internal companion object Codec : PacketCodec<ClientboundServerDataPacket> {
|
internal companion object Codec : PacketCodec<ClientboundServerDataPacket> {
|
||||||
override fun encode(buffer: BytesBuffer, value: ClientboundServerDataPacket) {}
|
override fun encode(buffer: BytesBuffer, value: ClientboundServerDataPacket) {}
|
||||||
override fun decode(buffer: BytesBuffer): ClientboundServerDataPacket {
|
override fun decode(buffer: BytesBuffer): ClientboundServerDataPacket {
|
||||||
val motd = buffer.readTextComponent()
|
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)
|
return ClientboundServerDataPacket(motd, icon)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -7,12 +7,12 @@
|
|||||||
|
|
||||||
package cn.rtast.libmc.protocol.packet.play.clientbound
|
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.MinecraftPacket
|
||||||
import cn.rtast.libmc.packet.PacketCodec
|
import cn.rtast.libmc.packet.PacketCodec
|
||||||
import cn.rtast.libmc.primitives.readOptional
|
import cn.rtast.libmc.primitives.readOptional
|
||||||
import cn.rtast.libmc.protocol.protocol.game.chat.TextComponent
|
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.readTextComponent
|
||||||
import cn.rtast.libmc.network.BytesBuffer
|
|
||||||
|
|
||||||
public data class ClientboundTestInstanceBlockStatusPacket(
|
public data class ClientboundTestInstanceBlockStatusPacket(
|
||||||
val status: TextComponent,
|
val status: TextComponent,
|
||||||
@@ -26,9 +26,9 @@ public data class ClientboundTestInstanceBlockStatusPacket(
|
|||||||
override fun decode(buffer: BytesBuffer): ClientboundTestInstanceBlockStatusPacket {
|
override fun decode(buffer: BytesBuffer): ClientboundTestInstanceBlockStatusPacket {
|
||||||
val status = buffer.readTextComponent()
|
val status = buffer.readTextComponent()
|
||||||
val hasSize = buffer.readBoolean()
|
val hasSize = buffer.readBoolean()
|
||||||
val sizeX = buffer.readOptional { readDouble() } // ?
|
val sizeX = buffer.readOptional(hasSize) { readDouble() }
|
||||||
val sizeY = buffer.readOptional { readDouble() } // ?
|
val sizeY = buffer.readOptional(hasSize) { readDouble() }
|
||||||
val sizeZ = buffer.readOptional { readDouble() } // ?
|
val sizeZ = buffer.readOptional(hasSize) { readDouble() }
|
||||||
return ClientboundTestInstanceBlockStatusPacket(status, hasSize, sizeX, sizeY, sizeZ)
|
return ClientboundTestInstanceBlockStatusPacket(status, hasSize, sizeX, sizeY, sizeZ)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -8,16 +8,16 @@
|
|||||||
package cn.rtast.libmc.protocol.packet.play.clientbound
|
package cn.rtast.libmc.protocol.packet.play.clientbound
|
||||||
|
|
||||||
import cn.rtast.libmc.nbt.NBTTag
|
import cn.rtast.libmc.nbt.NBTTag
|
||||||
|
import cn.rtast.libmc.network.BytesBuffer
|
||||||
import cn.rtast.libmc.packet.MinecraftPacket
|
import cn.rtast.libmc.packet.MinecraftPacket
|
||||||
import cn.rtast.libmc.packet.PacketCodec
|
import cn.rtast.libmc.packet.PacketCodec
|
||||||
import cn.rtast.libmc.primitives.readMcString
|
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.primitives.readVarInt
|
||||||
import cn.rtast.libmc.protocol.protocol.game.chat.TextComponent
|
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.readTextComponent
|
||||||
import cn.rtast.libmc.protocol.protocol.game.scoreboard.ScoreNumberFormat
|
import cn.rtast.libmc.protocol.protocol.game.scoreboard.ScoreNumberFormat
|
||||||
import cn.rtast.libmc.protocol.protocol.util.readNetworkNBTCompound
|
import cn.rtast.libmc.protocol.protocol.util.readNetworkNBTCompound
|
||||||
import cn.rtast.libmc.network.BytesBuffer
|
|
||||||
|
|
||||||
public data class ClientboundUpdateScorePacket(
|
public data class ClientboundUpdateScorePacket(
|
||||||
val entityName: String,
|
val entityName: String,
|
||||||
@@ -32,8 +32,8 @@ public data class ClientboundUpdateScorePacket(
|
|||||||
val entityName = buffer.readMcString()
|
val entityName = buffer.readMcString()
|
||||||
val objectiveName = buffer.readMcString()
|
val objectiveName = buffer.readMcString()
|
||||||
val value = buffer.readVarInt()
|
val value = buffer.readVarInt()
|
||||||
val displayName = buffer.readOptional { readTextComponent() }
|
val displayName = buffer.readPrefixOptional { readTextComponent() }
|
||||||
val numberFormat = buffer.readOptional {
|
val numberFormat = buffer.readPrefixOptional {
|
||||||
when (val type = readVarInt()) {
|
when (val type = readVarInt()) {
|
||||||
0 -> ScoreNumberFormat.Blank
|
0 -> ScoreNumberFormat.Blank
|
||||||
1 -> ScoreNumberFormat.Styled(styling = readNetworkNBTCompound().element as NBTTag.CompoundTag) // fix me
|
1 -> ScoreNumberFormat.Styled(styling = readNetworkNBTCompound().element as NBTTag.CompoundTag) // fix me
|
||||||
|
|||||||
+1
-1
@@ -34,7 +34,7 @@ public data class ClientboundWaypointPacket(
|
|||||||
readRight = { readIdentifier() }
|
readRight = { readIdentifier() }
|
||||||
)
|
)
|
||||||
val iconStyle = buffer.readIdentifier()
|
val iconStyle = buffer.readIdentifier()
|
||||||
val color = buffer.readOptional {
|
val color = buffer.readPrefixOptional {
|
||||||
val red = readUByte()
|
val red = readUByte()
|
||||||
val green = readUByte()
|
val green = readUByte()
|
||||||
val blue = readUByte()
|
val blue = readUByte()
|
||||||
|
|||||||
+10
@@ -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)
|
||||||
+31
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
+1673
File diff suppressed because it is too large.
Load diff
+18
@@ -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,
|
||||||
|
)
|
||||||
+17
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
+24
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
+41
@@ -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<BannerPattern>, 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)
|
||||||
|
}
|
||||||
+17
@@ -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,
|
||||||
|
)
|
||||||
+137
@@ -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<PropertyMatcher>?,
|
||||||
|
val nbt: NBTCompound?,
|
||||||
|
val components: List<ExactDataComponentMatcher>,
|
||||||
|
val partialComponents: List<PartialDataComponentMatcher>,
|
||||||
|
)
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
+17
@@ -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,
|
||||||
|
)
|
||||||
+10
@@ -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)
|
||||||
+22
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
+47
@@ -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<Int>,
|
||||||
|
val fadeColors: List<Int>,
|
||||||
|
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)
|
||||||
|
}
|
||||||
+19
@@ -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<SoundEvent>,
|
||||||
|
val useDuration: Float,
|
||||||
|
val range: Float,
|
||||||
|
val description: TextComponent,
|
||||||
|
)
|
||||||
+19
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
+19
@@ -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<SoundEvent>,
|
||||||
|
val description: TextComponent,
|
||||||
|
val duration: Float,
|
||||||
|
val output: Int,
|
||||||
|
)
|
||||||
+31
@@ -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)
|
||||||
|
}
|
||||||
+16
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -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)
|
||||||
+16
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
@@ -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?,
|
||||||
|
)
|
||||||
+16
@@ -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<TrimMaterialOverride>,
|
||||||
|
val description: TextComponent,
|
||||||
|
)
|
||||||
+12
@@ -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)
|
||||||
+17
@@ -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,
|
||||||
|
)
|
||||||
+10
@@ -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?)
|
||||||
+12
@@ -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?)
|
||||||
+16
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
+27
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
+25
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
+43
@@ -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) }
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2026 RTAkland
|
||||||
|
* Author: RTAkland
|
||||||
|
* Date: 2026/9/10
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package cn.rtast.libmc.protocol.protocol.game.item.slot
|
||||||
|
|
||||||
+59
@@ -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<DataComponent>,
|
||||||
|
val componentsToRemove: List<Int>,
|
||||||
|
) {
|
||||||
|
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<DataComponent>(addCount)
|
||||||
|
repeat(addCount) {
|
||||||
|
val componentId = readVarInt()
|
||||||
|
componentsToAdd.add(readDataComponent(componentId))
|
||||||
|
}
|
||||||
|
val componentsToRemove = ArrayList<Int>(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)
|
||||||
|
}
|
||||||
+16
@@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
+90
@@ -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<PotionEffect>, 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<ConsumeEffect> {
|
||||||
|
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<ConsumeEffect>) {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+45
@@ -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) }
|
||||||
|
}
|
||||||
+28
@@ -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)
|
||||||
|
}
|
||||||
+69
@@ -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<GameProfile.Property>,
|
||||||
|
) : 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) }
|
||||||
|
}
|
||||||
+1
-1
@@ -19,7 +19,7 @@ public data class SoundEvent(val name: Identifier, val hasFixedRange: Boolean, v
|
|||||||
internal fun BytesBuffer.readSoundEvent(): SoundEvent {
|
internal fun BytesBuffer.readSoundEvent(): SoundEvent {
|
||||||
val name = readIdentifier()
|
val name = readIdentifier()
|
||||||
val hasFixedRange = readBoolean()
|
val hasFixedRange = readBoolean()
|
||||||
val fixedRange = readOptional { readFloat() }
|
val fixedRange = readOptional(hasFixedRange) { readFloat() }
|
||||||
return SoundEvent(name, hasFixedRange, fixedRange)
|
return SoundEvent(name, hasFixedRange, fixedRange)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
@@ -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)
|
||||||
+8
@@ -13,4 +13,12 @@ import cn.rtast.libmc.protocol.protocol.state.ProtocolState
|
|||||||
public sealed interface SessionEvent {
|
public sealed interface SessionEvent {
|
||||||
public data class DisconnectedEvent(val reason: TextComponent, val state: ProtocolState) : SessionEvent
|
public data class DisconnectedEvent(val reason: TextComponent, val state: ProtocolState) : SessionEvent
|
||||||
public object ConnectedEvent : 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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+171
@@ -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<Int, PacketCodec<out DataComponent>>()
|
||||||
|
private val classToIdMap = mutableMapOf<KClass<out DataComponent>, Int>()
|
||||||
|
private lateinit var codecArray: Array<PacketCodec<DataComponent>>
|
||||||
|
|
||||||
|
private fun <T : DataComponent> register(kClass: KClass<T>, codec: PacketCodec<T>) {
|
||||||
|
val id = codecMap.size
|
||||||
|
codecMap[id] = codec
|
||||||
|
classToIdMap[kClass] = id
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : DataComponent> register(codec: PacketCodec<T>) = register(T::class, codec)
|
||||||
|
|
||||||
|
fun freeze() {
|
||||||
|
val maxId = codecMap.keys.maxOrNull() ?: -1
|
||||||
|
codecArray = Array(maxId + 1) { index ->
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
codecMap[index] as? PacketCodec<DataComponent> ?: 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)
|
||||||
|
}
|
||||||
+4
-4
@@ -4,7 +4,7 @@
|
|||||||
* Date: 2026/9/5
|
* 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.clientbound.*
|
||||||
import cn.rtast.libmc.protocol.packet.configuration.serverbound.*
|
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.ProtocolState
|
||||||
import cn.rtast.libmc.protocol.protocol.state.ProtocolStateRegistry
|
import cn.rtast.libmc.protocol.protocol.state.ProtocolStateRegistry
|
||||||
|
|
||||||
internal object GamePacketsProtocolCodec {
|
internal object GamePacketsProtocolRegistry {
|
||||||
val clientboundGameProtocols = ProtocolStateRegistry().apply {
|
val clientboundGameProtocols = ProtocolStateRegistry().apply {
|
||||||
register(ProtocolState.STATUS) {
|
register(ProtocolState.STATUS) {
|
||||||
register(0x00, ClientboundStatusResponsePacket)
|
register(0x00, ClientboundStatusResponsePacket)
|
||||||
@@ -78,9 +78,9 @@ internal object GamePacketsProtocolCodec {
|
|||||||
register(0x0F, ClientboundCommandSuggestionsPacket)
|
register(0x0F, ClientboundCommandSuggestionsPacket)
|
||||||
register(0x10, ClientboundCommandsPacket)
|
register(0x10, ClientboundCommandsPacket)
|
||||||
register(0x11, ClientboundContainerClosePacket)
|
register(0x11, ClientboundContainerClosePacket)
|
||||||
// register(0x12, ClientboundContainerSetContentPacket)
|
register(0x12, ClientboundContainerSetContentPacket)
|
||||||
register(0x13, ClientboundContainerSetDataPacket)
|
register(0x13, ClientboundContainerSetDataPacket)
|
||||||
// register(0x14, ClientboundContainerSetSlotPacket)
|
register(0x14, ClientboundContainerSetSlotPacket)
|
||||||
register(0x15, ClientboundCookieRequestPacket)
|
register(0x15, ClientboundCookieRequestPacket)
|
||||||
register(0x16, ClientboundCooldownPacket)
|
register(0x16, ClientboundCooldownPacket)
|
||||||
register(0x17, ClientboundCustomChatCompletionsPacket)
|
register(0x17, ClientboundCustomChatCompletionsPacket)
|
||||||
@@ -9,7 +9,10 @@ package client
|
|||||||
|
|
||||||
import cn.rtast.libmc.crypto.AuthenticationProvider
|
import cn.rtast.libmc.crypto.AuthenticationProvider
|
||||||
import cn.rtast.libmc.protocol.client.createMinecraftClient
|
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.ClientboundPlayerChatMessagePacket
|
||||||
|
import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundServerDataPacket
|
||||||
import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundStepTickPacket
|
import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundStepTickPacket
|
||||||
import cn.rtast.libmc.protocol.protocol.session.SessionEvent
|
import cn.rtast.libmc.protocol.protocol.session.SessionEvent
|
||||||
import cn.rtast.libmc.protocol.protocol.session.onEvent
|
import cn.rtast.libmc.protocol.protocol.session.onEvent
|
||||||
@@ -95,13 +98,14 @@ class TestClient {
|
|||||||
login()
|
login()
|
||||||
// disconnect()
|
// disconnect()
|
||||||
}
|
}
|
||||||
cli.onEvent<SessionEvent.DisconnectedEvent> {
|
cli.onEvent<SessionEvent.ChangedState> {
|
||||||
println(it.reason.toJsonString())
|
println(it)
|
||||||
}
|
}
|
||||||
cli.onPacket<ClientboundPlayerChatMessagePacket> { chatTracker.onReceivePlayerChat(it.messageSignature) }
|
cli.onPacket<ClientboundPlayerChatMessagePacket> { chatTracker.onReceivePlayerChat(it.messageSignature) }
|
||||||
cli.onPacket<ClientboundStepTickPacket> { println(it) }
|
cli.onPacket<ClientboundContainerSetSlotPacket> { println(it) }
|
||||||
cli.on { packet, direction -> println("$direction -> $packet") }
|
// cli.on { packet, direction -> println("$direction -> $packet") }
|
||||||
cli.connect()
|
cli.connect()
|
||||||
|
|
||||||
// awaitCancellation()
|
// awaitCancellation()
|
||||||
while (true) {
|
while (true) {
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user