From 86155c8f3fbfc90725db66d57f8f66ed82201a59 Mon Sep 17 00:00:00 2001 From: Bixilon Date: Fri, 12 Nov 2021 18:46:29 +0100 Subject: [PATCH] wip: improved chunk storing format --- .../data/entities/block/BlockEntity.kt | 2 +- .../entities/block/CampfireBlockEntity.kt | 2 +- .../entities/block/MobSpawnerBlockEntity.kt | 2 +- .../entities/block/NoteBlockBlockEntity.kt | 4 +- .../dimension/DimensionProperties.kt | 2 + .../data/registries/tweaker/VersionTweaker.kt | 41 ------ .../de/bixilon/minosoft/data/world/Chunk.kt | 133 ++++++++++-------- .../bixilon/minosoft/data/world/ChunkData.kt | 14 +- .../minosoft/data/world/ChunkSection.kt | 81 ++++++----- .../de/bixilon/minosoft/data/world/World.kt | 93 ++++-------- .../container/RegistrySectionDataProvider.kt | 43 ++++++ .../world/container/SectionDataProvider.kt | 112 +++++++++++++++ .../data/world/container/SemaphoreLock.kt | 36 +++++ .../minosoft/gui/rendering/RenderConstants.kt | 2 - .../gui/rendering/block/WorldRenderer.kt | 24 ++-- .../minosoft/gui/rendering/util/VecUtil.kt | 15 +- .../network/connection/play/PlayConnection.kt | 2 +- .../packets/s2c/play/BlockActionS2CP.kt | 2 +- .../s2c/play/BlockEntityMetaDataS2CP.kt | 2 +- .../packets/s2c/play/ChunkDataS2CP.kt | 13 +- .../packets/s2c/play/MassBlockSetS2CP.kt | 15 +- .../packets/s2c/play/MassChunkDataS2CP.kt | 6 - .../packets/s2c/play/SignTextSetS2CP.kt | 10 +- .../minosoft/protocol/protocol/PacketTypes.kt | 2 + .../bixilon/minosoft/util/chunk/ChunkUtil.kt | 19 ++- 25 files changed, 391 insertions(+), 286 deletions(-) create mode 100644 src/main/java/de/bixilon/minosoft/data/world/container/RegistrySectionDataProvider.kt create mode 100644 src/main/java/de/bixilon/minosoft/data/world/container/SectionDataProvider.kt create mode 100644 src/main/java/de/bixilon/minosoft/data/world/container/SemaphoreLock.kt diff --git a/src/main/java/de/bixilon/minosoft/data/entities/block/BlockEntity.kt b/src/main/java/de/bixilon/minosoft/data/entities/block/BlockEntity.kt index 45d83f10b..92d56c481 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/block/BlockEntity.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/block/BlockEntity.kt @@ -24,5 +24,5 @@ abstract class BlockEntity( open fun updateNBT(nbt: Map) = Unit - open fun realTick(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i) = Unit + open fun tick(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i) = Unit } diff --git a/src/main/java/de/bixilon/minosoft/data/entities/block/CampfireBlockEntity.kt b/src/main/java/de/bixilon/minosoft/data/entities/block/CampfireBlockEntity.kt index 5926b9f9b..4d47198e3 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/block/CampfireBlockEntity.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/block/CampfireBlockEntity.kt @@ -59,7 +59,7 @@ class CampfireBlockEntity(connection: PlayConnection) : BlockEntity(connection) } - override fun realTick(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i) { + override fun tick(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i) { if (blockState.properties[BlockProperties.LIT] != true) { return } diff --git a/src/main/java/de/bixilon/minosoft/data/entities/block/MobSpawnerBlockEntity.kt b/src/main/java/de/bixilon/minosoft/data/entities/block/MobSpawnerBlockEntity.kt index dec6af2cd..e05fb71bd 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/block/MobSpawnerBlockEntity.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/block/MobSpawnerBlockEntity.kt @@ -58,7 +58,7 @@ class MobSpawnerBlockEntity(connection: PlayConnection) : BlockEntity(connection // ToDo: {MaxNearbyEntities: 6s, RequiredPlayerRange: 16s, SpawnCount: 4s, x: -80, y: 4, SpawnData: {id: "minecraft:zombie"}, z: 212, id: "minecraft:mob_spawner", MaxSpawnDelay: 800s, SpawnRange: 4s, Delay: 0s, MinSpawnDelay: 200s} } - override fun realTick(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i) { + override fun tick(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i) { spawnParticles(blockPosition) } diff --git a/src/main/java/de/bixilon/minosoft/data/entities/block/NoteBlockBlockEntity.kt b/src/main/java/de/bixilon/minosoft/data/entities/block/NoteBlockBlockEntity.kt index b9e91a180..990d6af4e 100644 --- a/src/main/java/de/bixilon/minosoft/data/entities/block/NoteBlockBlockEntity.kt +++ b/src/main/java/de/bixilon/minosoft/data/entities/block/NoteBlockBlockEntity.kt @@ -50,8 +50,8 @@ class NoteBlockBlockEntity(connection: PlayConnection) : BlockEntity(connection) // ToDo: Play sound? } - override fun realTick(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i) { - super.realTick(connection, blockState, blockPosition) + override fun tick(connection: PlayConnection, blockState: BlockState, blockPosition: Vec3i) { + super.tick(connection, blockState, blockPosition) if (!showParticleNextTick) { return } diff --git a/src/main/java/de/bixilon/minosoft/data/registries/dimension/DimensionProperties.kt b/src/main/java/de/bixilon/minosoft/data/registries/dimension/DimensionProperties.kt index e7e9e0649..42877009a 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/dimension/DimensionProperties.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/dimension/DimensionProperties.kt @@ -37,6 +37,8 @@ data class DimensionProperties( } else { height / ProtocolDefinition.SECTION_HEIGHT_Y } + val sections = highestSection - lowestSection + val lightLevels = FloatArray(16) init { diff --git a/src/main/java/de/bixilon/minosoft/data/registries/tweaker/VersionTweaker.kt b/src/main/java/de/bixilon/minosoft/data/registries/tweaker/VersionTweaker.kt index a3af8f62a..c9a095dd6 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/tweaker/VersionTweaker.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/tweaker/VersionTweaker.kt @@ -18,12 +18,7 @@ import de.bixilon.minosoft.data.entities.entities.animal.horse.* import de.bixilon.minosoft.data.entities.entities.monster.* import de.bixilon.minosoft.data.entities.entities.vehicle.* import de.bixilon.minosoft.data.entities.meta.EntityMetaData -import de.bixilon.minosoft.data.registries.blocks.BlockState -import de.bixilon.minosoft.data.world.ChunkSection -import de.bixilon.minosoft.data.world.ChunkSection.Companion.indexPosition -import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import de.bixilon.minosoft.protocol.protocol.ProtocolVersions -import glm_.vec3.Vec3i object VersionTweaker { // some data was packed in mata data in early versions (1.8). This function converts it to the real resource location @@ -87,40 +82,4 @@ object VersionTweaker { } return fakeClass } - - @JvmStatic - fun transformSections(sections: Map, versionId: Int) { - // some blocks need to be tweaked. eg. Grass with a snow block on top becomes snowy grass block - if (versionId >= ProtocolDefinition.FLATTING_VERSION_ID) { - return - } - for ((sectionHeight, section) in sections) { - for ((index, blockState) in section.blocks.withIndex()) { - if (blockState == null) { - continue - } - val location = index.indexPosition - val newBlock = transformBlock(blockState, sections, location, sectionHeight) - if (newBlock === blockState) { - continue - } - if (newBlock == null) { - section.setBlockState(location, null) - continue - } - section.setBlockState(location, newBlock) - } - } - } - - - @JvmStatic - fun transformBlock(originalBlock: BlockState?, sections: Map, inChunkSectionPositions: Vec3i, sectionHeight: Int): BlockState? { - // ToDo: Broken - return originalBlock - } - - private fun getBlockAbove(sections: Map, inChunkSectionPositions: Vec3i, sectionHeight: Int): BlockState? { - return sections[sectionHeight]?.getBlockState(inChunkSectionPositions) - } } diff --git a/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt b/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt index f5fd359dd..eda2a88c3 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/Chunk.kt @@ -16,102 +16,113 @@ import de.bixilon.minosoft.data.entities.block.BlockEntity import de.bixilon.minosoft.data.registries.blocks.BlockState import de.bixilon.minosoft.data.world.biome.source.BiomeSource import de.bixilon.minosoft.data.world.light.LightAccessor -import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY -import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkSectionPosition -import de.bixilon.minosoft.gui.rendering.util.VecUtil.of import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection -import de.bixilon.minosoft.util.KUtil.toSynchronizedMap +import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import glm_.vec2.Vec2i import glm_.vec3.Vec3i /** - * Collection of chunks sections (allocated in y) + * Collection of chunks sections (from the lowest section to the highest section in y axis) */ class Chunk( - var sections: MutableMap? = null, + private val connection: PlayConnection, + private var sections: Array? = null, var biomeSource: BiomeSource? = null, var lightAccessor: LightAccessor? = null, -) { - private val lock = Object() +) : Iterable { + val lowestSection = connection.world.dimension!!.lowestSection + + val blocksInitialized: Boolean + get() = sections != null + val biomesInitialized + get() = biomeSource != null + val lightInitialized + get() = lightAccessor != null + val isFullyLoaded: Boolean - get() { - return sections != null && biomeSource != null && lightAccessor != null - } + get() = blocksInitialized && biomesInitialized && lightInitialized - operator fun get(inChunkPosition: Vec3i): BlockState? { - return sections?.get(inChunkPosition.sectionHeight)?.getBlockState(inChunkPosition.inChunkSectionPosition) + operator fun get(sectionHeight: Int): ChunkSection? = sections?.getOrNull(sectionHeight - lowestSection) + + fun get(x: Int, y: Int, z: Int): BlockState? { + return this[y.sectionHeight]?.blocks?.get(x, y % ProtocolDefinition.SECTION_HEIGHT_Y, z) } - operator fun get(x: Int, y: Int, z: Int): BlockState? { - return get(Vec3i(x, y, z)) + operator fun get(position: Vec3i): BlockState? = get(position.x, position.y, position.z) + + fun set(x: Int, y: Int, z: Int, blockState: BlockState?, blockEntity: BlockEntity? = null) { + val section = getOrPut(y.sectionHeight) + section.blocks[x, y % ProtocolDefinition.SECTION_HEIGHT_Y, z] = blockState + section.blockEntities[x, y % ProtocolDefinition.SECTION_HEIGHT_Y, z] = blockEntity // ToDo } + operator fun set(position: Vec3i, blockState: BlockState?) = set(position.x, position.y, position.z, blockState) + fun setBlocks(blocks: Map) { - for ((location, blockInfo) in blocks) { - set(location, blockInfo) + for ((location, blockState) in blocks) { + set(location, blockState) } } + fun getBlockEntity(x: Int, y: Int, z: Int): BlockEntity? { + return this[y.sectionHeight]?.blockEntities?.get(x, y % ProtocolDefinition.SECTION_HEIGHT_Y, z) + } + + fun getBlockEntity(position: Vec3i): BlockEntity? = getBlockEntity(position.x, position.y, position.z) + + fun setBlockEntity(x: Int, y: Int, z: Int, blockEntity: BlockEntity?) { + getOrPut(y.sectionHeight).blockEntities[x, y % ProtocolDefinition.SECTION_HEIGHT_Y, z] = blockEntity + } + + fun setBlockEntity(position: Vec3i, blockEntity: BlockEntity?) = setBlockEntity(position.x, position.y, position.z, blockEntity) + fun setData(data: ChunkData, merge: Boolean = false) { - synchronized(lock) { - data.blocks?.let { - if (sections == null) { - sections = mutableMapOf() - } - if (!merge) { - sections?.clear() - } - // replace all chunk sections - for ((sectionHeight, chunkSection) in it) { - getOrPut(sectionHeight).setData(chunkSection) - } + data.blocks?.let { + var sections = this.sections + if (sections == null || !merge) { + sections = arrayOfNulls(connection.world.dimension!!.sections) + this.sections = sections } - data.biomeSource?.let { - this.biomeSource = it - } - data.lightAccessor?.let { - this.lightAccessor = it + + // replace all chunk sections + for ((index, section) in it.withIndex()) { + section ?: continue + sections[index] = section } } - } - - - operator fun set(inChunkPosition: Vec3i, blockState: BlockState?) { - getOrPut(inChunkPosition.sectionHeight).setBlockState(inChunkPosition.inChunkSectionPosition, blockState) + data.biomeSource?.let { + this.biomeSource = it + } + data.lightAccessor?.let { + this.lightAccessor = it + } } private fun getOrPut(sectionHeight: Int): ChunkSection { - if (sections == null) { - throw IllegalStateException("Chunk not received/initialized yet!") - } - return sections!![sectionHeight].let { - var section = it - if (section == null) { - section = ChunkSection() - sections!![sectionHeight] = section - } - section + val sections = sections ?: throw NullPointerException("Sections not initialized yet!") + val sectionIndex = sectionHeight - lowestSection + + var section = sections[sectionIndex] + if (section == null) { + section = ChunkSection(connection.registries) + sections[sectionIndex] = section } + return section } - fun realTick(connection: PlayConnection, chunkPosition: Vec2i) { + fun tick(connection: PlayConnection, chunkPosition: Vec2i) { if (!isFullyLoaded) { return } - val sections = sections - sections ?: return - for ((height, section) in sections.toSynchronizedMap()) { - section.realTick(connection, Vec3i.of(chunkPosition, height, Vec3i.EMPTY)) + val sections = sections!! + for ((index, section) in sections.withIndex()) { + section ?: continue + section.tick(connection, chunkPosition, index - lowestSection) } } - - fun getBlockEntity(inChunkPosition: Vec3i): BlockEntity? { - return sections?.get(inChunkPosition.sectionHeight)?.getBlockEntity(inChunkPosition.inChunkSectionPosition) - } - - operator fun set(inChunkPosition: Vec3i, blockEntity: BlockEntity?) { - sections?.get(inChunkPosition.sectionHeight)?.setBlockEntity(inChunkPosition.inChunkSectionPosition, blockEntity) + override fun iterator(): Iterator { + return sections!!.iterator() } } diff --git a/src/main/java/de/bixilon/minosoft/data/world/ChunkData.kt b/src/main/java/de/bixilon/minosoft/data/world/ChunkData.kt index 2feff2d34..b297a1cac 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/ChunkData.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/ChunkData.kt @@ -17,20 +17,14 @@ import de.bixilon.minosoft.data.world.biome.source.BiomeSource import de.bixilon.minosoft.data.world.light.LightAccessor data class ChunkData( - var blocks: Map? = null, + var blocks: Array? = null, var biomeSource: BiomeSource? = null, var lightAccessor: LightAccessor? = null, ) { fun replace(data: ChunkData) { - data.blocks?.let { - this.blocks = it - } - data.biomeSource?.let { - this.biomeSource = it - } - data.lightAccessor?.let { - this.lightAccessor = it - } + data.blocks?.let { this.blocks = it } + data.biomeSource?.let { this.biomeSource = it } + data.lightAccessor?.let { this.lightAccessor = it } } } diff --git a/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt b/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt index f3c46f055..e560781e5 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt @@ -13,54 +13,69 @@ package de.bixilon.minosoft.data.world import de.bixilon.minosoft.data.entities.block.BlockEntity +import de.bixilon.minosoft.data.registries.biomes.Biome import de.bixilon.minosoft.data.registries.blocks.BlockState -import de.bixilon.minosoft.data.world.block.entities.ArrayBlockEntityProvider -import de.bixilon.minosoft.data.world.block.entities.BlockEntityProvider -import de.bixilon.minosoft.data.world.block.entities.MapBlockEntityProvider +import de.bixilon.minosoft.data.registries.registries.Registries +import de.bixilon.minosoft.data.world.container.RegistrySectionDataProvider +import de.bixilon.minosoft.data.world.container.SectionDataProvider +import de.bixilon.minosoft.gui.rendering.util.VecUtil.of import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition +import de.bixilon.minosoft.util.KUtil.unsafeCast +import glm_.vec2.Vec2i import glm_.vec3.Vec3i /** * Collection of 16x16x16 blocks */ class ChunkSection( - var blocks: Array = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION), - private var blockEntities: BlockEntityProvider = MapBlockEntityProvider(), + val blocks: RegistrySectionDataProvider, + @Deprecated("TODO") + val biomes: RegistrySectionDataProvider, + val blockEntities: SectionDataProvider, + @Deprecated("TODO") + val light: ByteArray, // packed (skyLight: 0xF0, blockLight: 0x0F) ) { - fun getBlockState(inChunkSectionPositions: Vec3i): BlockState? { - return blocks[inChunkSectionPositions.index] - } - - fun setBlockState(inChunkSectionPositions: Vec3i, blockState: BlockState?) { - blocks[inChunkSectionPositions.index] = blockState - } - - fun setData(chunkSection: ChunkSection) { - blocks = chunkSection.blocks.clone() - blockEntities = chunkSection.blockEntities.clone() - } - - fun getBlockEntity(inChunkSectionPositions: Vec3i): BlockEntity? { - return blockEntities[inChunkSectionPositions] - } - - fun setBlockEntity(inChunkSectionPositions: Vec3i, blockEntity: BlockEntity?) { - blockEntities[inChunkSectionPositions] = blockEntity - val blockEntities = blockEntities - if (blockEntities.size > BlockEntityProvider.BLOCK_ENTITY_MAP_LIMIT_UP && blockEntities is MapBlockEntityProvider) { - this.blockEntities = ArrayBlockEntityProvider(blockEntities) - } else if (blockEntities.size <= BlockEntityProvider.BLOCK_ENTITY_MAP_LIMIT_DOWN && blockEntities is ArrayBlockEntityProvider) { - this.blockEntities = MapBlockEntityProvider(blockEntities) + constructor(registries: Registries, blocks: Array? = null) : this(RegistrySectionDataProvider(registries.blockStateRegistry.unsafeCast()), RegistrySectionDataProvider(registries.biomeRegistry), SectionDataProvider(), ByteArray(ProtocolDefinition.BLOCKS_PER_SECTION)) { + if (blocks != null) { + this.blocks.setData(blocks) } } - fun realTick(connection: PlayConnection, chunkSectionPosition: Vec3i) { - blockEntities.forEach { entity, inChunkSectionPosition -> - val block = blocks[inChunkSectionPosition.index] ?: return@forEach // maybe block already got destroyed - entity.realTick(connection, block, chunkSectionPosition + inChunkSectionPosition) + fun tick(connection: PlayConnection, chunkPosition: Vec2i, sectionHeight: Int) { + acquire() + for ((index, blockEntity) in blockEntities.withIndex()) { + blockEntity ?: continue + val position = Vec3i.of(chunkPosition, sectionHeight, index.indexPosition) + val blockState = blocks[index] ?: continue + blockEntity.tick(connection, blockState, position) } + release() + } + + fun acquire() { + blocks.acquire() + biomes.acquire() + blockEntities.acquire() + } + + fun release() { + blocks.release() + biomes.release() + blockEntities.release() + } + + fun lock() { + blocks.lock() + biomes.lock() + blockEntities.lock() + } + + fun unlock() { + blocks.unlock() + biomes.unlock() + blockEntities.unlock() } companion object { diff --git a/src/main/java/de/bixilon/minosoft/data/world/World.kt b/src/main/java/de/bixilon/minosoft/data/world/World.kt index 2d41ebcff..ceec0a3cb 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/World.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/World.kt @@ -21,7 +21,6 @@ import de.bixilon.minosoft.data.registries.blocks.BlockState import de.bixilon.minosoft.data.registries.blocks.types.FluidBlock import de.bixilon.minosoft.data.registries.dimension.DimensionProperties import de.bixilon.minosoft.data.registries.sounds.SoundEvent -import de.bixilon.minosoft.data.registries.tweaker.VersionTweaker import de.bixilon.minosoft.data.world.biome.accessor.BiomeAccessor import de.bixilon.minosoft.data.world.biome.accessor.NullBiomeAccessor import de.bixilon.minosoft.data.world.light.WorldLightAccessor @@ -31,10 +30,8 @@ import de.bixilon.minosoft.gui.rendering.sound.AudioPlayer import de.bixilon.minosoft.gui.rendering.util.VecUtil.blockPosition import de.bixilon.minosoft.gui.rendering.util.VecUtil.chunkPosition import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkPosition -import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkSectionPosition import de.bixilon.minosoft.gui.rendering.util.VecUtil.minus import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus -import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight import de.bixilon.minosoft.modding.event.EventInitiators import de.bixilon.minosoft.modding.event.events.BlockSetEvent import de.bixilon.minosoft.modding.event.events.ChunkUnloadEvent @@ -43,6 +40,7 @@ import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import de.bixilon.minosoft.util.KUtil.synchronizedMapOf import de.bixilon.minosoft.util.KUtil.toSynchronizedMap import de.bixilon.minosoft.util.MMath +import de.bixilon.minosoft.util.collections.SynchronizedMap import glm_.func.common.clamp import glm_.vec2.Vec2i import glm_.vec3.Vec3 @@ -58,7 +56,7 @@ import kotlin.random.Random class World( val connection: PlayConnection, ) : BiomeAccessor { - val chunks: MutableMap = synchronizedMapOf() + val chunks: SynchronizedMap = synchronizedMapOf() val entities = WorldEntities() var hardcore = false var dimension: DimensionProperties? = null @@ -81,14 +79,12 @@ class World( return chunks[blockPosition.chunkPosition]?.get(blockPosition.inChunkPosition) } - @Synchronized operator fun get(chunkPosition: Vec2i): Chunk? { return chunks[chunkPosition] } - @Synchronized fun getOrCreateChunk(chunkPosition: Vec2i): Chunk { - return chunks.getOrPut(chunkPosition) { Chunk() } + return chunks.getOrPut(chunkPosition) { Chunk(connection) } } fun setBlockState(blockPosition: Vec3i, blockState: BlockState?) { @@ -96,32 +92,24 @@ class World( } operator fun set(blockPosition: Vec3i, blockState: BlockState?) { - val chunkPosition = blockPosition.chunkPosition - chunks[chunkPosition]?.let { - val sections = it.sections ?: return - - val transformedBlockState = if (connection.version.isFlattened()) { - blockState - } else { - VersionTweaker.transformBlock(blockState, sections, blockPosition.inChunkSectionPosition, blockPosition.sectionHeight) - } - val inChunkPosition = blockPosition.inChunkPosition - val previousBlock = it[inChunkPosition] - if (previousBlock == transformedBlockState) { - return - } - previousBlock?.block?.onBreak(connection, blockPosition, previousBlock, it.getBlockEntity(inChunkPosition)) - blockState?.block?.onPlace(connection, blockPosition, blockState) - it[inChunkPosition] = transformedBlockState - connection.fireEvent(BlockSetEvent( - connection = connection, - blockPosition = blockPosition, - blockState = transformedBlockState, - )) + val chunk = chunks[blockPosition.chunkPosition] ?: return + val inChunkPosition = blockPosition.inChunkPosition + val previousBlock = chunk[inChunkPosition] + if (previousBlock == blockState) { + return } + previousBlock?.block?.onBreak(connection, blockPosition, previousBlock, chunk.getBlockEntity(inChunkPosition)) + blockState?.block?.onPlace(connection, blockPosition, blockState) + chunk[inChunkPosition] = blockState + connection.fireEvent(BlockSetEvent( + connection = connection, + blockPosition = blockPosition, + blockState = blockState, + )) } fun isPositionChangeable(blockPosition: Vec3i): Boolean { + // ToDo: World border val dimension = connection.world.dimension!! return (blockPosition.y >= dimension.minY || blockPosition.y < dimension.height) } @@ -134,37 +122,22 @@ class World( } fun unloadChunk(chunkPosition: Vec2i) { - chunks.remove(chunkPosition)?.let { - connection.fireEvent(ChunkUnloadEvent(connection, EventInitiators.UNKNOWN, chunkPosition)) - } - } - - fun replaceChunk(position: Vec2i, chunk: Chunk) { - chunks[position] = chunk - } - - fun replaceChunks(chunkMap: HashMap) { - for ((chunkLocation, chunk) in chunkMap) { - chunks[chunkLocation] = chunk - } + chunks.remove(chunkPosition) ?: return + connection.fireEvent(ChunkUnloadEvent(connection, EventInitiators.UNKNOWN, chunkPosition)) } fun getBlockEntity(blockPosition: Vec3i): BlockEntity? { return get(blockPosition.chunkPosition)?.getBlockEntity(blockPosition.inChunkPosition) } - operator fun set(blockPosition: Vec3i, blockEntity: BlockEntity?) { - get(blockPosition.chunkPosition)?.set(blockPosition.inChunkPosition, blockEntity) - } - fun setBlockEntity(blockPosition: Vec3i, blockEntity: BlockEntity?) { - this[blockPosition] = blockEntity + get(blockPosition.chunkPosition)?.setBlockEntity(blockPosition.inChunkPosition, blockEntity) } fun setBlockEntities(blockEntities: Map) { - for ((blockPosition, entityMetaData) in blockEntities) { - set(blockPosition, entityMetaData) + for ((blockPosition, blockEntity) in blockEntities) { + setBlockEntity(blockPosition, blockEntity) } } @@ -172,9 +145,9 @@ class World( return biomeAccessor.getBiome(blockPosition) } - fun realTick() { + fun tick() { for ((chunkPosition, chunk) in chunks.toSynchronizedMap()) { - chunk.realTick(connection, chunkPosition) + chunk.tick(connection, chunkPosition) } } @@ -201,24 +174,6 @@ class World( return ret.toMap() } - fun getBlocks(start: Vec3i, end: Vec3i): Map { - val blocks: MutableMap = mutableMapOf() - - for (z in start.z..end.z) { - for (y in start.y..end.y) { - for (x in start.x..end.x) { - val blockPosition = Vec3i(x, y, z) - this[blockPosition]?.let { - blocks[blockPosition] = it - } - } - } - } - - return blocks.toMap() - } - - fun playSoundEvent(resourceLocation: ResourceLocation, position: Vec3i? = null, volume: Float = 1.0f, pitch: Float = 1.0f) { audioPlayer?.playSoundEvent(resourceLocation, position, volume, pitch) } diff --git a/src/main/java/de/bixilon/minosoft/data/world/container/RegistrySectionDataProvider.kt b/src/main/java/de/bixilon/minosoft/data/world/container/RegistrySectionDataProvider.kt new file mode 100644 index 000000000..4241b8077 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/world/container/RegistrySectionDataProvider.kt @@ -0,0 +1,43 @@ +/* + * Minosoft + * Copyright (C) 2021 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.data.world.container + +import de.bixilon.minosoft.data.registries.registries.registry.AbstractRegistry +import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition + +class RegistrySectionDataProvider( + val registry: AbstractRegistry, + data: Array = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION), +) : SectionDataProvider(data) { + + @Suppress("UNCHECKED_CAST") + fun setIdData(ids: Array) { + val data: Array = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION) + + for ((index, id) in ids.withIndex()) { + data[index] = registry[id] + } + + setData(data as Array) + } + + + override fun copy(): RegistrySectionDataProvider { + acquire() + val clone = RegistrySectionDataProvider(registry, data.clone()) + release() + + return clone + } +} diff --git a/src/main/java/de/bixilon/minosoft/data/world/container/SectionDataProvider.kt b/src/main/java/de/bixilon/minosoft/data/world/container/SectionDataProvider.kt new file mode 100644 index 000000000..ca284f5f5 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/world/container/SectionDataProvider.kt @@ -0,0 +1,112 @@ +/* + * Minosoft + * Copyright (C) 2021 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.data.world.container + +import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition + +open class SectionDataProvider( + data: Array = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION), +) : Iterable { + protected var data = data + private set + protected val lock = SemaphoreLock() // lock while reading (blocks writing) + var count: Int = 0 + private set + + init { + recalculateCount() + } + + @Suppress("UNCHECKED_CAST") + operator fun get(index: Int): T { + lock.acquire() + val value = data[index] as T + lock.release() + return value + } + + private fun recalculateCount() { + var count = 0 + for (value in data) { + if (value == null) { + continue + } + count++ + } + this.count = count + } + + operator fun get(x: Int, y: Int, z: Int): T { + return get(y shl 8 or (z shl 4) or x) + } + + operator fun set(x: Int, y: Int, z: Int, value: T) { + set(y shl 8 or (z shl 4) or x, value) + } + + operator fun set(index: Int, value: T) { + lock() + val previous = data[index] + if (value == null) { + if (previous == null) { + return + } + count-- + } else if (previous == null) { + count++ + } + data[index] = value + unlock() + } + + fun acquire() { + lock.acquire() + } + + fun release() { + lock.release() + } + + fun lock() { + lock.lock() + } + + fun unlock() { + lock.unlock() + } + + + @Suppress("UNCHECKED_CAST") + @Synchronized + fun setData(data: Array) { + lock() + check(data.size == ProtocolDefinition.BLOCKS_PER_SECTION) { "Size does not match!" } + this.data = data as Array + recalculateCount() + unlock() + } + + open fun copy(): SectionDataProvider { + acquire() + val clone = SectionDataProvider(data.clone()) + release() + + return clone + } + + @Suppress("UNCHECKED_CAST") + override fun iterator(): Iterator { + return data.iterator() as Iterator + } +} diff --git a/src/main/java/de/bixilon/minosoft/data/world/container/SemaphoreLock.kt b/src/main/java/de/bixilon/minosoft/data/world/container/SemaphoreLock.kt new file mode 100644 index 000000000..8dade8430 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/world/container/SemaphoreLock.kt @@ -0,0 +1,36 @@ +/* + * Minosoft + * Copyright (C) 2021 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.data.world.container + +import java.util.concurrent.Semaphore + +class SemaphoreLock { + private val semaphore = Semaphore(Int.MAX_VALUE) + + fun acquire() { + semaphore.acquire() + } + + fun release() { + semaphore.release() + } + + fun lock() { + semaphore.acquire(Int.MAX_VALUE) + } + + fun unlock() { + semaphore.release(Int.MAX_VALUE) + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderConstants.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderConstants.kt index 93223a8d2..412dab504 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/RenderConstants.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/RenderConstants.kt @@ -43,8 +43,6 @@ object RenderConstants { const val TEXT_LINE_PADDING = 2 val WORD_SEPARATORS = arrayOf(' ', '.', ',', '!', '-', '?') - const val CHUNK_SECTIONS_PER_MESH = 1 - const val FRUSTUM_CULLING_ENABLED = true const val SHOW_FPS_IN_WINDOW_TITLE = true diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/block/WorldRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/block/WorldRenderer.kt index 78dc597f2..19f9c40c4 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/block/WorldRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/block/WorldRenderer.kt @@ -29,7 +29,10 @@ import de.bixilon.minosoft.data.world.Chunk import de.bixilon.minosoft.data.world.ChunkSection import de.bixilon.minosoft.data.world.ChunkSection.Companion.indexPosition import de.bixilon.minosoft.data.world.World -import de.bixilon.minosoft.gui.rendering.* +import de.bixilon.minosoft.gui.rendering.RenderWindow +import de.bixilon.minosoft.gui.rendering.Renderer +import de.bixilon.minosoft.gui.rendering.RendererBuilder +import de.bixilon.minosoft.gui.rendering.RenderingStates import de.bixilon.minosoft.gui.rendering.block.mesh.ChunkSectionMeshCollection import de.bixilon.minosoft.gui.rendering.block.renderable.BlockLikeRenderContext import de.bixilon.minosoft.gui.rendering.input.camera.Frustum @@ -171,7 +174,7 @@ class WorldRenderer( connection.registerEvent(CallbackEventInvoker.of { unloadChunk(it.chunkPosition) }) - connection.registerEvent(CallbackEventInvoker.of { prepareChunk(it.chunkPosition) }) + connection.registerEvent(CallbackEventInvoker.of { prepareChunk(it.chunkPosition, it.chunk) }) connection.registerEvent(CallbackEventInvoker.of { prepareChunkSection(it.blockPosition.chunkPosition, it.blockPosition.sectionHeight) }) @@ -297,7 +300,9 @@ class WorldRenderer( var currentChunks: MutableMap = synchronizedMapOf() var currentIndex = 0 - for ((sectionHeight, section) in chunk.sections!!) { + for ((index, section) in chunk.withIndex()) { + section ?: continue + val sectionHeight = index - chunk.lowestSection if (sectionHeight.sectionIndex != currentIndex) { prepareChunkSections(chunkPosition, currentChunks) currentChunks = synchronizedMapOf() @@ -419,9 +424,8 @@ class WorldRenderer( private fun prepareChunkSection(chunkPosition: Vec2i, sectionHeight: Int) { val sections: MutableMap = synchronizedMapOf() val chunk = world[chunkPosition]!! - val lowestSectionHeight = sectionHeight.sectionIndex * RenderConstants.CHUNK_SECTIONS_PER_MESH - for (i in lowestSectionHeight until lowestSectionHeight + RenderConstants.CHUNK_SECTIONS_PER_MESH) { - sections[i] = chunk.sections?.get(i) ?: continue + for ((index, section) in chunk.withIndex()) { + sections[index - chunk.lowestSection] = section ?: continue } prepareChunkSections(chunkPosition, sections) } @@ -508,13 +512,7 @@ class WorldRenderer( } val Int.sectionIndex: Int - get() { - val divided = this / RenderConstants.CHUNK_SECTIONS_PER_MESH - if (this < 0) { - return divided - 1 - } - return divided - } + get() = this private operator fun Int.plus(upOrDown: Directions): Int { return this + upOrDown.vector.y diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt index 994531268..89d076ad2 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt @@ -241,15 +241,16 @@ object VecUtil { return Vec3i(inVec2i.x, y, inVec2i.z) } - val Vec3i.sectionHeight: Int - get() { - return if (y < 0) { - (y + 1) / ProtocolDefinition.SECTION_HEIGHT_Y - 1 - } else { - y / ProtocolDefinition.SECTION_HEIGHT_Y - } + val Int.sectionHeight: Int + get() = if (this < 0) { + (this + 1) / ProtocolDefinition.SECTION_HEIGHT_Y - 1 + } else { + this / ProtocolDefinition.SECTION_HEIGHT_Y } + val Vec3i.sectionHeight: Int + get() = y.sectionHeight + val Vec3i.entityPosition: Vec3d get() = Vec3d(x + 0.5f, y, z + 0.5f) // ToDo: Confirm diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/PlayConnection.kt b/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/PlayConnection.kt index 9fcaad66a..83dfbb2c3 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/PlayConnection.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/PlayConnection.kt @@ -158,7 +158,7 @@ class PlayConnection( }) worldTickTask = TimeWorker.addTask(TimeWorkerTask(ProtocolDefinition.TICK_TIME, maxDelayTime = ProtocolDefinition.TICK_TIME / 2) { - world.realTick() + world.tick() }) randomTickTask = TimeWorker.addTask(TimeWorkerTask(ProtocolDefinition.TICK_TIME, maxDelayTime = ProtocolDefinition.TICK_TIME / 2) { diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/BlockActionS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/BlockActionS2CP.kt index 1bf58a281..3c6b198a7 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/BlockActionS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/BlockActionS2CP.kt @@ -45,7 +45,7 @@ class BlockActionS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() { return } val blockEntity = factory.build(connection) - connection.world[position] = blockEntity + connection.world.setBlockEntity(position, blockEntity) blockEntity } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/BlockEntityMetaDataS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/BlockEntityMetaDataS2CP.kt index 6b982836f..9f45962f2 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/BlockEntityMetaDataS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/BlockEntityMetaDataS2CP.kt @@ -37,7 +37,7 @@ class BlockEntityMetaDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() { connection.world.getBlockEntity(position)?.updateNBT(nbt) ?: let { val blockEntity = DefaultBlockEntityMetaDataFactory.buildBlockEntity(DefaultBlockEntityMetaDataFactory[type]!!, connection) blockEntity.updateNBT(nbt) - connection.world[position] = blockEntity + connection.world.setBlockEntity(position, blockEntity) } connection.fireEvent(BlockEntityMetaDataChangeEvent(connection, this)) } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ChunkDataS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ChunkDataS2CP.kt index f32122a3a..dce5cc940 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ChunkDataS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ChunkDataS2CP.kt @@ -15,10 +15,11 @@ package de.bixilon.minosoft.protocol.packets.s2c.play import de.bixilon.minosoft.Minosoft import de.bixilon.minosoft.data.entities.block.BlockEntity import de.bixilon.minosoft.data.registries.ResourceLocation -import de.bixilon.minosoft.data.registries.tweaker.VersionTweaker import de.bixilon.minosoft.data.world.ChunkData import de.bixilon.minosoft.data.world.biome.source.SpatialBiomeArray import de.bixilon.minosoft.datafixer.BlockEntityFixer.fix +import de.bixilon.minosoft.gui.rendering.util.VecUtil.EMPTY +import de.bixilon.minosoft.gui.rendering.util.VecUtil.of import de.bixilon.minosoft.modding.event.EventInitiators import de.bixilon.minosoft.modding.event.events.ChunkDataChangeEvent import de.bixilon.minosoft.modding.event.events.ChunkUnloadEvent @@ -106,10 +107,11 @@ class ChunkDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() { buffer.pointer = size + lastPos } if (buffer.versionId >= ProtocolVersions.V_1_9_4) { + val positionOffset = Vec3i.of(chunkPosition, dimension.lowestSection, Vec3i.EMPTY) val blockEntitiesCount = buffer.readVarInt() for (i in 0 until blockEntitiesCount) { val nbt = buffer.readNBT().asCompound() - val position = Vec3i(nbt["x"]!!.toInt(), nbt["y"]!!.toInt(), nbt["z"]!!.toInt()) + val position = Vec3i(nbt["x"]!!.toInt(), nbt["y"]!!.toInt(), nbt["z"]!!.toInt()) - positionOffset val resourceLocation = ResourceLocation(nbt["id"].unsafeCast()).fix() val type = buffer.connection.registries.blockEntityTypeRegistry[resourceLocation] ?: let { Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.WARN) { "Unknown block entity: $resourceLocation" } @@ -124,13 +126,12 @@ class ChunkDataS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() { } override fun handle(connection: PlayConnection) { - chunkData?.blocks?.let { - VersionTweaker.transformSections(it, connection.version.versionId) - } chunkData?.let { val chunk = connection.world.getOrCreateChunk(chunkPosition) chunk.setData(chunkData!!) - connection.world.setBlockEntities(blockEntities) + for ((position, blockEntity) in blockEntities) { + chunk.setBlockEntity(position, blockEntity) + } connection.fireEvent(ChunkDataChangeEvent(connection, this)) } ?: let { connection.world.unloadChunk(chunkPosition) diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/MassBlockSetS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/MassBlockSetS2CP.kt index 436180728..20cda731a 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/MassBlockSetS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/MassBlockSetS2CP.kt @@ -14,9 +14,6 @@ package de.bixilon.minosoft.protocol.packets.s2c.play import de.bixilon.minosoft.data.registries.blocks.BlockState -import de.bixilon.minosoft.data.registries.tweaker.VersionTweaker -import de.bixilon.minosoft.gui.rendering.util.VecUtil.inChunkSectionPosition -import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight import de.bixilon.minosoft.modding.event.events.MassBlockSetEvent import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.protocol.packets.s2c.PlayS2CPacket @@ -81,21 +78,11 @@ class MassBlockSetS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() { override fun handle(connection: PlayConnection) { val chunk = connection.world[chunkPosition] ?: return // thanks mojang - if (chunk.sections == null) { + if (!chunk.blocksInitialized) { return } chunk.setBlocks(blocks) - // tweak - if (!connection.version.isFlattened()) { - for ((key, value) in blocks) { - val block = VersionTweaker.transformBlock(value, chunk.sections!!, key.inChunkSectionPosition, key.sectionHeight) - if (block === value) { - continue - } - chunk[key] = block - } - } connection.fireEvent(MassBlockSetEvent(connection, this)) } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/MassChunkDataS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/MassChunkDataS2CP.kt index 44c375002..66894cf13 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/MassChunkDataS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/MassChunkDataS2CP.kt @@ -13,10 +13,8 @@ package de.bixilon.minosoft.protocol.packets.s2c.play import de.bixilon.minosoft.Minosoft -import de.bixilon.minosoft.data.registries.tweaker.VersionTweaker import de.bixilon.minosoft.data.world.ChunkData import de.bixilon.minosoft.modding.event.EventInitiators - import de.bixilon.minosoft.modding.event.events.ChunkDataChangeEvent import de.bixilon.minosoft.modding.event.events.ChunkUnloadEvent import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection @@ -73,10 +71,6 @@ class MassChunkDataS2CP() : PlayS2CPacket() { override fun handle(connection: PlayConnection) { // transform data for ((chunkPosition, data) in data) { - data?.blocks?.let { - VersionTweaker.transformSections(it, connection.version.versionId) - } - data?.let { val chunk = connection.world.getOrCreateChunk(chunkPosition) chunk.setData(data) diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/SignTextSetS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/SignTextSetS2CP.kt index cb61de973..38ae0b113 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/SignTextSetS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/SignTextSetS2CP.kt @@ -26,7 +26,7 @@ import de.bixilon.minosoft.util.logging.LogMessageType import glm_.vec3.Vec3i class SignTextSetS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() { - val signPosition: Vec3i = if (buffer.versionId < ProtocolVersions.V_14W04A) { + val position: Vec3i = if (buffer.versionId < ProtocolVersions.V_14W04A) { buffer.readShortBlockPosition() } else { buffer.readBlockPosition() @@ -43,16 +43,14 @@ class SignTextSetS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() { } override fun handle(connection: PlayConnection) { - val signBlockEntity = connection.world.getBlockEntity(signPosition)?.unsafeCast() ?: let { - val blockEntity = SignBlockEntity(connection) - connection.world[signPosition] = blockEntity - blockEntity + val signBlockEntity = connection.world.getBlockEntity(position)?.unsafeCast() ?: SignBlockEntity(connection).apply { + connection.world.setBlockEntity(position, this) } signBlockEntity.lines = lines } override fun log() { - Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Sign text set (position=$signPosition, lines=$lines" } + Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Sign text set (position=$position, lines=$lines" } } } diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketTypes.kt b/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketTypes.kt index a89e324cf..4dd96673d 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketTypes.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/PacketTypes.kt @@ -52,6 +52,7 @@ import de.bixilon.minosoft.protocol.packets.s2c.status.StatusPongS2CP class PacketTypes { + @Suppress("UNUSED") enum class C2S(val clazz: Class? = null) { HANDSHAKING_HANDSHAKE(HandshakeC2SP::class.java), STATUS_PING(StatusPingC2SP::class.java), @@ -145,6 +146,7 @@ class PacketTypes { } + @Suppress("UNUSED") enum class S2C( val playFactory: ((buffer: PlayInByteBuffer) -> PlayS2CPacket)? = null, val statusFactory: ((buffer: InByteBuffer) -> StatusS2CPacket)? = null, diff --git a/src/main/java/de/bixilon/minosoft/util/chunk/ChunkUtil.kt b/src/main/java/de/bixilon/minosoft/util/chunk/ChunkUtil.kt index 9127322bb..7db9dffae 100644 --- a/src/main/java/de/bixilon/minosoft/util/chunk/ChunkUtil.kt +++ b/src/main/java/de/bixilon/minosoft/util/chunk/ChunkUtil.kt @@ -24,7 +24,6 @@ import de.bixilon.minosoft.data.world.palette.Palette.Companion.choosePalette import de.bixilon.minosoft.protocol.protocol.PlayInByteBuffer import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import de.bixilon.minosoft.protocol.protocol.ProtocolVersions.* -import de.bixilon.minosoft.util.KUtil.synchronizedMapOf import java.util.* @@ -59,7 +58,7 @@ object ChunkUtil { // parse data var arrayPosition = 0 - val sectionMap: MutableMap = synchronizedMapOf() + val sections: Array = arrayOfNulls(dimension.sections) for ((sectionIndex, sectionHeight) in (dimension.lowestSection until dimension.highestSection).withIndex()) { if (!sectionBitMask[sectionIndex]) { continue @@ -91,9 +90,9 @@ object ChunkUtil { blocks[blockNumber] = buffer.connection.registries.blockStateRegistry[blockId] ?: continue } - sectionMap[sectionHeight] = ChunkSection(blocks) + sections[sectionHeight - dimension.lowestSection] = ChunkSection(buffer.connection.registries, blocks) } - chunkData.blocks = sectionMap + chunkData.blocks = sections return chunkData } @@ -125,7 +124,7 @@ object ChunkUtil { } var arrayPos = 0 - val sectionMap: MutableMap = synchronizedMapOf() + val sections: Array = arrayOfNulls(dimension.sections) for ((sectionIndex, sectionHeight) in (dimension.lowestSection until dimension.highestSection).withIndex()) { // max sections per chunks in chunk column if (!sectionBitMask[sectionIndex]) { continue @@ -136,15 +135,15 @@ object ChunkUtil { val block = buffer.connection.registries.blockStateRegistry[blockId] ?: continue blocks[blockNumber] = block } - sectionMap[sectionHeight] = ChunkSection(blocks) + sections[sectionHeight] = ChunkSection(buffer.connection.registries, blocks) } - chunkData.blocks = sectionMap + chunkData.blocks = sections return chunkData } fun readPaletteChunk(buffer: PlayInByteBuffer, dimension: DimensionProperties, sectionBitMask: BitSet, isFullChunk: Boolean, containsSkyLight: Boolean = false): ChunkData { val chunkData = ChunkData() - val sectionMap: MutableMap = synchronizedMapOf() + val sections: Array = arrayOfNulls(dimension.sections) for ((sectionIndex, sectionHeight) in (dimension.lowestSection until sectionBitMask.length()).withIndex()) { // max sections per chunks in chunk column if (!sectionBitMask[sectionIndex]) { @@ -193,10 +192,10 @@ object ChunkUtil { // ToDo chunkData.lightAccessor = DummyLightAccessor } - sectionMap[sectionHeight] = ChunkSection(blocks) + sections[sectionHeight - dimension.lowestSection] = ChunkSection(buffer.connection.registries, blocks) } - chunkData.blocks = sectionMap + chunkData.blocks = sections if (buffer.versionId < V_19W36A && isFullChunk) { chunkData.biomeSource = readLegacyBiomeArray(buffer) }