From 31a11a6df4922b590a50a5ff3d3c00d42a45599d Mon Sep 17 00:00:00 2001 From: peterbell10 Date: Mon, 23 Jul 2018 19:12:51 +0100 Subject: Optimise chunk set (#4260) Closes #1244 Initially I was just going to add the cChunkData to cSetChunkData but profiling revealed that the copying wasn't even the biggest slowdown. Much more time was being spent in cChunk::CreateBlockEntities and cChunk::WakeUpSimulators than was in memcpy so I've made those significantly faster as well. Optimisations performed: * cSetChunkData now stores blocks in a cChunkData object * cChunkData objects can now perform moves even if they are using different pools * cChunk::CreateBlockEntities now iterates in the correct order and only over present chunk sections * Similarly for cChunk::WakeUpSimulators * cSetChunkData::CalculateHeightMap now shortcuts to the highest present chunk section before checking blocks directly --- src/Chunk.cpp | 159 ++++++++++++++++++++++++++-------------------------------- 1 file changed, 70 insertions(+), 89 deletions(-) (limited to 'src/Chunk.cpp') diff --git a/src/Chunk.cpp b/src/Chunk.cpp index f43b5b4bb..03415b348 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -322,26 +322,15 @@ void cChunk::SetAllData(cSetChunkData & a_SetChunkData) memcpy(m_BiomeMap, a_SetChunkData.GetBiomes(), sizeof(m_BiomeMap)); memcpy(m_HeightMap, a_SetChunkData.GetHeightMap(), sizeof(m_HeightMap)); - m_ChunkData.SetBlockTypes(a_SetChunkData.GetBlockTypes()); - m_ChunkData.SetMetas(a_SetChunkData.GetBlockMetas()); - if (a_SetChunkData.IsLightValid()) - { - m_ChunkData.SetBlockLight(a_SetChunkData.GetBlockLight()); - m_ChunkData.SetSkyLight(a_SetChunkData.GetSkyLight()); - m_IsLightValid = true; - } - else - { - m_IsLightValid = false; - } + m_ChunkData.Assign(std::move(a_SetChunkData.GetChunkData())); + m_IsLightValid = a_SetChunkData.IsLightValid(); // Clear the block entities present - either the loader / saver has better, or we'll create empty ones: for (auto & KeyPair : m_BlockEntities) { delete KeyPair.second; } - m_BlockEntities.clear(); - std::swap(a_SetChunkData.GetBlockEntities(), m_BlockEntities); + m_BlockEntities = std::move(a_SetChunkData.GetBlockEntities()); // Check that all block entities have a valid blocktype at their respective coords (DEBUG-mode only): #ifdef _DEBUG @@ -504,9 +493,9 @@ void cChunk::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock -bool cChunk::HasBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ) +bool cChunk::HasBlockEntityAt(Vector3i a_BlockPos) { - return (GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ) != nullptr); + return (GetBlockEntity(a_BlockPos) != nullptr); } @@ -1433,48 +1422,32 @@ int cChunk::GetHeight(int a_X, int a_Z) void cChunk::CreateBlockEntities(void) { - for (int x = 0; x < Width; x++) + for (size_t SectionIdx = 0; SectionIdx != cChunkData::NumSections; ++SectionIdx) { - for (int z = 0; z < Width; z++) + const auto * Section = m_ChunkData.GetSection(SectionIdx); + if (Section == nullptr) { - for (int y = 0; y < Height; y++) + continue; + } + + for (size_t BlockIdx = 0; BlockIdx != cChunkData::SectionBlockCount; ++BlockIdx) + { + auto BlockType = Section->m_BlockTypes[BlockIdx]; + if (cBlockEntity::IsBlockEntityBlockType(BlockType)) { - BLOCKTYPE BlockType = GetBlock(x, y, z); - switch (BlockType) + auto RelPos = IndexToCoordinate(BlockIdx); + RelPos.y += SectionIdx * cChunkData::SectionHeight; + auto WorldPos = RelativeToAbsolute(RelPos, m_PosX, m_PosZ); + + if (!HasBlockEntityAt(WorldPos)) { - case E_BLOCK_BEACON: - case E_BLOCK_BED: - case E_BLOCK_TRAPPED_CHEST: - case E_BLOCK_CHEST: - case E_BLOCK_COMMAND_BLOCK: - case E_BLOCK_DISPENSER: - case E_BLOCK_DROPPER: - case E_BLOCK_ENDER_CHEST: - case E_BLOCK_LIT_FURNACE: - case E_BLOCK_FURNACE: - case E_BLOCK_HOPPER: - case E_BLOCK_SIGN_POST: - case E_BLOCK_WALLSIGN: - case E_BLOCK_HEAD: - case E_BLOCK_NOTE_BLOCK: - case E_BLOCK_JUKEBOX: - case E_BLOCK_FLOWER_POT: - case E_BLOCK_MOB_SPAWNER: - case E_BLOCK_BREWING_STAND: - { - if (!HasBlockEntityAt(x + m_PosX * Width, y, z + m_PosZ * Width)) - { - AddBlockEntityClean(cBlockEntity::CreateByBlockType( - BlockType, GetMeta(x, y, z), - x + m_PosX * Width, y, z + m_PosZ * Width, m_World - )); - } - break; - } - } // switch (BlockType) - } // for y - } // for z - } // for x + AddBlockEntityClean(cBlockEntity::CreateByBlockType( + BlockType, GetMeta(RelPos), WorldPos.x, WorldPos.y, WorldPos.z, m_World + )); + } + } + } + } } @@ -1483,48 +1456,56 @@ void cChunk::CreateBlockEntities(void) void cChunk::WakeUpSimulators(void) { - cSimulator * WaterSimulator = m_World->GetWaterSimulator(); - cSimulator * LavaSimulator = m_World->GetLavaSimulator(); - cSimulator * RedstoneSimulator = m_World->GetRedstoneSimulator(); - int BaseX = m_PosX * cChunkDef::Width; - int BaseZ = m_PosZ * cChunkDef::Width; - for (int x = 0; x < Width; x++) + auto * WaterSimulator = m_World->GetWaterSimulator(); + auto * LavaSimulator = m_World->GetLavaSimulator(); + auto * RedstoneSimulator = m_World->GetRedstoneSimulator(); + + for (size_t SectionIdx = 0; SectionIdx != cChunkData::NumSections; ++SectionIdx) { - int BlockX = x + BaseX; - for (int z = 0; z < Width; z++) + const auto * Section = m_ChunkData.GetSection(SectionIdx); + if (Section == nullptr) + { + continue; + } + + for (size_t BlockIdx = 0; BlockIdx != cChunkData::SectionBlockCount; ++BlockIdx) { - int BlockZ = z + BaseZ; - for (int y = GetHeight(x, z); y >= 0; y--) + auto BlockType = Section->m_BlockTypes[BlockIdx]; + + // Defer calculation until it's actually needed + auto WorldPos = [&] { - BLOCKTYPE Block = GetBlock(x, y, z); + auto RelPos = IndexToCoordinate(BlockIdx); + RelPos.y += SectionIdx * cChunkData::SectionHeight; + return RelativeToAbsolute(RelPos, m_PosX, m_PosZ); + }; - // The redstone sim takes multiple blocks, use the inbuilt checker - if (RedstoneSimulator->IsAllowedBlock(Block)) + // The redstone sim takes multiple blocks, use the inbuilt checker + if (RedstoneSimulator->IsAllowedBlock(BlockType)) + { + RedstoneSimulator->AddBlock(WorldPos(), this); + continue; + } + + switch (BlockType) + { + case E_BLOCK_WATER: { - RedstoneSimulator->AddBlock({BlockX, y, BlockZ}, this); - continue; + WaterSimulator->AddBlock(WorldPos(), this); + break; } - - switch (Block) + case E_BLOCK_LAVA: { - case E_BLOCK_WATER: - { - WaterSimulator->AddBlock({BlockX, y, BlockZ}, this); - break; - } - case E_BLOCK_LAVA: - { - LavaSimulator->AddBlock({BlockX, y, BlockZ}, this); - break; - } - default: - { - break; - } - } // switch (BlockType) - } // for y - } // for z - } // for x + LavaSimulator->AddBlock(WorldPos(), this); + break; + } + default: + { + break; + } + } // switch (BlockType) + } + } } -- cgit v1.2.3