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
master
madmaxoft@gmail.com 2012-08-25 17:52:08 +00:00
parent 2c5f9350d6
commit bb25ba4977
6 changed files with 155 additions and 124 deletions

View File

@ -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 <json/json.h>
@ -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<unsigned int>::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);
}

View File

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

View File

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

View File

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

View File

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

View File

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