cClientHandle: gotten rid of the obnoxious m_pState, now using direct members instead

git-svn-id: http://mc-server.googlecode.com/svn/trunk@228 0a769ca7-a7f5-676a-18bf-c427514a06d6
master
madmaxoft@gmail.com 2012-02-02 21:13:24 +00:00
parent dca87cd214
commit f86d796295
4 changed files with 406 additions and 352 deletions

View File

@ -75,8 +75,6 @@
#define MAX_SEMAPHORES (2000) #define MAX_SEMAPHORES (2000)
typedef std::list<cPacket*> PacketList;
@ -88,59 +86,22 @@ extern std::string GetWSAError();
struct cClientHandle::sClientHandleState
{
int ProtocolVersion;
std::string Username;
std::string Password;
PacketList PendingParsePackets;
PacketList PendingNrmSendPackets;
PacketList PendingLowSendPackets;
cThread* pReceiveThread;
cThread* pSendThread;
cThread* pAuthenticateThread;
cSocket Socket;
cCriticalSection CriticalSection;
cCriticalSection SendCriticalSection;
cCriticalSection SocketCriticalSection;
cSemaphore* pSemaphore;
Vector3d ConfirmPosition;
cPacket* PacketMap[256];
sClientHandleState(void)
: ProtocolVersion( 23 )
, pReceiveThread( 0 )
, pSendThread( 0 )
, pAuthenticateThread( 0 )
, pSemaphore( 0 )
{
for( int i = 0; i < 256; ++i )
PacketMap[i] = 0;
}
} ;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cClientHandle: // cClientHandle:
cClientHandle::cClientHandle(const cSocket & a_Socket) cClientHandle::cClientHandle(const cSocket & a_Socket)
: m_bDestroyed( false ) : mProtocolVersion( 23 )
, m_Player( 0 ) , pReceiveThread(NULL)
, pSendThread(NULL)
, mSocket(a_Socket)
, mSemaphore(MAX_SEMAPHORES)
, m_bDestroyed( false )
, m_Player(NULL)
, m_bKicking( false ) , m_bKicking( false )
, m_TimeLastPacket( cWorld::GetTime() ) , m_TimeLastPacket( cWorld::GetTime() )
, m_bLoggedIn( false ) , m_bLoggedIn( false )
, m_bKeepThreadGoing( true ) , m_bKeepThreadGoing( true )
, m_bSendLoginResponse( false ) , m_bSendLoginResponse( false )
, m_pState( new sClientHandleState )
, m_Ping(1000) , m_Ping(1000)
, m_bPositionConfirmed( false ) , m_bPositionConfirmed( false )
{ {
@ -149,43 +110,43 @@ cClientHandle::cClientHandle(const cSocket & a_Socket)
cTimer t1; cTimer t1;
m_LastPingTime = t1.GetNowTime(); m_LastPingTime = t1.GetNowTime();
m_pState->Socket = a_Socket;
m_pState->pSemaphore = new cSemaphore( MAX_SEMAPHORES, 0 );
// All the packets that can be received from the client // All the packets that can be received from the client
m_pState->PacketMap[E_KEEP_ALIVE] = new cPacket_KeepAlive; for (int i = 0; i < ARRAYCOUNT(mPacketMap); ++i)
m_pState->PacketMap[E_HANDSHAKE] = new cPacket_Handshake; {
m_pState->PacketMap[E_LOGIN] = new cPacket_Login; mPacketMap[i] = NULL;
m_pState->PacketMap[E_PLAYERPOS] = new cPacket_PlayerPosition; }
m_pState->PacketMap[E_PLAYERLOOK] = new cPacket_PlayerLook; mPacketMap[E_KEEP_ALIVE] = new cPacket_KeepAlive;
m_pState->PacketMap[E_PLAYERMOVELOOK] = new cPacket_PlayerMoveLook; mPacketMap[E_HANDSHAKE] = new cPacket_Handshake;
m_pState->PacketMap[E_CHAT] = new cPacket_Chat; mPacketMap[E_LOGIN] = new cPacket_Login;
m_pState->PacketMap[E_ANIMATION] = new cPacket_ArmAnim; mPacketMap[E_PLAYERPOS] = new cPacket_PlayerPosition;
m_pState->PacketMap[E_FLYING] = new cPacket_Flying; mPacketMap[E_PLAYERLOOK] = new cPacket_PlayerLook;
m_pState->PacketMap[E_BLOCK_DIG] = new cPacket_BlockDig; mPacketMap[E_PLAYERMOVELOOK] = new cPacket_PlayerMoveLook;
m_pState->PacketMap[E_BLOCK_PLACE] = new cPacket_BlockPlace; mPacketMap[E_CHAT] = new cPacket_Chat;
m_pState->PacketMap[E_DISCONNECT] = new cPacket_Disconnect; mPacketMap[E_ANIMATION] = new cPacket_ArmAnim;
m_pState->PacketMap[E_ITEM_SWITCH] = new cPacket_ItemSwitch; mPacketMap[E_FLYING] = new cPacket_Flying;
m_pState->PacketMap[E_ENTITY_EQUIPMENT] = new cPacket_EntityEquipment; mPacketMap[E_BLOCK_DIG] = new cPacket_BlockDig;
m_pState->PacketMap[E_CREATIVE_INVENTORY_ACTION] = new cPacket_CreativeInventoryAction; mPacketMap[E_BLOCK_PLACE] = new cPacket_BlockPlace;
m_pState->PacketMap[E_NEW_INVALID_STATE] = new cPacket_NewInvalidState; mPacketMap[E_DISCONNECT] = new cPacket_Disconnect;
m_pState->PacketMap[E_PICKUP_SPAWN] = new cPacket_PickupSpawn; mPacketMap[E_ITEM_SWITCH] = new cPacket_ItemSwitch;
m_pState->PacketMap[E_USE_ENTITY] = new cPacket_UseEntity; mPacketMap[E_ENTITY_EQUIPMENT] = new cPacket_EntityEquipment;
m_pState->PacketMap[E_WINDOW_CLOSE] = new cPacket_WindowClose; mPacketMap[E_CREATIVE_INVENTORY_ACTION] = new cPacket_CreativeInventoryAction;
m_pState->PacketMap[E_WINDOW_CLICK] = new cPacket_WindowClick; mPacketMap[E_NEW_INVALID_STATE] = new cPacket_NewInvalidState;
m_pState->PacketMap[E_PACKET_13] = new cPacket_13; mPacketMap[E_PICKUP_SPAWN] = new cPacket_PickupSpawn;
m_pState->PacketMap[E_UPDATE_SIGN] = new cPacket_UpdateSign; mPacketMap[E_USE_ENTITY] = new cPacket_UseEntity;
m_pState->PacketMap[E_RESPAWN] = new cPacket_Respawn; mPacketMap[E_WINDOW_CLOSE] = new cPacket_WindowClose;
m_pState->PacketMap[E_PING] = new cPacket_Ping; mPacketMap[E_WINDOW_CLICK] = new cPacket_WindowClick;
mPacketMap[E_PACKET_13] = new cPacket_13;
mPacketMap[E_UPDATE_SIGN] = new cPacket_UpdateSign;
mPacketMap[E_RESPAWN] = new cPacket_Respawn;
mPacketMap[E_PING] = new cPacket_Ping;
memset( m_LoadedChunks, 0x00, sizeof(cChunk*)*VIEWDISTANCE*VIEWDISTANCE ); memset(m_LoadedChunks, 0x00, sizeof(m_LoadedChunks));
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
m_pState->pReceiveThread = new cThread( ReceiveThread, this, "cClientHandle::ReceiveThread" ); pReceiveThread = new cThread( ReceiveThread, this, "cClientHandle::ReceiveThread" );
m_pState->pSendThread = new cThread( SendThread, this, "cClientHandle::SendThread" ); pSendThread = new cThread( SendThread, this, "cClientHandle::SendThread" );
m_pState->pReceiveThread->Start( true ); pReceiveThread->Start( true );
m_pState->pSendThread->Start( true ); pSendThread->Start( true );
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
LOG("New ClientHandle" ); LOG("New ClientHandle" );
@ -215,60 +176,55 @@ cClientHandle::~cClientHandle()
} }
} }
if (m_pState && m_pState->Username.size() > 0) if (mUsername.size() > 0)
{ {
cPacket_Chat Left( m_pState->Username + " left the game!"); cPacket_Chat Left(mUsername + " left the game!");
cRoot::Get()->GetServer()->Broadcast( Left, this ); cRoot::Get()->GetServer()->Broadcast( Left, this );
} }
// First stop sending thread // First stop sending thread
m_bKeepThreadGoing = false; m_bKeepThreadGoing = false;
m_pState->SocketCriticalSection.Lock(); cCSLock Lock(mSocketCriticalSection);
if( m_pState->Socket ) if (mSocket.IsValid())
{ {
cPacket_Disconnect Disconnect; cPacket_Disconnect Disconnect;
Disconnect.m_Reason = "Server shut down? Kthnxbai"; Disconnect.m_Reason = "Server shut down? Kthnxbai";
Disconnect.Send( m_pState->Socket ); Disconnect.Send(mSocket);
m_pState->Socket.CloseSocket(); mSocket.CloseSocket();
m_pState->Socket = 0;
} }
m_pState->SocketCriticalSection.Unlock(); Lock.Unlock();
m_pState->pSemaphore->Signal(); mSemaphore.Signal();
delete m_pState->pReceiveThread; delete pReceiveThread;
delete m_pState->pSendThread; delete pSendThread;
delete m_pState->pSemaphore;
while( !m_pState->PendingParsePackets.empty() ) while (!mPendingParsePackets.empty())
{ {
delete *m_pState->PendingParsePackets.begin(); delete *mPendingParsePackets.begin();
m_pState->PendingParsePackets.erase( m_pState->PendingParsePackets.begin() ); mPendingParsePackets.erase(mPendingParsePackets.begin());
} }
while( !m_pState->PendingNrmSendPackets.empty() ) while (!mPendingNrmSendPackets.empty())
{ {
delete *m_pState->PendingNrmSendPackets.begin(); delete *mPendingNrmSendPackets.begin();
m_pState->PendingNrmSendPackets.erase( m_pState->PendingNrmSendPackets.begin() ); mPendingNrmSendPackets.erase(mPendingNrmSendPackets.begin());
} }
while( !m_pState->PendingLowSendPackets.empty() ) while (!mPendingLowSendPackets.empty())
{ {
delete *m_pState->PendingLowSendPackets.begin(); delete *mPendingLowSendPackets.begin();
m_pState->PendingLowSendPackets.erase( m_pState->PendingLowSendPackets.begin() ); mPendingLowSendPackets.erase(mPendingLowSendPackets.begin());
} }
if(m_Player) if (m_Player != NULL)
{ {
m_Player->SetClientHandle( 0 ); m_Player->SetClientHandle(NULL);
m_Player->Destroy(); m_Player->Destroy();
m_Player = 0; m_Player = NULL;
} }
for(int i = 0; i < 256; i++) for (int i = 0; i < ARRAYCOUNT(mPacketMap); i++)
{ {
if( m_pState->PacketMap[i] ) delete mPacketMap[i];
delete m_pState->PacketMap[i];
} }
delete m_pState;
} }
@ -278,13 +234,11 @@ cClientHandle::~cClientHandle()
void cClientHandle::Destroy() void cClientHandle::Destroy()
{ {
m_bDestroyed = true; m_bDestroyed = true;
m_pState->SocketCriticalSection.Lock(); cCSLock Lock(mSocketCriticalSection);
if( m_pState->Socket ) if (mSocket.IsValid())
{ {
m_pState->Socket.CloseSocket(); mSocket.CloseSocket();
m_pState->Socket = 0;
} }
m_pState->SocketCriticalSection.Unlock();
} }
@ -313,7 +267,11 @@ void cClientHandle::Authenticate(void)
void cClientHandle::StreamChunks(void) void cClientHandle::StreamChunks(void)
{ {
if (!m_bLoggedIn) if (!m_bLoggedIn)
{
return; return;
}
assert(m_Player != NULL);
int ChunkPosX = (int)floor(m_Player->GetPosX() / 16); int ChunkPosX = (int)floor(m_Player->GetPosX() / 16);
int ChunkPosZ = (int)floor(m_Player->GetPosZ() / 16); int ChunkPosZ = (int)floor(m_Player->GetPosZ() / 16);
@ -329,13 +287,20 @@ void cClientHandle::StreamChunks(void)
int RelX = x - (MaxDist - 1) / 2; int RelX = x - (MaxDist - 1) / 2;
int RelZ = z - (MaxDist - 1) / 2; int RelZ = z - (MaxDist - 1) / 2;
cChunk * Chunk = World->GetChunk( ChunkPosX + RelX, 0, ChunkPosZ + RelZ ); // Touch all chunks in wide range, so they get generated cChunk * Chunk = World->GetChunk( ChunkPosX + RelX, 0, ChunkPosZ + RelZ ); // Touch all chunks in wide range, so they get generated
if( x >= GENERATEDISTANCE && x < VIEWDISTANCE+GENERATEDISTANCE && z >= GENERATEDISTANCE && z < VIEWDISTANCE+GENERATEDISTANCE ) // but player only needs chunks in view distance if (
(x >= GENERATEDISTANCE) &&
(x < VIEWDISTANCE + GENERATEDISTANCE) &&
(z >= GENERATEDISTANCE) &&
(z < VIEWDISTANCE + GENERATEDISTANCE)
) // but player only needs chunks in view distance
{
NeededChunks[(x - GENERATEDISTANCE) + (z - GENERATEDISTANCE) * VIEWDISTANCE] = Chunk; NeededChunks[(x - GENERATEDISTANCE) + (z - GENERATEDISTANCE) * VIEWDISTANCE] = Chunk;
} }
} }
}
cChunk * MissingChunks[VIEWDISTANCE * VIEWDISTANCE]; cChunk * MissingChunks[VIEWDISTANCE * VIEWDISTANCE];
memset( MissingChunks, 0, VIEWDISTANCE*VIEWDISTANCE*sizeof(cChunk*) ); memset(MissingChunks, 0, sizeof(MissingChunks));
unsigned int MissIndex = 0; unsigned int MissIndex = 0;
for(int i = 0; i < VIEWDISTANCE * VIEWDISTANCE; i++) // Handshake loop - touch each chunk once for(int i = 0; i < VIEWDISTANCE * VIEWDISTANCE; i++) // Handshake loop - touch each chunk once
{ {
@ -359,24 +324,26 @@ void cClientHandle::StreamChunks(void)
} }
if (MissIndex > 0) if (MissIndex > 0)
{ // Chunks are gonna be streamed in, so chunks probably also need to be streamed out <- optimization {
// Chunks are gonna be streamed in, so chunks probably also need to be streamed out <- optimization
for(int x = 0; x < VIEWDISTANCE; x++) for(int x = 0; x < VIEWDISTANCE; x++)
{ {
for(int z = 0; z < VIEWDISTANCE; z++) for(int z = 0; z < VIEWDISTANCE; z++)
{ {
cChunk* Chunk = m_LoadedChunks[x + z*VIEWDISTANCE]; cChunk* Chunk = m_LoadedChunks[x + z*VIEWDISTANCE];
if( Chunk ) if (Chunk != NULL)
{ {
if( Chunk->GetPosX() < ChunkPosX-(VIEWDISTANCE-1)/2 if ( (Chunk->GetPosX() < ChunkPosX - (VIEWDISTANCE - 1) / 2)
|| Chunk->GetPosX() > ChunkPosX+(VIEWDISTANCE-1)/2 || (Chunk->GetPosX() > ChunkPosX + (VIEWDISTANCE - 1) / 2)
|| Chunk->GetPosZ() < ChunkPosZ-(VIEWDISTANCE-1)/2 || (Chunk->GetPosZ() < ChunkPosZ - (VIEWDISTANCE - 1) / 2)
|| Chunk->GetPosZ() > ChunkPosZ+(VIEWDISTANCE-1)/2 ) || (Chunk->GetPosZ() > ChunkPosZ + (VIEWDISTANCE - 1) / 2)
)
{ {
Chunk->RemoveClient( this ); Chunk->RemoveClient( this );
Chunk->AsyncUnload( this ); // TODO - I think it's possible to unload the chunk immediately instead of next tick Chunk->AsyncUnload( this ); // TODO - I think it's possible to unload the chunk immediately instead of next tick
// I forgot why I made it happen next tick // I forgot why I made it happen next tick
m_LoadedChunks[x + z*VIEWDISTANCE] = 0; m_LoadedChunks[x + z * VIEWDISTANCE] = NULL;
} }
} }
} }
@ -384,7 +351,7 @@ void cClientHandle::StreamChunks(void)
StreamChunksSmart( MissingChunks, MissIndex ); StreamChunksSmart( MissingChunks, MissIndex );
memcpy( m_LoadedChunks, NeededChunks, VIEWDISTANCE*VIEWDISTANCE*sizeof(cChunk*) ); memcpy(m_LoadedChunks, NeededChunks, sizeof(NeededChunks));
} }
} }
@ -455,9 +422,8 @@ void cClientHandle::RemoveFromAllChunks()
void cClientHandle::AddPacket(cPacket * a_Packet) void cClientHandle::AddPacket(cPacket * a_Packet)
{ {
m_pState->CriticalSection.Lock(); cCSLock Lock(mCriticalSection);
m_pState->PendingParsePackets.push_back( a_Packet->Clone() ); mPendingParsePackets.push_back(a_Packet->Clone());
m_pState->CriticalSection.Unlock();
} }
@ -467,7 +433,7 @@ void cClientHandle::AddPacket(cPacket * a_Packet)
void cClientHandle::RemovePacket( cPacket * a_Packet ) void cClientHandle::RemovePacket( cPacket * a_Packet )
{ {
delete a_Packet; delete a_Packet;
m_pState->PendingParsePackets.remove( a_Packet ); mPendingParsePackets.remove( a_Packet );
} }
@ -476,13 +442,12 @@ void cClientHandle::RemovePacket( cPacket * a_Packet )
void cClientHandle::HandlePendingPackets() void cClientHandle::HandlePendingPackets()
{ {
m_pState->CriticalSection.Lock(); cCSLock Lock(mCriticalSection);
while( m_pState->PendingParsePackets.begin() != m_pState->PendingParsePackets.end() ) while (!mPendingParsePackets.empty())
{ {
HandlePacket( *m_pState->PendingParsePackets.begin() ); HandlePacket( *mPendingParsePackets.begin() );
RemovePacket( *m_pState->PendingParsePackets.begin() ); RemovePacket( *mPendingParsePackets.begin() );
} }
m_pState->CriticalSection.Unlock();
} }
@ -498,7 +463,10 @@ void cClientHandle::HandlePacket( cPacket* a_Packet )
//LOG("Packet: 0x%02x", a_Packet->m_PacketID ); //LOG("Packet: 0x%02x", a_Packet->m_PacketID );
if( m_bKicking ) return; if (m_bKicking)
{
return;
}
if (!m_bLoggedIn) if (!m_bLoggedIn)
{ {
@ -507,8 +475,8 @@ void cClientHandle::HandlePacket( cPacket* a_Packet )
case E_NEW_INVALID_STATE: // New/Invalid State packet received. I'm guessing the client only sends it when there's a problem with the bed? case E_NEW_INVALID_STATE: // New/Invalid State packet received. I'm guessing the client only sends it when there's a problem with the bed?
{ {
LOGINFO("Got New Invalid State packet"); LOGINFO("Got New Invalid State packet");
}
break; break;
}
case E_PING: // Somebody tries to retrieve information about the server case E_PING: // Somebody tries to retrieve information about the server
{ {
@ -522,42 +490,52 @@ void cClientHandle::HandlePacket( cPacket* a_Packet )
cRoot::Get()->GetWorld()->GetMaxPlayers() cRoot::Get()->GetWorld()->GetMaxPlayers()
); );
Kick(Reply.c_str()); Kick(Reply.c_str());
}
break; break;
}
case E_HANDSHAKE: case E_HANDSHAKE:
{ {
cPacket_Handshake * PacketData = reinterpret_cast<cPacket_Handshake*>(a_Packet); cPacket_Handshake * PacketData = reinterpret_cast<cPacket_Handshake*>(a_Packet);
m_pState->Username = PacketData->m_Username; mUsername = PacketData->m_Username;
LOG("HANDSHAKE %s", GetUsername().c_str()); LOG("HANDSHAKE %s", GetUsername().c_str());
cPacket_Chat Connecting(m_pState->Username + " is connecting.");
if (cRoot::Get()->GetWorld()->GetNumPlayers() >= cRoot::Get()->GetWorld()->GetMaxPlayers()) { if (cRoot::Get()->GetWorld()->GetNumPlayers() >= cRoot::Get()->GetWorld()->GetMaxPlayers())
{
Kick("The server is currently full :( -- Try again later"); Kick("The server is currently full :( -- Try again later");
break; break;
} }
cPacket_Chat Connecting(mUsername + " is connecting.");
cRoot::Get()->GetServer()->Broadcast( Connecting, this ); cRoot::Get()->GetServer()->Broadcast( Connecting, this );
// Give a server handshake thingy back // Give a server handshake thingy back
cPacket_Handshake Handshake; cPacket_Handshake Handshake;
Handshake.m_Username = cRoot::Get()->GetServer()->GetServerID();//ServerID;//"2e66f1dc032ab5f0"; Handshake.m_Username = cRoot::Get()->GetServer()->GetServerID();//ServerID;//"2e66f1dc032ab5f0";
Send( Handshake ); Send( Handshake );
}
break; break;
}
case E_LOGIN: case E_LOGIN:
{ {
LOG("LOGIN %s", GetUsername().c_str()); LOG("LOGIN %s", GetUsername().c_str());
cPacket_Login * PacketData = reinterpret_cast<cPacket_Login*>(a_Packet); cPacket_Login * PacketData = reinterpret_cast<cPacket_Login*>(a_Packet);
if (PacketData->m_ProtocolVersion < m_pState->ProtocolVersion) { if (PacketData->m_ProtocolVersion < mProtocolVersion)
{
Kick("Your client is outdated!"); Kick("Your client is outdated!");
return; return;
} }
else if( PacketData->m_ProtocolVersion > m_pState->ProtocolVersion ) { else if( PacketData->m_ProtocolVersion > mProtocolVersion )
{
Kick("Your client version is higher than the server!"); Kick("Your client version is higher than the server!");
return; return;
} }
if( m_pState->Username.compare( PacketData->m_Username ) != 0 ) if (mUsername.compare(PacketData->m_Username) != 0)
{ {
Kick("Login Username does not match Handshake username!"); LOGWARNING("Login Username does not match Handshake username (\"%s\" / \"%s\" for client \"%s\")",
mUsername.c_str(),
PacketData->m_Username.c_str(),
mSocket.GetIPString().c_str()
);
Kick("Hacked client"); // Don't tell them why we don't want them
return; return;
} }
@ -568,20 +546,22 @@ void cClientHandle::HandlePacket( cPacket* a_Packet )
} }
// Schedule for authentication; until then, let them wait (but do not block) // Schedule for authentication; until then, let them wait (but do not block)
cRoot::Get()->GetAuthenticator().Authenticate(m_pState->Username, cRoot::Get()->GetServer()->GetServerID()); cRoot::Get()->GetAuthenticator().Authenticate(mUsername, cRoot::Get()->GetServer()->GetServerID());
}
break; break;
}
case E_PLAYERMOVELOOK: // After this is received we're safe to send anything case E_PLAYERMOVELOOK: // After this is received we're safe to send anything
{ {
if( !m_Player ) if (m_Player == NULL)
{ {
Kick("Received wrong packet! Check your login sequence!"); LOGWARNING("Received PlayerMoveLook packet for NULL player from client \"%s\", kicking.", mSocket.GetIPString().c_str());
Kick("Hacked client"); // Don't tell them why we don't want them
return; return;
} }
if ( !cRoot::Get()->GetPluginManager()->CallHook( cPluginManager::E_PLUGIN_PLAYER_JOIN, 1, m_Player)) if ( !cRoot::Get()->GetPluginManager()->CallHook( cPluginManager::E_PLUGIN_PLAYER_JOIN, 1, m_Player))
{ {
// Broadcast that this player has joined the game! Yay~ // Broadcast that this player has joined the game! Yay~
cPacket_Chat Joined( m_pState->Username + " joined the game!"); cPacket_Chat Joined(mUsername + " joined the game!");
cRoot::Get()->GetServer()->Broadcast( Joined, this ); cRoot::Get()->GetServer()->Broadcast( Joined, this );
} }
@ -592,25 +572,34 @@ void cClientHandle::HandlePacket( cPacket* a_Packet )
// Then we can start doing more stuffs! :D // Then we can start doing more stuffs! :D
m_bLoggedIn = true; m_bLoggedIn = true;
LOG("%s completely logged in", GetUsername().c_str()); LOG("Player \"%s\" completely logged in", GetUsername().c_str());
StreamChunks(); StreamChunks();
// Send position // Send position
m_pState->ConfirmPosition = m_Player->GetPosition(); mConfirmPosition = m_Player->GetPosition();
Send( cPacket_PlayerMoveLook( m_Player ) ); Send( cPacket_PlayerMoveLook( m_Player ) );
break;
} }
break;
case E_KEEP_ALIVE: case E_KEEP_ALIVE:
{
break; break;
}
default: default:
{ {
LOG("INVALID RESPONSE FOR LOGIN: needed 0x%02x got 0x%02x", E_PLAYERMOVELOOK, a_Packet->m_PacketID ); LOG("INVALID RESPONSE FOR LOGIN: needed 0x%02x, got 0x%02x from client \"%s\", username \"%s\"",
Kick("INVALID RESPONSE FOR LOGIN: needed 0x0d!"); E_PLAYERMOVELOOK,
} a_Packet->m_PacketID,
mSocket.GetIPString().c_str(),
mUsername.c_str()
);
Kick("Hacked client"); // Don't tell them why we don't like them
break; break;
} }
} // switch (Packet type)
} }
else if( !m_bPositionConfirmed ) // m_bLoggedIn == true else if (!m_bPositionConfirmed) // m_bLoggedIn is true
{ {
switch (a_Packet->m_PacketID) switch (a_Packet->m_PacketID)
{ {
@ -620,20 +609,19 @@ void cClientHandle::HandlePacket( cPacket* a_Packet )
Vector3d ReceivedPosition = Vector3d(PacketData->m_PosX, PacketData->m_PosY, PacketData->m_PosZ); Vector3d ReceivedPosition = Vector3d(PacketData->m_PosX, PacketData->m_PosY, PacketData->m_PosZ);
// Test the distance between points with a small/large enough value instead of comparing directly. Floating point inaccuracies might screw stuff up // Test the distance between points with a small/large enough value instead of comparing directly. Floating point inaccuracies might screw stuff up
if( ( ReceivedPosition - m_pState->ConfirmPosition ).SqrLength() < 1.0 ) if ((ReceivedPosition - mConfirmPosition).SqrLength() < 1.0)
{ {
// Test // Test
if( ReceivedPosition.Equals( m_pState->ConfirmPosition ) ) if( ReceivedPosition.Equals(mConfirmPosition))
{ {
LOGINFO("Exact position confirmed by client!"); LOGINFO("Exact position confirmed by client!");
} }
m_bPositionConfirmed = true; m_bPositionConfirmed = true;
} }
}
break; break;
} } // case E_PLAYERMOVELOOK
} // switch (Packet type)
} } // if (! position confirmed)
if (m_bPositionConfirmed) if (m_bPositionConfirmed)
{ {
@ -647,7 +635,7 @@ void cClientHandle::HandlePacket( cPacket* a_Packet )
} }
break; break;
} }
break;
case E_PLAYERPOS: case E_PLAYERPOS:
{ {
cPacket_PlayerPosition* PacketData = reinterpret_cast<cPacket_PlayerPosition*>(a_Packet); cPacket_PlayerPosition* PacketData = reinterpret_cast<cPacket_PlayerPosition*>(a_Packet);
@ -655,11 +643,11 @@ void cClientHandle::HandlePacket( cPacket* a_Packet )
m_Player->MoveTo( Vector3d( PacketData->m_PosX, PacketData->m_PosY, PacketData->m_PosZ ) ); m_Player->MoveTo( Vector3d( PacketData->m_PosX, PacketData->m_PosY, PacketData->m_PosZ ) );
m_Player->SetStance( PacketData->m_Stance ); m_Player->SetStance( PacketData->m_Stance );
m_Player->SetTouchGround( PacketData->m_bFlying ); m_Player->SetTouchGround( PacketData->m_bFlying );
}
break; break;
}
case E_BLOCK_DIG: case E_BLOCK_DIG:
{ {
int LastActionCnt = m_Player->GetLastBlockActionCnt(); int LastActionCnt = m_Player->GetLastBlockActionCnt();
if ( (cRoot::Get()->GetWorld()->GetTime() - m_Player->GetLastBlockActionTime()) < 0.1 ) { //only allow block interactions every 0.1 seconds if ( (cRoot::Get()->GetWorld()->GetTime() - m_Player->GetLastBlockActionTime()) < 0.1 ) { //only allow block interactions every 0.1 seconds
m_Player->SetLastBlockActionTime(); //Player tried to interact with a block. Reset last block interation time. m_Player->SetLastBlockActionTime(); //Player tried to interact with a block. Reset last block interation time.
@ -670,7 +658,9 @@ void cClientHandle::HandlePacket( cPacket* a_Packet )
Kick("You're a baaaaaad boy!"); Kick("You're a baaaaaad boy!");
break; break;
} }
} else { }
else
{
m_Player->SetLastBlockActionCnt(0); //reset count m_Player->SetLastBlockActionCnt(0); //reset count
m_Player->SetLastBlockActionTime(); //Player tried to interact with a block. Reset last block interation time. m_Player->SetLastBlockActionTime(); //Player tried to interact with a block. Reset last block interation time.
} }
@ -685,11 +675,9 @@ void cClientHandle::HandlePacket( cPacket* a_Packet )
{ {
cWorld* World = m_Player->GetWorld(); cWorld* World = m_Player->GetWorld();
char OldBlock = World->GetBlock(PacketData->m_PosX, PacketData->m_PosY, PacketData->m_PosZ); char OldBlock = World->GetBlock(PacketData->m_PosX, PacketData->m_PosY, PacketData->m_PosZ);
char MetaData = World->GetBlockMeta(PacketData->m_PosX, PacketData->m_PosY, PacketData->m_PosZ); char MetaData = World->GetBlockMeta(PacketData->m_PosX, PacketData->m_PosY, PacketData->m_PosZ);
bool bBroken = (PacketData->m_Status == 0x02) || g_BlockOneHitDig[(int)OldBlock] || ( (PacketData->m_Status == 0x00) && (m_Player->GetGameMode() == 1) ); bool bBroken = (PacketData->m_Status == 0x02) || g_BlockOneHitDig[(int)OldBlock] || ( (PacketData->m_Status == 0x00) && (m_Player->GetGameMode() == 1) );
if (bBroken == false) bBroken = (m_Player->GetInventory().GetEquippedItem().m_ItemID == E_ITEM_SHEARS && OldBlock == E_BLOCK_LEAVES); if (bBroken == false) bBroken = (m_Player->GetInventory().GetEquippedItem().m_ItemID == E_ITEM_SHEARS && OldBlock == E_BLOCK_LEAVES);
@ -701,7 +689,6 @@ void cClientHandle::HandlePacket( cPacket* a_Packet )
cItem PickupItem; cItem PickupItem;
if (bBroken && !(m_Player->GetGameMode() == 1) ) // broken if (bBroken && !(m_Player->GetGameMode() == 1) ) // broken
{ {
ENUM_ITEM_ID PickupID = cBlockToPickup::ToPickup( (ENUM_BLOCK_ID)OldBlock, m_Player->GetInventory().GetEquippedItem().m_ItemID ); ENUM_ITEM_ID PickupID = cBlockToPickup::ToPickup( (ENUM_BLOCK_ID)OldBlock, m_Player->GetInventory().GetEquippedItem().m_ItemID );
PickupItem.m_ItemID = PickupID; PickupItem.m_ItemID = PickupID;
PickupItem.m_ItemHealth = MetaData; PickupItem.m_ItemHealth = MetaData;
@ -778,11 +765,11 @@ void cClientHandle::HandlePacket( cPacket* a_Packet )
World->SendBlockTo( PacketData->m_PosX, PacketData->m_PosY, PacketData->m_PosZ, m_Player ); World->SendBlockTo( PacketData->m_PosX, PacketData->m_PosY, PacketData->m_PosZ, m_Player );
} }
} }
}
break; break;
} // case E_BLOCK_DIG
case E_BLOCK_PLACE: case E_BLOCK_PLACE:
{ {
int LastActionCnt = m_Player->GetLastBlockActionCnt(); int LastActionCnt = m_Player->GetLastBlockActionCnt();
if ( (cRoot::Get()->GetWorld()->GetTime() - m_Player->GetLastBlockActionTime()) < 0.1 ) { //only allow block interactions every 0.1 seconds if ( (cRoot::Get()->GetWorld()->GetTime() - m_Player->GetLastBlockActionTime()) < 0.1 ) { //only allow block interactions every 0.1 seconds
m_Player->SetLastBlockActionTime(); //Player tried to interact with a block. Reset last block interation time. m_Player->SetLastBlockActionTime(); //Player tried to interact with a block. Reset last block interation time.
@ -792,7 +779,9 @@ void cClientHandle::HandlePacket( cPacket* a_Packet )
Kick("You're a baaaaaad boy!"); Kick("You're a baaaaaad boy!");
break; break;
} }
} else { }
else
{
m_Player->SetLastBlockActionCnt(0); //reset count m_Player->SetLastBlockActionCnt(0); //reset count
m_Player->SetLastBlockActionTime(); //Player tried to interact with a block. Reset last block interation time. m_Player->SetLastBlockActionTime(); //Player tried to interact with a block. Reset last block interation time.
} }
@ -1235,8 +1224,9 @@ void cClientHandle::HandlePacket( cPacket* a_Packet )
} }
} }
*/ */
}
break; break;
} // case E_BLOCK_PLACE
case E_PICKUP_SPAWN: case E_PICKUP_SPAWN:
{ {
LOG("Received packet E_PICKUP_SPAWN"); LOG("Received packet E_PICKUP_SPAWN");
@ -1251,18 +1241,20 @@ void cClientHandle::HandlePacket( cPacket* a_Packet )
cPickup* Pickup = new cPickup( PacketData ); cPickup* Pickup = new cPickup( PacketData );
Pickup->Initialize( m_Player->GetWorld() ); Pickup->Initialize( m_Player->GetWorld() );
} }
}
break; break;
} // case E_PICKUP_SPAWN
case E_CHAT: case E_CHAT:
{ {
cPacket_Chat* PacketData = reinterpret_cast<cPacket_Chat*>(a_Packet); cPacket_Chat* PacketData = reinterpret_cast<cPacket_Chat*>(a_Packet);
if (!cRoot::Get()->GetServer()->Command( *this, PacketData->m_Message.c_str())) if (!cRoot::Get()->GetServer()->Command( *this, PacketData->m_Message.c_str()))
{ {
PacketData->m_Message.insert( 0, "<"+m_Player->GetColor() + m_pState->Username + cChatColor::White + "> " ); PacketData->m_Message.insert( 0, "<" + m_Player->GetColor() + mUsername + cChatColor::White + "> " );
cRoot::Get()->GetServer()->Broadcast( *PacketData ); cRoot::Get()->GetServer()->Broadcast( *PacketData );
} }
}
break; break;
} // case E_CHAT
case E_PLAYERLOOK: case E_PLAYERLOOK:
{ {
cPacket_PlayerLook* PacketData = reinterpret_cast<cPacket_PlayerLook*>(a_Packet); cPacket_PlayerLook* PacketData = reinterpret_cast<cPacket_PlayerLook*>(a_Packet);
@ -1270,8 +1262,9 @@ void cClientHandle::HandlePacket( cPacket* a_Packet )
m_Player->SetPitch( PacketData->m_Pitch ); m_Player->SetPitch( PacketData->m_Pitch );
m_Player->SetTouchGround( PacketData->m_bFlying ); m_Player->SetTouchGround( PacketData->m_bFlying );
m_Player->WrapRotation(); m_Player->WrapRotation();
}
break; break;
} // case E_PLAYERLOOK
case E_PLAYERMOVELOOK: case E_PLAYERMOVELOOK:
{ {
cPacket_PlayerMoveLook* PacketData = reinterpret_cast<cPacket_PlayerMoveLook*>(a_Packet); cPacket_PlayerMoveLook* PacketData = reinterpret_cast<cPacket_PlayerMoveLook*>(a_Packet);
@ -1281,15 +1274,17 @@ void cClientHandle::HandlePacket( cPacket* a_Packet )
m_Player->SetRotation( PacketData->m_Rotation ); m_Player->SetRotation( PacketData->m_Rotation );
m_Player->SetPitch( PacketData->m_Pitch ); m_Player->SetPitch( PacketData->m_Pitch );
m_Player->WrapRotation(); m_Player->WrapRotation();
}
break; break;
} // case E_PLAYERMOVELOOK
case E_ANIMATION: case E_ANIMATION:
{ {
cPacket_ArmAnim* PacketData = reinterpret_cast<cPacket_ArmAnim*>(a_Packet); cPacket_ArmAnim* PacketData = reinterpret_cast<cPacket_ArmAnim*>(a_Packet);
PacketData->m_EntityID = m_Player->GetUniqueID(); PacketData->m_EntityID = m_Player->GetUniqueID();
cRoot::Get()->GetServer()->Broadcast( *PacketData, this ); cRoot::Get()->GetServer()->Broadcast( *PacketData, this );
}
break; break;
} // case E_ANIMATION
case E_ITEM_SWITCH: case E_ITEM_SWITCH:
{ {
cPacket_ItemSwitch* PacketData = reinterpret_cast<cPacket_ItemSwitch*>(a_Packet); cPacket_ItemSwitch* PacketData = reinterpret_cast<cPacket_ItemSwitch*>(a_Packet);
@ -1301,20 +1296,16 @@ void cClientHandle::HandlePacket( cPacket* a_Packet )
Equipment.m_Slot = 0; Equipment.m_Slot = 0;
Equipment.m_UniqueID = m_Player->GetUniqueID(); Equipment.m_UniqueID = m_Player->GetUniqueID();
cRoot::Get()->GetServer()->Broadcast( Equipment, this ); cRoot::Get()->GetServer()->Broadcast( Equipment, this );
}
break; break;
} // case E_ITEM_SWITCH
case E_WINDOW_CLOSE: case E_WINDOW_CLOSE:
{ {
cPacket_WindowClose* PacketData = reinterpret_cast<cPacket_WindowClose*>(a_Packet); cPacket_WindowClose* PacketData = reinterpret_cast<cPacket_WindowClose*>(a_Packet);
m_Player->CloseWindow(PacketData->m_Close); m_Player->CloseWindow(PacketData->m_Close);
/*
if( PacketData->m_Close > 0 ) // Don't care about closing inventory
{
m_Player->CloseWindow();
}
*/
}
break; break;
} // case E_WINDOW_CLOSE
case E_WINDOW_CLICK: case E_WINDOW_CLICK:
{ {
cPacket_WindowClick* PacketData = reinterpret_cast<cPacket_WindowClick*>(a_Packet); cPacket_WindowClick* PacketData = reinterpret_cast<cPacket_WindowClick*>(a_Packet);
@ -1328,8 +1319,9 @@ void cClientHandle::HandlePacket( cPacket* a_Packet )
if( Window ) Window->Clicked( PacketData, *m_Player ); if( Window ) Window->Clicked( PacketData, *m_Player );
else LOG("No 'other' window! WTF"); else LOG("No 'other' window! WTF");
} }
}
break; break;
} // case E_WINDOW_CLICK
case E_UPDATE_SIGN: case E_UPDATE_SIGN:
{ {
cPacket_UpdateSign* PacketData = reinterpret_cast<cPacket_UpdateSign*>(a_Packet); cPacket_UpdateSign* PacketData = reinterpret_cast<cPacket_UpdateSign*>(a_Packet);
@ -1342,8 +1334,9 @@ void cClientHandle::HandlePacket( cPacket* a_Packet )
Sign->SetLines( PacketData->m_Line1, PacketData->m_Line2, PacketData->m_Line3, PacketData->m_Line4 ); Sign->SetLines( PacketData->m_Line1, PacketData->m_Line2, PacketData->m_Line3, PacketData->m_Line4 );
Sign->SendTo( 0 ); // Broadcast to all players in chunk Sign->SendTo( 0 ); // Broadcast to all players in chunk
} }
}
break; break;
} // case E_UPDATE_SIGN
case E_USE_ENTITY: case E_USE_ENTITY:
{ {
cPacket_UseEntity* PacketData = reinterpret_cast<cPacket_UseEntity*>(a_Packet); cPacket_UseEntity* PacketData = reinterpret_cast<cPacket_UseEntity*>(a_Packet);
@ -1357,26 +1350,29 @@ void cClientHandle::HandlePacket( cPacket* a_Packet )
Pawn->TakeDamage( 1, m_Player ); Pawn->TakeDamage( 1, m_Player );
} }
} }
}
break; break;
} // case E_USE_ENTITY
case E_RESPAWN: case E_RESPAWN:
{ {
m_Player->Respawn(); m_Player->Respawn();
}
break; break;
} // case E_RESPAWN
case E_DISCONNECT: case E_DISCONNECT:
{ {
LOG("Received d/c packet from %s", GetUsername().c_str()); LOG("Received d/c packet from \"%s\"", GetUsername().c_str());
cPacket_Disconnect* PacketData = reinterpret_cast<cPacket_Disconnect*>(a_Packet); cPacket_Disconnect* PacketData = reinterpret_cast<cPacket_Disconnect*>(a_Packet);
if( !cRoot::Get()->GetPluginManager()->CallHook( cPluginManager::E_PLUGIN_DISCONNECT, 2, PacketData->m_Reason.c_str(), m_Player ) ) if( !cRoot::Get()->GetPluginManager()->CallHook( cPluginManager::E_PLUGIN_DISCONNECT, 2, PacketData->m_Reason.c_str(), m_Player ) )
{ {
cPacket_Chat DisconnectMessage( m_pState->Username + " disconnected: " + PacketData->m_Reason ); cPacket_Chat DisconnectMessage(mUsername + " disconnected: " + PacketData->m_Reason);
cRoot::Get()->GetServer()->Broadcast( DisconnectMessage ); cRoot::Get()->GetServer()->Broadcast( DisconnectMessage );
} }
Destroy(); Destroy();
return; return;
}
break; break;
} // case E_DISCONNECT
case E_KEEP_ALIVE: case E_KEEP_ALIVE:
{ {
cPacket_KeepAlive *PacketData = reinterpret_cast<cPacket_KeepAlive*>(a_Packet); cPacket_KeepAlive *PacketData = reinterpret_cast<cPacket_KeepAlive*>(a_Packet);
@ -1385,12 +1381,10 @@ void cClientHandle::HandlePacket( cPacket* a_Packet )
cTimer t1; cTimer t1;
m_Ping = (short)((t1.GetNowTime() - m_PingStartTime) / 2); m_Ping = (short)((t1.GetNowTime() - m_PingStartTime) / 2);
} }
}
break; break;
default: } // case E_KEEP_ALIVE
break; } // switch (Packet type)
} } // if (normal game)
}
} }
@ -1403,7 +1397,7 @@ void cClientHandle::Tick(float a_Dt)
if (cWorld::GetTime() - m_TimeLastPacket > 30.f) // 30 seconds time-out if (cWorld::GetTime() - m_TimeLastPacket > 30.f) // 30 seconds time-out
{ {
cPacket_Disconnect DC("Nooooo!! You timed out! D: Come back!"); cPacket_Disconnect DC("Nooooo!! You timed out! D: Come back!");
DC.Send( m_pState->Socket ); DC.Send(mSocket);
cSleep::MilliSleep(1000); // Give packet some time to be received cSleep::MilliSleep(1000); // Give packet some time to be received
@ -1412,7 +1406,9 @@ void cClientHandle::Tick(float a_Dt)
cTimer t1; cTimer t1;
// Send ping packet // Send ping packet
if (m_LastPingTime + cClientHandle::PING_TIME_MS <= t1.GetNowTime()) { if (m_LastPingTime + cClientHandle::PING_TIME_MS <= t1.GetNowTime())
{
// TODO: why a random ping ID, can't we just use normal ascending numbers?
MTRand r1; MTRand r1;
m_PingID = r1.randInt(); m_PingID = r1.randInt();
cPacket_KeepAlive Ping(m_PingID); cPacket_KeepAlive Ping(m_PingID);
@ -1433,7 +1429,7 @@ void cClientHandle::Tick(float a_Dt)
World->LockEntities(); World->LockEntities();
m_Player->LoginSetGameMode ( World->GetGameMode() ); //set player's gamemode to server's gamemode at login. TODO: set to last player's gamemode at logout m_Player->LoginSetGameMode ( World->GetGameMode() ); //set player's gamemode to server's gamemode at login. TODO: set to last player's gamemode at logout
m_Player->SetIP ( m_pState->Socket.GetIPString() ); m_Player->SetIP (mSocket.GetIPString());
cRoot::Get()->GetPluginManager()->CallHook( cPluginManager::E_PLUGIN_PLAYER_SPAWN, 1, m_Player ); cRoot::Get()->GetPluginManager()->CallHook( cPluginManager::E_PLUGIN_PLAYER_SPAWN, 1, m_Player );
@ -1481,13 +1477,13 @@ void cClientHandle::Send( const cPacket & a_Packet, ENUM_PRIORITY a_Priority /*
if( m_bKicking ) return; // Don't add more packets if player is getting kicked anyway if( m_bKicking ) return; // Don't add more packets if player is getting kicked anyway
bool bSignalSemaphore = true; bool bSignalSemaphore = true;
m_pState->SendCriticalSection.Lock(); cCSLock Lock(mSendCriticalSection);
if (a_Priority == E_PRIORITY_NORMAL) if (a_Priority == E_PRIORITY_NORMAL)
{ {
if (a_Packet.m_PacketID == E_REL_ENT_MOVE_LOOK) if (a_Packet.m_PacketID == E_REL_ENT_MOVE_LOOK)
{ {
PacketList & Packets = m_pState->PendingNrmSendPackets; PacketList & Packets = mPendingNrmSendPackets;
for( std::list<cPacket*>::iterator itr = Packets.begin(); itr != Packets.end(); ++itr ) for (PacketList::iterator itr = Packets.begin(); itr != Packets.end(); ++itr)
{ {
bool bBreak = false; bool bBreak = false;
switch ((*itr)->m_PacketID) switch ((*itr)->m_PacketID)
@ -1505,21 +1501,26 @@ void cClientHandle::Send( const cPacket & a_Packet, ENUM_PRIORITY a_Priority /*
delete PacketData; delete PacketData;
break; break;
} }
}
break; break;
default: } // case E_REL_END_MOVE_LOOK
break; } // switch (*itr -> Packet type)
}
if (bBreak) if (bBreak)
{
break; break;
} }
} // for itr - Packets[]
} // if (E_REL_ENT_MOVE_LOOK
mPendingNrmSendPackets.push_back(a_Packet.Clone());
} }
m_pState->PendingNrmSendPackets.push_back( a_Packet.Clone() ); else if( a_Priority == E_PRIORITY_LOW )
{
mPendingLowSendPackets.push_back( a_Packet.Clone() );
} }
else if( a_Priority == E_PRIORITY_LOW ) m_pState->PendingLowSendPackets.push_back( a_Packet.Clone() ); Lock.Unlock();
m_pState->SendCriticalSection.Unlock();
if (bSignalSemaphore) if (bSignalSemaphore)
m_pState->pSemaphore->Signal(); {
mSemaphore.Signal();
}
} }
@ -1529,32 +1530,34 @@ void cClientHandle::Send( const cPacket & a_Packet, ENUM_PRIORITY a_Priority /*
void cClientHandle::SendThread( void *lpParam ) void cClientHandle::SendThread( void *lpParam )
{ {
cClientHandle* self = (cClientHandle*)lpParam; cClientHandle* self = (cClientHandle*)lpParam;
sClientHandleState* m_pState = self->m_pState; PacketList & NrmSendPackets = self->mPendingNrmSendPackets;
PacketList & NrmSendPackets = m_pState->PendingNrmSendPackets; PacketList & LowSendPackets = self->mPendingLowSendPackets;
PacketList & LowSendPackets = m_pState->PendingLowSendPackets;
while( self->m_bKeepThreadGoing && m_pState->Socket ) while (self->m_bKeepThreadGoing && self->mSocket.IsValid())
{ {
m_pState->pSemaphore->Wait(); self->mSemaphore.Wait();
m_pState->SendCriticalSection.Lock(); cCSLock Lock(self->mSendCriticalSection);
//LOG("Pending packets: %i", m_PendingPackets.size() );
if (NrmSendPackets.size() + LowSendPackets.size() > MAX_SEMAPHORES) if (NrmSendPackets.size() + LowSendPackets.size() > MAX_SEMAPHORES)
{ {
LOGERROR("ERROR: Too many packets in queue for player %s !!", self->GetUsername().c_str()); LOGERROR("ERROR: Too many packets in queue for player %s !!", self->mUsername.c_str());
cPacket_Disconnect DC("Too many packets in queue."); cPacket_Disconnect DC("Too many packets in queue.");
DC.Send( m_pState->Socket ); DC.Send(self->mSocket);
cSleep::MilliSleep( 1000 ); // Give packet some time to be received cSleep::MilliSleep( 1000 ); // Give packet some time to be received
Lock.Unlock();
self->Destroy(); self->Destroy();
m_pState->SendCriticalSection.Unlock();
break; break;
} }
if (NrmSendPackets.size() == 0 && LowSendPackets.size() == 0) if (NrmSendPackets.size() == 0 && LowSendPackets.size() == 0)
{ {
if( self->m_bKeepThreadGoing ) LOGERROR("ERROR: Semaphore was signaled while PendingSendPackets.size == 0"); assert(!self->m_bKeepThreadGoing);
m_pState->SendCriticalSection.Unlock(); if (self->m_bKeepThreadGoing)
{
LOGERROR("ERROR: Semaphore was signaled while no packets to send");
}
continue; continue;
} }
if (NrmSendPackets.size() > MAX_SEMAPHORES / 2) if (NrmSendPackets.size() > MAX_SEMAPHORES / 2)
@ -1562,31 +1565,31 @@ void cClientHandle::SendThread( void *lpParam )
LOGINFO("Pending packets: %i Last: 0x%02x", NrmSendPackets.size(), (*NrmSendPackets.rbegin())->m_PacketID ); LOGINFO("Pending packets: %i Last: 0x%02x", NrmSendPackets.size(), (*NrmSendPackets.rbegin())->m_PacketID );
} }
cPacket* Packet = 0; cPacket * Packet = NULL;
if( NrmSendPackets.size() > 0 ) if (!NrmSendPackets.empty())
{ {
Packet = *NrmSendPackets.begin(); Packet = *NrmSendPackets.begin();
NrmSendPackets.erase( NrmSendPackets.begin() ); NrmSendPackets.erase( NrmSendPackets.begin() );
} }
else if( LowSendPackets.size() > 0 ) else if (!LowSendPackets.empty())
{ {
Packet = *LowSendPackets.begin(); Packet = *LowSendPackets.begin();
LowSendPackets.erase( LowSendPackets.begin() ); LowSendPackets.erase( LowSendPackets.begin() );
} }
m_pState->SendCriticalSection.Unlock(); Lock.Unlock();
m_pState->SocketCriticalSection.Lock(); cCSLock SocketLock(self->mSocketCriticalSection);
if( !m_pState->Socket ) if (!self->mSocket.IsValid())
{ {
m_pState->SocketCriticalSection.Unlock();
break; break;
} }
//LOG("Send packet: 0x%2x", Packet->m_PacketID );
bool bSuccess = Packet->Send( m_pState->Socket ); bool bSuccess = Packet->Send(self->mSocket);
m_pState->SocketCriticalSection.Unlock(); SocketLock.Unlock();
if (!bSuccess) if (!bSuccess)
{ {
LOGERROR("ERROR: While sending packet 0x%02x", Packet->m_PacketID ); LOGERROR("ERROR: While sending packet 0x%02x to client \"%s\"", Packet->m_PacketID, self->mUsername.c_str());
delete Packet; delete Packet;
self->Destroy(); self->Destroy();
break; break;
@ -1630,8 +1633,7 @@ void cClientHandle::ReceiveThread( void *lpParam )
} }
else else
{ {
//LOG("Recv packet: 0x%2x", (unsigned char)temp ); cPacket* pPacket = self->mPacketMap[(unsigned char)temp];
cPacket* pPacket = self->m_pState->PacketMap[ (unsigned char)temp ];
if (pPacket) if (pPacket)
{ {
if (pPacket->Parse(socket)) if (pPacket->Parse(socket))
@ -1642,7 +1644,7 @@ void cClientHandle::ReceiveThread( void *lpParam )
else else
{ {
LOGERROR("Something went wrong during PacketID 0x%02x (%s)", temp, cSocket::GetLastErrorString() ); LOGERROR("Something went wrong during PacketID 0x%02x (%s)", temp, cSocket::GetLastErrorString() );
LOG("CLIENT %s DISCONNECTED", self->GetUsername().c_str()); LOG("CLIENT %s DISCONNECTED", self->mUsername.c_str());
break; break;
} }
} }
@ -1650,7 +1652,6 @@ void cClientHandle::ReceiveThread( void *lpParam )
{ {
LOG("Unknown packet: 0x%02x \'%c\' %i", (unsigned char)temp, (unsigned char)temp, (unsigned char)temp ); LOG("Unknown packet: 0x%02x \'%c\' %i", (unsigned char)temp, (unsigned char)temp, (unsigned char)temp );
AString Reason; AString Reason;
Printf(Reason, "[C->S] Unknown PacketID: 0x%02x", (unsigned char)temp ); Printf(Reason, "[C->S] Unknown PacketID: 0x%02x", (unsigned char)temp );
cPacket_Disconnect DC(Reason); cPacket_Disconnect DC(Reason);
@ -1674,7 +1675,7 @@ void cClientHandle::ReceiveThread( void *lpParam )
const AString & cClientHandle::GetUsername(void) const const AString & cClientHandle::GetUsername(void) const
{ {
return m_pState->Username; return mUsername;
} }
@ -1683,7 +1684,7 @@ const AString & cClientHandle::GetUsername(void) const
const cSocket & cClientHandle::GetSocket() const cSocket & cClientHandle::GetSocket()
{ {
return m_pState->Socket; return mSocket;
} }

View File

@ -1,13 +1,32 @@
#pragma once
class cSocket; // cClientHandle.h
class cSemaphore;
class cEvent; // Interfaces to the cClientHandle class representing a client connected to this server. The client need not be a player yet
class Game;
class cPacket;
#pragma once
#ifndef CCLIENTHANDLE_H_INCLUDED
#define CCLIENTHANDLE_H_INCLUDED
#include "Packets/cPacket.h"
#include "Vector3d.h"
// class Game;
class cChunk; class cChunk;
class cPlayer; class cPlayer;
class cRedstone; class cRedstone;
class cClientHandle // tolua_export class cClientHandle // tolua_export
{ // tolua_export { // tolua_export
public: public:
@ -22,7 +41,7 @@ public:
cClientHandle(const cSocket & a_Socket); cClientHandle(const cSocket & a_Socket);
~cClientHandle(); ~cClientHandle();
static const int VIEWDISTANCE = 15; // MUST be odd number or CRASH! static const int VIEWDISTANCE = 17; // MUST be odd number or CRASH!
static const int GENERATEDISTANCE = 2; // Server generates this many chunks AHEAD of player sight. static const int GENERATEDISTANCE = 2; // Server generates this many chunks AHEAD of player sight.
const cSocket & GetSocket(); const cSocket & GetSocket();
@ -62,8 +81,27 @@ private:
void SendLoginResponse(); void SendLoginResponse();
struct sClientHandleState; int mProtocolVersion;
sClientHandleState* m_pState; AString mUsername;
AString mPassword;
PacketList mPendingParsePackets;
PacketList mPendingNrmSendPackets;
PacketList mPendingLowSendPackets;
cThread* pReceiveThread;
cThread* pSendThread;
cSocket mSocket;
cCriticalSection mCriticalSection;
cCriticalSection mSendCriticalSection;
cCriticalSection mSocketCriticalSection;
cSemaphore mSemaphore;
Vector3d mConfirmPosition;
cPacket * mPacketMap[256];
bool m_bDestroyed; bool m_bDestroyed;
cPlayer * m_Player; cPlayer * m_Player;
@ -83,3 +121,12 @@ private:
bool m_bKeepThreadGoing; bool m_bKeepThreadGoing;
}; // tolua_export }; // tolua_export
#endif // CCLIENTHANDLE_H_INCLUDED

View File

@ -167,7 +167,8 @@ void cPlayer::Tick(float a_Dt)
cPacket_EntityLook EntityLook( this ); cPacket_EntityLook EntityLook( this );
InChunk->Broadcast( EntityLook, m_ClientHandle ); InChunk->Broadcast( EntityLook, m_ClientHandle );
m_bDirtyOrientation = false; m_bDirtyOrientation = false;
} else if(m_bDirtyPosition ) }
else if(m_bDirtyPosition )
{ {
cRoot::Get()->GetPluginManager()->CallHook( cPluginManager::E_PLUGIN_PLAYER_MOVE, 1, this ); cRoot::Get()->GetPluginManager()->CallHook( cPluginManager::E_PLUGIN_PLAYER_MOVE, 1, this );
@ -242,12 +243,14 @@ void cPlayer::Tick(float a_Dt)
cTimer t1; cTimer t1;
// Send Player List (Once per m_LastPlayerListTime/1000 ms) // Send Player List (Once per m_LastPlayerListTime/1000 ms)
if (m_LastPlayerListTime + cPlayer::PLAYER_LIST_TIME_MS <= t1.GetNowTime()) { if (m_LastPlayerListTime + cPlayer::PLAYER_LIST_TIME_MS <= t1.GetNowTime())
{
cWorld::PlayerList PlayerList = cRoot::Get()->GetWorld()->GetAllPlayers(); cWorld::PlayerList PlayerList = cRoot::Get()->GetWorld()->GetAllPlayers();
for( cWorld::PlayerList::iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr) for( cWorld::PlayerList::iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr)
{ {
if ((*itr) && (*itr)->GetClientHandle() && !((*itr)->GetClientHandle()->IsDestroyed())) { if ((*itr) && (*itr)->GetClientHandle() && !((*itr)->GetClientHandle()->IsDestroyed()))
cPacket_PlayerListItem PlayerListItem(GetColor() + GetName(), true, GetClientHandle()->GetPing()); {
cPacket_PlayerListItem PlayerListItem(GetColor() + m_pState->PlayerName, true, GetClientHandle()->GetPing());
(*itr)->GetClientHandle()->Send( PlayerListItem ); (*itr)->GetClientHandle()->Send( PlayerListItem );
} }
} }

View File

@ -1,3 +1,4 @@
#pragma once #pragma once
#include "../cSocket.h" #include "../cSocket.h"
@ -7,7 +8,6 @@
class cSocket;
class cPacket class cPacket
{ {
public: public:
@ -53,6 +53,9 @@ public:
static int RecvAll( cSocket & a_Socket, char* a_Data, unsigned int a_Size, int a_Options ); static int RecvAll( cSocket & a_Socket, char* a_Data, unsigned int a_Size, int a_Options );
}; };
typedef std::list <cPacket*> PacketList;
typedef std::deque<cPacket *> PacketQueue;