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
master
madmaxoft@gmail.com 2012-03-22 15:53:40 +00:00
parent ed7b680d3c
commit 389062a1ed
6 changed files with 51 additions and 22 deletions

View File

@ -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[]
}

View File

@ -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;

View File

@ -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];

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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);