From 0c7ba090f00da787292ce602c442d7f000e65acd Mon Sep 17 00:00:00 2001 From: Bixilon Date: Mon, 26 Apr 2021 15:27:28 +0200 Subject: [PATCH] improve block entity storage --- .../locale/minecraft/MinecraftLanguage.kt | 1 - .../minosoft/data/world/ChunkSection.kt | 26 +++++----- .../entities/ArrayBlockEntityProvider.kt | 47 +++++++++++++++++++ .../block/entities/BlockEntityProvider.kt | 31 ++++++++++++ .../block/entities/MapBlockEntityProvider.kt | 46 ++++++++++++++++++ .../packets/s2c/play/ChunkDataS2CP.kt | 4 -- 6 files changed, 138 insertions(+), 17 deletions(-) create mode 100644 src/main/java/de/bixilon/minosoft/data/world/block/entities/ArrayBlockEntityProvider.kt create mode 100644 src/main/java/de/bixilon/minosoft/data/world/block/entities/BlockEntityProvider.kt create mode 100644 src/main/java/de/bixilon/minosoft/data/world/block/entities/MapBlockEntityProvider.kt diff --git a/src/main/java/de/bixilon/minosoft/data/locale/minecraft/MinecraftLanguage.kt b/src/main/java/de/bixilon/minosoft/data/locale/minecraft/MinecraftLanguage.kt index 79cfe1496..2aac1ce91 100644 --- a/src/main/java/de/bixilon/minosoft/data/locale/minecraft/MinecraftLanguage.kt +++ b/src/main/java/de/bixilon/minosoft/data/locale/minecraft/MinecraftLanguage.kt @@ -94,6 +94,5 @@ open class MinecraftLanguage : Translator { companion object { private val FORMATTER_ORDER_REGEX = "%(\\w+)\\\$[sd]".toRegex() // %1$s fell from a high place private val FORMATTER_SPLIT_REGEX = "%[ds]".toRegex() // %s fell from a high place - } } 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 ee84547e5..fede4e277 100644 --- a/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt +++ b/src/main/java/de/bixilon/minosoft/data/world/ChunkSection.kt @@ -14,6 +14,9 @@ package de.bixilon.minosoft.data.world import de.bixilon.minosoft.data.entities.block.BlockEntity import de.bixilon.minosoft.data.mappings.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.protocol.protocol.ProtocolDefinition import glm_.vec3.Vec3i @@ -21,9 +24,8 @@ import glm_.vec3.Vec3i * Collection of 16x16x16 blocks */ class ChunkSection( - val blocks: Array = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION), - val blockEntities: Array = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION), - // ToDo: BlockEntityMeta + var blocks: Array = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION), + private var blockEntities: BlockEntityProvider = MapBlockEntityProvider(), ) { fun getBlockState(inChunkSectionPositions: Vec3i): BlockState? { @@ -34,22 +36,22 @@ class ChunkSection( blocks[inChunkSectionPositions.index] = blockState } - fun getBlockState(x: Int, y: Int, z: Int): BlockState? { - return getBlockState(Vec3i(x, y, z)) - } - fun setData(chunkSection: ChunkSection) { - for ((index, blockInfo) in chunkSection.blocks.withIndex()) { - blocks[index] = blockInfo - } + blocks = chunkSection.blocks.clone() } fun getBlockEntity(inChunkSectionPositions: Vec3i): BlockEntity? { - return blockEntities[inChunkSectionPositions.index] + return blockEntities[inChunkSectionPositions] } fun setBlockEntity(inChunkSectionPositions: Vec3i, blockEntity: BlockEntity?) { - blockEntities[inChunkSectionPositions.index] = 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) + } } companion object { diff --git a/src/main/java/de/bixilon/minosoft/data/world/block/entities/ArrayBlockEntityProvider.kt b/src/main/java/de/bixilon/minosoft/data/world/block/entities/ArrayBlockEntityProvider.kt new file mode 100644 index 000000000..cb2ed9a7f --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/world/block/entities/ArrayBlockEntityProvider.kt @@ -0,0 +1,47 @@ +/* + * 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.block.entities + +import de.bixilon.minosoft.data.entities.block.BlockEntity +import de.bixilon.minosoft.data.world.ChunkSection.Companion.index +import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition +import glm_.vec3.Vec3i + +class ArrayBlockEntityProvider() : BlockEntityProvider { + override var size: Int = 0 + private set + + + constructor(blockEntityProvider: MapBlockEntityProvider) : this() { + for ((position, blockEntity) in blockEntityProvider.blockEntities) { + blockEntities[position.index] = blockEntity + } + } + + var blockEntities: Array = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION) + + override fun get(inChunkSectionPosition: Vec3i): BlockEntity? { + return blockEntities[inChunkSectionPosition.index] + } + + override fun set(inChunkSectionPosition: Vec3i, blockEntity: BlockEntity?) { + val previous = blockEntities[inChunkSectionPosition.index] + blockEntities[inChunkSectionPosition.index] = blockEntity + if (previous != null && blockEntity == null) { + size-- + } else if (previous == null && blockEntity != null) { + size++ + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/data/world/block/entities/BlockEntityProvider.kt b/src/main/java/de/bixilon/minosoft/data/world/block/entities/BlockEntityProvider.kt new file mode 100644 index 000000000..f25004084 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/world/block/entities/BlockEntityProvider.kt @@ -0,0 +1,31 @@ +/* + * 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.block.entities + +import de.bixilon.minosoft.data.entities.block.BlockEntity +import glm_.vec3.Vec3i + +interface BlockEntityProvider { + val size: Int + + operator fun get(inChunkSectionPosition: Vec3i): BlockEntity? + + operator fun set(inChunkSectionPosition: Vec3i, blockEntity: BlockEntity?) + + companion object { + const val BLOCK_ENTITY_MAP_LIMIT_UP = 100 + const val BLOCK_ENTITY_MAP_LIMIT_DOWN = 80 + } + +} diff --git a/src/main/java/de/bixilon/minosoft/data/world/block/entities/MapBlockEntityProvider.kt b/src/main/java/de/bixilon/minosoft/data/world/block/entities/MapBlockEntityProvider.kt new file mode 100644 index 000000000..cff0e5c56 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/world/block/entities/MapBlockEntityProvider.kt @@ -0,0 +1,46 @@ +/* + * 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.block.entities + +import de.bixilon.minosoft.data.entities.block.BlockEntity +import de.bixilon.minosoft.data.world.ChunkSection.Companion.indexPosition +import glm_.vec3.Vec3i + +class MapBlockEntityProvider() : BlockEntityProvider { + override val size: Int + get() = blockEntities.size + + var blockEntities: MutableMap = mutableMapOf() + + constructor(blockEntityProvider: ArrayBlockEntityProvider) : this() { + for ((index, blockEntity) in blockEntityProvider.blockEntities.withIndex()) { + if (blockEntity == null) { + continue + } + blockEntities[index.indexPosition] = blockEntity + } + } + + override fun get(inChunkSectionPosition: Vec3i): BlockEntity? { + return blockEntities[inChunkSectionPosition] + } + + override fun set(inChunkSectionPosition: Vec3i, blockEntity: BlockEntity?) { + if (blockEntity == null) { + blockEntities.remove(inChunkSectionPosition) + return + } + blockEntities[inChunkSectionPosition] = blockEntity + } +} 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 a5b103af6..3256c9bed 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 @@ -133,10 +133,6 @@ class ChunkDataS2CP() : PlayS2CPacket() { connection.world.unloadChunk(chunkPosition) connection.fireEvent(ChunkUnloadEvent(connection, chunkPosition)) } - - for ((blockPosition, blockEntity) in blockEntities) { - connection.world.setBlockEntity(blockPosition, blockEntity) - } } override fun log() {