diff options
Diffstat (limited to 'src/Chunk.cpp')
-rw-r--r-- | src/Chunk.cpp | 117 |
1 files changed, 58 insertions, 59 deletions
diff --git a/src/Chunk.cpp b/src/Chunk.cpp index aa1544c7d..efdce7edc 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -336,13 +336,16 @@ void cChunk::GetAllData(cChunkDataCallback & a_Callback) const void cChunk::SetAllData(SetChunkData && a_SetChunkData) { - std::copy(a_SetChunkData.HeightMap, a_SetChunkData.HeightMap + std::size(a_SetChunkData.HeightMap), m_HeightMap); - std::copy(a_SetChunkData.BiomeMap, a_SetChunkData.BiomeMap + std::size(a_SetChunkData.BiomeMap), m_BiomeMap); + std::copy_n(a_SetChunkData.HeightMap, std::size(a_SetChunkData.HeightMap), m_HeightMap); + std::copy_n(a_SetChunkData.BiomeMap, std::size(a_SetChunkData.BiomeMap), m_BiomeMap); m_BlockData = std::move(a_SetChunkData.BlockData); m_LightData = std::move(a_SetChunkData.LightData); m_IsLightValid = a_SetChunkData.IsLightValid; + m_PendingSendBlocks.clear(); + m_PendingSendBlockEntities.clear(); + // Entities need some extra steps to destroy, so here we're keeping the old ones. // Move the entities already in the chunk, including player entities, so that we don't lose any: a_SetChunkData.Entities.insert( @@ -383,15 +386,17 @@ void cChunk::SetAllData(SetChunkData && a_SetChunkData) } #endif - // Set all block entities' World variable: + // Set the chunk data as valid. + // This may be needed for some simulators that perform actions upon block adding (Vaporize), + // as well as some block entities upon being added to the chunk (Chests). + SetPresence(cpPresent); + + // Initialise all block entities: for (auto & KeyPair : m_BlockEntities) { - KeyPair.second->SetWorld(m_World); + KeyPair.second->OnAddToWorld(*m_World, *this); } - // Set the chunk data as valid. This may be needed for some simulators that perform actions upon block adding (Vaporize) - SetPresence(cpPresent); - // Wake up all simulators for their respective blocks: WakeUpSimulators(); } @@ -466,22 +471,34 @@ void cChunk::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock } // for y // Erase all affected block entities: - cCuboid affectedArea( // In world coordinates - {BlockStartX, a_MinBlockY, BlockStartZ}, - {BlockEndX, a_MinBlockY + SizeY - 1, BlockEndZ} - ); - for (auto itr = m_BlockEntities.begin(); itr != m_BlockEntities.end();) { - if (affectedArea.IsInside(itr->second->GetPos())) - { - itr->second->Destroy(); - itr->second->OnRemoveFromWorld(); - itr = m_BlockEntities.erase(itr); - } - else + // The affected area, in world coordinates. + cCuboid affectedArea( + { BlockStartX, a_MinBlockY, BlockStartZ }, + { BlockEndX, a_MinBlockY + SizeY - 1, BlockEndZ } + ); + + // Where in the pending block entity send list to start removing the invalidated elements from. + auto PendingRemove = m_PendingSendBlockEntities.end(); + + for (auto itr = m_BlockEntities.begin(); itr != m_BlockEntities.end();) { - ++itr; + if (affectedArea.IsInside(itr->second->GetPos())) + { + itr->second->Destroy(); + itr->second->OnRemoveFromWorld(); + + PendingRemove = std::remove(m_PendingSendBlockEntities.begin(), PendingRemove, itr->second.get()); // Search the remaining valid pending sends. + itr = m_BlockEntities.erase(itr); + } + else + { + ++itr; + } } + + // Remove all the deleted block entities from the pending send list: + m_PendingSendBlockEntities.erase(PendingRemove, m_PendingSendBlockEntities.end()); } // Clone block entities from a_Area into this chunk: @@ -500,27 +517,15 @@ void cChunk::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock { continue; } - // This block entity is inside the chunk, clone it (and remove any that is there currently): - auto idx = static_cast<size_t>(cChunkDef::MakeIndex(posX - m_PosX * cChunkDef::Width, posY, posZ - m_PosZ * cChunkDef::Width)); - auto itr = m_BlockEntities.find(idx); - if (itr != m_BlockEntities.end()) - { - m_BlockEntities.erase(itr); - } - auto clone = be->Clone({posX, posY, posZ}); - clone->SetWorld(m_World); - AddBlockEntity(std::move(clone)); - } - } -} - - + // This block entity is inside the chunk. + // The code above should have removed any that were here before: + ASSERT(GetBlockEntityRel(cChunkDef::AbsoluteToRelative({ posX, posY, posZ })) == nullptr); - -bool cChunk::HasBlockEntityAt(Vector3i a_BlockPos) -{ - return (GetBlockEntity(a_BlockPos) != nullptr); + // Clone, and add the new one: + AddBlockEntity(be->Clone({posX, posY, posZ})); + } + } } @@ -1287,12 +1292,15 @@ void cChunk::SetBlock(Vector3i a_RelPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_Blo GetWorld()->GetSimulatorManager()->WakeUp(*this, a_RelPos); // If there was a block entity, remove it: - cBlockEntity * BlockEntity = GetBlockEntityRel(a_RelPos); - if (BlockEntity != nullptr) + if (const auto FindResult = m_BlockEntities.find(cChunkDef::MakeIndex(a_RelPos)); FindResult != m_BlockEntities.end()) { - BlockEntity->Destroy(); - BlockEntity->OnRemoveFromWorld(); - RemoveBlockEntity(BlockEntity); + auto & BlockEntity = *FindResult->second; + + BlockEntity.Destroy(); + BlockEntity.OnRemoveFromWorld(); + + m_BlockEntities.erase(FindResult); + m_PendingSendBlockEntities.erase(std::remove(m_PendingSendBlockEntities.begin(), m_PendingSendBlockEntities.end(), &BlockEntity), m_PendingSendBlockEntities.end()); } // If the new block is a block entity, create the entity object: @@ -1414,11 +1422,14 @@ void cChunk::SendBlockTo(int a_RelX, int a_RelY, int a_RelZ, cClientHandle * a_C void cChunk::AddBlockEntity(OwnedBlockEntity a_BlockEntity) { + const auto BlockEntityPtr = a_BlockEntity.get(); [[maybe_unused]] const auto Result = m_BlockEntities.emplace( cChunkDef::MakeIndex(a_BlockEntity->GetRelX(), a_BlockEntity->GetPosY(), a_BlockEntity->GetRelZ()), std::move(a_BlockEntity) ); - ASSERT(Result.second); // No block entity already at this position + + ASSERT(Result.second); // No block entity already at this position. + BlockEntityPtr->OnAddToWorld(*m_World, *this); } @@ -1435,7 +1446,7 @@ cBlockEntity * cChunk::GetBlockEntity(Vector3i a_AbsPos) return nullptr; } - auto itr = m_BlockEntities.find(static_cast<size_t>(cChunkDef::MakeIndexNoCheck(relPos))); + auto itr = m_BlockEntities.find(cChunkDef::MakeIndex(relPos)); return (itr == m_BlockEntities.end()) ? nullptr : itr->second.get(); } @@ -1446,7 +1457,7 @@ cBlockEntity * cChunk::GetBlockEntity(Vector3i a_AbsPos) cBlockEntity * cChunk::GetBlockEntityRel(Vector3i a_RelPos) { ASSERT(cChunkDef::IsValidRelPos(a_RelPos)); - auto itr = m_BlockEntities.find(static_cast<size_t>(cChunkDef::MakeIndexNoCheck(a_RelPos))); + auto itr = m_BlockEntities.find(cChunkDef::MakeIndex(a_RelPos)); return (itr == m_BlockEntities.end()) ? nullptr : itr->second.get(); } @@ -1527,18 +1538,6 @@ void cChunk::SetAreaBiome(int a_MinRelX, int a_MaxRelX, int a_MinRelZ, int a_Max -void cChunk::RemoveBlockEntity(cBlockEntity * a_BlockEntity) -{ - MarkDirty(); - ASSERT(a_BlockEntity != nullptr); - m_BlockEntities.erase(static_cast<size_t>(cChunkDef::MakeIndex(a_BlockEntity->GetRelX(), a_BlockEntity->GetPosY(), a_BlockEntity->GetRelZ()))); - m_PendingSendBlockEntities.erase(std::remove(m_PendingSendBlockEntities.begin(), m_PendingSendBlockEntities.end(), a_BlockEntity), m_PendingSendBlockEntities.end()); -} - - - - - bool cChunk::AddClient(cClientHandle * a_Client) { if (std::find(m_LoadedByClient.begin(), m_LoadedByClient.end(), a_Client) != m_LoadedByClient.end()) |