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-c427514a06d6master
parent
2c5f9350d6
commit
bb25ba4977
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue