From d1b0d0f5b5c288c235c8bb3412b32bb446564e66 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Thu, 20 Aug 2020 12:50:22 +0100 Subject: Remove level of indirection in cChunk storage - No more unique_ptr storage --- src/Chunk.cpp | 37 ++++++++++++------------ src/Chunk.h | 7 ++--- src/ChunkMap.cpp | 86 ++++++++++++++++++++++---------------------------------- src/ChunkMap.h | 24 ++++++++-------- 4 files changed, 67 insertions(+), 87 deletions(-) diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 1aa377651..afbc3adca 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -56,7 +56,6 @@ cChunk::cChunk( int a_ChunkX, int a_ChunkZ, cChunkMap * a_ChunkMap, cWorld * a_World, - cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP, cAllocationPool & a_Pool ): m_Presence(cpInvalid), @@ -71,30 +70,31 @@ cChunk::cChunk( m_World(a_World), m_ChunkMap(a_ChunkMap), m_ChunkData(a_Pool), - m_NeighborXM(a_NeighborXM), - m_NeighborXP(a_NeighborXP), - m_NeighborZM(a_NeighborZM), - m_NeighborZP(a_NeighborZP), m_WaterSimulatorData(a_World->GetWaterSimulator()->CreateChunkData()), m_LavaSimulatorData (a_World->GetLavaSimulator ()->CreateChunkData()), m_RedstoneSimulatorData(a_World->GetRedstoneSimulator()->CreateChunkData()), m_AlwaysTicked(0) { - if (a_NeighborXM != nullptr) + m_NeighborXM = a_ChunkMap->FindChunk(a_ChunkX - 1, a_ChunkZ); + m_NeighborXP = a_ChunkMap->FindChunk(a_ChunkX + 1, a_ChunkZ); + m_NeighborZM = a_ChunkMap->FindChunk(a_ChunkX, a_ChunkZ - 1); + m_NeighborZP = a_ChunkMap->FindChunk(a_ChunkX, a_ChunkZ + 1); + + if (m_NeighborXM != nullptr) { - a_NeighborXM->m_NeighborXP = this; + m_NeighborXM->m_NeighborXP = this; } - if (a_NeighborXP != nullptr) + if (m_NeighborXP != nullptr) { - a_NeighborXP->m_NeighborXM = this; + m_NeighborXP->m_NeighborXM = this; } - if (a_NeighborZM != nullptr) + if (m_NeighborZM != nullptr) { - a_NeighborZM->m_NeighborZP = this; + m_NeighborZM->m_NeighborZP = this; } - if (a_NeighborZP != nullptr) + if (m_NeighborZP != nullptr) { - a_NeighborZP->m_NeighborZM = this; + m_NeighborZP->m_NeighborZM = this; } } @@ -188,10 +188,11 @@ void cChunk::MarkRegenerating(void) -bool cChunk::HasPlayerEntities() +bool cChunk::HasPlayerEntities() const { - return std::any_of(m_Entities.begin(), m_Entities.end(), - [](std::unique_ptr& Entity) + return std::any_of( + m_Entities.begin(), m_Entities.end(), + [](const auto & Entity) { return Entity->IsPlayer(); } @@ -202,7 +203,7 @@ bool cChunk::HasPlayerEntities() -bool cChunk::CanUnload(void) +bool cChunk::CanUnload(void) const { return m_LoadedByClient.empty() && // The chunk is not used by any client @@ -216,7 +217,7 @@ bool cChunk::CanUnload(void) -bool cChunk::CanUnloadAfterSaving(void) +bool cChunk::CanUnloadAfterSaving(void) const { return m_LoadedByClient.empty() && // The chunk is not used by any client diff --git a/src/Chunk.h b/src/Chunk.h index 25de55ec6..8c236045e 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -64,7 +64,6 @@ public: cChunk( int a_ChunkX, int a_ChunkZ, // Chunk coords cChunkMap * a_ChunkMap, cWorld * a_World, // Parent objects - cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP, // Neighbor chunks cAllocationPool & a_Pool ); cChunk(cChunk & other) = delete; @@ -89,10 +88,10 @@ public: /** Returns true iff the chunk has changed since it was last saved. */ bool IsDirty(void) const {return m_IsDirty; } - bool CanUnload(void); + bool CanUnload(void) const; /** Returns true if the chunk could have been unloaded if it weren't dirty */ - bool CanUnloadAfterSaving(void); + bool CanUnloadAfterSaving(void) const; bool IsLightValid(void) const {return m_IsLightValid; } @@ -673,7 +672,7 @@ private: void MoveEntityToNewChunk(OwnedEntity a_Entity); /** Check m_Entities for cPlayer objects. */ - bool HasPlayerEntities(); + bool HasPlayerEntities() const; }; typedef cChunk * cChunkPtr; diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index 6ec3da404..dbfd07d45 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -22,10 +22,6 @@ #include "DeadlockDetect.h" #include "BlockEntities/BlockEntity.h" -#ifndef _WIN32 - #include // abs -#endif - #include "zlib/zlib.h" #include "json/json.h" @@ -65,27 +61,11 @@ cChunkMap::~cChunkMap() cChunkPtr cChunkMap::ConstructChunk(int a_ChunkX, int a_ChunkZ) { - auto Chunk = FindChunk(a_ChunkX, a_ChunkZ); - if (Chunk == nullptr) - { - return ( - *m_Chunks.emplace( - ChunkCoordinate{ a_ChunkX, a_ChunkZ }, - std::make_unique( - a_ChunkX, - a_ChunkZ, - this, - GetWorld(), - FindChunk(a_ChunkX - 1, a_ChunkZ), - FindChunk(a_ChunkX + 1, a_ChunkZ), - FindChunk(a_ChunkX, a_ChunkZ - 1), - FindChunk(a_ChunkX, a_ChunkZ + 1), - *m_Pool - ) - ).first - ).second.get(); - } - return Chunk; + // If not exists insert. Then, return the chunk at these coordinates: + return &m_Chunks.try_emplace( + ChunkCoordinate{ a_ChunkX, a_ChunkZ }, + a_ChunkX, a_ChunkZ, this, m_World, *m_Pool + ).first->second; } @@ -151,7 +131,7 @@ cChunk * cChunkMap::FindChunk(int a_ChunkX, int a_ChunkZ) ASSERT(m_CSChunks.IsLockedByCurrentThread()); auto Chunk = m_Chunks.find({ a_ChunkX, a_ChunkZ }); - return (Chunk == m_Chunks.end()) ? nullptr : Chunk->second.get(); + return (Chunk == m_Chunks.end()) ? nullptr : &Chunk->second; } @@ -936,9 +916,9 @@ void cChunkMap::RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_ void cChunkMap::RemoveClientFromChunks(cClientHandle * a_Client) { cCSLock Lock(m_CSChunks); - for (const auto & Chunk : m_Chunks) + for (auto & Chunk : m_Chunks) { - Chunk.second->RemoveClient(a_Client); + Chunk.second.RemoveClient(a_Client); } } @@ -985,12 +965,12 @@ void cChunkMap::AddEntityIfNotPresent(OwnedEntity a_Entity) -bool cChunkMap::HasEntity(UInt32 a_UniqueID) +bool cChunkMap::HasEntity(UInt32 a_UniqueID) const { cCSLock Lock(m_CSChunks); for (const auto & Chunk : m_Chunks) { - if (Chunk.second->IsValid() && Chunk.second->HasEntity(a_UniqueID)) + if (Chunk.second.IsValid() && Chunk.second.HasEntity(a_UniqueID)) { return true; } @@ -1020,12 +1000,12 @@ OwnedEntity cChunkMap::RemoveEntity(cEntity & a_Entity) -bool cChunkMap::ForEachEntity(cEntityCallback a_Callback) +bool cChunkMap::ForEachEntity(cEntityCallback a_Callback) const { cCSLock Lock(m_CSChunks); for (const auto & Chunk : m_Chunks) { - if (Chunk.second->IsValid() && !Chunk.second->ForEachEntity(a_Callback)) + if (Chunk.second.IsValid() && !Chunk.second.ForEachEntity(a_Callback)) { return false; } @@ -1281,13 +1261,13 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ -bool cChunkMap::DoWithEntityByID(UInt32 a_UniqueID, cEntityCallback a_Callback) +bool cChunkMap::DoWithEntityByID(UInt32 a_UniqueID, cEntityCallback a_Callback) const { cCSLock Lock(m_CSChunks); bool res = false; for (const auto & Chunk : m_Chunks) { - if (Chunk.second->IsValid() && Chunk.second->DoWithEntityByID(a_UniqueID, a_Callback, res)) + if (Chunk.second.IsValid() && Chunk.second.DoWithEntityByID(a_UniqueID, a_Callback, res)) { return res; } @@ -1876,12 +1856,12 @@ bool cChunkMap::ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinCh -bool cChunkMap::ForEachLoadedChunk(cFunctionRef a_Callback) +bool cChunkMap::ForEachLoadedChunk(cFunctionRef a_Callback) const { cCSLock Lock(m_CSChunks); for (const auto & Chunk : m_Chunks) { - if (Chunk.second->IsValid()) + if (Chunk.second.IsValid()) { if (a_Callback(Chunk.first.ChunkX, Chunk.first.ChunkZ)) { @@ -1934,7 +1914,7 @@ bool cChunkMap::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBl -void cChunkMap::GetChunkStats(int & a_NumChunksValid, int & a_NumChunksDirty) +void cChunkMap::GetChunkStats(int & a_NumChunksValid, int & a_NumChunksDirty) const { a_NumChunksValid = 0; a_NumChunksDirty = 0; @@ -1942,7 +1922,7 @@ void cChunkMap::GetChunkStats(int & a_NumChunksValid, int & a_NumChunksDirty) for (const auto & Chunk : m_Chunks) { a_NumChunksValid++; - if (Chunk.second->IsDirty()) + if (Chunk.second.IsDirty()) { a_NumChunksDirty++; } @@ -1990,14 +1970,14 @@ void cChunkMap::SetNextBlockToTick(const Vector3i a_BlockPos) void cChunkMap::CollectMobCensus(cMobCensus & a_ToFill) { cCSLock Lock(m_CSChunks); - for (const auto & Chunk : m_Chunks) + for (auto & Chunk : m_Chunks) { // We do count every Mobs in the world. But we are assuming that every chunk not loaded by any client // doesn't affect us. Normally they should not have mobs because every "too far" mobs despawn // If they have (f.i. when player disconnect) we assume we don't have to make them live or despawn - if (Chunk.second->IsValid() && Chunk.second->HasAnyClients()) + if (Chunk.second.IsValid() && Chunk.second.HasAnyClients()) { - Chunk.second->CollectMobCensus(a_ToFill); + Chunk.second.CollectMobCensus(a_ToFill); } } } @@ -2009,12 +1989,12 @@ void cChunkMap::CollectMobCensus(cMobCensus & a_ToFill) void cChunkMap::SpawnMobs(cMobSpawner & a_MobSpawner) { cCSLock Lock(m_CSChunks); - for (const auto & Chunk : m_Chunks) + for (auto & Chunk : m_Chunks) { // We only spawn close to players - if (Chunk.second->IsValid() && Chunk.second->HasAnyClients()) + if (Chunk.second.IsValid() && Chunk.second.HasAnyClients()) { - Chunk.second->SpawnMobs(a_MobSpawner); + Chunk.second.SpawnMobs(a_MobSpawner); } } } @@ -2026,12 +2006,12 @@ void cChunkMap::SpawnMobs(cMobSpawner & a_MobSpawner) void cChunkMap::Tick(std::chrono::milliseconds a_Dt) { cCSLock Lock(m_CSChunks); - for (const auto & Chunk : m_Chunks) + for (auto & Chunk : m_Chunks) { // Only tick chunks that are valid and should be ticked: - if (Chunk.second->IsValid() && Chunk.second->ShouldBeTicked()) + if (Chunk.second.IsValid() && Chunk.second.ShouldBeTicked()) { - Chunk.second->Tick(a_Dt); + Chunk.second.Tick(a_Dt); } } } @@ -2063,7 +2043,7 @@ void cChunkMap::UnloadUnusedChunks(void) for (auto itr = m_Chunks.begin(); itr != m_Chunks.end();) { if ( - (itr->second->CanUnload()) && // Can unload + (itr->second.CanUnload()) && // Can unload !cPluginManager::Get()->CallHookChunkUnloading(*GetWorld(), itr->first.ChunkX, itr->first.ChunkZ) // Plugins agree ) { @@ -2080,12 +2060,12 @@ void cChunkMap::UnloadUnusedChunks(void) -void cChunkMap::SaveAllChunks(void) +void cChunkMap::SaveAllChunks(void) const { cCSLock Lock(m_CSChunks); for (const auto & Chunk : m_Chunks) { - if (Chunk.second->IsValid() && Chunk.second->IsDirty()) + if (Chunk.second.IsValid() && Chunk.second.IsDirty()) { GetWorld()->GetStorage().QueueSaveChunk(Chunk.first.ChunkX, Chunk.first.ChunkZ); } @@ -2096,7 +2076,7 @@ void cChunkMap::SaveAllChunks(void) -size_t cChunkMap::GetNumChunks(void) +size_t cChunkMap::GetNumChunks(void) const { cCSLock Lock(m_CSChunks); return m_Chunks.size(); @@ -2106,13 +2086,13 @@ size_t cChunkMap::GetNumChunks(void) -size_t cChunkMap::GetNumUnusedDirtyChunks(void) +size_t cChunkMap::GetNumUnusedDirtyChunks(void) const { cCSLock Lock(m_CSChunks); size_t res = 0; for (const auto & Chunk : m_Chunks) { - if (Chunk.second->IsValid() && Chunk.second->CanUnloadAfterSaving()) + if (Chunk.second.IsValid() && Chunk.second.CanUnloadAfterSaving()) { res += 1; } diff --git a/src/ChunkMap.h b/src/ChunkMap.h index c6fb6dc18..3d1a7b7d3 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -209,14 +209,14 @@ public: void AddEntityIfNotPresent(OwnedEntity a_Entity); /** Returns true if the entity with specified ID is present in the chunks */ - bool HasEntity(UInt32 a_EntityID); + bool HasEntity(UInt32 a_EntityID) const; /** Removes the entity from its appropriate chunk Returns an owning reference to the found entity. */ OwnedEntity RemoveEntity(cEntity & a_Entity); /** Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true */ - bool ForEachEntity(cEntityCallback a_Callback); // Lua-accessible + bool ForEachEntity(cEntityCallback a_Callback) const; // Lua-accessible /** Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true */ bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback a_Callback); // Lua-accessible @@ -231,7 +231,7 @@ public: /** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false. */ - bool DoWithEntityByID(UInt32 a_EntityID, cEntityCallback a_Callback); // Lua-accessible + bool DoWithEntityByID(UInt32 a_EntityID, cEntityCallback a_Callback) const; // Lua-accessible /** Calls the callback for each block entity in the specified chunk. Returns true if all block entities processed, false if the callback aborted by returning true. */ @@ -352,13 +352,13 @@ public: bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback); /** Calls the callback for each loaded chunk. Returns true if all chunks have been processed successfully */ - bool ForEachLoadedChunk(cFunctionRef a_Callback); + bool ForEachLoadedChunk(cFunctionRef a_Callback) const; /** Writes the block area into the specified coords. Returns true if all chunks have been processed. Prefer cBlockArea::Write() instead. */ bool WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes); /** Returns the number of valid chunks and the number of dirty chunks */ - void GetChunkStats(int & a_NumChunksValid, int & a_NumChunksDirty); + void GetChunkStats(int & a_NumChunksValid, int & a_NumChunksDirty) const; /** Grows the plant at the specified position by at most a_NumStages. The block's Grow handler is invoked. @@ -382,14 +382,14 @@ public: void TickBlock(const Vector3i a_BlockPos); void UnloadUnusedChunks(void); - void SaveAllChunks(void); + void SaveAllChunks(void) const; - cWorld * GetWorld(void) { return m_World; } + cWorld * GetWorld(void) const { return m_World; } - size_t GetNumChunks(void); + size_t GetNumChunks(void) const; /** Returns the number of unused dirty chunks. Those are chunks that we can save and then unload */ - size_t GetNumUnusedDirtyChunks(void); + size_t GetNumUnusedDirtyChunks(void) const; void ChunkValidated(void); // Called by chunks that have become valid @@ -453,9 +453,9 @@ private: mutable cCriticalSection m_CSChunks; - /** A map of chunk coordinates to chunk pointers - Uses a map (as opposed to unordered_map) because sorted maps are apparently faster */ - std::map, ChunkCoordinate::Comparer> m_Chunks; + /** A map of chunk coordinates to chunks. + Uses a map (as opposed to unordered_map) because sorted maps are apparently faster. */ + std::map m_Chunks; cEvent m_evtChunkValid; // Set whenever any chunk becomes valid, via ChunkValidated() -- cgit v1.2.3