Implemented 0x30-ClientboundLightUpdatePacket

This commit is contained in:
2026-09-11 12:11:24 +08:00
parent 8fbc2406ac
commit faff00cfc1
4 files changed
+138 -4

No files matched your search

@@ -0,0 +1,36 @@
/*
* 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.world.LightData
public data class ClientboundLightUpdatePacket(
/**
* Chunk coordinate (block coordinate divided by 16, rounded down)
*/
val chunkX: Int,
/**
* Chunk coordinate (block coordinate divided by 16, rounded down)
*/
val chunkZ: Int,
val data: LightData,
) : MinecraftPacket {
internal companion object Codec : PacketCodec<ClientboundLightUpdatePacket> {
override fun encode(buffer: BytesBuffer, value: ClientboundLightUpdatePacket) {}
override fun decode(buffer: BytesBuffer): ClientboundLightUpdatePacket {
val chunkX = buffer.readVarInt()
val chunkZ = buffer.readVarInt()
val data = LightData.decode(buffer)
return ClientboundLightUpdatePacket(chunkX, chunkZ, data)
}
}
}
@@ -0,0 +1,98 @@
/*
* Copyright © 2026 RTAkland
* Author: RTAkland
* Date: 2026/9/11
*/
package cn.rtast.libmc.protocol.protocol.game.world
import cn.rtast.libmc.network.BytesBuffer
import cn.rtast.libmc.packet.PacketCodec
import cn.rtast.libmc.primitives.*
public data class LightData(
val skyLightMask: BitSet,
val blockLightMask: BitSet,
val emptySkyLightMask: BitSet,
val emptyBlockLightMask: BitSet,
val skyLightArrays: List<ByteArray>, // fixed 2048
val blockLightArrays: List<ByteArray>, // fixed 2048
) {
internal companion object Codec : PacketCodec<LightData> {
private const val LIGHT_ARRAY_SIZE = 2048
override fun encode(buffer: BytesBuffer, value: LightData) {
buffer.writeBitSet(value.skyLightMask)
buffer.writeBitSet(value.blockLightMask)
buffer.writeBitSet(value.emptySkyLightMask)
buffer.writeBitSet(value.emptyBlockLightMask)
buffer.writeVarInt(value.skyLightArrays.size)
buffer.writePrefixed(value.skyLightArrays) { array ->
require(array.size == LIGHT_ARRAY_SIZE)
writeVarInt(array.size)
writeBytes(array)
}
buffer.writePrefixed(value.blockLightArrays) { array ->
require(array.size == LIGHT_ARRAY_SIZE)
writeVarInt(array.size)
writeBytes(array)
}
}
override fun decode(buffer: BytesBuffer): LightData {
val skyLightMask = buffer.readBitSet()
val blockLightMask = buffer.readBitSet()
val emptySkyLightMask = buffer.readBitSet()
val emptyBlockLightMask = buffer.readBitSet()
val skyLightArrays = buffer.readPrefixed {
val length = readVarInt()
require(length == LIGHT_ARRAY_SIZE)
readBytes(length)
}
val blockLightArrays = buffer.readPrefixed {
val length = readVarInt()
require(length == LIGHT_ARRAY_SIZE)
readBytes(length)
}
return LightData(
skyLightMask, blockLightMask, emptySkyLightMask,
emptyBlockLightMask, skyLightArrays, blockLightArrays
)
}
}
public fun hasSkyLight(sectionY: Int, minSectionY: Int): Boolean {
val bitIndex = sectionY - (minSectionY - 1)
return skyLightMask.getBit(bitIndex)
}
public fun hasBlockLight(sectionY: Int, minSectionY: Int): Boolean {
val bitIndex = sectionY - (minSectionY - 1)
return blockLightMask.getBit(bitIndex)
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false
other as LightData
if (!skyLightMask.contentEquals(other.skyLightMask)) return false
if (!blockLightMask.contentEquals(other.blockLightMask)) return false
if (!emptySkyLightMask.contentEquals(other.emptySkyLightMask)) return false
if (!emptyBlockLightMask.contentEquals(other.emptyBlockLightMask)) return false
if (skyLightArrays != other.skyLightArrays) return false
if (blockLightArrays != other.blockLightArrays) return false
return true
}
override fun hashCode(): Int {
var result = skyLightMask.contentHashCode()
result = 31 * result + blockLightMask.contentHashCode()
result = 31 * result + emptySkyLightMask.contentHashCode()
result = 31 * result + emptyBlockLightMask.contentHashCode()
result = 31 * result + skyLightArrays.hashCode()
result = 31 * result + blockLightArrays.hashCode()
return result
}
}
@@ -108,7 +108,7 @@ internal object GamePacketsProtocolRegistry {
// register(0x2D, ClientboundLevelChunkUpdateWithLightPacket) // register(0x2D, ClientboundLevelChunkUpdateWithLightPacket)
register(0x2E, ClientboundLevelEventPacket) register(0x2E, ClientboundLevelEventPacket)
register(0x2F, ClientboundLevelParticlePacket) register(0x2F, ClientboundLevelParticlePacket)
// register(0x30, ClientboundLightUpdatePacket) register(0x30, ClientboundLightUpdatePacket)
register(0x31, ClientboundLoginPlayPacket) register(0x31, ClientboundLoginPlayPacket)
register(0x32, ClientboundLowDiskSpaceWarningPacket) register(0x32, ClientboundLowDiskSpaceWarningPacket)
register(0x33, ClientboundMapItemDataPacket) register(0x33, ClientboundMapItemDataPacket)
@@ -11,6 +11,7 @@ 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.ClientboundContainerSetSlotPacket import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundContainerSetSlotPacket
import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundLevelParticlePacket import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundLevelParticlePacket
import cn.rtast.libmc.protocol.packet.play.clientbound.ClientboundLightUpdatePacket
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.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
@@ -101,9 +102,8 @@ class TestClient {
println(it) println(it)
} }
cli.onPacket<ClientboundPlayerChatMessagePacket> { chatTracker.onReceivePlayerChat(it.messageSignature) } cli.onPacket<ClientboundPlayerChatMessagePacket> { chatTracker.onReceivePlayerChat(it.messageSignature) }
cli.onPacket<ClientboundContainerSetSlotPacket> { println(it) } cli.onPacket<ClientboundLightUpdatePacket> { println(it) }
cli.onPacket<ClientboundLevelParticlePacket> { println(it) } cli.on { packet, direction -> println("$direction -> $packet") }
// cli.on { packet, direction -> println("$direction -> $packet") }
cli.connect() cli.connect()
// awaitCancellation() // awaitCancellation()