1
0

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
This commit is contained in:
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 ) void cChunk::RemoveClient( cClientHandle* a_Client )
{ {
m_LoadedByClient.remove( a_Client ); for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr)
if ( !a_Client->IsDestroyed() )
{ {
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() ); continue;
cPacket_DestroyEntity DestroyEntity( *itr );
a_Client->Send( DestroyEntity );
} }
}
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); 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 cChunkMap::cChunkLayer::GetNumChunksLoaded(void) const
{ {
int NumChunks = 0; int NumChunks = 0;

View File

@ -102,8 +102,8 @@ public:
/// Removes the client from the chunk /// Removes the client from the chunk
void RemoveChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client); void RemoveChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client);
/// Removes the client from all chunks specified /// Removes the client from all chunks it is present in
void RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoordsList & a_Chunks); void RemoveClientFromChunks(cClientHandle * a_Client);
/// Moves the entity from its current chunk to the new chunk specified /// 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); 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 Tick( float a_Dt, MTRand & a_TickRand );
void RemoveClient(cClientHandle * a_Client);
protected: protected:
cChunkPtr m_Chunks[LAYER_SIZE * LAYER_SIZE]; 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 // Removes the client from all chunks. Used when switching worlds or destroying the player
void cClientHandle::RemoveFromAllChunks() void cClientHandle::RemoveFromAllChunks()
{ {
cCSLock Lock(m_CSChunkLists);
cWorld * World = m_Player->GetWorld(); cWorld * World = m_Player->GetWorld();
if (World != NULL) 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 /// Removes client from the chunk specified
void RemoveChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client); void RemoveChunkClient(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client);
/// Removes the client from all chunks specified /// Removes the client from all chunks it is present in
void RemoveClientFromChunks(cClientHandle * a_Client, const cChunkCoordsList & a_Chunks); 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) /// 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); void SendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client);