network: only clear chunks when changing dimensions after respawn

This fixes missing chunks when the server does some dirty hacking with respawn packets
This commit is contained in:
Bixilon 2022-12-14 18:59:39 +01:00
parent 14588f55c4
commit d3c96e6c6e
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
8 changed files with 30 additions and 28 deletions

View File

@ -154,7 +154,7 @@ class WorldRenderer(
connection.events.listen<VisibilityGraphChangeEvent> { onFrustumChange() } connection.events.listen<VisibilityGraphChangeEvent> { onFrustumChange() }
connection.events.listen<RespawnEvent> { unloadWorld() } connection.events.listen<RespawnEvent> { if (it.dimensionChange) unloadWorld() }
connection.events.listen<ChunkDataChangeEvent> { queueChunk(it.chunkPosition, it.chunk) } connection.events.listen<ChunkDataChangeEvent> { queueChunk(it.chunkPosition, it.chunk) }
connection.events.listen<BlockSetEvent> { connection.events.listen<BlockSetEvent> {
val chunkPosition = it.blockPosition.chunkPosition val chunkPosition = it.blockPosition.chunkPosition

View File

@ -14,12 +14,9 @@ package de.bixilon.minosoft.modding.event.events
import de.bixilon.minosoft.modding.event.events.connection.play.PlayConnectionEvent import de.bixilon.minosoft.modding.event.events.connection.play.PlayConnectionEvent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.packets.s2c.play.RespawnS2CP
@Deprecated("Observables") @Deprecated("Observables")
class RespawnEvent( class RespawnEvent(
connection: PlayConnection, connection: PlayConnection,
) : PlayConnectionEvent(connection) { val dimensionChange: Boolean,
) : PlayConnectionEvent(connection)
constructor(connection: PlayConnection, packet: RespawnS2CP) : this(connection)
}

View File

@ -27,5 +27,5 @@ class ChunkDataChangeEvent(
val chunk: Chunk, val chunk: Chunk,
) : PlayConnectionEvent(connection) { ) : PlayConnectionEvent(connection) {
constructor(connection: PlayConnection, packet: ChunkS2CP) : this(connection, packet.chunkPosition, connection.world[packet.chunkPosition]!!) constructor(connection: PlayConnection, packet: ChunkS2CP) : this(connection, packet.position, connection.world[packet.position]!!)
} }

View File

@ -124,7 +124,6 @@ class ConnectionUtil(
} }
fun prepareSpawn() { fun prepareSpawn() {
connection.world.clear()
connection.player.velocity = Vec3d.EMPTY connection.player.velocity = Vec3d.EMPTY
connection.world.audioPlayer?.stopAllSounds() connection.world.audioPlayer?.stopAllSounds()
connection.world.particleRenderer?.removeAllParticles() connection.world.particleRenderer?.removeAllParticles()

View File

@ -146,6 +146,7 @@ class InitializeS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket {
} }
override fun handle(connection: PlayConnection) { override fun handle(connection: PlayConnection) {
connection.world.clear()
connection.util.prepareSpawn() connection.util.prepareSpawn()
val playerEntity = connection.player val playerEntity = connection.player
val previousGamemode = playerEntity.additional.gamemode val previousGamemode = playerEntity.additional.gamemode

View File

@ -107,9 +107,13 @@ class RespawnS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket {
override fun handle(connection: PlayConnection) { override fun handle(connection: PlayConnection) {
connection.util.prepareSpawn() connection.util.prepareSpawn()
connection.player.additional.gamemode = gamemode connection.player.additional.gamemode = gamemode
val dimensionChange = this.dimension != connection.world.dimension
if (dimensionChange) {
connection.world.clear()
}
connection.world.dimension = dimension connection.world.dimension = dimension
connection.state = PlayConnectionStates.SPAWNING connection.state = PlayConnectionStates.SPAWNING
connection.fire(RespawnEvent(connection, this)) connection.fire(RespawnEvent(connection, dimensionChange))
} }
override fun log(reducedLog: Boolean) { override fun log(reducedLog: Boolean) {

View File

@ -50,9 +50,9 @@ import java.util.*
@LoadPacket(lowPriority = true) @LoadPacket(lowPriority = true)
class ChunkS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket { class ChunkS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket {
val chunkPosition: Vec2i val position: Vec2i
val chunkData: ChunkData = ChunkData() val data: ChunkData = ChunkData()
var unloadChunk: Boolean = false var unload: Boolean = false
private set private set
var heightMap: Map<String, Any>? = null var heightMap: Map<String, Any>? = null
private set private set
@ -61,7 +61,7 @@ class ChunkS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket {
init { init {
val dimension = buffer.connection.world.dimension!! val dimension = buffer.connection.world.dimension!!
chunkPosition = buffer.readChunkPosition() position = buffer.readChunkPosition()
if (buffer.versionId < V_20W45A) { if (buffer.versionId < V_20W45A) {
isFullChunk = !buffer.readBoolean() isFullChunk = !buffer.readBoolean()
} }
@ -77,9 +77,9 @@ class ChunkS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket {
} }
val chunkData = ChunkUtil.readChunkPacket(decompressed, dimension, sectionBitMask, addBitMask, !isFullChunk, dimension.hasSkyLight) val chunkData = ChunkUtil.readChunkPacket(decompressed, dimension, sectionBitMask, addBitMask, !isFullChunk, dimension.hasSkyLight)
if (chunkData == null) { if (chunkData == null) {
unloadChunk = true unload = true
} else { } else {
this.chunkData.replace(chunkData) this.data.replace(chunkData)
} }
} else { } else {
if (buffer.versionId in V_1_16_PRE7 until V_1_16_2_PRE2) { if (buffer.versionId in V_1_16_PRE7 until V_1_16_2_PRE2) {
@ -96,7 +96,7 @@ class ChunkS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket {
heightMap = buffer.readNBT()?.toJsonObject() heightMap = buffer.readNBT()?.toJsonObject()
} }
if (!isFullChunk && buffer.versionId < V_21W37A) { if (!isFullChunk && buffer.versionId < V_21W37A) {
this.chunkData.biomeSource = SpatialBiomeArray(buffer.readBiomeArray()) this.data.biomeSource = SpatialBiomeArray(buffer.readBiomeArray())
} }
readingData = ChunkReadingData(PlayInByteBuffer(buffer.readByteArray(), buffer.connection), dimension, sectionBitMask) readingData = ChunkReadingData(PlayInByteBuffer(buffer.readByteArray(), buffer.connection), dimension, sectionBitMask)
@ -109,7 +109,7 @@ class ChunkS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket {
buffer.versionId < V_21W37A -> { buffer.versionId < V_21W37A -> {
val blockEntities: MutableMap<Vec3i, BlockEntity> = mutableMapOf() val blockEntities: MutableMap<Vec3i, BlockEntity> = mutableMapOf()
val positionOffset = Vec3i.of(chunkPosition, dimension.minSection, Vec3i.EMPTY) val positionOffset = Vec3i.of(position, dimension.minSection, Vec3i.EMPTY)
for (i in 0 until buffer.readVarInt()) { for (i in 0 until buffer.readVarInt()) {
val nbt = buffer.readNBT().asJsonObject() val nbt = buffer.readNBT().asJsonObject()
val position = Vec3i(nbt["x"]?.toInt() ?: continue, nbt["y"]?.toInt() ?: continue, nbt["z"]?.toInt() ?: continue) - positionOffset val position = Vec3i(nbt["x"]?.toInt() ?: continue, nbt["y"]?.toInt() ?: continue, nbt["z"]?.toInt() ?: continue) - positionOffset
@ -123,7 +123,7 @@ class ChunkS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket {
entity.updateNBT(nbt) entity.updateNBT(nbt)
blockEntities[position] = entity blockEntities[position] = entity
} }
this.chunkData.blockEntities = blockEntities this.data.blockEntities = blockEntities
} }
else -> { else -> {
@ -141,7 +141,7 @@ class ChunkS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket {
} }
blockEntities[Vec3i(xz shr 4, y, xz and 0x0F)] = entity blockEntities[Vec3i(xz shr 4, y, xz and 0x0F)] = entity
} }
this.chunkData.blockEntities = blockEntities this.data.blockEntities = blockEntities
} }
} }
@ -149,7 +149,7 @@ class ChunkS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket {
if (StaticConfiguration.IGNORE_SERVER_LIGHT) { if (StaticConfiguration.IGNORE_SERVER_LIGHT) {
buffer.pointer = buffer.size buffer.pointer = buffer.size
} else { } else {
this.chunkData.replace(ChunkLightS2CP(buffer, chunkPosition).chunkData) this.data.replace(ChunkLightS2CP(buffer, position).chunkData)
} }
} }
} }
@ -159,30 +159,30 @@ class ChunkS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket {
if (readingData.buffer.versionId < V_21W37A) { if (readingData.buffer.versionId < V_21W37A) {
val chunkData = ChunkUtil.readChunkPacket(buffer, dimension, sectionBitMask!!, null, !isFullChunk, dimension.hasSkyLight) val chunkData = ChunkUtil.readChunkPacket(buffer, dimension, sectionBitMask!!, null, !isFullChunk, dimension.hasSkyLight)
if (chunkData == null) { if (chunkData == null) {
unloadChunk = true unload = true
} else { } else {
this@ChunkS2CP.chunkData.replace(chunkData) this@ChunkS2CP.data.replace(chunkData)
} }
} else { } else {
this@ChunkS2CP.chunkData.replace(ChunkUtil.readPaletteChunk(buffer, dimension, null, isFullChunk = true, containsSkyLight = false)) this@ChunkS2CP.data.replace(ChunkUtil.readPaletteChunk(buffer, dimension, null, isFullChunk = true, containsSkyLight = false))
} }
} }
override fun handle(connection: PlayConnection) { override fun handle(connection: PlayConnection) {
if (unloadChunk) { if (unload) {
connection.world.unloadChunk(chunkPosition) connection.world.unloadChunk(position)
return return
} }
readingData.readChunkData() readingData.readChunkData()
val chunk = connection.world.getOrCreateChunk(chunkPosition) val chunk = connection.world.getOrCreateChunk(position)
chunk.setData(chunkData) chunk.setData(data)
} }
override fun log(reducedLog: Boolean) { override fun log(reducedLog: Boolean) {
if (reducedLog) { if (reducedLog) {
return return
} }
Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Chunk (chunkPosition=$chunkPosition)" } Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Chunk (chunkPosition=$position)" }
} }
private data class ChunkReadingData( private data class ChunkReadingData(

View File

@ -225,6 +225,7 @@ object KUtil {
return null return null
} }
@Deprecated("Kutil")
private inline fun String.checkInt(): Int? { private inline fun String.checkInt(): Int? {
var first = true var first = true
for (point in codePoints()) { for (point in codePoints()) {