From 389062a1ed8063d82ddd611f3426c9b2b088e0fc Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Thu, 22 Mar 2012 15:53:40 +0000 Subject: Fixed a deadlock by removing clients from all chunks upon their exit, not using the clients chunklists. git-svn-id: http://mc-server.googlecode.com/svn/trunk@426 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/cChunk.cpp | 25 +++++++++++++++++-------- source/cChunkMap.cpp | 23 +++++++++++++++++++---- source/cChunkMap.h | 6 ++++-- source/cClientHandle.cpp | 11 +++++++---- source/cWorld.cpp | 4 ++-- source/cWorld.h | 4 ++-- 6 files changed, 51 insertions(+), 22 deletions(-) diff --git a/source/cChunk.cpp b/source/cChunk.cpp index 2dde0cc0d..e48ababd0 100644 --- a/source/cChunk.cpp +++ b/source/cChunk.cpp @@ -1196,17 +1196,26 @@ bool cChunk::AddClient(cClientHandle* a_Client) void cChunk::RemoveClient( cClientHandle* a_Client ) { - m_LoadedByClient.remove( a_Client ); - - if ( !a_Client->IsDestroyed() ) + for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr) { - for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr ) + if (*itr != a_Client) { - LOG("chunk [%i, %i] destroying entity #%i for player \"%s\"", m_PosX, m_PosZ, (*itr)->GetUniqueID(), a_Client->GetUsername().c_str() ); - cPacket_DestroyEntity DestroyEntity( *itr ); - a_Client->Send( DestroyEntity ); + continue; } - } + + m_LoadedByClient.erase(itr); + + if ( !a_Client->IsDestroyed() ) + { + for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr ) + { + LOGD("chunk [%i, %i] destroying entity #%i for player \"%s\"", m_PosX, m_PosZ, (*itr)->GetUniqueID(), a_Client->GetUsername().c_str() ); + cPacket_DestroyEntity DestroyEntity( *itr ); + a_Client->Send( DestroyEntity ); + } + } + return; + } // for itr - m_LoadedByClient[] } diff --git a/source/cChunkMap.cpp b/source/cChunkMap.cpp index 33441a406..e01899f28 100644 --- a/source/cChunkMap.cpp +++ b/source/cChunkMap.cpp @@ -747,14 +747,14 @@ void cChunkMap::RemoveChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cCli -void cChunkMap::RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoordsList & a_Chunks) +void cChunkMap::RemoveClientFromChunks(cClientHandle * a_Client) { cCSLock Lock(m_CSLayers); - for (cChunkCoordsList::const_iterator itr = a_Chunks.begin(); itr != a_Chunks.end(); ++itr) + for (cChunkLayerList::const_iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr) { - GetChunkNoGen(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ)->RemoveClient(a_Client); - } + (*itr)->RemoveClient(a_Client); + } // for itr - m_Layers[] } @@ -1006,6 +1006,21 @@ void cChunkMap::cChunkLayer::Tick(float a_Dt, MTRand & a_TickRand) +void cChunkMap::cChunkLayer::RemoveClient(cClientHandle * a_Client) +{ + for (int i = 0; i < ARRAYCOUNT(m_Chunks); i++) + { + if (m_Chunks[i] != NULL) + { + m_Chunks[i]->RemoveClient(a_Client); + } + } // for i - m_Chunks[] +} + + + + + int cChunkMap::cChunkLayer::GetNumChunksLoaded(void) const { int NumChunks = 0; diff --git a/source/cChunkMap.h b/source/cChunkMap.h index f2d55b6b8..ea93db80b 100644 --- a/source/cChunkMap.h +++ b/source/cChunkMap.h @@ -102,8 +102,8 @@ public: /// Removes the client from the chunk void RemoveChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client); - /// Removes the client from all chunks specified - void RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoordsList & a_Chunks); + /// Removes the client from all chunks it is present in + void RemoveClientFromChunks(cClientHandle * a_Client); /// Moves the entity from its current chunk to the new chunk specified void MoveEntityToChunk(cEntity * a_Entity, int a_ChunkX, int a_ChunkY, int a_ChunkZ); @@ -162,6 +162,8 @@ private: void Tick( float a_Dt, MTRand & a_TickRand ); + void RemoveClient(cClientHandle * a_Client); + protected: cChunkPtr m_Chunks[LAYER_SIZE * LAYER_SIZE]; diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp index d7b1aa55c..3df4b36b2 100644 --- a/source/cClientHandle.cpp +++ b/source/cClientHandle.cpp @@ -461,14 +461,17 @@ void cClientHandle::StreamChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) // Removes the client from all chunks. Used when switching worlds or destroying the player void cClientHandle::RemoveFromAllChunks() { - cCSLock Lock(m_CSChunkLists); cWorld * World = m_Player->GetWorld(); if (World != NULL) { - World->RemoveClientFromChunks(this, m_LoadedChunks); + World->RemoveClientFromChunks(this); + } + + { + cCSLock Lock(m_CSChunkLists); + m_LoadedChunks.clear(); + m_ChunksToSend.clear(); } - m_LoadedChunks.clear(); - m_ChunksToSend.clear(); } diff --git a/source/cWorld.cpp b/source/cWorld.cpp index daf72ac69..266d425e4 100644 --- a/source/cWorld.cpp +++ b/source/cWorld.cpp @@ -1345,9 +1345,9 @@ void cWorld::RemoveChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClient -void cWorld::RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoordsList & a_Chunks) +void cWorld::RemoveClientFromChunks(cClientHandle * a_Client) { - m_ChunkMap->RemoveClientFromChunks(a_Client, a_Chunks); + m_ChunkMap->RemoveClientFromChunks(a_Client); } diff --git a/source/cWorld.h b/source/cWorld.h index 56c63502b..a8591af65 100644 --- a/source/cWorld.h +++ b/source/cWorld.h @@ -150,8 +150,8 @@ public: /// Removes client from the chunk specified void RemoveChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client); - /// Removes the client from all chunks specified - void RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoordsList & a_Chunks); + /// Removes the client from all chunks it is present in + void RemoveClientFromChunks(cClientHandle * a_Client); /// Sends the chunk to the client specified, if the chunk is valid. If not valid, the request is ignored (ChunkSender will send that chunk when it becomes valid) void SendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client); -- cgit v1.2.3