From bb25ba4977198728b6ee30b61fcc6f48d1d94d4d Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Sat, 25 Aug 2012 17:52:08 +0000 Subject: [PATCH] Removed cPackets from cChunk. Also decoupled a possible deadlock in player login code. git-svn-id: http://mc-server.googlecode.com/svn/trunk@788 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/cChunk.cpp | 147 ++++++++++---------------- source/cChunk.h | 15 ++- source/cClientHandle.cpp | 71 ++++++++++++- source/cClientHandle.h | 3 + source/packets/cPacket_MultiBlock.cpp | 19 ++-- source/packets/cPacket_MultiBlock.h | 24 ++--- 6 files changed, 155 insertions(+), 124 deletions(-) diff --git a/source/cChunk.cpp b/source/cChunk.cpp index 2c97b5955..53c310a2e 100644 --- a/source/cChunk.cpp +++ b/source/cChunk.cpp @@ -31,13 +31,6 @@ #include "cPluginManager.h" #include "blocks/Block.h" -#include "packets/cPacket_DestroyEntity.h" -#include "packets/cPacket_PreChunk.h" -#include "packets/cPacket_BlockChange.h" -#include "packets/cPacket_MultiBlock.h" - -#include "blocks/Block.h" - #include @@ -358,58 +351,14 @@ void cChunk::Stay(bool a_Stay) void cChunk::Tick(float a_Dt, MTRand & a_TickRandom) { - cCSLock Lock(m_CSBlockLists); - unsigned int PendingSendBlocks = m_PendingSendBlocks.size(); - if( PendingSendBlocks > 1 ) - { - cPacket_MultiBlock MultiBlock; - MultiBlock.m_ChunkX = m_PosX; - MultiBlock.m_ChunkZ = m_PosZ; - MultiBlock.m_NumBlocks = (short)PendingSendBlocks; - MultiBlock.m_Data = new cPacket_MultiBlock::sBlockChange[ PendingSendBlocks ]; - MultiBlock.m_DataSize = PendingSendBlocks * sizeof( cPacket_MultiBlock::sBlockChange ); - //LOG("Sending multiblock packet for %i blocks", PendingSendBlocks ); - for( unsigned int i = 0; i < PendingSendBlocks; i++) - { - unsigned int index = m_PendingSendBlocks[i]; - Vector3i BlockPos = IndexToCoordinate( index ); + BroadcastPendingBlockChanges(); - unsigned int Coords = BlockPos.y | (BlockPos.z << 8) | (BlockPos.x << 12); - unsigned int Blocks = GetNibble( m_BlockMeta, index ) | (m_BlockTypes[index] << 4); - MultiBlock.m_Data[i].Data = Coords << 16 | Blocks; - } - m_PendingSendBlocks.clear(); - PendingSendBlocks = m_PendingSendBlocks.size(); - Broadcast( MultiBlock ); - } - if( PendingSendBlocks > 0 ) + // Unload the chunk from all clients that have queued unloading: + for (cClientHandleList::iterator itr = m_UnloadQuery.begin(), end = m_UnloadQuery.end(); itr != end; ++itr) { - for( unsigned int i = 0; i < PendingSendBlocks; i++) - { - unsigned int index = m_PendingSendBlocks[i]; - Vector3i WorldPos = PositionToWorldPosition( IndexToCoordinate( index ) ); - - cPacket_BlockChange BlockChange; - BlockChange.m_PosX = WorldPos.x; - BlockChange.m_PosY = (unsigned char)WorldPos.y; - BlockChange.m_PosZ = WorldPos.z; - BlockChange.m_BlockType = m_BlockTypes[index]; - BlockChange.m_BlockMeta = GetNibble( m_BlockMeta, index ); - Broadcast( BlockChange ); - } - m_PendingSendBlocks.clear(); - } - Lock.Unlock(); - - while ( !m_UnloadQuery.empty() ) - { - cPacket_PreChunk UnloadPacket; - UnloadPacket.m_PosX = GetPosX(); - UnloadPacket.m_PosZ = GetPosZ(); - UnloadPacket.m_bLoad = false; // Unload - (*m_UnloadQuery.begin())->Send( UnloadPacket ); - m_UnloadQuery.remove( *m_UnloadQuery.begin() ); + (*itr)->SendUnloadChunk(m_PosX, m_PosZ); } + m_UnloadQuery.clear(); CheckBlocks(); @@ -429,6 +378,35 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom) +void cChunk::BroadcastPendingBlockChanges(void) +{ + sSetBlockVector Changes; + { + cCSLock Lock(m_CSBlockLists); + if (m_PendingSendBlocks.empty()) + { + return; + } + Changes.reserve(m_PendingSendBlocks.size()); + for (std::vector::iterator itr = m_PendingSendBlocks.begin(), end = m_PendingSendBlocks.end(); itr != end; ++itr) + { + unsigned int index = *itr; + Vector3i RelPos = IndexToCoordinate(index); + Changes.push_back(sSetBlock(m_PosX, m_PosZ, RelPos.x, RelPos.y, RelPos.z, GetBlock(index), GetMeta(index))); + } // for itr - m_PendingSendBlocks[] + m_PendingSendBlocks.clear(); + } + + for (cClientHandleList::iterator itr = m_LoadedByClient.begin(), end = m_LoadedByClient.end(); itr != end; ++itr) + { + (*itr)->SendBlockChanges(m_PosX, m_PosZ, Changes); + } +} + + + + + void cChunk::CheckBlocks(void) { cCSLock Lock2(m_CSBlockLists); @@ -1176,42 +1154,24 @@ void cChunk::FastSetBlock( int a_X, int a_Y, int a_Z, BLOCKTYPE a_BlockType, BLO -void cChunk::SendBlockTo( int a_X, int a_Y, int a_Z, cClientHandle* a_Client ) +void cChunk::SendBlockTo(int a_RelX, int a_RelY, int a_RelZ, cClientHandle * a_Client) { - if( a_Client == 0 ) + unsigned int index = MakeIndex(a_RelX, a_RelY, a_RelZ); + if (index == INDEX_OUT_OF_RANGE) { - cCSLock Lock(m_CSBlockLists); - unsigned int index = MakeIndex( a_X, a_Y, a_Z ); - if( index != INDEX_OUT_OF_RANGE ) - { - m_PendingSendBlocks.push_back( index ); - } - else - { - LOGWARN("cChunk::SendBlockTo Index out of range!"); - } + LOGWARN("cChunk::SendBlockTo Index out of range!"); return; } - for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr ) + if (a_Client == NULL) { - if ( *itr == a_Client ) - { - unsigned int index = MakeIndex( a_X, a_Y, a_Z ); - Vector3i WorldPos = PositionToWorldPosition( a_X, a_Y, a_Z ); - cPacket_BlockChange BlockChange; - BlockChange.m_PosX = WorldPos.x; - BlockChange.m_PosY = (unsigned char)WorldPos.y; - BlockChange.m_PosZ = WorldPos.z; - if( index != INDEX_OUT_OF_RANGE ) - { - BlockChange.m_BlockType = m_BlockTypes[ index ]; - BlockChange.m_BlockMeta = GetNibble( m_BlockMeta, index ); - } // else it's both 0 - a_Client->Send( BlockChange ); - break; - } + // Queue the block for all clients in the chunk (will be sent in Tick()) + m_PendingSendBlocks.push_back(index); + return; } + + Vector3i wp = PositionToWorldPosition(a_RelX, a_RelY, a_RelZ); + a_Client->SendBlockChange(wp.x, wp.y, wp.z, GetBlock(index), GetMeta(index)); } @@ -1362,13 +1322,12 @@ void cChunk::RemoveClient( cClientHandle* a_Client ) m_LoadedByClient.erase(itr); - if ( !a_Client->IsDestroyed() ) + 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 ); + a_Client->SendDestroyEntity(*(*itr)); } } return; @@ -1982,20 +1941,20 @@ void cChunk::SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHa -void cChunk::PositionToWorldPosition(int a_ChunkX, int a_ChunkY, int a_ChunkZ, int & a_X, int & a_Y, int & a_Z) +void cChunk::PositionToWorldPosition(int a_RelX, int a_RelY, int a_RelZ, int & a_BlockX, int & a_BlockY, int & a_BlockZ) { - a_Y = a_ChunkY; - a_X = m_PosX * Width + a_ChunkX; - a_Z = m_PosZ * Width + a_ChunkZ; + a_BlockY = a_RelY; + a_BlockX = m_PosX * Width + a_RelX; + a_BlockZ = m_PosZ * Width + a_RelZ; } -Vector3i cChunk::PositionToWorldPosition( int a_ChunkX, int a_ChunkY, int a_ChunkZ ) +Vector3i cChunk::PositionToWorldPosition(int a_RelX, int a_RelY, int a_RelZ) { - return Vector3i( m_PosX * Width + a_ChunkX, m_PosY * Height + a_ChunkY, m_PosZ * Width + a_ChunkZ ); + return Vector3i(m_PosX * Width + a_RelX, m_PosY * Height + a_RelY, m_PosZ * Width + a_RelZ); } diff --git a/source/cChunk.h b/source/cChunk.h index 707ea5840..1b08f4d6b 100644 --- a/source/cChunk.h +++ b/source/cChunk.h @@ -138,7 +138,7 @@ public: int GetHeight( int a_X, int a_Z ); - void SendBlockTo( int a_X, int a_Y, int a_Z, cClientHandle* a_Client ); + void SendBlockTo(int a_RelX, int a_RelY, int a_RelZ, cClientHandle * a_Client); /// Adds a client to the chunk; returns true if added, false if already there bool AddClient (cClientHandle* a_Client ); @@ -193,9 +193,13 @@ public: void SendBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle & a_Client); - void PositionToWorldPosition(int a_ChunkX, int a_ChunkY, int a_ChunkZ, int & a_X, int & a_Y, int & a_Z); - Vector3i PositionToWorldPosition( const Vector3i & a_InChunkPos ) { return PositionToWorldPosition( a_InChunkPos.x, a_InChunkPos.y, a_InChunkPos.z ); } - Vector3i PositionToWorldPosition( int a_ChunkX, int a_ChunkY, int a_ChunkZ ); + Vector3i PositionToWorldPosition(const Vector3i & a_RelPos) + { + return PositionToWorldPosition(a_RelPos.x, a_RelPos.y, a_RelPos.z); + } + + void PositionToWorldPosition(int a_RelX, int a_RelY, int a_RelZ, int & a_BlockX, int & a_BlockY, int & a_BlockZ); + Vector3i PositionToWorldPosition(int a_RelX, int a_RelY, int a_RelZ ); inline void MarkDirty(void) { @@ -268,6 +272,9 @@ private: // Makes a copy of the list cClientHandleList GetAllClients(void) const {return m_LoadedByClient; } + /// Sends m_PendingSendBlocks to all clients + void BroadcastPendingBlockChanges(void); + /// Checks the block scheduled for checking in m_ToTickBlocks[] void CheckBlocks(void); diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp index 90672a1ec..a0ec88f80 100644 --- a/source/cClientHandle.cpp +++ b/source/cClientHandle.cpp @@ -1400,7 +1400,11 @@ void cClientHandle::Send(const cPacket & a_Packet, ENUM_PRIORITY a_Priority /* = if ((itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ)) { m_ChunksToSend.erase(itr); + + // TODO: _X: Decouple this from packet sending, it creates a deadlock possibility + // -- postpone till Tick() instead, using a bool flag CheckIfWorldDownloaded(); + Found = true; break; } @@ -1908,14 +1912,77 @@ void cClientHandle::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & +void cClientHandle::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) +{ + cPacket_BlockChange BlockChange; + BlockChange.m_PosX = a_BlockX; + BlockChange.m_PosY = (unsigned char)a_BlockY; + BlockChange.m_PosZ = a_BlockZ; + BlockChange.m_BlockType = a_BlockType; + BlockChange.m_BlockMeta = a_BlockMeta; + Send(BlockChange); +} + + + + + +void cClientHandle::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) +{ + if (a_Changes.size() == 1) + { + // Special packet for single-block changes + const sSetBlock & blk = a_Changes.front(); + SendBlockChange(a_ChunkX * cChunkDef::Width + blk.x, blk.y, a_ChunkZ * cChunkDef::Height + blk.z, blk.BlockType, blk.BlockMeta); + return; + } + + cPacket_MultiBlock MultiBlock; + MultiBlock.m_ChunkX = a_ChunkX; + MultiBlock.m_ChunkZ = a_ChunkZ; + MultiBlock.m_NumBlocks = (short)a_Changes.size(); + MultiBlock.m_Data = new cPacket_MultiBlock::sBlockChange[a_Changes.size()]; + int i = 0; + for (sSetBlockVector::const_iterator itr = a_Changes.begin(), end = a_Changes.end(); itr != end; ++itr, i++) + { + unsigned int Coords = itr->y | (itr->z << 8) | (itr->x << 12); + unsigned int Blocks = itr->BlockMeta | (itr->BlockType << 4); + MultiBlock.m_Data[i].Data = Coords << 16 | Blocks; + } + Send(MultiBlock); +} + + + + + +void cClientHandle::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) +{ + cPacket_PreChunk UnloadPacket; + UnloadPacket.m_PosX = a_ChunkX; + UnloadPacket.m_PosZ = a_ChunkZ; + UnloadPacket.m_bLoad = false; // Unload + Send(UnloadPacket); +} + + + + + void cClientHandle::CheckIfWorldDownloaded(void) { if (m_State != csDownloadingWorld) { return; } - cCSLock Lock(m_CSChunkLists); - if (m_ChunksToSend.empty()) + + bool ShouldSendConfirm = false; + { + cCSLock Lock(m_CSChunkLists); + ShouldSendConfirm = m_ChunksToSend.empty(); + } + + if (ShouldSendConfirm) { SendConfirmPosition(); } diff --git a/source/cClientHandle.h b/source/cClientHandle.h index 0dc0c2fd9..9c8586ae5 100644 --- a/source/cClientHandle.h +++ b/source/cClientHandle.h @@ -114,6 +114,9 @@ public: void SendSpawnMob (const cMonster & a_Mob); void SendUpdateSign (int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4); void SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player); + void SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); + void SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes); + void SendUnloadChunk(int a_ChunkX, int a_ChunkZ); const AString & GetUsername(void) const; //tolua_export diff --git a/source/packets/cPacket_MultiBlock.cpp b/source/packets/cPacket_MultiBlock.cpp index 9ae175508..68daf2700 100644 --- a/source/packets/cPacket_MultiBlock.cpp +++ b/source/packets/cPacket_MultiBlock.cpp @@ -7,15 +7,14 @@ -cPacket_MultiBlock::cPacket_MultiBlock( const cPacket_MultiBlock & a_Copy ) +cPacket_MultiBlock::cPacket_MultiBlock(const cPacket_MultiBlock & a_Copy) { - m_PacketID = E_MULTI_BLOCK; - m_ChunkX = a_Copy.m_ChunkX; - m_ChunkZ = a_Copy.m_ChunkZ; + m_PacketID = E_MULTI_BLOCK; + m_ChunkX = a_Copy.m_ChunkX; + m_ChunkZ = a_Copy.m_ChunkZ; m_NumBlocks = a_Copy.m_NumBlocks; - m_DataSize = a_Copy.m_DataSize; - m_Data = new sBlockChange[m_NumBlocks]; - memcpy( m_Data, a_Copy.m_Data, sizeof(sBlockChange)*m_NumBlocks ); + m_Data = new sBlockChange[m_NumBlocks]; + memcpy(m_Data, a_Copy.m_Data, sizeof(sBlockChange) * m_NumBlocks); } @@ -24,7 +23,7 @@ cPacket_MultiBlock::cPacket_MultiBlock( const cPacket_MultiBlock & a_Copy ) cPacket_MultiBlock::~cPacket_MultiBlock() { - delete [] m_Data; + delete[] m_Data; } @@ -38,8 +37,8 @@ void cPacket_MultiBlock::Serialize(AString & a_Data) const AppendInteger(a_Data, m_ChunkZ); AppendShort (a_Data, m_NumBlocks); - AppendInteger(a_Data, m_DataSize); - for( int i = 0; i < m_NumBlocks; ++i ) + AppendInteger(a_Data, sizeof(*m_Data) * m_NumBlocks); + for (short i = 0; i < m_NumBlocks; ++i) { AppendInteger(a_Data, m_Data[i].Data); } diff --git a/source/packets/cPacket_MultiBlock.h b/source/packets/cPacket_MultiBlock.h index af3d24267..7399fe853 100644 --- a/source/packets/cPacket_MultiBlock.h +++ b/source/packets/cPacket_MultiBlock.h @@ -12,34 +12,30 @@ class cPacket_MultiBlock : public cPacket public: struct sBlockChange { - sBlockChange() - : Data( 0 ) - {} unsigned int Data; -// short Data; // 4bits metadata ... 12bits block ID -// short Coords; // 8bits Y ... 4bits Z ... 4bits X + // short Data; // 4bits metadata ... 12bits block ID + // short Coords; // 8bits Y ... 4bits Z ... 4bits X }; cPacket_MultiBlock() : m_ChunkX( 0 ) , m_ChunkZ( 0 ) , m_NumBlocks( 0 ) - , m_DataSize( 0 ) , m_Data( NULL ) - { m_PacketID = E_MULTI_BLOCK; } + { + m_PacketID = E_MULTI_BLOCK; + } - cPacket_MultiBlock( const cPacket_MultiBlock & a_Copy ); + cPacket_MultiBlock(const cPacket_MultiBlock & a_Copy); ~cPacket_MultiBlock(); virtual cPacket* Clone() const { return new cPacket_MultiBlock(*this); } virtual void Serialize(AString & a_Data) const override; - int m_ChunkX; - int m_ChunkZ; - short m_NumBlocks; - - int m_DataSize; // Should be 4 * m_NumBlocks ?? - sBlockChange * m_Data; + int m_ChunkX; + int m_ChunkZ; + short m_NumBlocks; + sBlockChange * m_Data; // m_NumBlocks items in the array };