chunk storage: store blocks as flat array (improve memory usage A LOT)

This commit is contained in:
Bixilon 2021-03-04 00:36:07 +01:00
parent a32c6c6074
commit 71a75b7b53
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
5 changed files with 46 additions and 27 deletions

View File

@ -93,7 +93,11 @@ object VersionTweaker {
return
}
for ((sectionHeight, section) in sections) {
for ((location, blockInfo) in section.blocks) {
for ((index, blockInfo) in section.blocks.withIndex()) {
if (blockInfo == null) {
continue
}
val location = ChunkSection.getPosition(index)
val newBlock = transformBlock(blockInfo.block, sections, location, sectionHeight)
if (newBlock === blockInfo.block) {
continue

View File

@ -56,7 +56,7 @@ class Chunk(
}
// replace all chunk sections
for ((sectionHeight, chunkSection) in it) {
getSectionOrCreate(sectionHeight).setData(chunkSection, merge)
getSectionOrCreate(sectionHeight).setData(chunkSection)
}
}
data.biomeAccessor?.let {
@ -82,7 +82,7 @@ class Chunk(
getSectionOrCreate(position.getSectionHeight()).let {
val inChunkSectionLocation = position.getInChunkSectionLocation()
if (block == null) {
it.blocks.remove(inChunkSectionLocation)
it.blocks[ChunkSection.getIndex(inChunkSectionLocation)] = null
return
}
it.setBlockInfo(inChunkSectionLocation, BlockInfo(block))

View File

@ -13,24 +13,21 @@
package de.bixilon.minosoft.data.world
import de.bixilon.minosoft.data.mappings.blocks.BlockState
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
/**
* Collection of 16x16x16 blocks
*/
class ChunkSection constructor(
val blocks: MutableMap<InChunkSectionPosition, BlockInfo> = mutableMapOf(),
class ChunkSection(
val blocks: Array<BlockInfo?> = arrayOfNulls(ProtocolDefinition.BLOCKS_PER_SECTION),
) {
fun getBlockInfo(position: InChunkSectionPosition): BlockInfo? {
return blocks[position]
return blocks[getIndex(position)]
}
fun setBlockInfo(position: InChunkSectionPosition, blockInfo: BlockInfo?) {
if (blockInfo == null) {
blocks.remove(position)
return
}
blocks[position] = blockInfo
blocks[getIndex(position)] = blockInfo
}
fun getBlockInfo(x: Int, y: Int, z: Int): BlockInfo? {
@ -45,10 +42,23 @@ class ChunkSection constructor(
setBlockInfo(position, BlockInfo(block))
}
fun setData(chunkSection: ChunkSection, merge: Boolean = false) {
if (!merge) {
this.blocks.clear()
fun setData(chunkSection: ChunkSection) {
for ((index, blockInfo) in chunkSection.blocks.withIndex()) {
blocks[index] = blockInfo
}
}
companion object {
fun getIndex(position: InChunkSectionPosition): Int {
return getIndex(position.x, position.y, position.z)
}
fun getIndex(x: Int, y: Int, z: Int): Int {
return y shl 8 or (z shl 4) or x
}
fun getPosition(index: Int): InChunkSectionPosition {
return InChunkSectionPosition(index and 0x0F, (index shr 8) and 0x0F, (index shr 4) and 0x0F)
}
this.blocks.putAll(chunkSection.blocks)
}
}

View File

@ -58,8 +58,11 @@ class WorldRenderer(
val mesh = ChunkMesh()
for ((position, blockInfo) in section.blocks) {
val blockPosition = BlockPosition(chunkPosition, sectionHeight, position)
for ((index, blockInfo) in section.blocks.withIndex()) {
if (blockInfo == null) {
continue
}
val blockPosition = BlockPosition(chunkPosition, sectionHeight, ChunkSection.getPosition(index))
val neighborBlocks: Array<BlockInfo?> = arrayOfNulls(Directions.DIRECTIONS.size)
for (direction in Directions.DIRECTIONS) {

View File

@ -19,7 +19,6 @@ import de.bixilon.minosoft.data.mappings.blocks.BlockState;
import de.bixilon.minosoft.data.world.BlockInfo;
import de.bixilon.minosoft.data.world.ChunkData;
import de.bixilon.minosoft.data.world.ChunkSection;
import de.bixilon.minosoft.data.world.InChunkSectionPosition;
import de.bixilon.minosoft.data.world.biome.DummyBiomeAccessor;
import de.bixilon.minosoft.data.world.biome.XZBiomeAccessor;
import de.bixilon.minosoft.data.world.light.DummyLightAccessor;
@ -62,7 +61,7 @@ public final class ChunkUtil {
HashMap<Integer, ChunkSection> sectionMap = new HashMap<>();
for (int sectionHeight = dimension.getLowestSection(); sectionHeight < dimension.getHighestSection(); sectionHeight++) { // max sections per chunks in chunk column
if (BitByte.isBitSet(sectionBitMasks[0], sectionHeight)) {
HashMap<InChunkSectionPosition, BlockInfo> blockMap = new HashMap<>();
BlockInfo[] blocks = new BlockInfo[ProtocolDefinition.BLOCKS_PER_SECTION];
for (int nibbleY = 0; nibbleY < ProtocolDefinition.SECTION_HEIGHT_Y; nibbleY++) {
for (int nibbleZ = 0; nibbleZ < ProtocolDefinition.SECTION_WIDTH_Z; nibbleZ++) {
@ -90,12 +89,15 @@ public final class ChunkUtil {
continue;
}
BlockState block = buffer.getConnection().getMapping().getBlockState(fullBlockId);
blockMap.put(new InChunkSectionPosition(nibbleX, nibbleY, nibbleZ), new BlockInfo(block));
if (block == null) {
continue;
}
blocks[ChunkSection.Companion.getIndex(nibbleX, nibbleY, nibbleZ)] = new BlockInfo(block);
arrayPos++;
}
}
}
sectionMap.put(dimension.getLowestSection() + sectionHeight, new ChunkSection(blockMap)); // ToDo
sectionMap.put(dimension.getLowestSection() + sectionHeight, new ChunkSection(blocks)); // ToDo
}
}
return new ChunkData(sectionMap, new DummyBiomeAccessor(buffer.getConnection().getMapping().getBiomeRegistry().get(0)), DummyLightAccessor.INSTANCE);
@ -126,7 +128,7 @@ public final class ChunkUtil {
if (!BitByte.isBitSet(sectionBitMasks[0], sectionHeight)) {
continue;
}
HashMap<InChunkSectionPosition, BlockInfo> blockMap = new HashMap<>();
BlockInfo[] blocks = new BlockInfo[ProtocolDefinition.BLOCKS_PER_SECTION];
for (int nibbleY = 0; nibbleY < ProtocolDefinition.SECTION_HEIGHT_Y; nibbleY++) {
for (int nibbleZ = 0; nibbleZ < ProtocolDefinition.SECTION_WIDTH_Z; nibbleZ++) {
@ -137,12 +139,12 @@ public final class ChunkUtil {
arrayPos++;
continue;
}
blockMap.put(new InChunkSectionPosition(nibbleX, nibbleY, nibbleZ), new BlockInfo(block));
blocks[ChunkSection.Companion.getIndex(nibbleX, nibbleY, nibbleZ)] = new BlockInfo(block);
arrayPos++;
}
}
}
sectionMap.put(dimension.getLowestSection() + sectionHeight, new ChunkSection(blockMap));
sectionMap.put(dimension.getLowestSection() + sectionHeight, new ChunkSection(blocks));
}
return new ChunkData(sectionMap, new DummyBiomeAccessor(buffer.getConnection().getMapping().getBiomeRegistry().get(0)), DummyLightAccessor.INSTANCE); // ToDo
}
@ -162,7 +164,7 @@ public final class ChunkUtil {
long[] data = buffer.readLongArray();
HashMap<InChunkSectionPosition, BlockInfo> blockMap = new HashMap<>();
BlockInfo[] blocks = new BlockInfo[ProtocolDefinition.BLOCKS_PER_SECTION];
for (int nibbleY = 0; nibbleY < ProtocolDefinition.SECTION_HEIGHT_Y; nibbleY++) {
for (int nibbleZ = 0; nibbleZ < ProtocolDefinition.SECTION_WIDTH_Z; nibbleZ++) {
for (int nibbleX = 0; nibbleX < ProtocolDefinition.SECTION_WIDTH_X; nibbleX++) {
@ -193,7 +195,7 @@ public final class ChunkUtil {
if (block == null) {
continue;
}
blockMap.put(new InChunkSectionPosition(nibbleX, nibbleY, nibbleZ), new BlockInfo(block));
blocks[ChunkSection.Companion.getIndex(nibbleX, nibbleY, nibbleZ)] = new BlockInfo(block);
}
}
}
@ -206,7 +208,7 @@ public final class ChunkUtil {
// ToDo
}
sectionMap.put(dimension.getLowestSection() + sectionHeight, new ChunkSection(blockMap));
sectionMap.put(dimension.getLowestSection() + sectionHeight, new ChunkSection(blocks));
}
ChunkData chunkData = new ChunkData();
chunkData.setBlocks(sectionMap);