2012-01-29 19:28:19 +00:00
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
2011-10-03 18:41:19 +00:00
#include "cClientHandle.h"
#include "cServer.h"
#include "cWorld.h"
#include "cChunk.h"
#include "cPickup.h"
#include "cPluginManager.h"
#include "cPlayer.h"
#include "cInventory.h"
#include "cChestEntity.h"
#include "cSignEntity.h"
#include "cWindow.h"
#include "cCraftingWindow.h"
#include "cItem.h"
#include "cTorch.h"
#include "cStairs.h"
2011-11-10 02:05:51 +00:00
#include "cDoors.h"
2011-10-03 18:41:19 +00:00
#include "cLadder.h"
#include "cSign.h"
2011-11-04 05:01:55 +00:00
#include "cRedstone.h"
2011-11-05 18:28:19 +00:00
#include "cPiston.h"
2011-10-03 18:41:19 +00:00
#include "cBlockToPickup.h"
#include "cMonster.h"
#include "cChatColor.h"
#include "cThread.h"
#include "cSocket.h"
2011-12-27 18:39:06 +00:00
#include "cTimer.h"
2011-10-03 18:41:19 +00:00
#include "cTracer.h"
#include "Vector3f.h"
#include "Vector3d.h"
#include "cSleep.h"
#include "cRoot.h"
#include "cBlockingTCPLink.h"
#include "cAuthenticator.h"
2011-12-27 18:39:06 +00:00
#include "MersenneTwister.h"
2011-10-03 18:41:19 +00:00
#include "packets/cPacket_KeepAlive.h"
#include "packets/cPacket_PlayerPosition.h"
#include "packets/cPacket_Respawn.h"
#include "packets/cPacket_UpdateHealth.h"
#include "packets/cPacket_RelativeEntityMoveLook.h"
#include "packets/cPacket_Chat.h"
#include "packets/cPacket_Login.h"
#include "packets/cPacket_WindowClick.h"
#include "packets/cPacket_PlayerMoveLook.h"
#include "packets/cPacket_TimeUpdate.h"
#include "packets/cPacket_BlockDig.h"
#include "packets/cPacket_Handshake.h"
#include "packets/cPacket_PlayerLook.h"
#include "packets/cPacket_ArmAnim.h"
#include "packets/cPacket_BlockPlace.h"
#include "packets/cPacket_Flying.h"
#include "packets/cPacket_Disconnect.h"
#include "packets/cPacket_PickupSpawn.h"
#include "packets/cPacket_ItemSwitch.h"
#include "packets/cPacket_EntityEquipment.h"
2012-01-01 04:55:17 +00:00
#include "packets/cPacket_CreativeInventoryAction.h"
2011-11-02 20:40:39 +00:00
#include "packets/cPacket_NewInvalidState.h"
2011-10-03 18:41:19 +00:00
#include "packets/cPacket_UseEntity.h"
#include "packets/cPacket_WindowClose.h"
#include "packets/cPacket_13.h"
#include "packets/cPacket_UpdateSign.h"
#include "packets/cPacket_Ping.h"
2011-12-26 01:07:35 +00:00
#include "packets/cPacket_PlayerListItem.h"
2011-10-03 18:41:19 +00:00
2011-11-07 22:59:29 +00:00
#define AddPistonDir( x, y, z, dir, amount ) switch(dir) { case 0: (y)-=(amount); break; case 1: (y)+=(amount); break;\
case 2: (z)-=(amount); break; case 3: (z)+=(amount); break;\
case 4: (x)-=(amount); break; case 5: (x)+=(amount); break; }
2011-10-03 18:41:19 +00:00
#define MAX_SEMAPHORES (2000)
typedef std :: list < cPacket *> PacketList ;
2012-01-31 18:06:24 +00:00
// fwd: cServer.cpp:
extern std :: string GetWSAError ();
2011-10-03 18:41:19 +00:00
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 ;
2012-01-19 18:12:39 +00:00
Vector3d ConfirmPosition ;
2011-10-03 18:41:19 +00:00
cPacket * PacketMap [ 256 ];
2012-01-31 18:06:24 +00:00
sClientHandleState ( void )
: ProtocolVersion ( 23 )
, pReceiveThread ( 0 )
, pSendThread ( 0 )
, pAuthenticateThread ( 0 )
, pSemaphore ( 0 )
{
for ( int i = 0 ; i < 256 ; ++ i )
PacketMap [ i ] = 0 ;
}
} ;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cClientHandle:
2011-10-03 18:41:19 +00:00
cClientHandle :: cClientHandle ( const cSocket & a_Socket )
: m_bDestroyed ( false )
, m_Player ( 0 )
, m_bKicking ( false )
, m_TimeLastPacket ( cWorld :: GetTime () )
, m_bLoggedIn ( false )
, m_bKeepThreadGoing ( true )
2011-11-01 21:57:08 +00:00
, m_bSendLoginResponse ( false )
2011-10-03 18:41:19 +00:00
, m_pState ( new sClientHandleState )
2011-12-26 03:05:31 +00:00
, m_Ping ( 1000 )
2012-01-19 18:12:39 +00:00
, m_bPositionConfirmed ( false )
2011-10-03 18:41:19 +00:00
{
2012-01-01 16:20:52 +00:00
LOG ( "cClientHandle::cClientHandle" );
2011-12-27 18:39:06 +00:00
cTimer t1 ;
m_LastPingTime = t1 . GetNowTime ();
2011-10-03 18:41:19 +00:00
m_pState -> Socket = a_Socket ;
m_pState -> pSemaphore = new cSemaphore ( MAX_SEMAPHORES , 0 );
// All the packets that can be received from the client
2012-01-31 18:06:24 +00:00
m_pState -> PacketMap [ E_KEEP_ALIVE ] = new cPacket_KeepAlive ;
m_pState -> PacketMap [ E_HANDSHAKE ] = new cPacket_Handshake ;
m_pState -> PacketMap [ E_LOGIN ] = new cPacket_Login ;
m_pState -> PacketMap [ E_PLAYERPOS ] = new cPacket_PlayerPosition ;
m_pState -> PacketMap [ E_PLAYERLOOK ] = new cPacket_PlayerLook ;
m_pState -> PacketMap [ E_PLAYERMOVELOOK ] = new cPacket_PlayerMoveLook ;
m_pState -> PacketMap [ E_CHAT ] = new cPacket_Chat ;
m_pState -> PacketMap [ E_ANIMATION ] = new cPacket_ArmAnim ;
m_pState -> PacketMap [ E_FLYING ] = new cPacket_Flying ;
m_pState -> PacketMap [ E_BLOCK_DIG ] = new cPacket_BlockDig ;
m_pState -> PacketMap [ E_BLOCK_PLACE ] = new cPacket_BlockPlace ;
m_pState -> PacketMap [ E_DISCONNECT ] = new cPacket_Disconnect ;
m_pState -> PacketMap [ E_ITEM_SWITCH ] = new cPacket_ItemSwitch ;
m_pState -> PacketMap [ E_ENTITY_EQUIPMENT ] = new cPacket_EntityEquipment ;
m_pState -> PacketMap [ E_CREATIVE_INVENTORY_ACTION ] = new cPacket_CreativeInventoryAction ;
m_pState -> PacketMap [ E_NEW_INVALID_STATE ] = new cPacket_NewInvalidState ;
m_pState -> PacketMap [ E_PICKUP_SPAWN ] = new cPacket_PickupSpawn ;
m_pState -> PacketMap [ E_USE_ENTITY ] = new cPacket_UseEntity ;
m_pState -> PacketMap [ E_WINDOW_CLOSE ] = new cPacket_WindowClose ;
m_pState -> PacketMap [ E_WINDOW_CLICK ] = new cPacket_WindowClick ;
m_pState -> PacketMap [ E_PACKET_13 ] = new cPacket_13 ;
m_pState -> PacketMap [ E_UPDATE_SIGN ] = new cPacket_UpdateSign ;
m_pState -> PacketMap [ E_RESPAWN ] = new cPacket_Respawn ;
m_pState -> PacketMap [ E_PING ] = new cPacket_Ping ;
2011-10-03 18:41:19 +00:00
memset ( m_LoadedChunks , 0x00 , sizeof ( cChunk * ) * VIEWDISTANCE * VIEWDISTANCE );
//////////////////////////////////////////////////////////////////////////
2011-12-23 14:26:29 +00:00
m_pState -> pReceiveThread = new cThread ( ReceiveThread , this , "cClientHandle::ReceiveThread" );
m_pState -> pSendThread = new cThread ( SendThread , this , "cClientHandle::SendThread" );
2011-10-03 18:41:19 +00:00
m_pState -> pReceiveThread -> Start ( true );
m_pState -> pSendThread -> Start ( true );
//////////////////////////////////////////////////////////////////////////
LOG ( "New ClientHandle" );
}
2012-01-31 18:06:24 +00:00
2011-10-03 18:41:19 +00:00
cClientHandle ::~ cClientHandle ()
{
LOG ( "Deleting client %s" , GetUsername () );
for ( unsigned int i = 0 ; i < VIEWDISTANCE * VIEWDISTANCE ; i ++ )
{
if ( m_LoadedChunks [ i ] ) m_LoadedChunks [ i ] -> RemoveClient ( this );
}
2012-01-02 19:03:19 +00:00
2011-12-26 02:46:53 +00:00
cWorld :: PlayerList PlayerList = cRoot :: Get () -> GetWorld () -> GetAllPlayers ();
for ( cWorld :: PlayerList :: iterator itr = PlayerList . begin (); itr != PlayerList . end (); ++ itr )
{
if (( * itr ) && ( * itr ) -> GetClientHandle () && strlen ( GetUsername ()) > 0 )
{
2012-01-02 19:03:19 +00:00
std :: string NameColor = ( m_Player ? m_Player -> GetColor () : "" );
cPacket_PlayerListItem PlayerList ( NameColor + GetUsername (), false , ( short ) 9999 );
2011-12-26 03:05:31 +00:00
( * itr ) -> GetClientHandle () -> Send ( PlayerList );
2011-12-26 02:46:53 +00:00
}
2011-12-26 03:05:31 +00:00
}
if ( m_pState && m_pState -> Username . size () > 0 )
{
cPacket_Chat Left ( m_pState -> Username + " left the game!" );
cRoot :: Get () -> GetServer () -> Broadcast ( Left , this );
2011-12-26 02:46:53 +00:00
}
2011-10-03 18:41:19 +00:00
// First stop sending thread
m_bKeepThreadGoing = false ;
m_pState -> SocketCriticalSection . Lock ();
if ( m_pState -> Socket )
{
cPacket_Disconnect Disconnect ;
Disconnect . m_Reason = "Server shut down? Kthnxbai" ;
Disconnect . Send ( m_pState -> Socket );
2011-10-21 21:25:29 +00:00
m_pState -> Socket . CloseSocket ();
2011-10-03 18:41:19 +00:00
m_pState -> Socket = 0 ;
}
m_pState -> SocketCriticalSection . Unlock ();
m_pState -> pSemaphore -> Signal ();
delete m_pState -> pAuthenticateThread ;
delete m_pState -> pReceiveThread ;
delete m_pState -> pSendThread ;
delete m_pState -> pSemaphore ;
while ( ! m_pState -> PendingParsePackets . empty () )
{
delete * m_pState -> PendingParsePackets . begin ();
m_pState -> PendingParsePackets . erase ( m_pState -> PendingParsePackets . begin () );
}
while ( ! m_pState -> PendingNrmSendPackets . empty () )
{
delete * m_pState -> PendingNrmSendPackets . begin ();
m_pState -> PendingNrmSendPackets . erase ( m_pState -> PendingNrmSendPackets . begin () );
}
2011-12-28 16:01:15 +00:00
while ( ! m_pState -> PendingLowSendPackets . empty () )
{
delete * m_pState -> PendingLowSendPackets . begin ();
m_pState -> PendingLowSendPackets . erase ( m_pState -> PendingLowSendPackets . begin () );
}
2011-10-03 18:41:19 +00:00
if ( m_Player )
{
m_Player -> SetClientHandle ( 0 );
2012-01-01 16:20:52 +00:00
m_Player -> Destroy ();
m_Player = 0 ;
}
2011-10-03 18:41:19 +00:00
for ( int i = 0 ; i < 256 ; i ++ )
{
if ( m_pState -> PacketMap [ i ] )
delete m_pState -> PacketMap [ i ];
}
delete m_pState ;
}
2012-01-31 18:06:24 +00:00
2011-10-03 18:41:19 +00:00
void cClientHandle :: Destroy ()
{
m_bDestroyed = true ;
m_pState -> SocketCriticalSection . Lock ();
if ( m_pState -> Socket )
{
2011-10-21 21:25:29 +00:00
m_pState -> Socket . CloseSocket ();
2011-10-03 18:41:19 +00:00
m_pState -> Socket = 0 ;
}
m_pState -> SocketCriticalSection . Unlock ();
}
2012-01-31 18:06:24 +00:00
2011-10-03 18:41:19 +00:00
void cClientHandle :: Kick ( const char * a_Reason )
{
Send ( cPacket_Disconnect ( a_Reason ) );
m_bKicking = true ;
}
2012-01-31 18:06:24 +00:00
2011-10-03 18:41:19 +00:00
void cClientHandle :: StreamChunks ()
{
if ( ! m_bLoggedIn )
return ;
2011-11-01 21:57:08 +00:00
int ChunkPosX = ( int ) floor ( m_Player -> GetPosX () / 16 );
int ChunkPosZ = ( int ) floor ( m_Player -> GetPosZ () / 16 );
2011-10-03 18:41:19 +00:00
2011-12-24 23:34:30 +00:00
cWorld * World = m_Player -> GetWorld ();
cChunk * NeededChunks [ VIEWDISTANCE * VIEWDISTANCE ] = { 0 };
const int MaxDist = VIEWDISTANCE + GENERATEDISTANCE * 2 ;
for ( int x = 0 ; x < MaxDist ; x ++ )
2011-10-03 18:41:19 +00:00
{
2011-12-24 23:34:30 +00:00
for ( int z = 0 ; z < MaxDist ; z ++ )
2011-10-03 18:41:19 +00:00
{
2011-12-24 23:34:30 +00:00
int RelX = x - ( 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
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 ;
2011-10-03 18:41:19 +00:00
}
}
cChunk * MissingChunks [ VIEWDISTANCE * VIEWDISTANCE ];
memset ( MissingChunks , 0 , VIEWDISTANCE * VIEWDISTANCE * sizeof ( cChunk * ) );
unsigned int MissIndex = 0 ;
for ( int i = 0 ; i < VIEWDISTANCE * VIEWDISTANCE ; i ++ ) // Handshake loop - touch each chunk once
{
2011-12-24 23:34:30 +00:00
if ( NeededChunks [ i ] == 0 ) continue ; // Chunk is not yet loaded, so ignore
// This can cause MissIndex to be 0 and thus chunks will not be unloaded while they are actually out of range,
// which might actually be a good thing, otherwise it would keep trying to unload chunks until the new chunks are fully loaded
2011-10-03 18:41:19 +00:00
bool bChunkMissing = true ;
for ( int j = 0 ; j < VIEWDISTANCE * VIEWDISTANCE ; j ++ )
{
if ( m_LoadedChunks [ j ] == NeededChunks [ i ] )
{
bChunkMissing = false ;
break ;
}
}
if ( bChunkMissing )
{
MissingChunks [ MissIndex ] = NeededChunks [ i ];
MissIndex ++ ;
}
}
if ( MissIndex > 0 )
2011-12-24 23:34:30 +00:00
{ // Chunks are gonna be streamed in, so chunks probably also need to be streamed out <- optimization
2011-10-03 18:41:19 +00:00
for ( int x = 0 ; x < VIEWDISTANCE ; x ++ )
{
for ( int z = 0 ; z < VIEWDISTANCE ; z ++ )
{
cChunk * Chunk = m_LoadedChunks [ x + z * VIEWDISTANCE ];
if ( Chunk )
{
if ( 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 -> RemoveClient ( this );
2011-12-24 23:34:30 +00:00
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
m_LoadedChunks [ x + z * VIEWDISTANCE ] = 0 ;
2011-10-03 18:41:19 +00:00
}
}
}
}
StreamChunksSmart ( MissingChunks , MissIndex );
memcpy ( m_LoadedChunks , NeededChunks , VIEWDISTANCE * VIEWDISTANCE * sizeof ( cChunk * ) );
}
}
2012-01-31 18:06:24 +00:00
2011-12-24 23:34:30 +00:00
// Sends chunks to the player from the player position outward
2011-10-03 18:41:19 +00:00
void cClientHandle :: StreamChunksSmart ( cChunk ** a_Chunks , unsigned int a_NumChunks )
{
2011-11-01 21:57:08 +00:00
int X = ( int ) floor ( m_Player -> GetPosX () / 16 );
int Y = ( int ) floor ( m_Player -> GetPosY () / 128 );
int Z = ( int ) floor ( m_Player -> GetPosZ () / 16 );
2011-10-03 18:41:19 +00:00
bool bAllDone = false ;
while ( ! bAllDone )
{
bAllDone = true ;
int ClosestIdx = - 1 ;
unsigned int ClosestSqrDist = ( unsigned int ) - 1 ; // wraps around, becomes biggest number possible
for ( unsigned int i = 0 ; i < a_NumChunks ; ++ i )
{
if ( a_Chunks [ i ] )
{
bAllDone = false ;
int DistX = a_Chunks [ i ] -> GetPosX () - X ;
int DistY = a_Chunks [ i ] -> GetPosY () - Y ;
int DistZ = a_Chunks [ i ] -> GetPosZ () - Z ;
unsigned int SqrDist = ( DistX * DistX ) + ( DistY * DistY ) + ( DistZ * DistZ );
if ( SqrDist < ClosestSqrDist )
{
ClosestSqrDist = SqrDist ;
ClosestIdx = i ;
}
}
}
if ( ClosestIdx > - 1 )
{
a_Chunks [ ClosestIdx ] -> Send ( this );
a_Chunks [ ClosestIdx ] -> AddClient ( this );
2012-01-19 18:12:39 +00:00
//LOGINFO("CCC: Sending chunk %i %i", a_Chunks[ClosestIdx]->GetPosX(), a_Chunks[ClosestIdx]->GetPosZ() );
2011-10-03 18:41:19 +00:00
a_Chunks [ ClosestIdx ] = 0 ;
}
}
}
2012-01-31 18:06:24 +00:00
2011-12-26 21:54:08 +00:00
// This removes the client from all chunks. Used when switching worlds
void cClientHandle :: RemoveFromAllChunks ()
{
for ( int i = 0 ; i < VIEWDISTANCE * VIEWDISTANCE ; i ++ )
{
if ( m_LoadedChunks [ i ] )
{
m_LoadedChunks [ i ] -> RemoveClient ( this );
m_LoadedChunks [ i ] -> AsyncUnload ( this );
m_LoadedChunks [ i ] = 0 ;
}
}
}
2012-01-31 18:06:24 +00:00
2011-10-03 18:41:19 +00:00
void cClientHandle :: AddPacket ( cPacket * a_Packet )
{
m_pState -> CriticalSection . Lock ();
m_pState -> PendingParsePackets . push_back ( a_Packet -> Clone () );
m_pState -> CriticalSection . Unlock ();
}
2012-01-31 18:06:24 +00:00
2011-10-03 18:41:19 +00:00
void cClientHandle :: RemovePacket ( cPacket * a_Packet )
{
delete a_Packet ;
m_pState -> PendingParsePackets . remove ( a_Packet );
}
2012-01-31 18:06:24 +00:00
2011-10-03 18:41:19 +00:00
void cClientHandle :: HandlePendingPackets ()
{
m_pState -> CriticalSection . Lock ();
while ( m_pState -> PendingParsePackets . begin () != m_pState -> PendingParsePackets . end () )
{
HandlePacket ( * m_pState -> PendingParsePackets . begin () );
RemovePacket ( * m_pState -> PendingParsePackets . begin () );
}
m_pState -> CriticalSection . Unlock ();
}
2012-01-31 18:06:24 +00:00
2011-10-03 18:41:19 +00:00
void cClientHandle :: HandlePacket ( cPacket * a_Packet )
{
m_TimeLastPacket = cWorld :: GetTime ();
2012-01-31 18:06:24 +00:00
// cPacket* CopiedPacket = a_Packet->Clone();
// a_Packet = CopiedPacket;
2011-10-03 18:41:19 +00:00
//LOG("Packet: 0x%02x", a_Packet->m_PacketID );
if ( m_bKicking ) return ;
if ( ! m_bLoggedIn )
{
switch ( a_Packet -> m_PacketID )
{
2011-11-02 20:40:39 +00:00
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?
2011-12-26 14:29:52 +00:00
{
LOGINFO ( "Got New Invalid State packet" );
}
break ;
2012-01-01 04:55:17 +00:00
2011-12-24 23:34:30 +00:00
case E_PING : // Somebody tries to retrieve information about the server
2011-10-03 18:41:19 +00:00
{
LOGINFO ( "Got ping" );
2011-12-23 23:58:54 +00:00
char NumPlayers [ 8 ], cMaxPlayers [ 8 ];
sprintf_s ( NumPlayers , 8 , "%i" , cRoot :: Get () -> GetWorld () -> GetNumPlayers ());
sprintf_s ( cMaxPlayers , 8 , "%i" , cRoot :: Get () -> GetWorld () -> GetMaxPlayers ());
std :: string response = std :: string ( cRoot :: Get () -> GetWorld () -> GetDescription () + cChatColor :: Delimiter + NumPlayers + cChatColor :: Delimiter + cMaxPlayers );
2011-10-03 18:41:19 +00:00
Kick ( response . c_str () );
}
break ;
case E_HANDSHAKE :
{
cPacket_Handshake * PacketData = reinterpret_cast < cPacket_Handshake *> ( a_Packet );
m_pState -> Username = PacketData -> m_Username ;
LOG ( "HANDSHAKE %s" , GetUsername () );
cPacket_Chat Connecting ( m_pState -> Username + " is connecting." );
2011-12-23 23:58:54 +00:00
2011-12-26 14:29:52 +00:00
if ( cRoot :: Get () -> GetWorld () -> GetNumPlayers () >= cRoot :: Get () -> GetWorld () -> GetMaxPlayers ()) {
2011-12-23 23:58:54 +00:00
Kick ( "The server is currently full :( -- Try again later" );
break ;
}
2011-10-03 18:41:19 +00:00
cRoot :: Get () -> GetServer () -> Broadcast ( Connecting , this );
// Give a server handshake thingy back
cPacket_Handshake Handshake ;
Handshake . m_Username = cRoot :: Get () -> GetServer () -> GetServerID (); //ServerID;//"2e66f1dc032ab5f0";
Send ( Handshake );
}
break ;
case E_LOGIN :
{
LOG ( "LOGIN %s" , GetUsername () );
cPacket_Login * PacketData = reinterpret_cast < cPacket_Login *> ( a_Packet );
2012-01-20 17:39:16 +00:00
if ( PacketData -> m_ProtocolVersion < m_pState -> ProtocolVersion ) {
2011-12-26 09:09:47 +00:00
Kick ( "Your client is outdated!" );
return ;
2012-01-20 17:39:16 +00:00
}
else if ( PacketData -> m_ProtocolVersion > m_pState -> ProtocolVersion ) {
Kick ( "Your client version is higher than the server!" );
return ;
2011-12-26 09:09:47 +00:00
}
2011-10-03 18:41:19 +00:00
if ( m_pState -> Username . compare ( PacketData -> m_Username ) != 0 )
{
Kick ( "Login Username does not match Handshake username!" );
return ;
}
if ( cRoot :: Get () -> GetPluginManager () -> CallHook ( cPluginManager :: E_PLUGIN_LOGIN , 1 , PacketData ) )
{
Destroy ();
return ;
}
if ( m_pState -> pAuthenticateThread ) delete m_pState -> pAuthenticateThread ;
2011-12-23 14:26:29 +00:00
m_pState -> pAuthenticateThread = new cThread ( AuthenticateThread , this , "cClientHandle::AuthenticateThread" );
2011-10-03 18:41:19 +00:00
m_pState -> pAuthenticateThread -> Start ( true );
}
break ;
case E_PLAYERMOVELOOK : // After this is received we're safe to send anything
{
if ( ! m_Player )
{
Kick ( "Received wrong packet! Check your login sequence!" );
return ;
}
if ( ! cRoot :: Get () -> GetPluginManager () -> CallHook ( cPluginManager :: E_PLUGIN_PLAYER_JOIN , 1 , m_Player ) )
{
// Broadcast that this player has joined the game! Yay~
cPacket_Chat Joined ( m_pState -> Username + " joined the game!" );
cRoot :: Get () -> GetServer () -> Broadcast ( Joined , this );
}
2011-12-31 21:08:23 +00:00
2011-10-03 18:41:19 +00:00
// Now initialize player (adds to entity list etc.)
2011-11-02 20:19:57 +00:00
cWorld * PlayerWorld = cRoot :: Get () -> GetWorld ( m_Player -> GetLoadedWorldName () );
if ( ! PlayerWorld ) PlayerWorld = cRoot :: Get () -> GetDefaultWorld ();
2011-12-31 21:08:23 +00:00
m_Player -> Initialize ( PlayerWorld );
2011-10-03 18:41:19 +00:00
// Then we can start doing more stuffs! :D
m_bLoggedIn = true ;
LOG ( "%s completely logged in" , GetUsername () );
StreamChunks ();
2011-12-31 21:08:23 +00:00
// Send position
2012-01-19 18:12:39 +00:00
m_pState -> ConfirmPosition = m_Player -> GetPosition ();
2011-12-31 21:08:23 +00:00
Send ( cPacket_PlayerMoveLook ( m_Player ) );
2011-10-03 18:41:19 +00:00
}
break ;
case E_KEEP_ALIVE :
break ;
default :
{
LOG ( "INVALID RESPONSE FOR LOGIN: needed 0x%02x got 0x%02x" , E_PLAYERMOVELOOK , a_Packet -> m_PacketID );
Kick ( "INVALID RESPONSE FOR LOGIN: needed 0x0d!" );
}
break ;
}
}
2012-01-19 18:12:39 +00:00
else if ( ! m_bPositionConfirmed ) // m_bLoggedIn == true
{
switch ( a_Packet -> m_PacketID )
{
case E_PLAYERMOVELOOK :
{
cPacket_PlayerMoveLook * PacketData = reinterpret_cast < cPacket_PlayerMoveLook *> ( a_Packet );
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
if ( ( ReceivedPosition - m_pState -> ConfirmPosition ). SqrLength () < 1.0 )
{
// Test
if ( ReceivedPosition . Equals ( m_pState -> ConfirmPosition ) )
{
LOGINFO ( "Exact position confirmed by client!" );
}
m_bPositionConfirmed = true ;
}
}
break ;
}
}
if ( m_bPositionConfirmed )
2011-10-03 18:41:19 +00:00
{
switch ( a_Packet -> m_PacketID )
{
2012-01-01 04:55:17 +00:00
case E_CREATIVE_INVENTORY_ACTION : // This is for creative Inventory changes
{
if ( m_Player -> GetGameMode () == 1 ) //Just to be sure
{
m_Player -> GetInventory (). Clicked ( a_Packet );
}
break ;
}
break ;
2011-10-03 18:41:19 +00:00
case E_PLAYERPOS :
{
cPacket_PlayerPosition * PacketData = reinterpret_cast < cPacket_PlayerPosition *> ( a_Packet );
//LOG("recv player pos: %0.2f %0.2f %0.2f", 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 -> SetTouchGround ( PacketData -> m_bFlying );
}
break ;
case E_BLOCK_DIG :
{
2011-11-10 16:30:14 +00:00
int LastActionCnt = m_Player -> GetLastBlockActionCnt ();
2011-12-28 16:09:36 +00:00
if ( ( cRoot :: Get () -> GetWorld () -> GetTime () - m_Player -> GetLastBlockActionTime ()) < 0.1 ) { //only allow block interactions every 0.1 seconds
2011-11-01 20:09:13 +00:00
m_Player -> SetLastBlockActionTime (); //Player tried to interact with a block. Reset last block interation time.
2011-11-10 16:30:14 +00:00
m_Player -> SetLastBlockActionCnt ( LastActionCnt + 1 );
2011-12-28 16:09:36 +00:00
if ( m_Player -> GetLastBlockActionCnt () > MAXBLOCKCHANGEINTERACTIONS ) { //kick if more than MAXBLOCKCHANGEINTERACTIONS per .1 seconds
2011-11-10 16:30:14 +00:00
LOGWARN ( "Player %s tried to interact with a block too quickly! (could indicate bot) Was Kicked." , GetUsername () );
2011-12-22 21:36:24 +00:00
//TODO Too many false-positives :s for example on a minimal server lagg :s should be re checked
2011-11-10 16:30:14 +00:00
Kick ( "You're a baaaaaad boy!" );
break ;
}
} else {
m_Player -> SetLastBlockActionCnt ( 0 ); //reset count
m_Player -> SetLastBlockActionTime (); //Player tried to interact with a block. Reset last block interation time.
2011-11-01 20:09:13 +00:00
}
2011-11-10 16:30:14 +00:00
2011-10-03 18:41:19 +00:00
cPacket_BlockDig * PacketData = reinterpret_cast < cPacket_BlockDig *> ( a_Packet );
2011-10-26 18:47:50 +00:00
LOG ( "OnBlockDig: %i %i %i Dir: %i Stat: %i" , PacketData -> m_PosX , PacketData -> m_PosY , PacketData -> m_PosZ , PacketData -> m_Direction , PacketData -> m_Status );
2011-10-03 18:41:19 +00:00
if ( PacketData -> m_Status == 0x04 ) // Drop block
{
m_Player -> TossItem ( false );
}
else
{
2011-10-31 00:52:20 +00:00
cWorld * World = m_Player -> GetWorld ();
2011-12-28 21:00:35 +00:00
2011-10-03 18:41:19 +00:00
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 );
2011-12-28 21:00:35 +00:00
2011-11-01 20:09:13 +00:00
bool bBroken = ( PacketData -> m_Status == 0x02 ) || g_BlockOneHitDig [( int ) OldBlock ] || ( ( PacketData -> m_Status == 0x00 ) && ( m_Player -> GetGameMode () == 1 ) );
2011-12-22 21:36:24 +00:00
if ( bBroken == false ) bBroken = ( m_Player -> GetInventory (). GetEquippedItem (). m_ItemID == E_ITEM_SHEARS && OldBlock == E_BLOCK_LEAVES );
2011-10-03 18:41:19 +00:00
2011-12-25 01:40:31 +00:00
if ( OldBlock == E_BLOCK_WOODEN_DOOR && ! bBroken )
{
cDoors :: ChangeDoor ( m_Player -> GetWorld (), PacketData -> m_PosX , PacketData -> m_PosY , PacketData -> m_PosZ );
}
2011-10-03 18:41:19 +00:00
cItem PickupItem ;
2011-11-01 20:09:13 +00:00
if ( bBroken && ! ( m_Player -> GetGameMode () == 1 ) ) // broken
2011-10-03 18:41:19 +00:00
{
2011-12-25 01:40:31 +00:00
2011-10-03 18:41:19 +00:00
ENUM_ITEM_ID PickupID = cBlockToPickup :: ToPickup ( ( ENUM_BLOCK_ID ) OldBlock , m_Player -> GetInventory (). GetEquippedItem (). m_ItemID );
PickupItem . m_ItemID = PickupID ;
PickupItem . m_ItemHealth = MetaData ;
2011-12-25 01:40:31 +00:00
PickupItem . m_ItemCount = cBlockToPickup :: PickupCount ( OldBlock );
if ( OldBlock == E_BLOCK_LAPIS_ORE )
{
2011-11-07 18:19:38 +00:00
PickupItem . m_ItemHealth = 4 ;
}
2011-12-25 01:40:31 +00:00
if ( cDoors :: IsDoor ( OldBlock ))
{
PickupItem . m_ItemHealth = 1 ; //For a complete door this works :D
2011-11-07 18:19:38 +00:00
}
2011-10-03 18:41:19 +00:00
}
if ( ! cRoot :: Get () -> GetPluginManager () -> CallHook ( cPluginManager :: E_PLUGIN_BLOCK_DIG , 2 , PacketData , m_Player , & PickupItem ) )
{
2011-12-28 21:00:35 +00:00
int pX = PacketData -> m_PosX , pY = PacketData -> m_PosY , pZ = PacketData -> m_PosZ ;
AddDirection ( pX , ( char & ) pY , pZ , PacketData -> m_Direction );
char PossibleBlock = World -> GetBlock ( pX , pY , pZ );
if ( PossibleBlock == E_BLOCK_FIRE )
{
PacketData -> m_PosX = pX ;
2011-12-29 13:16:23 +00:00
PacketData -> m_PosY = ( char ) pY ;
2011-12-28 21:00:35 +00:00
PacketData -> m_PosZ = pZ ;
bBroken = true ;
}
2011-10-03 18:41:19 +00:00
if ( bBroken ) // Block broken
{
2011-10-31 00:52:20 +00:00
if ( World -> DigBlock ( PacketData -> m_PosX , PacketData -> m_PosY , PacketData -> m_PosZ , PickupItem ) )
2011-10-03 18:41:19 +00:00
{
2011-11-04 05:01:55 +00:00
if ( OldBlock == E_BLOCK_REDSTONE_TORCH_ON ) {
cRedstone Redstone ( World );
2011-11-07 22:59:29 +00:00
Redstone . ChangeRedstone ( PacketData -> m_PosX , PacketData -> m_PosY , PacketData -> m_PosZ , false );
2011-11-04 05:01:55 +00:00
}
if ( OldBlock == E_BLOCK_REDSTONE_TORCH_OFF ) {
cRedstone Redstone ( World );
2011-11-07 22:59:29 +00:00
Redstone . ChangeRedstone ( PacketData -> m_PosX , PacketData -> m_PosY , PacketData -> m_PosZ , false );
2011-11-06 21:20:38 +00:00
}
if ( OldBlock == E_BLOCK_REDSTONE_WIRE ) {
cRedstone Redstone ( World );
2011-11-07 22:59:29 +00:00
Redstone . ChangeRedstone ( PacketData -> m_PosX , PacketData -> m_PosY , PacketData -> m_PosZ , false );
}
if (( OldBlock == E_BLOCK_PISTON ) || ( OldBlock == E_BLOCK_STICKY_PISTON ) ) {
int newX = PacketData -> m_PosX ;
int newY = PacketData -> m_PosY ;
int newZ = PacketData -> m_PosZ ;
AddPistonDir ( newX , newY , newZ , MetaData & ~ ( 8 ), 1 )
if ( World -> GetBlock ( newX , newY , newZ ) == E_BLOCK_PISTON_EXTENSION ) {
World -> SetBlock ( newX , newY , newZ , E_BLOCK_AIR , 0 );
}
2011-11-04 05:01:55 +00:00
}
2011-12-25 01:40:31 +00:00
if ( cDoors :: IsDoor ( OldBlock )) //Special actions for destroyed door (Destroy second part)
{
if ( MetaData & 8 ) //was Upper part of door
{
if ( cDoors :: IsDoor ( World -> GetBlock ( PacketData -> m_PosX , PacketData -> m_PosY - 1 , PacketData -> m_PosZ )))
World -> SetBlock ( PacketData -> m_PosX , PacketData -> m_PosY - 1 , PacketData -> m_PosZ , E_BLOCK_AIR , 0 );
} else { //Was lower part
if ( cDoors :: IsDoor ( World -> GetBlock ( PacketData -> m_PosX , PacketData -> m_PosY + 1 , PacketData -> m_PosZ )))
World -> SetBlock ( PacketData -> m_PosX , PacketData -> m_PosY + 1 , PacketData -> m_PosZ , E_BLOCK_AIR , 0 );
}
}
2011-12-28 21:00:35 +00:00
m_Player -> UseEquippedItem ();
2011-10-03 18:41:19 +00:00
}
}
}
else
{
2011-10-31 00:52:20 +00:00
World -> SendBlockTo ( PacketData -> m_PosX , PacketData -> m_PosY , PacketData -> m_PosZ , m_Player );
2011-10-03 18:41:19 +00:00
}
}
}
break ;
case E_BLOCK_PLACE :
{
2011-11-10 16:30:14 +00:00
int LastActionCnt = m_Player -> GetLastBlockActionCnt ();
2011-12-28 16:09:36 +00:00
if ( ( cRoot :: Get () -> GetWorld () -> GetTime () - m_Player -> GetLastBlockActionTime ()) < 0.1 ) { //only allow block interactions every 0.1 seconds
2011-11-07 18:19:38 +00:00
m_Player -> SetLastBlockActionTime (); //Player tried to interact with a block. Reset last block interation time.
2011-11-10 16:30:14 +00:00
m_Player -> SetLastBlockActionCnt ( LastActionCnt + 1 );
2011-12-28 16:09:36 +00:00
if ( m_Player -> GetLastBlockActionCnt () > MAXBLOCKCHANGEINTERACTIONS ) { //kick if more than MAXBLOCKCHANGEINTERACTIONS per .1 seconds
2011-11-10 16:30:14 +00:00
LOGWARN ( "Player %s tried to interact with a block too quickly! (could indicate bot) Was Kicked." , GetUsername () );
Kick ( "You're a baaaaaad boy!" );
break ;
}
} else {
m_Player -> SetLastBlockActionCnt ( 0 ); //reset count
m_Player -> SetLastBlockActionTime (); //Player tried to interact with a block. Reset last block interation time.
2011-11-07 18:19:38 +00:00
}
2011-11-10 16:30:14 +00:00
2011-10-03 18:41:19 +00:00
cPacket_BlockPlace * PacketData = reinterpret_cast < cPacket_BlockPlace *> ( a_Packet );
cItem & Equipped = m_Player -> GetInventory (). GetEquippedItem ();
2011-11-07 22:59:29 +00:00
2012-01-01 04:55:17 +00:00
if ( ( Equipped . m_ItemID != PacketData -> m_ItemType )) // Not valid
2011-10-03 18:41:19 +00:00
{
LOGWARN ( "Player %s tried to place a block that was not selected! (could indicate bot)" , GetUsername () );
break ;
}
if ( cRoot :: Get () -> GetPluginManager () -> CallHook ( cPluginManager :: E_PLUGIN_BLOCK_PLACE , 2 , PacketData , m_Player ) )
{
if ( PacketData -> m_Direction > - 1 )
{
AddDirection ( PacketData -> m_PosX , PacketData -> m_PosY , PacketData -> m_PosZ , PacketData -> m_Direction );
2011-10-31 00:52:20 +00:00
m_Player -> GetWorld () -> SendBlockTo ( PacketData -> m_PosX , PacketData -> m_PosY , PacketData -> m_PosZ , m_Player );
2011-10-03 18:41:19 +00:00
}
break ;
}
//LOG("%i %i %i %i %i %i", PacketData->m_Count, PacketData->m_Direction, PacketData->m_ItemType, PacketData->m_PosX, PacketData->m_PosY, PacketData->m_PosZ );
//printf("Place Dir:%i %i %i %i : %i\n", PacketData->m_Direction, PacketData->m_PosX, PacketData->m_PosY, PacketData->m_PosZ, PacketData->m_ItemType);
// 'use' useable items instead of placing blocks
bool bPlaceBlock = true ;
2011-11-06 20:39:44 +00:00
bool UpdateRedstone = false ;
bool AddedCurrent = false ;
2011-11-11 00:21:52 +00:00
2011-10-03 18:41:19 +00:00
if ( PacketData -> m_Direction >= 0 )
{
2011-11-11 00:21:52 +00:00
2011-10-31 00:52:20 +00:00
ENUM_BLOCK_ID BlockID = ( ENUM_BLOCK_ID ) m_Player -> GetWorld () -> GetBlock ( PacketData -> m_PosX , PacketData -> m_PosY , PacketData -> m_PosZ );
2011-10-03 18:41:19 +00:00
switch ( BlockID )
{
2011-11-03 05:53:54 +00:00
case E_BLOCK_REDSTONE_REPEATER_ON :
case E_BLOCK_REDSTONE_REPEATER_OFF :
{
2011-11-06 20:39:44 +00:00
//no need to update redstone current with a repeater
2011-11-03 05:53:54 +00:00
//todo: Find meta value of repeater and change it to one step more.
}
break ;
2011-10-03 18:41:19 +00:00
case E_BLOCK_WORKBENCH :
{
bPlaceBlock = false ;
cWindow * Window = new cCraftingWindow ( 0 , true );
m_Player -> OpenWindow ( Window );
}
break ;
case E_BLOCK_FURNACE :
case E_BLOCK_CHEST :
{
bPlaceBlock = false ;
2011-10-31 00:52:20 +00:00
cBlockEntity * BlockEntity = m_Player -> GetWorld () -> GetBlockEntity ( PacketData -> m_PosX , PacketData -> m_PosY , PacketData -> m_PosZ );
2011-10-03 18:41:19 +00:00
if ( BlockEntity )
{
BlockEntity -> UsedBy ( * m_Player );
}
}
break ;
2011-11-10 02:05:51 +00:00
case E_BLOCK_WOODEN_DOOR :
{
bPlaceBlock = false ;
2011-12-25 01:40:31 +00:00
cDoors :: ChangeDoor ( m_Player -> GetWorld (), PacketData -> m_PosX , PacketData -> m_PosY , PacketData -> m_PosZ );
2011-11-10 02:05:51 +00:00
}
break ;
2011-10-03 18:41:19 +00:00
default :
break ;
};
}
// Some checks to see if it's a placeable item :P
if ( bPlaceBlock )
{
cItem Item ;
Item . m_ItemID = Equipped . m_ItemID ;
Item . m_ItemCount = 1 ;
2011-11-03 05:53:54 +00:00
LOG ( "PacketData->m_ItemType: %i" , ( int ) PacketData -> m_ItemType );
2011-10-03 18:41:19 +00:00
// Hacked in edible items go!~
2011-12-28 11:27:36 +00:00
// TODO: Handle hunger
2011-10-03 18:41:19 +00:00
bool bEat = false ;
2011-11-10 02:05:51 +00:00
bool isDoor = false ;
2011-10-03 18:41:19 +00:00
switch ( Item . m_ItemID )
{
case E_ITEM_APPLE :
2011-12-29 15:31:48 +00:00
//m_Player->Heal( 4 ); // 2 hearts
m_Player -> Feed ( 24 ); // 2 food bars
2011-10-03 18:41:19 +00:00
bEat = true ;
break ;
case E_ITEM_GOLDEN_APPLE :
2011-12-29 15:31:48 +00:00
//m_Player->Heal( 20 ); // 10 hearts
m_Player -> Feed ( 60 ); // 5 food
2011-10-03 18:41:19 +00:00
bEat = true ;
break ;
case E_ITEM_MUSHROOM_SOUP :
2011-12-29 15:31:48 +00:00
///m_Player->Heal( 10 ); // 5 hearts
m_Player -> Feed ( 48 ); // 4 food
2011-10-03 18:41:19 +00:00
bEat = true ;
break ;
case E_ITEM_BREAD :
2011-12-29 15:31:48 +00:00
//m_Player->Heal( 5 ); // 2.5 hearts
m_Player -> Feed ( 30 ); // 2.5 food
2011-10-03 18:41:19 +00:00
bEat = true ;
break ;
case E_ITEM_RAW_MEAT :
2011-12-29 15:31:48 +00:00
//m_Player->Heal( 3 ); // 1.5 hearts
m_Player -> Feed ( 18 ); // 1.5 food
2011-10-03 18:41:19 +00:00
bEat = true ;
break ;
case E_ITEM_COOKED_MEAT :
2011-12-29 15:31:48 +00:00
//m_Player->Heal( 8 ); // 4 hearts
m_Player -> Feed ( 48 ); // 4 food
2011-10-03 18:41:19 +00:00
bEat = true ;
break ;
case E_ITEM_RAW_FISH :
2011-12-29 15:31:48 +00:00
//m_Player->Heal( 2 ); // 1 heart
m_Player -> Feed ( 12 ); // 1 food
2011-10-03 18:41:19 +00:00
bEat = true ;
break ;
case E_ITEM_COOKED_FISH :
2011-12-29 15:31:48 +00:00
//m_Player->Heal( 5 ); // 2.5 hearts
m_Player -> Feed ( 30 ); // 2.5 food
2011-10-03 18:41:19 +00:00
bEat = true ;
break ;
2011-12-28 11:27:36 +00:00
case E_ITEM_RAW_CHICKEN :
2011-12-29 15:31:48 +00:00
//m_Player->Heal(3);
m_Player -> Feed ( 12 ); // 1 food
2011-12-28 11:27:36 +00:00
bEat = true ;
break ;
case E_ITEM_COOKED_CHICKEN :
2011-12-29 15:31:48 +00:00
//m_Player->Heal( 8 );
m_Player -> Feed ( 36 ); // 3 food
2011-12-28 11:27:36 +00:00
bEat = true ;
break ;
2011-12-28 11:32:43 +00:00
case E_ITEM_RAW_BEEF :
2011-12-29 15:31:48 +00:00
//m_Player->Heal(3);
m_Player -> Feed ( 18 ); // 1.5 food
2011-12-28 11:32:43 +00:00
bEat = true ;
break ;
case E_ITEM_STEAK :
2011-12-29 15:31:48 +00:00
//m_Player->Heal( 8 );
m_Player -> Feed ( 48 ); // 4 food
2011-12-28 11:32:43 +00:00
bEat = true ;
break ;
2011-10-03 18:41:19 +00:00
default :
break ;
};
if ( bEat )
{
m_Player -> GetInventory (). RemoveItem ( Item );
break ;
}
if ( PacketData -> m_Direction < 0 ) // clicked in air
break ;
2011-12-21 20:42:34 +00:00
//TODO: Wrong Blocks!
2012-01-01 04:55:17 +00:00
int ClickedBlock = ( int ) m_Player -> GetWorld () -> GetBlock ( PacketData -> m_PosX , PacketData -> m_PosY , PacketData -> m_PosZ );
2011-10-03 18:41:19 +00:00
char MetaData = ( char ) Equipped . m_ItemHealth ;
2011-11-10 16:30:14 +00:00
bool LavaBucket = false ;
bool WaterBucket = false ;
2011-12-28 21:00:35 +00:00
bool bRemoveItem = true ;
2012-01-01 04:55:17 +00:00
bool bIgnoreCollision = false ;
if ( ClickedBlock == E_BLOCK_STEP )
{
if ( MetaData == m_Player -> GetWorld () -> GetBlockMeta ( PacketData -> m_PosX , PacketData -> m_PosY , PacketData -> m_PosZ ) && PacketData -> m_Direction == 1 ) //only make double slab if meta values are the same and if player clicked on top of the block (Dir = 1)
{
PacketData -> m_ItemType = E_BLOCK_DOUBLE_STEP ;
PacketData -> m_PosY -- ;
bIgnoreCollision = true ;
}
}
2011-11-11 00:21:52 +00:00
2011-10-03 18:41:19 +00:00
switch ( PacketData -> m_ItemType ) // Special handling for special items
{
2011-11-10 16:30:14 +00:00
case E_ITEM_BUCKET :
2011-12-21 20:42:34 +00:00
//TODO: Change this, it is just a small hack to get it working a little bit. seems like the Client sends the position from the first hitable block :s
2012-01-01 04:55:17 +00:00
ClickedBlock = ( int ) m_Player -> GetWorld () -> GetBlock ( PacketData -> m_PosX , PacketData -> m_PosY + 1 , PacketData -> m_PosZ );
LOG ( "Bucket Clicked BlockID: %d" , ClickedBlock );
switch ( ClickedBlock )
2011-11-10 16:30:14 +00:00
{
case E_BLOCK_WATER :
case E_BLOCK_STATIONARY_WATER :
WaterBucket = true ;
break ;
case E_BLOCK_LAVA :
case E_BLOCK_STATIONARY_LAVA :
LavaBucket = true ;
break ;
}
break ;
case E_ITEM_LAVA_BUCKET :
2011-12-21 20:42:34 +00:00
if (( m_Player -> GetGameMode () == 1 ) || ( m_Player -> GetInventory (). RemoveItem ( Item )))
{
2011-12-29 02:44:21 +00:00
PacketData -> m_ItemType = E_BLOCK_LAVA ;
if ( m_Player -> GetGameMode () == 1 )
break ; //No new Bucket for creative players
2011-12-21 20:42:34 +00:00
cItem NewItem ;
NewItem . m_ItemID = E_ITEM_BUCKET ;
NewItem . m_ItemCount = 1 ;
m_Player -> GetInventory (). AddItem ( NewItem );
2011-12-29 02:44:21 +00:00
2011-12-21 20:42:34 +00:00
}
2011-11-10 16:30:14 +00:00
break ;
case E_ITEM_WATER_BUCKET :
2011-12-21 20:42:34 +00:00
if (( m_Player -> GetGameMode () == 1 ) || ( m_Player -> GetInventory (). RemoveItem ( Item )))
{
2011-12-29 02:44:21 +00:00
PacketData -> m_ItemType = E_BLOCK_WATER ;
if ( m_Player -> GetGameMode () == 1 )
break ; //No new Bucket for creative players
2011-12-21 20:42:34 +00:00
cItem NewItem ;
NewItem . m_ItemID = E_ITEM_BUCKET ;
NewItem . m_ItemCount = 1 ;
m_Player -> GetInventory (). AddItem ( NewItem );
2011-12-29 02:44:21 +00:00
2011-12-21 20:42:34 +00:00
}
2011-11-10 16:30:14 +00:00
break ;
2011-10-03 18:41:19 +00:00
case E_BLOCK_TORCH :
MetaData = cTorch :: DirectionToMetaData ( PacketData -> m_Direction );
break ;
2011-11-03 05:53:54 +00:00
case E_BLOCK_REDSTONE_TORCH_OFF :
2011-11-04 05:01:55 +00:00
{
2011-11-06 20:39:44 +00:00
MetaData = cTorch :: DirectionToMetaData ( PacketData -> m_Direction );
2011-11-04 05:01:55 +00:00
if ( g_BlockTransparent [ ( int ) m_Player -> GetWorld () -> GetBlock ( PacketData -> m_PosX , PacketData -> m_PosY + 2 , PacketData -> m_PosZ ) ] == true ) { //if block above is transparent
2011-11-06 09:23:20 +00:00
//printf("transparent above me\n");
2011-11-04 05:01:55 +00:00
} else {
2011-11-06 09:23:20 +00:00
//printf("transparent not above me\n");
2011-11-04 05:01:55 +00:00
}
2011-11-06 20:39:44 +00:00
UpdateRedstone = true ;
2011-11-07 22:59:29 +00:00
AddedCurrent = false ;
2011-11-06 20:39:44 +00:00
break ;
2011-11-04 05:01:55 +00:00
}
2011-11-03 05:53:54 +00:00
case E_BLOCK_REDSTONE_TORCH_ON :
2011-11-06 20:39:44 +00:00
{
MetaData = cTorch :: DirectionToMetaData ( PacketData -> m_Direction );
UpdateRedstone = true ;
2011-11-07 22:59:29 +00:00
AddedCurrent = true ;
2011-11-06 20:39:44 +00:00
break ;
}
2011-11-03 05:53:54 +00:00
case E_ITEM_REDSTONE_DUST :
2011-11-04 05:01:55 +00:00
MetaData = 0 ;
2011-11-03 05:53:54 +00:00
PacketData -> m_ItemType = E_BLOCK_REDSTONE_WIRE ;
2011-11-06 20:39:44 +00:00
UpdateRedstone = true ;
AddedCurrent = false ;
2011-11-03 05:53:54 +00:00
break ;
case E_ITEM_REDSTONE_REPEATER :
2011-11-04 05:01:55 +00:00
MetaData = cRedstone :: RepeaterRotationToMetaData ( m_Player -> GetRotation () );
2011-11-03 05:53:54 +00:00
PacketData -> m_ItemType = E_BLOCK_REDSTONE_REPEATER_OFF ;
2011-11-06 20:39:44 +00:00
UpdateRedstone = true ;
AddedCurrent = false ;
2011-11-03 05:53:54 +00:00
break ;
2011-11-05 18:28:19 +00:00
case E_BLOCK_PISTON :
case E_BLOCK_STICKY_PISTON :
MetaData = cPiston :: RotationPitchToMetaData ( m_Player -> GetRotation (), m_Player -> GetPitch () );
2011-11-06 20:39:44 +00:00
UpdateRedstone = true ;
AddedCurrent = false ;
2011-11-05 18:28:19 +00:00
break ;
2011-11-10 02:05:51 +00:00
case E_ITEM_IRON_DOOR :
{
PacketData -> m_ItemType = E_BLOCK_IRON_DOOR ;
MetaData = cDoors :: RotationToMetaData ( m_Player -> GetRotation () );
isDoor = true ;
}
break ;
case E_ITEM_WOODEN_DOOR :
{
PacketData -> m_ItemType = E_BLOCK_WOODEN_DOOR ;
MetaData = cDoors :: RotationToMetaData ( m_Player -> GetRotation () );
isDoor = true ;
}
break ;
2012-01-01 02:48:26 +00:00
case E_BLOCK_CHEST :
case E_BLOCK_FURNACE :
case E_BLOCK_DISPENSER :
MetaData = cPiston :: RotationPitchToMetaData ( m_Player -> GetRotation (), 0 ); // Same orientation as pistons, just ignore pitch
break ;
2011-10-03 18:41:19 +00:00
case E_BLOCK_COBBLESTONE_STAIRS :
2011-11-05 18:28:19 +00:00
case E_BLOCK_BRICK_STAIRS :
case E_BLOCK_STONE_BRICK_STAIRS :
case E_BLOCK_NETHER_BRICK_STAIRS :
2011-10-03 18:41:19 +00:00
case E_BLOCK_WOODEN_STAIRS :
MetaData = cStairs :: RotationToMetaData ( m_Player -> GetRotation () );
break ;
case E_BLOCK_LADDER :
MetaData = cLadder :: DirectionToMetaData ( PacketData -> m_Direction );
break ;
case E_ITEM_SIGN :
LOG ( "Dir: %i" , PacketData -> m_Direction );
if ( PacketData -> m_Direction == 1 )
{
2012-01-01 16:20:52 +00:00
LOG ( "Player Rotation: %f" , m_Player -> GetRotation () );
2011-10-03 18:41:19 +00:00
MetaData = cSign :: RotationToMetaData ( m_Player -> GetRotation () );
LOG ( "Sign rotation %i" , MetaData );
PacketData -> m_ItemType = E_BLOCK_SIGN_POST ;
}
else
{
MetaData = cSign :: DirectionToMetaData ( PacketData -> m_Direction );
PacketData -> m_ItemType = E_BLOCK_WALLSIGN ;
}
break ;
2011-12-28 21:00:35 +00:00
case E_ITEM_FLINT_AND_STEEL :
PacketData -> m_ItemType = E_ITEM_FIRE ;
m_Player -> UseEquippedItem ();
bRemoveItem = false ;
break ;
2011-10-03 18:41:19 +00:00
default :
break ;
};
2011-11-10 16:30:14 +00:00
if ( LavaBucket ) {
if ( ( m_Player -> GetGameMode () == 1 ) || ( m_Player -> GetInventory (). RemoveItem ( Item )) ) {
cItem NewItem ;
NewItem . m_ItemID = E_ITEM_LAVA_BUCKET ;
NewItem . m_ItemCount = 1 ;
m_Player -> GetInventory (). AddItem ( NewItem );
2011-12-21 20:42:34 +00:00
m_Player -> GetWorld () -> SetBlock ( PacketData -> m_PosX , PacketData -> m_PosY + 1 , PacketData -> m_PosZ , E_BLOCK_AIR , 0 );
2011-11-10 16:30:14 +00:00
}
} else if ( WaterBucket ) {
if ( ( m_Player -> GetGameMode () == 1 ) || ( m_Player -> GetInventory (). RemoveItem ( Item )) ) {
cItem NewItem ;
NewItem . m_ItemID = E_ITEM_WATER_BUCKET ;
NewItem . m_ItemCount = 1 ;
m_Player -> GetInventory (). AddItem ( NewItem );
2011-12-21 20:42:34 +00:00
m_Player -> GetWorld () -> SetBlock ( PacketData -> m_PosX , PacketData -> m_PosY + 1 , PacketData -> m_PosZ , E_BLOCK_AIR , 0 );
2011-11-10 16:30:14 +00:00
}
} else if ( IsValidBlock ( PacketData -> m_ItemType ) ) {
2011-11-07 22:59:29 +00:00
int X = PacketData -> m_PosX ;
char Y = PacketData -> m_PosY ;
int Z = PacketData -> m_PosZ ;
AddDirection ( X , Y , Z , PacketData -> m_Direction );
2011-11-11 00:21:52 +00:00
int PlaceBlock = m_Player -> GetWorld () -> GetBlock ( X , Y , Z );
2012-01-01 04:55:17 +00:00
if ( PlaceBlock != E_BLOCK_AIR
&& PlaceBlock != E_BLOCK_WATER
&& PlaceBlock != E_BLOCK_STATIONARY_WATER
&& PlaceBlock != E_BLOCK_LAVA
&& PlaceBlock != E_BLOCK_STATIONARY_LAVA
&& ! bIgnoreCollision ) { //tried to place a block *into* another?
2011-11-07 22:59:29 +00:00
break ; //happens when you place a block aiming at side of block like torch or stem
}
2011-11-11 00:21:52 +00:00
2012-01-23 15:11:45 +00:00
// Check whether selected item is allowed to be placed on specific surface
bool bIllegalSurface = false ;
ENUM_BLOCK_ID SurfaceBlock = ( ENUM_BLOCK_ID ) m_Player -> GetWorld () -> GetBlock ( X , Y - 1 , Z );
switch ( PacketData -> m_ItemType )
{
case E_BLOCK_YELLOW_FLOWER : // Can ONLY be placed on dirt/grass
case E_BLOCK_RED_ROSE :
case E_BLOCK_SAPLING :
switch ( SurfaceBlock )
{
case E_BLOCK_DIRT :
case E_BLOCK_GRASS :
bIllegalSurface = false ;
break ;
default :
bIllegalSurface = true ;
break ;
};
break ;
case E_BLOCK_BROWN_MUSHROOM : // Can be placed on pretty much anything, with exceptions
case E_BLOCK_RED_MUSHROOM :
switch ( SurfaceBlock )
{
case E_BLOCK_GLASS :
case E_BLOCK_YELLOW_FLOWER :
case E_BLOCK_RED_ROSE :
case E_BLOCK_BROWN_MUSHROOM :
case E_BLOCK_RED_MUSHROOM :
case E_BLOCK_CACTUS :
bIllegalSurface = true ;
break ;
}
break ;
case E_BLOCK_CACTUS :
if ( SurfaceBlock != E_BLOCK_SAND && SurfaceBlock != E_BLOCK_CACTUS ) // Cactus can only be placed on sand and itself
bIllegalSurface = true ;
// Check surroundings. Cacti may ONLY be surrounded by air
cWorld * World = m_Player -> GetWorld ();
if ( World -> GetBlock ( X - 1 , Y , Z ) != E_BLOCK_AIR
|| World -> GetBlock ( X + 1 , Y , Z ) != E_BLOCK_AIR
|| World -> GetBlock ( X , Y , Z - 1 ) != E_BLOCK_AIR
|| World -> GetBlock ( X , Y , Z + 1 ) != E_BLOCK_AIR
)
{
bIllegalSurface = true ;
}
break ;
};
if ( bIllegalSurface )
break ;
2011-12-28 21:00:35 +00:00
if ( bRemoveItem )
2011-10-03 18:41:19 +00:00
{
2011-12-28 21:00:35 +00:00
if (( m_Player -> GetGameMode () != 1 ) && ! m_Player -> GetInventory (). RemoveItem ( Item ))
break ;
}
2012-01-01 04:55:17 +00:00
2011-12-28 21:00:35 +00:00
if ( isDoor )
{
if ( ( m_Player -> GetWorld () -> GetBlock ( X , Y + 1 , Z ) == E_BLOCK_AIR ) || ( m_Player -> GetWorld () -> GetBlock ( X , Y + 1 , Z ) == E_BLOCK_AIR ) )
{
m_Player -> GetWorld () -> SetBlock ( X , Y + 1 , Z , ( char ) PacketData -> m_ItemType , MetaData + 8 );
2011-11-10 02:05:51 +00:00
m_Player -> GetWorld () -> SetBlock ( X , Y , Z , ( char ) PacketData -> m_ItemType , MetaData );
}
2011-12-28 21:00:35 +00:00
} else {
m_Player -> GetWorld () -> SetBlock ( X , Y , Z , ( char ) PacketData -> m_ItemType , MetaData );
}
2011-11-10 16:30:14 +00:00
2012-01-01 04:55:17 +00:00
2011-12-28 21:00:35 +00:00
if ( UpdateRedstone )
{
cRedstone Redstone ( m_Player -> GetWorld ());
Redstone . ChangeRedstone ( PacketData -> m_PosX , PacketData -> m_PosY + 1 , PacketData -> m_PosZ , AddedCurrent );
2011-10-03 18:41:19 +00:00
}
2011-12-28 21:00:35 +00:00
2011-10-03 18:41:19 +00:00
}
}
/*
// Remove stuff with stick! :D
if( m_Username.compare("FakeTruth") == 0 )
{ // It's me! :D
if( PacketData->m_ItemType == 280 )
{
cRoot::Get()->GetWorld()->SetBlock( PacketData->m_PosX, PacketData->m_PosY, PacketData->m_PosZ, 0, 0 );
}
}
*/
}
break ;
case E_PICKUP_SPAWN :
{
LOG ( "Received packet E_PICKUP_SPAWN" );
cPacket_PickupSpawn * PacketData = reinterpret_cast < cPacket_PickupSpawn *> ( a_Packet );
cItem DroppedItem ;
DroppedItem . m_ItemID = ( ENUM_ITEM_ID ) PacketData -> m_Item ;
DroppedItem . m_ItemCount = PacketData -> m_Count ;
DroppedItem . m_ItemHealth = 0x0 ; // TODO: Somehow figure out what item was dropped, and apply correct health
if ( m_Player -> GetInventory (). RemoveItem ( DroppedItem ) )
{
cPickup * Pickup = new cPickup ( PacketData );
2011-10-31 00:52:20 +00:00
Pickup -> Initialize ( m_Player -> GetWorld () );
2011-10-03 18:41:19 +00:00
}
}
break ;
case E_CHAT :
{
cPacket_Chat * PacketData = reinterpret_cast < cPacket_Chat *> ( a_Packet );
if ( ! cRoot :: Get () -> GetServer () -> Command ( * this , PacketData -> m_Message . c_str () ) )
{
PacketData -> m_Message . insert ( 0 , "<" + m_Player -> GetColor () + m_pState -> Username + cChatColor :: White + "> " );
cRoot :: Get () -> GetServer () -> Broadcast ( * PacketData );
}
}
break ;
case E_PLAYERLOOK :
{
cPacket_PlayerLook * PacketData = reinterpret_cast < cPacket_PlayerLook *> ( a_Packet );
m_Player -> SetRotation ( PacketData -> m_Rotation );
m_Player -> SetPitch ( PacketData -> m_Pitch );
m_Player -> SetTouchGround ( PacketData -> m_bFlying );
m_Player -> WrapRotation ();
}
break ;
case E_PLAYERMOVELOOK :
{
cPacket_PlayerMoveLook * PacketData = reinterpret_cast < cPacket_PlayerMoveLook *> ( a_Packet );
m_Player -> MoveTo ( Vector3d ( PacketData -> m_PosX , PacketData -> m_PosY , PacketData -> m_PosZ ) );
m_Player -> SetStance ( PacketData -> m_Stance );
m_Player -> SetTouchGround ( PacketData -> m_bFlying );
m_Player -> SetRotation ( PacketData -> m_Rotation );
m_Player -> SetPitch ( PacketData -> m_Pitch );
m_Player -> WrapRotation ();
}
break ;
case E_ANIMATION :
{
cPacket_ArmAnim * PacketData = reinterpret_cast < cPacket_ArmAnim *> ( a_Packet );
PacketData -> m_EntityID = m_Player -> GetUniqueID ();
cRoot :: Get () -> GetServer () -> Broadcast ( * PacketData , this );
}
break ;
case E_ITEM_SWITCH :
{
cPacket_ItemSwitch * PacketData = reinterpret_cast < cPacket_ItemSwitch *> ( a_Packet );
m_Player -> GetInventory (). SetEquippedSlot ( PacketData -> m_SlotNum );
cPacket_EntityEquipment Equipment ;
Equipment . m_ItemID = ( short ) m_Player -> GetInventory (). GetEquippedItem (). m_ItemID ;
Equipment . m_Slot = 0 ;
Equipment . m_UniqueID = m_Player -> GetUniqueID ();
cRoot :: Get () -> GetServer () -> Broadcast ( Equipment , this );
}
break ;
case E_WINDOW_CLOSE :
{
cPacket_WindowClose * PacketData = reinterpret_cast < cPacket_WindowClose *> ( a_Packet );
2011-12-25 14:03:01 +00:00
m_Player -> CloseWindow ( PacketData -> m_Close );
/*
2011-10-03 18:41:19 +00:00
if( PacketData->m_Close > 0 ) // Don't care about closing inventory
{
m_Player->CloseWindow();
}
2011-12-25 14:03:01 +00:00
*/
2011-10-03 18:41:19 +00:00
}
break ;
case E_WINDOW_CLICK :
{
cPacket_WindowClick * PacketData = reinterpret_cast < cPacket_WindowClick *> ( a_Packet );
if ( PacketData -> m_WindowID == 0 )
{
m_Player -> GetInventory (). Clicked ( PacketData );
}
else
{
cWindow * Window = m_Player -> GetWindow ();
if ( Window ) Window -> Clicked ( PacketData , * m_Player );
else LOG ( "No 'other' window! WTF" );
}
}
break ;
case E_UPDATE_SIGN :
{
cPacket_UpdateSign * PacketData = reinterpret_cast < cPacket_UpdateSign *> ( a_Packet );
2011-10-31 00:52:20 +00:00
cWorld * World = m_Player -> GetWorld ();
2011-10-03 18:41:19 +00:00
cChunk * Chunk = World -> GetChunkOfBlock ( PacketData -> m_PosX , PacketData -> m_PosY , PacketData -> m_PosZ );
cBlockEntity * BlockEntity = Chunk -> GetBlockEntity ( PacketData -> m_PosX , PacketData -> m_PosY , PacketData -> m_PosZ );
if ( BlockEntity && ( BlockEntity -> GetBlockType () == E_BLOCK_SIGN_POST || BlockEntity -> GetBlockType () == E_BLOCK_WALLSIGN ) )
{
cSignEntity * Sign = reinterpret_cast < cSignEntity * > ( BlockEntity );
Sign -> SetLines ( PacketData -> m_Line1 , PacketData -> m_Line2 , PacketData -> m_Line3 , PacketData -> m_Line4 );
Sign -> SendTo ( 0 ); // Broadcast to all players in chunk
}
}
break ;
case E_USE_ENTITY :
{
cPacket_UseEntity * PacketData = reinterpret_cast < cPacket_UseEntity *> ( a_Packet );
if ( PacketData -> m_bLeftClick )
{
2011-10-31 00:52:20 +00:00
cWorld * World = m_Player -> GetWorld ();
2011-10-03 18:41:19 +00:00
cEntity * Entity = World -> GetEntity ( PacketData -> m_TargetID );
if ( Entity && Entity -> IsA ( "cPawn" ) )
{
cPawn * Pawn = ( cPawn * ) Entity ;
Pawn -> TakeDamage ( 1 , m_Player );
}
}
}
break ;
case E_RESPAWN :
{
m_Player -> Respawn ();
}
break ;
case E_DISCONNECT :
{
2012-01-01 16:20:52 +00:00
LOG ( "Received d/c packet from %s" , GetUsername () );
2011-10-03 18:41:19 +00:00
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 ) )
{
cPacket_Chat DisconnectMessage ( m_pState -> Username + " disconnected: " + PacketData -> m_Reason );
cRoot :: Get () -> GetServer () -> Broadcast ( DisconnectMessage );
}
Destroy ();
return ;
}
break ;
2011-12-26 02:35:49 +00:00
case E_KEEP_ALIVE :
2011-12-27 18:39:06 +00:00
{
cPacket_KeepAlive * PacketData = reinterpret_cast < cPacket_KeepAlive *> ( a_Packet );
if ( PacketData -> m_KeepAliveID == m_PingID )
{
cTimer t1 ;
2011-12-28 16:09:36 +00:00
m_Ping = ( short )(( t1 . GetNowTime () - m_PingStartTime ) / 2 );
2011-12-27 18:39:06 +00:00
}
}
2011-12-26 02:35:49 +00:00
break ;
2011-10-03 18:41:19 +00:00
default :
2012-01-01 16:20:52 +00:00
break ;
2011-10-03 18:41:19 +00:00
}
}
}
2012-01-31 18:06:24 +00:00
2011-10-03 18:41:19 +00:00
void cClientHandle :: AuthenticateThread ( void * a_Param )
{
cClientHandle * self = ( cClientHandle * ) a_Param ;
cAuthenticator Authenticator ;
if ( ! Authenticator . Authenticate ( self -> GetUsername (), cRoot :: Get () -> GetServer () -> GetServerID () ) )
{
2011-12-25 14:03:01 +00:00
self -> Kick ( "Failed to verify username!" );
2011-10-03 18:41:19 +00:00
return ;
}
2011-11-01 21:57:08 +00:00
self -> m_bSendLoginResponse = true ;
2011-10-03 18:41:19 +00:00
}
2012-01-31 18:06:24 +00:00
2011-10-03 18:41:19 +00:00
void cClientHandle :: Tick ( float a_Dt )
{
( void ) a_Dt ;
if ( cWorld :: GetTime () - m_TimeLastPacket > 30.f ) // 30 seconds time-out
{
cPacket_Disconnect DC ( "Nooooo!! You timed out! D: Come back!" );
DC . Send ( m_pState -> Socket );
cSleep :: MilliSleep ( 1000 ); // Give packet some time to be received
Destroy ();
}
2011-12-27 18:39:06 +00:00
cTimer t1 ;
// Send ping packet
if ( m_LastPingTime + cClientHandle :: PING_TIME_MS <= t1 . GetNowTime ()) {
MTRand r1 ;
m_PingID = r1 . randInt ();
cPacket_KeepAlive Ping ( m_PingID );
m_PingStartTime = t1 . GetNowTime ();
Send ( Ping );
m_LastPingTime = m_PingStartTime ;
}
2011-11-01 21:57:08 +00:00
if ( m_bSendLoginResponse )
{
m_bSendLoginResponse = false ;
// Spawn player (only serversided, so data is loaded)
m_Player = new cPlayer ( this , GetUsername () ); // !!DO NOT INITIALIZE!! <- is done after receiving MoveLook Packet
2011-11-02 20:19:57 +00:00
2011-12-31 21:08:23 +00:00
cWorld * World = cRoot :: Get () -> GetWorld ( m_Player -> GetLoadedWorldName () );
2011-11-02 20:19:57 +00:00
if ( ! World ) World = cRoot :: Get () -> GetDefaultWorld ();
World -> LockEntities ();
2011-12-27 18:39:06 +00:00
m_Player -> LoginSetGameMode ( World -> GetGameMode () ); //set player's gamemode to server's gamemode at login. TODO: set to last player's gamemode at logout
2011-11-01 21:57:08 +00:00
2011-11-09 22:17:30 +00:00
m_Player -> SetIP ( m_pState -> Socket . GetIPString () );
2011-11-02 20:19:57 +00:00
cRoot :: Get () -> GetPluginManager () -> CallHook ( cPluginManager :: E_PLUGIN_PLAYER_SPAWN , 1 , m_Player );
2011-11-01 21:57:08 +00:00
// Return a server login packet
cPacket_Login LoginResponse ;
LoginResponse . m_ProtocolVersion = m_Player -> GetUniqueID ();
//LoginResponse.m_Username = "";
2011-11-01 22:19:21 +00:00
LoginResponse . m_ServerMode = m_Player -> GetGameMode (); //set gamemode from player.
2011-12-26 09:09:47 +00:00
LoginResponse . m_MapSeed = cRoot :: Get () -> GetWorld () -> GetWorldSeed ();
2011-11-01 21:57:08 +00:00
LoginResponse . m_Dimension = 0 ;
2011-12-25 13:44:22 +00:00
LoginResponse . m_MaxPlayers = ( unsigned char ) cRoot :: Get () -> GetWorld () -> GetMaxPlayers ();
2011-12-26 09:09:47 +00:00
LoginResponse . m_Difficulty = 2 ;
2011-11-01 21:57:08 +00:00
Send ( LoginResponse );
2011-11-09 23:24:51 +00:00
// Send Weather if raining:
if ( ( World -> GetWeather () == 1 ) || ( World -> GetWeather () == 2 ) ) {
cPacket_NewInvalidState RainPacket ;
RainPacket . m_Reason = 1 ; //begin rain
Send ( RainPacket );
}
2011-11-01 21:57:08 +00:00
// Send time
Send ( cPacket_TimeUpdate ( World -> GetWorldTime () ) );
// Send inventory
m_Player -> GetInventory (). SendWholeInventory ( this );
// Send health
2011-12-29 15:31:48 +00:00
cPacket_UpdateHealth Health ;
Health . m_Health = ( short ) m_Player -> GetHealth ();
Health . m_Food = m_Player -> GetFood ();
Health . m_Saturation = m_Player -> GetFoodSaturation ();
Send ( Health );
2011-11-01 22:27:09 +00:00
2011-11-01 21:57:08 +00:00
World -> UnlockEntities ();
}
2011-10-03 18:41:19 +00:00
}
2012-01-31 18:06:24 +00:00
2011-10-03 18:41:19 +00:00
void cClientHandle :: Send ( const cPacket & a_Packet , ENUM_PRIORITY a_Priority /* = E_PRIORITY_NORMAL */ )
{
if ( m_bKicking ) return ; // Don't add more packets if player is getting kicked anyway
bool bSignalSemaphore = true ;
m_pState -> SendCriticalSection . Lock ();
if ( a_Priority == E_PRIORITY_NORMAL )
{
if ( a_Packet . m_PacketID == E_REL_ENT_MOVE_LOOK )
{
PacketList & Packets = m_pState -> PendingNrmSendPackets ;
for ( std :: list < cPacket *>:: iterator itr = Packets . begin (); itr != Packets . end (); ++ itr )
{
bool bBreak = false ;
switch ( ( * itr ) -> m_PacketID )
{
case E_REL_ENT_MOVE_LOOK :
{
const cPacket_RelativeEntityMoveLook * ThisPacketData = reinterpret_cast < const cPacket_RelativeEntityMoveLook * > ( & a_Packet );
cPacket_RelativeEntityMoveLook * PacketData = reinterpret_cast < cPacket_RelativeEntityMoveLook * > ( * itr );
if ( ThisPacketData -> m_UniqueID == PacketData -> m_UniqueID )
{
//LOGINFO("Optimized by removing double packet");
Packets . erase ( itr );
bBreak = true ;
bSignalSemaphore = false ; // Because 1 packet is removed, semaphore count is the same
2011-10-26 23:18:31 +00:00
delete PacketData ;
2011-10-03 18:41:19 +00:00
break ;
}
}
break ;
2012-01-01 16:20:52 +00:00
default :
2011-10-03 18:41:19 +00:00
break ;
}
if ( bBreak )
break ;
}
}
m_pState -> PendingNrmSendPackets . push_back ( a_Packet . Clone () );
}
else if ( a_Priority == E_PRIORITY_LOW ) m_pState -> PendingLowSendPackets . push_back ( a_Packet . Clone () );
m_pState -> SendCriticalSection . Unlock ();
if ( bSignalSemaphore )
m_pState -> pSemaphore -> Signal ();
}
2012-01-31 18:06:24 +00:00
2011-10-03 18:41:19 +00:00
void cClientHandle :: SendThread ( void * lpParam )
{
cClientHandle * self = ( cClientHandle * ) lpParam ;
sClientHandleState * m_pState = self -> m_pState ;
PacketList & NrmSendPackets = m_pState -> PendingNrmSendPackets ;
PacketList & LowSendPackets = m_pState -> PendingLowSendPackets ;
while ( self -> m_bKeepThreadGoing && m_pState -> Socket )
{
m_pState -> pSemaphore -> Wait ();
m_pState -> SendCriticalSection . Lock ();
//LOG("Pending packets: %i", m_PendingPackets.size() );
if ( NrmSendPackets . size () + LowSendPackets . size () > MAX_SEMAPHORES )
{
LOGERROR ( "ERROR: Too many packets in queue for player %s !!" , self -> GetUsername () );
cPacket_Disconnect DC ( "Too many packets in queue." );
DC . Send ( m_pState -> Socket );
cSleep :: MilliSleep ( 1000 ); // Give packet some time to be received
self -> Destroy ();
m_pState -> SendCriticalSection . Unlock ();
break ;
}
if ( NrmSendPackets . size () == 0 && LowSendPackets . size () == 0 )
{
if ( self -> m_bKeepThreadGoing ) LOGERROR ( "ERROR: Semaphore was signaled while PendingSendPackets.size == 0" );
m_pState -> SendCriticalSection . Unlock ();
continue ;
}
if ( NrmSendPackets . size () > MAX_SEMAPHORES / 2 )
{
LOGINFO ( "Pending packets: %i Last: 0x%02x" , NrmSendPackets . size (), ( * NrmSendPackets . rbegin ()) -> m_PacketID );
}
cPacket * Packet = 0 ;
if ( NrmSendPackets . size () > 0 )
{
Packet = * NrmSendPackets . begin ();
NrmSendPackets . erase ( NrmSendPackets . begin () );
}
else if ( LowSendPackets . size () > 0 )
{
Packet = * LowSendPackets . begin ();
LowSendPackets . erase ( LowSendPackets . begin () );
}
m_pState -> SendCriticalSection . Unlock ();
m_pState -> SocketCriticalSection . Lock ();
if ( ! m_pState -> Socket )
{
m_pState -> SocketCriticalSection . Unlock ();
break ;
}
2012-01-19 18:12:39 +00:00
//LOG("Send packet: 0x%2x", Packet->m_PacketID );
2011-10-03 18:41:19 +00:00
bool bSuccess = Packet -> Send ( m_pState -> Socket );
m_pState -> SocketCriticalSection . Unlock ();
if ( ! bSuccess )
{
LOGERROR ( "ERROR: While sending packet 0x%02x" , Packet -> m_PacketID );
delete Packet ;
self -> Destroy ();
break ;
}
delete Packet ;
if ( self -> m_bKicking && ( NrmSendPackets . size () + LowSendPackets . size () == 0 ) ) // Disconnect player after all packets have been sent
{
cSleep :: MilliSleep ( 1000 ); // Give all packets some time to be received
self -> Destroy ();
break ;
}
}
return ;
}
2012-01-31 18:06:24 +00:00
2011-10-03 18:41:19 +00:00
void cClientHandle :: ReceiveThread ( void * lpParam )
{
LOG ( "ReceiveThread" );
cClientHandle * self = ( cClientHandle * ) lpParam ;
char temp = 0 ;
int iStat = 0 ;
cSocket socket = self -> GetSocket ();
while ( self -> m_bKeepThreadGoing )
{
2011-10-23 00:18:44 +00:00
iStat = socket . Receive ( & temp , 1 , 0 );
2011-10-03 18:41:19 +00:00
if ( cSocket :: IsSocketError ( iStat ) || iStat == 0 )
{
LOG ( "CLIENT DISCONNECTED (%i bytes):%s" , iStat , GetWSAError (). c_str () );
break ;
}
else
{
2012-01-19 18:12:39 +00:00
//LOG("Recv packet: 0x%2x", (unsigned char)temp );
2011-10-03 18:41:19 +00:00
cPacket * pPacket = self -> m_pState -> PacketMap [ ( unsigned char ) temp ];
if ( pPacket )
{
if ( pPacket -> Parse ( socket ) )
{
self -> AddPacket ( pPacket );
//self->HandlePendingPackets();
}
else
{
2011-10-23 00:18:44 +00:00
LOGERROR ( "Something went wrong during PacketID 0x%02x (%s)" , temp , cSocket :: GetLastErrorString () );
2011-10-03 18:41:19 +00:00
LOG ( "CLIENT %s DISCONNECTED" , self -> GetUsername () );
break ;
}
}
else
{
2012-01-31 18:06:24 +00:00
LOG ( "Unknown packet: 0x%02x \' %c \' %i" , ( unsigned char ) temp , ( unsigned char ) temp , ( unsigned char ) temp );
2011-10-03 18:41:19 +00:00
char c_Str [ 128 ];
2012-01-31 18:06:24 +00:00
sprintf_s ( c_Str , 128 , "[C->S] Unknown PacketID: 0x%02x" , ( unsigned char ) temp );
2011-10-03 18:41:19 +00:00
cPacket_Disconnect DC ( c_Str );
DC . Send ( socket );
cSleep :: MilliSleep ( 1000 ); // Give packet some time to be received
break ;
}
}
}
self -> Destroy ();
LOG ( "ReceiveThread STOPPED" );
return ;
}
2012-01-31 18:06:24 +00:00
2011-10-03 18:41:19 +00:00
const char * cClientHandle :: GetUsername ()
{
return m_pState -> Username . c_str ();
}
2012-01-31 18:06:24 +00:00
2011-10-03 18:41:19 +00:00
const cSocket & cClientHandle :: GetSocket ()
{
return m_pState -> Socket ;
2011-10-26 03:22:43 +00:00
}
2012-01-31 18:06:24 +00:00