From d3c96e6c6e7103ad0a52c317ab2969b201576abe Mon Sep 17 00:00:00 2001 From: Bixilon Date: Wed, 14 Dec 2022 18:59:39 +0100 Subject: [PATCH] network: only clear chunks when changing dimensions after respawn This fixes missing chunks when the server does some dirty hacking with respawn packets --- .../gui/rendering/world/WorldRenderer.kt | 2 +- .../modding/event/events/RespawnEvent.kt | 7 +--- .../blocks/chunk/ChunkDataChangeEvent.kt | 2 +- .../network/connection/play/ConnectionUtil.kt | 1 - .../packets/s2c/play/InitializeS2CP.kt | 1 + .../protocol/packets/s2c/play/RespawnS2CP.kt | 6 ++- .../packets/s2c/play/chunk/ChunkS2CP.kt | 38 +++++++++---------- .../java/de/bixilon/minosoft/util/KUtil.kt | 1 + 8 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt index 4263cc6a6..8ef51c402 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/world/WorldRenderer.kt @@ -154,7 +154,7 @@ class WorldRenderer( connection.events.listen { onFrustumChange() } - connection.events.listen { unloadWorld() } + connection.events.listen { if (it.dimensionChange) unloadWorld() } connection.events.listen { queueChunk(it.chunkPosition, it.chunk) } connection.events.listen { val chunkPosition = it.blockPosition.chunkPosition diff --git a/src/main/java/de/bixilon/minosoft/modding/event/events/RespawnEvent.kt b/src/main/java/de/bixilon/minosoft/modding/event/events/RespawnEvent.kt index 4a512d8ea..51cdb7e12 100644 --- a/src/main/java/de/bixilon/minosoft/modding/event/events/RespawnEvent.kt +++ b/src/main/java/de/bixilon/minosoft/modding/event/events/RespawnEvent.kt @@ -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.protocol.network.connection.play.PlayConnection -import de.bixilon.minosoft.protocol.packets.s2c.play.RespawnS2CP @Deprecated("Observables") class RespawnEvent( connection: PlayConnection, -) : PlayConnectionEvent(connection) { - - constructor(connection: PlayConnection, packet: RespawnS2CP) : this(connection) -} + val dimensionChange: Boolean, +) : PlayConnectionEvent(connection) diff --git a/src/main/java/de/bixilon/minosoft/modding/event/events/blocks/chunk/ChunkDataChangeEvent.kt b/src/main/java/de/bixilon/minosoft/modding/event/events/blocks/chunk/ChunkDataChangeEvent.kt index 9295315cf..11b4de436 100644 --- a/src/main/java/de/bixilon/minosoft/modding/event/events/blocks/chunk/ChunkDataChangeEvent.kt +++ b/src/main/java/de/bixilon/minosoft/modding/event/events/blocks/chunk/ChunkDataChangeEvent.kt @@ -27,5 +27,5 @@ class ChunkDataChangeEvent( val chunk: Chunk, ) : 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]!!) } diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/ConnectionUtil.kt b/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/ConnectionUtil.kt index 4320c02e4..715d751e4 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/ConnectionUtil.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/ConnectionUtil.kt @@ -124,7 +124,6 @@ class ConnectionUtil( } fun prepareSpawn() { - connection.world.clear() connection.player.velocity = Vec3d.EMPTY connection.world.audioPlayer?.stopAllSounds() connection.world.particleRenderer?.removeAllParticles() diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/InitializeS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/InitializeS2CP.kt index dfe182f61..d039b26d3 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/InitializeS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/InitializeS2CP.kt @@ -146,6 +146,7 @@ class InitializeS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket { } override fun handle(connection: PlayConnection) { + connection.world.clear() connection.util.prepareSpawn() val playerEntity = connection.player val previousGamemode = playerEntity.additional.gamemode diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/RespawnS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/RespawnS2CP.kt index af78aa9c2..19383a2bf 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/RespawnS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/RespawnS2CP.kt @@ -107,9 +107,13 @@ class RespawnS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket { override fun handle(connection: PlayConnection) { connection.util.prepareSpawn() connection.player.additional.gamemode = gamemode + val dimensionChange = this.dimension != connection.world.dimension + if (dimensionChange) { + connection.world.clear() + } connection.world.dimension = dimension connection.state = PlayConnectionStates.SPAWNING - connection.fire(RespawnEvent(connection, this)) + connection.fire(RespawnEvent(connection, dimensionChange)) } override fun log(reducedLog: Boolean) { diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/chunk/ChunkS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/chunk/ChunkS2CP.kt index 32d653712..b44845e3e 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/chunk/ChunkS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/chunk/ChunkS2CP.kt @@ -50,9 +50,9 @@ import java.util.* @LoadPacket(lowPriority = true) class ChunkS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket { - val chunkPosition: Vec2i - val chunkData: ChunkData = ChunkData() - var unloadChunk: Boolean = false + val position: Vec2i + val data: ChunkData = ChunkData() + var unload: Boolean = false private set var heightMap: Map? = null private set @@ -61,7 +61,7 @@ class ChunkS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket { init { val dimension = buffer.connection.world.dimension!! - chunkPosition = buffer.readChunkPosition() + position = buffer.readChunkPosition() if (buffer.versionId < V_20W45A) { isFullChunk = !buffer.readBoolean() } @@ -77,9 +77,9 @@ class ChunkS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket { } val chunkData = ChunkUtil.readChunkPacket(decompressed, dimension, sectionBitMask, addBitMask, !isFullChunk, dimension.hasSkyLight) if (chunkData == null) { - unloadChunk = true + unload = true } else { - this.chunkData.replace(chunkData) + this.data.replace(chunkData) } } else { 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() } 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) @@ -109,7 +109,7 @@ class ChunkS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket { buffer.versionId < V_21W37A -> { val blockEntities: MutableMap = 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()) { val nbt = buffer.readNBT().asJsonObject() 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) blockEntities[position] = entity } - this.chunkData.blockEntities = blockEntities + this.data.blockEntities = blockEntities } else -> { @@ -141,7 +141,7 @@ class ChunkS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket { } 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) { buffer.pointer = buffer.size } 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) { val chunkData = ChunkUtil.readChunkPacket(buffer, dimension, sectionBitMask!!, null, !isFullChunk, dimension.hasSkyLight) if (chunkData == null) { - unloadChunk = true + unload = true } else { - this@ChunkS2CP.chunkData.replace(chunkData) + this@ChunkS2CP.data.replace(chunkData) } } 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) { - if (unloadChunk) { - connection.world.unloadChunk(chunkPosition) + if (unload) { + connection.world.unloadChunk(position) return } readingData.readChunkData() - val chunk = connection.world.getOrCreateChunk(chunkPosition) - chunk.setData(chunkData) + val chunk = connection.world.getOrCreateChunk(position) + chunk.setData(data) } override fun log(reducedLog: Boolean) { if (reducedLog) { 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( diff --git a/src/main/java/de/bixilon/minosoft/util/KUtil.kt b/src/main/java/de/bixilon/minosoft/util/KUtil.kt index 5dd37da77..127a6978f 100644 --- a/src/main/java/de/bixilon/minosoft/util/KUtil.kt +++ b/src/main/java/de/bixilon/minosoft/util/KUtil.kt @@ -225,6 +225,7 @@ object KUtil { return null } + @Deprecated("Kutil") private inline fun String.checkInt(): Int? { var first = true for (point in codePoints()) {