From 38368f361db34bf026865a92e69954d0d8748bd6 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Tue, 2 Aug 2016 23:56:53 +0100 Subject: Simplified cChunkMap chunk storage (#2565) --- src/ChunkMap.cpp | 808 +++++++++++++++---------------------------------------- src/ChunkMap.h | 115 +++----- 2 files changed, 257 insertions(+), 666 deletions(-) diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index cb60b4841..7c4162b25 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -44,7 +44,6 @@ cChunkMap::cChunkMap(cWorld * a_World) : ) ) { - } @@ -53,91 +52,40 @@ cChunkMap::cChunkMap(cWorld * a_World) : cChunkMap::~cChunkMap() { - // Explicitly destroy all chunks and ChunkLayers, so that they're guaranteed to be + // Explicitly destroy all chunks, so that they're guaranteed to be // destroyed before other internals. This fixes crashes on stopping the server. // because the chunk destructor deletes entities and those may access the chunkmap. // Also, the cChunkData destructor accesses the chunkMap's allocator. - m_Layers.clear(); -} - - - - - -void cChunkMap::RemoveLayer(cChunkLayer * a_Layer) -{ - cCSLock Lock(m_CSLayers); - m_Layers.erase(std::pair(a_Layer->GetX(), a_Layer->GetZ())); -} - - - - - -cChunkMap::cChunkLayer * cChunkMap::GetLayer(int a_LayerX, int a_LayerZ) -{ - cCSLock Lock(m_CSLayers); - auto it = m_Layers.find(std::pair(a_LayerX, a_LayerZ)); - if (it !=m_Layers.end()) - { - cChunkLayer & Layer = it->second; - return &Layer; - } - - // Not found, create new: - auto EmplaceResult = m_Layers.emplace(std::piecewise_construct, - std::forward_as_tuple(a_LayerX, a_LayerZ), - std::forward_as_tuple(a_LayerX, a_LayerZ, this, *m_Pool)); - - // EmplaceResult.second = a bool, if false, then the item is already there. - // EmplaceResult.first = an iterator pointing to the inserted item - // EmplaceResult.first->second = the inserted chunk layer - // EmplaceResult.first->first = the item's key (an std::pair if chunk X and chunk Z) - we don't need this - - ASSERT (EmplaceResult.second == true); // Make sure the element did not exist prior to the insertion - cChunkLayer & Layer = (EmplaceResult.first->second); - return &Layer; + m_Chunks.clear(); } -cChunkMap::cChunkLayer * cChunkMap::FindLayerForChunk(int a_ChunkX, int a_ChunkZ) +cChunkPtr cChunkMap::ConstructChunk(int a_ChunkX, int a_ChunkZ) { - const int LayerX = FAST_FLOOR_DIV(a_ChunkX, LAYER_SIZE); - const int LayerZ = FAST_FLOOR_DIV(a_ChunkZ, LAYER_SIZE); - return FindLayer(LayerX, LayerZ); -} - - - - - -cChunkMap::cChunkLayer * cChunkMap::FindLayer(int a_LayerX, int a_LayerZ) -{ - ASSERT(m_CSLayers.IsLockedByCurrentThread()); - - auto it = m_Layers.find(std::pair(a_LayerX, a_LayerZ)); - if (it != m_Layers.end()) + auto Chunk = FindChunk(a_ChunkX, a_ChunkZ); + if (Chunk == nullptr) { - cChunkLayer & Layer = it->second; - return &Layer; + return ( + *m_Chunks.emplace( + ChunkCoordinate{ a_ChunkX, a_ChunkZ }, + cpp14::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(); } - - // Not found - return nullptr; -} - - - - - -cChunkMap::cChunkLayer * cChunkMap::GetLayerForChunk(int a_ChunkX, int a_ChunkZ) -{ - const int LayerX = FAST_FLOOR_DIV(a_ChunkX, LAYER_SIZE); - const int LayerZ = FAST_FLOOR_DIV(a_ChunkZ, LAYER_SIZE); - return GetLayer(LayerX, LayerZ); + return Chunk; } @@ -146,16 +94,9 @@ cChunkMap::cChunkLayer * cChunkMap::GetLayerForChunk(int a_ChunkX, int a_ChunkZ) cChunkPtr cChunkMap::GetChunk(int a_ChunkX, int a_ChunkZ) { - ASSERT(m_CSLayers.IsLockedByCurrentThread()); // m_CSLayers should already be locked by the operation that called us + ASSERT(m_CSChunks.IsLockedByCurrentThread()); // m_CSChunks should already be locked by the operation that called us - cChunkLayer * Layer = GetLayerForChunk(a_ChunkX, a_ChunkZ); - if (Layer == nullptr) - { - // An error must have occurred, since layers are automatically created if they don't exist - return nullptr; - } - - cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkZ); + auto Chunk = ConstructChunk(a_ChunkX, a_ChunkZ); if (Chunk == nullptr) { return nullptr; @@ -175,16 +116,9 @@ cChunkPtr cChunkMap::GetChunk(int a_ChunkX, int a_ChunkZ) cChunkPtr cChunkMap::GetChunkNoGen(int a_ChunkX, int a_ChunkZ) { - ASSERT(m_CSLayers.IsLockedByCurrentThread()); // m_CSLayers should already be locked by the operation that called us + ASSERT(m_CSChunks.IsLockedByCurrentThread()); // m_CSChunks should already be locked by the operation that called us - cChunkLayer * Layer = GetLayerForChunk(a_ChunkX, a_ChunkZ); - if (Layer == nullptr) - { - // An error must have occurred, since layers are automatically created if they don't exist - return nullptr; - } - - cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkZ); + auto Chunk = ConstructChunk(a_ChunkX, a_ChunkZ); if (Chunk == nullptr) { return nullptr; @@ -202,18 +136,10 @@ cChunkPtr cChunkMap::GetChunkNoGen(int a_ChunkX, int a_ChunkZ) -cChunkPtr cChunkMap::GetChunkNoLoad( int a_ChunkX, int a_ChunkZ) +cChunkPtr cChunkMap::GetChunkNoLoad(int a_ChunkX, int a_ChunkZ) { - ASSERT(m_CSLayers.IsLockedByCurrentThread()); // m_CSLayers should already be locked by the operation that called us - - cChunkLayer * Layer = GetLayerForChunk( a_ChunkX, a_ChunkZ); - if (Layer == nullptr) - { - // An error must have occurred, since layers are automatically created if they don't exist - return nullptr; - } - - return Layer->GetChunk(a_ChunkX, a_ChunkZ); + ASSERT(m_CSChunks.IsLockedByCurrentThread()); // m_CSChunks should already be locked by the operation that called us + return ConstructChunk(a_ChunkX, a_ChunkZ); } @@ -222,8 +148,8 @@ cChunkPtr cChunkMap::GetChunkNoLoad( int a_ChunkX, int a_ChunkZ) bool cChunkMap::LockedGetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) { - // We already have m_CSLayers locked since this can be called only from within the tick thread - ASSERT(m_CSLayers.IsLockedByCurrentThread()); + // We already have m_CSChunks locked since this can be called only from within the tick thread + ASSERT(m_CSChunks.IsLockedByCurrentThread()); int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); @@ -244,8 +170,8 @@ bool cChunkMap::LockedGetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTY bool cChunkMap::LockedGetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType) { - // We already have m_CSLayers locked since this can be called only from within the tick thread - ASSERT(m_CSLayers.IsLockedByCurrentThread()); + // We already have m_CSChunks locked since this can be called only from within the tick thread + ASSERT(m_CSChunks.IsLockedByCurrentThread()); int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); @@ -265,8 +191,8 @@ bool cChunkMap::LockedGetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ, BLO bool cChunkMap::LockedGetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE & a_BlockMeta) { - // We already have m_CSLayers locked since this can be called only from within the tick thread - ASSERT(m_CSLayers.IsLockedByCurrentThread()); + // We already have m_CSChunks locked since this can be called only from within the tick thread + ASSERT(m_CSChunks.IsLockedByCurrentThread()); int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); @@ -286,7 +212,7 @@ bool cChunkMap::LockedGetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIB bool cChunkMap::LockedSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - // We already have m_CSLayers locked since this can be called only from within the tick thread + // We already have m_CSChunks locked since this can be called only from within the tick thread int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); @@ -305,7 +231,7 @@ bool cChunkMap::LockedSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTY bool cChunkMap::LockedFastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { - // We already have m_CSLayers locked since this can be called only from within the tick thread + // We already have m_CSChunks locked since this can be called only from within the tick thread int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); @@ -324,14 +250,10 @@ bool cChunkMap::LockedFastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLO cChunk * cChunkMap::FindChunk(int a_ChunkX, int a_ChunkZ) { - ASSERT(m_CSLayers.IsLockedByCurrentThread()); + ASSERT(m_CSChunks.IsLockedByCurrentThread()); - cChunkLayer * Layer = FindLayerForChunk(a_ChunkX, a_ChunkZ); - if (Layer == nullptr) - { - return nullptr; - } - return Layer->FindChunk(a_ChunkX, a_ChunkZ); + auto Chunk = m_Chunks.find({ a_ChunkX, a_ChunkZ }); + return (Chunk == m_Chunks.end()) ? nullptr : Chunk->second.get(); } @@ -340,7 +262,7 @@ cChunk * cChunkMap::FindChunk(int a_ChunkX, int a_ChunkZ) void cChunkMap::BroadcastAttachEntity(const cEntity & a_Entity, const cEntity & a_Vehicle) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == nullptr) { @@ -356,7 +278,7 @@ void cChunkMap::BroadcastAttachEntity(const cEntity & a_Entity, const cEntity & void cChunkMap::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); int x, z, ChunkX, ChunkZ; x = a_BlockX; z = a_BlockZ; @@ -376,7 +298,7 @@ void cChunkMap::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, c void cChunkMap::BroadcastBlockBreakAnimation(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); @@ -395,7 +317,7 @@ void cChunkMap::BroadcastBlockBreakAnimation(UInt32 a_EntityID, int a_BlockX, in void cChunkMap::BroadcastBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); @@ -412,7 +334,7 @@ void cChunkMap::BroadcastBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, c void cChunkMap::BroadcastCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == nullptr) { @@ -428,7 +350,7 @@ void cChunkMap::BroadcastCollectEntity(const cEntity & a_Entity, const cPlayer & void cChunkMap::BroadcastDestroyEntity(const cEntity & a_Entity, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == nullptr) { @@ -444,7 +366,7 @@ void cChunkMap::BroadcastDestroyEntity(const cEntity & a_Entity, const cClientHa void cChunkMap::BroadcastDetachEntity(const cEntity & a_Entity, const cEntity & a_PreviousVehicle) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == nullptr) { @@ -460,7 +382,7 @@ void cChunkMap::BroadcastDetachEntity(const cEntity & a_Entity, const cEntity & void cChunkMap::BroadcastEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == nullptr) { @@ -476,7 +398,7 @@ void cChunkMap::BroadcastEntityEffect(const cEntity & a_Entity, int a_EffectID, void cChunkMap::BroadcastEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == nullptr) { @@ -492,7 +414,7 @@ void cChunkMap::BroadcastEntityEquipment(const cEntity & a_Entity, short a_SlotN void cChunkMap::BroadcastEntityHeadLook(const cEntity & a_Entity, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == nullptr) { @@ -508,7 +430,7 @@ void cChunkMap::BroadcastEntityHeadLook(const cEntity & a_Entity, const cClientH void cChunkMap::BroadcastEntityLook(const cEntity & a_Entity, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == nullptr) { @@ -524,7 +446,7 @@ void cChunkMap::BroadcastEntityLook(const cEntity & a_Entity, const cClientHandl void cChunkMap::BroadcastEntityMetadata(const cEntity & a_Entity, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == nullptr) { @@ -540,7 +462,7 @@ void cChunkMap::BroadcastEntityMetadata(const cEntity & a_Entity, const cClientH void cChunkMap::BroadcastEntityRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == nullptr) { @@ -556,7 +478,7 @@ void cChunkMap::BroadcastEntityRelMove(const cEntity & a_Entity, char a_RelX, ch void cChunkMap::BroadcastEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == nullptr) { @@ -572,7 +494,7 @@ void cChunkMap::BroadcastEntityRelMoveLook(const cEntity & a_Entity, char a_RelX void cChunkMap::BroadcastEntityStatus(const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == nullptr) { @@ -588,7 +510,7 @@ void cChunkMap::BroadcastEntityStatus(const cEntity & a_Entity, char a_Status, c void cChunkMap::BroadcastEntityVelocity(const cEntity & a_Entity, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == nullptr) { @@ -604,7 +526,7 @@ void cChunkMap::BroadcastEntityVelocity(const cEntity & a_Entity, const cClientH void cChunkMap::BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == nullptr) { @@ -620,7 +542,7 @@ void cChunkMap::BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animat void cChunkMap::BroadcastParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmount, cClientHandle * a_Exclude) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(FloorC(a_SrcX), FloorC(a_SrcZ), ChunkX, ChunkZ); @@ -639,7 +561,7 @@ void cChunkMap::BroadcastParticleEffect(const AString & a_ParticleName, float a_ void cChunkMap::BroadcastRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == nullptr) @@ -656,7 +578,7 @@ void cChunkMap::BroadcastRemoveEntityEffect(const cEntity & a_Entity, int a_Effe void cChunkMap::BroadcastSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(FloorC(std::floor(a_X)), FloorC(std::floor(a_Z)), ChunkX, ChunkZ); @@ -675,7 +597,7 @@ void cChunkMap::BroadcastSoundEffect(const AString & a_SoundName, double a_X, do void cChunkMap::BroadcastSoundParticleEffect(const EffectID a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_SrcX, a_SrcZ, ChunkX, ChunkZ); @@ -694,7 +616,7 @@ void cChunkMap::BroadcastSoundParticleEffect(const EffectID a_EffectID, int a_Sr void cChunkMap::BroadcastSpawnEntity(cEntity & a_Entity, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), a_Entity.GetChunkZ()); if (Chunk == nullptr) { @@ -710,7 +632,7 @@ void cChunkMap::BroadcastSpawnEntity(cEntity & a_Entity, const cClientHandle * a void cChunkMap::BroadcastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); @@ -728,7 +650,7 @@ void cChunkMap::BroadcastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ, c void cChunkMap::BroadcastUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); @@ -747,7 +669,7 @@ void cChunkMap::BroadcastUseBed(const cEntity & a_Entity, int a_BlockX, int a_Bl void cChunkMap::SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle & a_Client) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); @@ -765,7 +687,7 @@ void cChunkMap::SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClien bool cChunkMap::UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) { // a_Player rclked block entity at the coords specified, handle it - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); @@ -782,7 +704,7 @@ bool cChunkMap::UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, i bool cChunkMap::DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); if (Chunk == nullptr) { @@ -819,7 +741,7 @@ bool cChunkMap::DoWithChunkAt(Vector3i a_BlockPos, std::function void cChunkMap::WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); int ChunkX, ChunkZ; cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); @@ -844,7 +766,7 @@ void cChunkMap::WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_M int MinChunkX, MinChunkZ, MaxChunkX, MaxChunkZ; cChunkDef::BlockToChunk(a_MinBlockX, a_MinBlockZ, MinChunkX, MinChunkZ); cChunkDef::BlockToChunk(a_MaxBlockX, a_MaxBlockZ, MaxChunkX, MaxChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); for (int z = MinChunkZ; z <= MaxChunkZ; z++) { int MinZ = std::max(a_MinBlockZ, z * cChunkDef::Width); @@ -878,7 +800,7 @@ void cChunkMap::WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_M void cChunkMap::MarkChunkDirty(int a_ChunkX, int a_ChunkZ) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -893,7 +815,7 @@ void cChunkMap::MarkChunkDirty(int a_ChunkX, int a_ChunkZ) void cChunkMap::MarkChunkSaving(int a_ChunkX, int a_ChunkZ) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -908,7 +830,7 @@ void cChunkMap::MarkChunkSaving(int a_ChunkX, int a_ChunkZ) void cChunkMap::MarkChunkSaved (int a_ChunkX, int a_ChunkZ) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -926,7 +848,7 @@ void cChunkMap::SetChunkData(cSetChunkData & a_SetChunkData) int ChunkX = a_SetChunkData.GetChunkX(); int ChunkZ = a_SetChunkData.GetChunkZ(); { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk == nullptr) { @@ -971,7 +893,7 @@ void cChunkMap::ChunkLighted( const cChunkDef::BlockNibbles & a_SkyLight ) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); if (Chunk == nullptr) { @@ -987,7 +909,7 @@ void cChunkMap::ChunkLighted( bool cChunkMap::GetChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_Callback) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -1003,7 +925,7 @@ bool cChunkMap::GetChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_ bool cChunkMap::GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_BlockTypes) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -1019,7 +941,7 @@ bool cChunkMap::GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_Blo bool cChunkMap::IsChunkQueued(int a_ChunkX, int a_ChunkZ) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); return (Chunk != nullptr) && Chunk->IsQueued(); } @@ -1030,7 +952,7 @@ bool cChunkMap::IsChunkQueued(int a_ChunkX, int a_ChunkZ) bool cChunkMap::IsChunkValid(int a_ChunkX, int a_ChunkZ) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); return (Chunk != nullptr) && Chunk->IsValid(); } @@ -1041,7 +963,7 @@ bool cChunkMap::IsChunkValid(int a_ChunkX, int a_ChunkZ) bool cChunkMap::HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); return (Chunk != nullptr) && Chunk->HasAnyClients(); } @@ -1054,7 +976,7 @@ int cChunkMap::GetHeight(int a_BlockX, int a_BlockZ) { for (;;) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); int ChunkX, ChunkZ, BlockY = 0; cChunkDef::AbsoluteToRelative(a_BlockX, BlockY, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); @@ -1081,7 +1003,7 @@ int cChunkMap::GetHeight(int a_BlockX, int a_BlockZ) bool cChunkMap::TryGetHeight(int a_BlockX, int a_BlockZ, int & a_Height) { // Returns false if chunk not loaded / generated - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); int ChunkX, ChunkZ, BlockY = 0; cChunkDef::AbsoluteToRelative(a_BlockX, BlockY, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); @@ -1099,7 +1021,7 @@ bool cChunkMap::TryGetHeight(int a_BlockX, int a_BlockZ, int & a_Height) void cChunkMap::SetBlocks(const sSetBlockVector & a_Blocks) { - cCSLock lock(m_CSLayers); + cCSLock lock(m_CSChunks); cChunkPtr chunk = nullptr; int lastChunkX = 0x7fffffff; // Bogus coords so that chunk is updated on first pass int lastChunkZ = 0x7fffffff; @@ -1138,7 +1060,7 @@ void cChunkMap::CollectPickupsByPlayer(cPlayer & a_Player) // We suppose that each player keeps their chunks in memory, therefore it makes little sense to try to re-load or even generate them. // The only time the chunks are not valid is when the player is downloading the initial world and they should not call this at that moment - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); GetChunkNoLoad(ChunkX, ChunkZ)->CollectPickupsByPlayer(a_Player); // Check the neighboring chunks as well: @@ -1159,7 +1081,7 @@ BLOCKTYPE cChunkMap::GetBlock(int a_BlockX, int a_BlockY, int a_BlockZ) cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ); // Query the chunk, if loaded: - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if ((Chunk != nullptr) && Chunk->IsValid()) { @@ -1179,7 +1101,7 @@ NIBBLETYPE cChunkMap::GetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ) cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ); // Query the chunk, if loaded: - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if ((Chunk != nullptr) && Chunk->IsValid()) { @@ -1197,7 +1119,7 @@ NIBBLETYPE cChunkMap::GetBlockSkyLight(int a_BlockX, int a_BlockY, int a_BlockZ) int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); if ((Chunk != nullptr) && Chunk->IsValid()) { @@ -1215,7 +1137,7 @@ NIBBLETYPE cChunkMap::GetBlockBlockLight(int a_BlockX, int a_BlockY, int a_Block int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); if ((Chunk != nullptr) && Chunk->IsValid()) { @@ -1234,7 +1156,7 @@ void cChunkMap::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYP cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); // a_BlockXYZ now contains relative coords! - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if ((Chunk != nullptr) && Chunk->IsValid()) { @@ -1254,7 +1176,7 @@ void cChunkMap::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_B int ChunkX, ChunkZ, X = a_BlockX, Y = a_BlockY, Z = a_BlockZ; cChunkDef::AbsoluteToRelative( X, Y, Z, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); if ((Chunk != nullptr) && Chunk->IsValid()) { @@ -1273,7 +1195,7 @@ bool cChunkMap::GetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCK int ChunkX, ChunkZ, X = a_BlockX, Y = a_BlockY, Z = a_BlockZ; cChunkDef::AbsoluteToRelative( X, Y, Z, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); if ((Chunk != nullptr) && Chunk->IsValid()) { @@ -1292,7 +1214,7 @@ bool cChunkMap::GetBlockInfo(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE int ChunkX, ChunkZ, X = a_BlockX, Y = a_BlockY, Z = a_BlockZ; cChunkDef::AbsoluteToRelative( X, Y, Z, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunk( ChunkX, ChunkZ); if ((Chunk != nullptr) && Chunk->IsValid()) { @@ -1308,7 +1230,7 @@ bool cChunkMap::GetBlockInfo(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE void cChunkMap::ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_FilterBlockType) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); for (sSetBlockVector::const_iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr) { cChunkPtr Chunk = GetChunk(itr->m_ChunkX, itr->m_ChunkZ); @@ -1329,7 +1251,7 @@ void cChunkMap::ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_Filt void cChunkMap::ReplaceTreeBlocks(const sSetBlockVector & a_Blocks) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); for (sSetBlockVector::const_iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr) { cChunkPtr Chunk = GetChunk(itr->m_ChunkX, itr->m_ChunkZ); @@ -1366,7 +1288,7 @@ EMCSBiome cChunkMap::GetBiomeAt (int a_BlockX, int a_BlockZ) int ChunkX, ChunkZ, X = a_BlockX, Y = 0, Z = a_BlockZ; cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if ((Chunk != nullptr) && Chunk->IsValid()) { @@ -1387,7 +1309,7 @@ bool cChunkMap::SetBiomeAt(int a_BlockX, int a_BlockZ, EMCSBiome a_Biome) int ChunkX, ChunkZ, X = a_BlockX, Y = 0, Z = a_BlockZ; cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if ((Chunk != nullptr) && Chunk->IsValid()) { @@ -1412,7 +1334,7 @@ bool cChunkMap::SetAreaBiome(int a_MinX, int a_MaxX, int a_MinZ, int a_MaxZ, EMC // Go through all chunks, set: bool res = true; - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); for (int x = MinChunkX; x <= MaxChunkX; x++) { int MinRelX = (x == MinChunkX) ? MinX : 0; @@ -1442,7 +1364,7 @@ bool cChunkMap::SetAreaBiome(int a_MinX, int a_MaxX, int a_MinZ, int a_MaxZ, EMC bool cChunkMap::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure) { bool res = true; - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); for (sSetBlockVector::iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr) { cChunkPtr Chunk = GetChunk(itr->m_ChunkX, itr->m_ChunkZ); @@ -1472,7 +1394,7 @@ bool cChunkMap::DigBlock(int a_BlockX, int a_BlockY, int a_BlockZ) cChunkDef::AbsoluteToRelative(PosX, PosY, PosZ, ChunkX, ChunkZ); { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr DestChunk = GetChunk( ChunkX, ChunkZ); if ((DestChunk == nullptr) || !DestChunk->IsValid()) { @@ -1495,7 +1417,7 @@ void cChunkMap::SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player) int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_X, a_Y, a_Z, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if ((Chunk != nullptr) && (Chunk->IsValid())) { @@ -1509,7 +1431,7 @@ void cChunkMap::SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player) void cChunkMap::CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk1 = GetChunkNoGen(a_ChunkX1, a_ChunkZ1); if (Chunk1 == nullptr) { @@ -1576,7 +1498,7 @@ void cChunkMap::CompareChunkClients(cChunk * a_Chunk1, cChunk * a_Chunk2, cClien bool cChunkMap::AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunk(a_ChunkX, a_ChunkZ); if (Chunk == nullptr) { @@ -1591,7 +1513,7 @@ bool cChunkMap::AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Cli void cChunkMap::RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if (Chunk == nullptr) { @@ -1606,13 +1528,11 @@ void cChunkMap::RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_ void cChunkMap::RemoveClientFromChunks(cClientHandle * a_Client) { - cCSLock Lock(m_CSLayers); - - for (auto & itr : m_Layers) + cCSLock Lock(m_CSChunks); + for (const auto & Chunk : m_Chunks) { - cChunkLayer & Layer = itr.second; - Layer.RemoveClient(a_Client); - } // for itr - m_Layers[] + Chunk.second->RemoveClient(a_Client); + } } @@ -1621,7 +1541,7 @@ void cChunkMap::RemoveClientFromChunks(cClientHandle * a_Client) void cChunkMap::AddEntity(cEntity * a_Entity) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunk(a_Entity->GetChunkX(), a_Entity->GetChunkZ()); if (Chunk == nullptr) // This will assert inside GetChunk in Debug builds { @@ -1639,7 +1559,7 @@ void cChunkMap::AddEntity(cEntity * a_Entity) void cChunkMap::AddEntityIfNotPresent(cEntity * a_Entity) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunk(a_Entity->GetChunkX(), a_Entity->GetChunkZ()); if (Chunk == nullptr) // This will assert inside GetChunk in Debug builds { @@ -1660,11 +1580,10 @@ void cChunkMap::AddEntityIfNotPresent(cEntity * a_Entity) bool cChunkMap::HasEntity(UInt32 a_UniqueID) { - cCSLock Lock(m_CSLayers); - for (auto & itr : m_Layers) + cCSLock Lock(m_CSChunks); + for (const auto & Chunk : m_Chunks) { - cChunkLayer & Layer = itr.second; - if (Layer.HasEntity(a_UniqueID)) + if (Chunk.second->IsValid() && Chunk.second->HasEntity(a_UniqueID)) { return true; } @@ -1678,7 +1597,7 @@ bool cChunkMap::HasEntity(UInt32 a_UniqueID) void cChunkMap::RemoveEntity(cEntity * a_Entity) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = a_Entity->GetParentChunk(); // Even if a chunk is not valid, it may still contain entities such as players; make sure to remove them (#1190) @@ -1695,11 +1614,10 @@ void cChunkMap::RemoveEntity(cEntity * a_Entity) bool cChunkMap::ForEachEntity(cEntityCallback & a_Callback) { - cCSLock Lock(m_CSLayers); - for (auto & itr : m_Layers) + cCSLock Lock(m_CSChunks); + for (const auto & Chunk : m_Chunks) { - cChunkLayer & Layer = itr.second; - if (!Layer.ForEachEntity(a_Callback)) + if (Chunk.second->IsValid() && !Chunk.second->ForEachEntity(a_Callback)) { return false; } @@ -1713,7 +1631,7 @@ bool cChunkMap::ForEachEntity(cEntityCallback & a_Callback) bool cChunkMap::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -1735,7 +1653,7 @@ bool cChunkMap::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & int MaxChunkZ = FloorC((a_Box.GetMaxZ() + cChunkDef::Width) / cChunkDef::Width); // Iterate over each chunk in the range: - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); for (int z = MinChunkZ; z <= MaxChunkZ; z++) { for (int x = MinChunkX; x <= MaxChunkX; x++) @@ -1956,12 +1874,11 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ bool cChunkMap::DoWithEntityByID(UInt32 a_UniqueID, cEntityCallback & a_Callback) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); bool res = false; - for (auto & itr : m_Layers) + for (const auto & Chunk : m_Chunks) { - cChunkLayer & Layer = itr.second; - if (Layer.DoWithEntityByID(a_UniqueID, a_Callback, res)) + if (Chunk.second->IsValid() && Chunk.second->DoWithEntityByID(a_UniqueID, a_Callback, res)) { return res; } @@ -1975,7 +1892,7 @@ bool cChunkMap::DoWithEntityByID(UInt32 a_UniqueID, cEntityCallback & a_Callback bool cChunkMap::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback & a_Callback) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -1990,7 +1907,7 @@ bool cChunkMap::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEnti bool cChunkMap::ForEachBrewingstandInChunk(int a_ChunkX, int a_ChunkZ, cBrewingstandCallback & a_Callback) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -2005,7 +1922,7 @@ bool cChunkMap::ForEachBrewingstandInChunk(int a_ChunkX, int a_ChunkZ, cBrewings bool cChunkMap::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -2020,7 +1937,7 @@ bool cChunkMap::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & bool cChunkMap::ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -2035,7 +1952,7 @@ bool cChunkMap::ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCa bool cChunkMap::ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallback & a_Callback) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -2050,7 +1967,7 @@ bool cChunkMap::ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallba bool cChunkMap::ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpenserCallback & a_Callback) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -2065,7 +1982,7 @@ bool cChunkMap::ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpens bool cChunkMap::ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback & a_Callback) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -2083,7 +2000,7 @@ bool cChunkMap::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cB int ChunkX, ChunkZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -2101,7 +2018,7 @@ bool cChunkMap::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeacon int ChunkX, ChunkZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -2119,7 +2036,7 @@ bool cChunkMap::DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, c int ChunkX, ChunkZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -2137,7 +2054,7 @@ bool cChunkMap::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCa int ChunkX, ChunkZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -2155,7 +2072,7 @@ bool cChunkMap::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDis int ChunkX, ChunkZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -2173,7 +2090,7 @@ bool cChunkMap::DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropp int ChunkX, ChunkZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -2191,7 +2108,7 @@ bool cChunkMap::DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cD int ChunkX, ChunkZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -2209,7 +2126,7 @@ bool cChunkMap::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurna int ChunkX, ChunkZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -2226,7 +2143,7 @@ bool cChunkMap::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNot int ChunkX, ChunkZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -2243,7 +2160,7 @@ bool cChunkMap::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, c int ChunkX, ChunkZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -2261,7 +2178,7 @@ bool cChunkMap::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHe int ChunkX, ChunkZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -2279,7 +2196,7 @@ bool cChunkMap::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlo int ChunkX, ChunkZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -2297,7 +2214,7 @@ bool cChunkMap::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & int ChunkX, ChunkZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); if ((Chunk == nullptr) || !Chunk->IsValid()) { @@ -2312,7 +2229,7 @@ bool cChunkMap::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & void cChunkMap::TouchChunk(int a_ChunkX, int a_ChunkZ) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); GetChunk(a_ChunkX, a_ChunkZ); } @@ -2322,7 +2239,7 @@ void cChunkMap::TouchChunk(int a_ChunkX, int a_ChunkZ) void cChunkMap::PrepareChunk(int a_ChunkX, int a_ChunkZ, std::unique_ptr a_Callback) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); // If the chunk is not prepared, queue it in the lighting thread, that will do all the needed processing: @@ -2345,7 +2262,7 @@ void cChunkMap::PrepareChunk(int a_ChunkX, int a_ChunkZ, std::unique_ptr a_Callback) { - cCSLock Lock(m_CSLayers); - for (auto & itr: m_Layers) + cCSLock Lock(m_CSChunks); + for (const auto & Chunk : m_Chunks) { - cChunkLayer & Layer = itr.second; - for (int x = 0; x < LAYER_SIZE; x++) + if (Chunk.second->IsValid()) { - for (int z = 0; z < LAYER_SIZE; z++) + if (a_Callback(Chunk.first.ChunkX, Chunk.first.ChunkZ)) { - cChunkPtr p = Layer.FindChunk(Layer.GetX() * LAYER_SIZE + x, Layer.GetZ() * LAYER_SIZE + z); - if ((p != nullptr) && p->IsValid()) // if chunk is loaded - { - if (a_Callback(p->GetPosX(), p->GetPosZ())) - { - return false; - } - } + return false; } } } @@ -2556,7 +2465,7 @@ bool cChunkMap::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBl // Iterate over chunks, write data into each: bool Result = true; - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); for (int z = MinChunkZ; z <= MaxChunkZ; z++) { for (int x = MinChunkX; x <= MaxChunkX; x++) @@ -2582,15 +2491,15 @@ void cChunkMap::GetChunkStats(int & a_NumChunksValid, int & a_NumChunksDirty) { a_NumChunksValid = 0; a_NumChunksDirty = 0; - cCSLock Lock(m_CSLayers); - for (auto & itr : m_Layers) + cCSLock Lock(m_CSChunks); + for (const auto & Chunk : m_Chunks) { - cChunkLayer & Layer = itr.second; - int NumValid = 0, NumDirty = 0; - Layer.GetChunkStats(NumValid, NumDirty); - a_NumChunksValid += NumValid; - a_NumChunksDirty += NumDirty; - } // for itr - m_Layers[] + a_NumChunksValid++; + if (Chunk.second->IsDirty()) + { + a_NumChunksDirty++; + } + } } @@ -2602,7 +2511,7 @@ bool cChunkMap::GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCK int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk != nullptr) { @@ -2620,7 +2529,7 @@ int cChunkMap::GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_Num int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk != nullptr) { @@ -2638,7 +2547,7 @@ int cChunkMap::GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlo int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk != nullptr) { @@ -2656,7 +2565,7 @@ bool cChunkMap::GrowTallGrass(int a_BlockX, int a_BlockY, int a_BlockZ) int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk != nullptr) { @@ -2674,7 +2583,7 @@ void cChunkMap::SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ) int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk != nullptr) { @@ -2687,12 +2596,17 @@ void cChunkMap::SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ) void cChunkMap::CollectMobCensus(cMobCensus & a_ToFill) { - cCSLock Lock(m_CSLayers); - for (auto & itr: m_Layers) + cCSLock Lock(m_CSChunks); + for (const auto & Chunk : m_Chunks) { - cChunkLayer & Layer = itr.second; - Layer.CollectMobCensus(a_ToFill); - } // for itr - m_Layers + // 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()) + { + Chunk.second->CollectMobCensus(a_ToFill); + } + } } @@ -2702,12 +2616,15 @@ void cChunkMap::CollectMobCensus(cMobCensus & a_ToFill) void cChunkMap::SpawnMobs(cMobSpawner & a_MobSpawner) { - cCSLock Lock(m_CSLayers); - for (auto & itr: m_Layers) + cCSLock Lock(m_CSChunks); + for (const auto & Chunk : m_Chunks) { - cChunkLayer & Layer = itr.second; - Layer.SpawnMobs(a_MobSpawner); - } // for itr - m_Layers + // We only spawn close to players + if (Chunk.second->IsValid() && Chunk.second->HasAnyClients()) + { + Chunk.second->SpawnMobs(a_MobSpawner); + } + } } @@ -2716,12 +2633,15 @@ void cChunkMap::SpawnMobs(cMobSpawner & a_MobSpawner) void cChunkMap::Tick(std::chrono::milliseconds a_Dt) { - cCSLock Lock(m_CSLayers); - for (auto & itr: m_Layers) + cCSLock Lock(m_CSChunks); + for (const auto & Chunk : m_Chunks) { - cChunkLayer & Layer = itr.second; - Layer.Tick(a_Dt); - } // for itr - m_Layers + // Only tick chunks that are valid and should be ticked: + if (Chunk.second->IsValid() && Chunk.second->ShouldBeTicked()) + { + Chunk.second->Tick(a_Dt); + } + } } @@ -2730,7 +2650,7 @@ void cChunkMap::Tick(std::chrono::milliseconds a_Dt) void cChunkMap::TickBlock(int a_BlockX, int a_BlockY, int a_BlockZ) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); @@ -2747,12 +2667,21 @@ void cChunkMap::TickBlock(int a_BlockX, int a_BlockY, int a_BlockZ) void cChunkMap::UnloadUnusedChunks(void) { - cCSLock Lock(m_CSLayers); - for (auto & itr: m_Layers) + cCSLock Lock(m_CSChunks); + for (auto itr = m_Chunks.begin(); itr != m_Chunks.end();) { - cChunkLayer & Layer = itr.second; - Layer.UnloadUnusedChunks(); - } // for itr - m_Layers + if ( + (itr->second->CanUnload()) && // Can unload + !cPluginManager::Get()->CallHookChunkUnloading(*GetWorld(), itr->first.ChunkX, itr->first.ChunkZ) // Plugins agree + ) + { + itr = m_Chunks.erase(itr); + } + else + { + ++itr; + } + } } @@ -2761,12 +2690,14 @@ void cChunkMap::UnloadUnusedChunks(void) void cChunkMap::SaveAllChunks(void) { - cCSLock Lock(m_CSLayers); - for (auto & itr: m_Layers) + cCSLock Lock(m_CSChunks); + for (const auto & Chunk : m_Chunks) { - cChunkLayer & Layer = itr.second; - Layer.Save(); - } // for itr - m_Layers[] + if (Chunk.second->IsValid() && Chunk.second->IsDirty()) + { + GetWorld()->GetStorage().QueueSaveChunk(Chunk.first.ChunkX, Chunk.first.ChunkZ); + } + } } @@ -2775,14 +2706,9 @@ void cChunkMap::SaveAllChunks(void) int cChunkMap::GetNumChunks(void) { - cCSLock Lock(m_CSLayers); - int NumChunks = 0; - for (auto & itr: m_Layers) - { - cChunkLayer & Layer = itr.second; - NumChunks += Layer.GetNumChunksLoaded(); - } - return NumChunks; + cCSLock Lock(m_CSChunks); + return static_cast(m_Chunks.size()); // TODO: change return value to unsigned type + } @@ -2804,7 +2730,7 @@ void cChunkMap::QueueTickBlock(int a_BlockX, int a_BlockY, int a_BlockZ) cChunkDef::AbsoluteToRelative(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); // a_BlockXYZ now contains relative coords! - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoLoad(ChunkX, ChunkZ); if (Chunk != nullptr) { @@ -2818,7 +2744,7 @@ void cChunkMap::QueueTickBlock(int a_BlockX, int a_BlockY, int a_BlockZ) void cChunkMap::SetChunkAlwaysTicked(int a_ChunkX, int a_ChunkZ, bool a_AlwaysTicked) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); if (Chunk != nullptr) { @@ -2830,299 +2756,13 @@ void cChunkMap::SetChunkAlwaysTicked(int a_ChunkX, int a_ChunkZ, bool a_AlwaysTi -//////////////////////////////////////////////////////////////////////////////// -// cChunkMap::cChunkLayer: - -cChunkMap::cChunkLayer::cChunkLayer( - int a_LayerX, int a_LayerZ, - cChunkMap * a_Parent, - cAllocationPool & a_Pool -) - : m_LayerX( a_LayerX) - , m_LayerZ( a_LayerZ) - , m_Parent( a_Parent) - , m_NumChunksLoaded( 0) - , m_Pool(a_Pool) -{ - memset(m_Chunks, 0, sizeof(m_Chunks)); -} - - - - - -cChunkMap::cChunkLayer::~cChunkLayer() -{ - for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); ++i) - { - delete m_Chunks[i]; - m_Chunks[i] = nullptr; // Must zero out, because further chunk deletions query the chunkmap for entities and that would touch deleted data - } // for i - m_Chunks[] -} - - - - - -cChunkPtr cChunkMap::cChunkLayer::GetChunk( int a_ChunkX, int a_ChunkZ) -{ - // Always returns an assigned chunkptr, but the chunk needn't be valid (loaded / generated) - callers must check - - const int LocalX = a_ChunkX - m_LayerX * LAYER_SIZE; - const int LocalZ = a_ChunkZ - m_LayerZ * LAYER_SIZE; - - if (!((LocalX < LAYER_SIZE) && (LocalZ < LAYER_SIZE) && (LocalX > -1) && (LocalZ > -1))) - { - ASSERT(!"Asking a cChunkLayer for a chunk that doesn't belong to it!"); - return nullptr; - } - - int Index = LocalX + LocalZ * LAYER_SIZE; - if (m_Chunks[Index] == nullptr) - { - cChunk * neixm = (LocalX > 0) ? m_Chunks[Index - 1] : m_Parent->FindChunk(a_ChunkX - 1, a_ChunkZ); - cChunk * neixp = (LocalX < LAYER_SIZE - 1) ? m_Chunks[Index + 1] : m_Parent->FindChunk(a_ChunkX + 1, a_ChunkZ); - cChunk * neizm = (LocalZ > 0) ? m_Chunks[Index - LAYER_SIZE] : m_Parent->FindChunk(a_ChunkX, a_ChunkZ - 1); - cChunk * neizp = (LocalZ < LAYER_SIZE - 1) ? m_Chunks[Index + LAYER_SIZE] : m_Parent->FindChunk(a_ChunkX, a_ChunkZ + 1); - m_Chunks[Index] = new cChunk(a_ChunkX, a_ChunkZ, m_Parent, m_Parent->GetWorld(), neixm, neixp, neizm, neizp, m_Pool); - } - return m_Chunks[Index]; -} - - - - - -cChunk * cChunkMap::cChunkLayer::FindChunk(int a_ChunkX, int a_ChunkZ) -{ - const int LocalX = a_ChunkX - m_LayerX * LAYER_SIZE; - const int LocalZ = a_ChunkZ - m_LayerZ * LAYER_SIZE; - - if (!((LocalX < LAYER_SIZE) && (LocalZ < LAYER_SIZE) && (LocalX > -1) && (LocalZ > -1))) - { - ASSERT(!"Asking a cChunkLayer for a chunk that doesn't belong to it!"); - return nullptr; - } - - int Index = LocalX + LocalZ * LAYER_SIZE; - return m_Chunks[Index]; -} - - - - -void cChunkMap::cChunkLayer::CollectMobCensus(cMobCensus & a_ToFill) -{ - for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); i++) - { - // 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 ((m_Chunks[i] != nullptr) && m_Chunks[i]->IsValid() && m_Chunks[i]->HasAnyClients()) - { - m_Chunks[i]->CollectMobCensus(a_ToFill); - } - } // for i - m_Chunks[] -} - - - - - - -void cChunkMap::cChunkLayer::SpawnMobs(cMobSpawner & a_MobSpawner) -{ - for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); i++) - { - // We only spawn close to players - if ((m_Chunks[i] != nullptr) && m_Chunks[i]->IsValid() && m_Chunks[i]->HasAnyClients()) - { - m_Chunks[i]->SpawnMobs(a_MobSpawner); - } - } // for i - m_Chunks[] -} - - - - - -void cChunkMap::cChunkLayer::Tick(std::chrono::milliseconds a_Dt) -{ - for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); i++) - { - // Only tick chunks that should be ticked: - // Note that chunks that are not IsValid() will only tick players and then bailout - if ((m_Chunks[i] != nullptr) && m_Chunks[i]->ShouldBeTicked()) - { - m_Chunks[i]->Tick(a_Dt); - } - } // for i - m_Chunks[] -} - - - - - -void cChunkMap::cChunkLayer::RemoveClient(cClientHandle * a_Client) -{ - for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); i++) - { - if (m_Chunks[i] != nullptr) - { - m_Chunks[i]->RemoveClient(a_Client); - } - } // for i - m_Chunks[] -} - - - - - -bool cChunkMap::cChunkLayer::ForEachEntity(cEntityCallback & a_Callback) -{ - // Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true - for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); i++) - { - if ((m_Chunks[i] != nullptr) && m_Chunks[i]->IsValid()) - { - if (!m_Chunks[i]->ForEachEntity(a_Callback)) - { - return false; - } - } - } - return true; -} - - - - - -bool cChunkMap::cChunkLayer::DoWithEntityByID(UInt32 a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackReturn) -{ - // 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. - for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); i++) - { - if ((m_Chunks[i] != nullptr) && m_Chunks[i]->IsValid()) - { - if (m_Chunks[i]->DoWithEntityByID(a_EntityID, a_Callback, a_CallbackReturn)) - { - return true; - } - } - } - return false; -} - - - - - -bool cChunkMap::cChunkLayer::HasEntity(UInt32 a_EntityID) -{ - for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); i++) - { - if ((m_Chunks[i] != nullptr) && m_Chunks[i]->IsValid()) - { - if (m_Chunks[i]->HasEntity(a_EntityID)) - { - return true; - } - } - } - return false; -} - - - - - -int cChunkMap::cChunkLayer::GetNumChunksLoaded(void) const -{ - int NumChunks = 0; - for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); ++i) - { - if (m_Chunks[i] != nullptr) - { - NumChunks++; - } - } // for i - m_Chunks[] - return NumChunks; -} - - - - - -void cChunkMap::cChunkLayer::GetChunkStats(int & a_NumChunksValid, int & a_NumChunksDirty) const -{ - int NumValid = 0; - int NumDirty = 0; - for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); ++i) - { - if (m_Chunks[i] == nullptr) - { - continue; - } - NumValid++; - if (m_Chunks[i]->IsDirty()) - { - NumDirty++; - } - } // for i - m_Chunks[] - a_NumChunksValid = NumValid; - a_NumChunksDirty = NumDirty; -} - - - - - -void cChunkMap::cChunkLayer::Save(void) -{ - cWorld * World = m_Parent->GetWorld(); - for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); ++i) - { - if ((m_Chunks[i] != nullptr) && m_Chunks[i]->IsValid() && m_Chunks[i]->IsDirty()) - { - World->GetStorage().QueueSaveChunk(m_Chunks[i]->GetPosX(), m_Chunks[i]->GetPosZ()); - } - } // for i - m_Chunks[] -} - - - - - -void cChunkMap::cChunkLayer::UnloadUnusedChunks(void) -{ - for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); i++) - { - if ( - (m_Chunks[i] != nullptr) && // Is valid - (m_Chunks[i]->CanUnload()) && // Can unload - !cPluginManager::Get()->CallHookChunkUnloading(*(m_Parent->GetWorld()), m_Chunks[i]->GetPosX(), m_Chunks[i]->GetPosZ()) // Plugins agree - ) - { - // The cChunk destructor calls our GetChunk() while removing its entities - // so we still need to be able to return the chunk. Therefore we first delete, then nullptrify - // Doing otherwise results in bug https://forum.cuberite.org/thread-355.html - delete m_Chunks[i]; - m_Chunks[i] = nullptr; - } - } // for i - m_Chunks[] -} - - - - void cChunkMap::FastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { int ChunkX, ChunkZ, X = a_BlockX, Y = a_BlockY, Z = a_BlockZ; cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ); - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ); if ((Chunk != nullptr) && Chunk->IsValid()) { @@ -3136,7 +2776,7 @@ void cChunkMap::FastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE void cChunkMap::AddChunkStay(cChunkStay & a_ChunkStay) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); // Add it to the list: ASSERT(std::find(m_ChunkStays.begin(), m_ChunkStays.end(), &a_ChunkStay) == m_ChunkStays.end()); // Has not yet been added @@ -3171,7 +2811,7 @@ void cChunkMap::AddChunkStay(cChunkStay & a_ChunkStay) /** Removes the specified cChunkStay descendant from the internal list of ChunkStays. */ void cChunkMap::DelChunkStay(cChunkStay & a_ChunkStay) { - cCSLock Lock(m_CSLayers); + cCSLock Lock(m_CSChunks); // Remove from the list of active chunkstays: bool HasFound = false; diff --git a/src/ChunkMap.h b/src/ChunkMap.h index 70d9954eb..328b0f74c 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -64,8 +64,6 @@ class cChunkMap { public: - static const int LAYER_SIZE = 32; - cChunkMap(cWorld * a_World); ~cChunkMap(); @@ -76,7 +74,6 @@ public: void BroadcastBlockBreakAnimation(UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = nullptr); void BroadcastBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude); void BroadcastCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, const cClientHandle * a_Exclude = nullptr); - void BroadcastCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude = nullptr); void BroadcastDestroyEntity(const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); void BroadcastDetachEntity(const cEntity & a_Entity, const cEntity & a_PreviousVehicle); void BroadcastEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration, const cClientHandle * a_Exclude = nullptr); @@ -399,7 +396,7 @@ public: void QueueTickBlock(int a_BlockX, int a_BlockY, int a_BlockZ); /** Returns the CS for locking the chunkmap; only cWorld::cLock may use this function! */ - cCriticalSection & GetCS(void) { return m_CSLayers; } + cCriticalSection & GetCS(void) { return m_CSChunks; } /** Increments (a_AlwaysTicked == true) or decrements (false) the m_AlwaysTicked counter for the specified chunk. If the m_AlwaysTicked counter is greater than zero, the chunk is ticked in the tick-thread regardless of @@ -417,64 +414,6 @@ private: friend class cChunkStay; - class cChunkLayer - { - public: - cChunkLayer( - int a_LayerX, int a_LayerZ, - cChunkMap * a_Parent, - cAllocationPool & a_Pool - ); - ~cChunkLayer(); - - cChunkLayer(const cChunkLayer & a_That) = delete; - - /** Always returns an assigned chunkptr, but the chunk needn't be valid (loaded / generated) - callers must check */ - cChunkPtr GetChunk( int a_ChunkX, int a_ChunkZ); - - /** Returns the specified chunk, or nullptr if not created yet */ - cChunk * FindChunk(int a_ChunkX, int a_ChunkZ); - - int GetX(void) const {return m_LayerX; } - int GetZ(void) const {return m_LayerZ; } - - int GetNumChunksLoaded(void) const ; - - void GetChunkStats(int & a_NumChunksValid, int & a_NumChunksDirty) const; - - void Save(void); - void UnloadUnusedChunks(void); - - /** Collect a mob census, of all mobs, their megatype, their chunk and their distance o closest player */ - void CollectMobCensus(cMobCensus & a_ToFill); - - /** Try to Spawn Monsters inside all Chunks */ - void SpawnMobs(cMobSpawner & a_MobSpawner); - - void Tick(std::chrono::milliseconds a_Dt); - - void RemoveClient(cClientHandle * a_Client); - - /** 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 - - /** 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. */ - bool DoWithEntityByID(UInt32 a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackReturn); // Lua-accessible - - /** Returns true if there is an entity with the specified ID within this layer's chunks */ - bool HasEntity(UInt32 a_EntityID); - - protected: - - cChunkPtr m_Chunks[LAYER_SIZE * LAYER_SIZE]; - int m_LayerX; - int m_LayerZ; - cChunkMap * m_Parent; - int m_NumChunksLoaded; - - cAllocationPool & m_Pool; - }; - class cStarvationCallbacks : public cAllocationPool::cStarvationCallbacks { @@ -492,27 +431,29 @@ private: } }; - typedef std::list cChunkLayerList; + struct ChunkCoordinate + { + struct Comparer + { + bool operator() (const ChunkCoordinate & a_Lhs, const ChunkCoordinate & a_Rhs) const + { + return ((a_Lhs.ChunkX == a_Rhs.ChunkX) ? (a_Lhs.ChunkZ < a_Rhs.ChunkZ) : (a_Lhs.ChunkX < a_Rhs.ChunkX)); + } + }; + + int ChunkX; + int ChunkZ; + }; typedef std::list cChunkStays; - /** Finds the cChunkLayer object responsible for the specified chunk; returns nullptr if not found. Assumes m_CSLayers is locked. */ - cChunkLayer * FindLayerForChunk(int a_ChunkX, int a_ChunkZ); - - /** Returns the specified cChunkLayer object; returns nullptr if not found. Assumes m_CSLayers is locked. */ - cChunkLayer * FindLayer(int a_LayerX, int a_LayerZ); - - /** Returns the cChunkLayer object responsible for the specified chunk; creates it if not found. */ - cChunkLayer * GetLayerForChunk (int a_ChunkX, int a_ChunkZ); - - /** Returns the specified cChunkLayer object; creates it if not found. */ - cChunkLayer * GetLayer(int a_LayerX, int a_LayerZ); + cCriticalSection m_CSChunks; - void RemoveLayer(cChunkLayer * a_Layer); + /** 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; - cCriticalSection m_CSLayers; - std::map, cChunkLayer> m_Layers; - cEvent m_evtChunkValid; // Set whenever any chunk becomes valid, via ChunkValidated() + cEvent m_evtChunkValid; // Set whenever any chunk becomes valid, via ChunkValidated() cWorld * m_World; @@ -521,9 +462,19 @@ private: std::unique_ptr > m_Pool; - cChunkPtr GetChunk (int a_ChunkX, int a_ChunkZ); // Also queues the chunk for loading / generating if not valid - cChunkPtr GetChunkNoGen (int a_ChunkX, int a_ChunkZ); // Also queues the chunk for loading if not valid; doesn't generate - cChunkPtr GetChunkNoLoad(int a_ChunkX, int a_ChunkZ); // Doesn't load, doesn't generate + /** Returns or creates and returns a chunk pointer corresponding to the given chunk coordinates. + Emplaces this chunk in the chunk map. + Developers SHOULD use the GetChunk variants instead of this function. */ + cChunkPtr ConstructChunk(int a_ChunkX, int a_ChunkZ); + + /** Constructs a chunk and queues it for loading / generating if not valid, returning it */ + cChunkPtr GetChunk(int a_ChunkX, int a_ChunkZ); + + /** Constructs a chunk and queues the chunk for loading if not valid, returning it; doesn't generate */ + cChunkPtr GetChunkNoGen(int a_ChunkX, int a_ChunkZ); + + /** Constructs a chunk, returning it. Doesn't load, doesn't generate */ + cChunkPtr GetChunkNoLoad(int a_ChunkX, int a_ChunkZ); /** Gets a block in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load) */ bool LockedGetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta); @@ -540,7 +491,7 @@ private: /** Fast-sets a block in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load) */ bool LockedFastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); - /** Locates a chunk ptr in the chunkmap; doesn't create it when not found; assumes m_CSLayers is locked. To be called only from cChunkMap. */ + /** Locates a chunk ptr in the chunkmap; doesn't create it when not found; assumes m_CSChunks is locked. To be called only from cChunkMap. */ cChunk * FindChunk(int a_ChunkX, int a_ChunkZ); /** Adds a new cChunkStay descendant to the internal list of ChunkStays; loads its chunks. -- cgit v1.2.3