2012-01-29 14:28:19 -05:00
# include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
2011-10-03 14:41:19 -04: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-09 21:05:51 -05:00
# include "cDoors.h"
2011-10-03 14:41:19 -04:00
# include "cLadder.h"
# include "cSign.h"
2011-11-04 01:01:55 -04:00
# include "cRedstone.h"
2011-11-05 14:28:19 -04:00
# include "cPiston.h"
2011-10-03 14:41:19 -04:00
# include "cBlockToPickup.h"
# include "cMonster.h"
# include "cChatColor.h"
# include "cThread.h"
# include "cSocket.h"
2011-12-27 13:39:06 -05:00
# include "cTimer.h"
2011-10-03 14:41:19 -04: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 13:39:06 -05:00
# include "MersenneTwister.h"
2011-10-03 14:41:19 -04: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"
2011-12-31 23:55:17 -05:00
# include "packets/cPacket_CreativeInventoryAction.h"
2011-11-02 16:40:39 -04:00
# include "packets/cPacket_NewInvalidState.h"
2011-10-03 14:41:19 -04: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-25 20:07:35 -05:00
# include "packets/cPacket_PlayerListItem.h"
2011-10-03 14:41:19 -04:00
2012-02-03 09:33:40 -05:00
# define AddPistonDir(x, y, z, dir, amount) switch (dir) { case 0: (y)-=(amount); break; case 1: (y)+=(amount); break;\
2011-11-07 17:59:29 -05:00
case 2 : ( z ) - = ( amount ) ; break ; case 3 : ( z ) + = ( amount ) ; break ; \
case 4 : ( x ) - = ( amount ) ; break ; case 5 : ( x ) + = ( amount ) ; break ; }
2011-10-03 14:41:19 -04:00
# define MAX_SEMAPHORES (2000)
2012-01-31 13:06:24 -05:00
// fwd: cServer.cpp:
extern std : : string GetWSAError ( ) ;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cClientHandle:
2011-10-03 14:41:19 -04:00
cClientHandle : : cClientHandle ( const cSocket & a_Socket )
2012-02-03 09:33:40 -05:00
: m_ProtocolVersion ( 23 )
, m_pSendThread ( NULL )
, m_Socket ( a_Socket )
, m_Semaphore ( MAX_SEMAPHORES )
, m_bDestroyed ( false )
2012-02-02 16:13:24 -05:00
, m_Player ( NULL )
2012-02-03 09:33:40 -05:00
, m_bKicking ( false )
, m_TimeLastPacket ( cWorld : : GetTime ( ) )
, m_bLoggedIn ( false )
, m_bKeepThreadGoing ( true )
, m_bSendLoginResponse ( false )
2011-12-25 22:05:31 -05:00
, m_Ping ( 1000 )
2012-02-03 09:33:40 -05:00
, m_bPositionConfirmed ( false )
2011-10-03 14:41:19 -04:00
{
2011-12-27 13:39:06 -05:00
cTimer t1 ;
m_LastPingTime = t1 . GetNowTime ( ) ;
2011-10-03 14:41:19 -04:00
// All the packets that can be received from the client
2012-02-03 09:33:40 -05:00
for ( int i = 0 ; i < ARRAYCOUNT ( m_PacketMap ) ; + + i )
{
m_PacketMap [ i ] = NULL ;
}
m_PacketMap [ E_KEEP_ALIVE ] = new cPacket_KeepAlive ;
m_PacketMap [ E_HANDSHAKE ] = new cPacket_Handshake ;
m_PacketMap [ E_LOGIN ] = new cPacket_Login ;
m_PacketMap [ E_PLAYERPOS ] = new cPacket_PlayerPosition ;
m_PacketMap [ E_PLAYERLOOK ] = new cPacket_PlayerLook ;
m_PacketMap [ E_PLAYERMOVELOOK ] = new cPacket_PlayerMoveLook ;
m_PacketMap [ E_CHAT ] = new cPacket_Chat ;
m_PacketMap [ E_ANIMATION ] = new cPacket_ArmAnim ;
m_PacketMap [ E_FLYING ] = new cPacket_Flying ;
m_PacketMap [ E_BLOCK_DIG ] = new cPacket_BlockDig ;
m_PacketMap [ E_BLOCK_PLACE ] = new cPacket_BlockPlace ;
m_PacketMap [ E_DISCONNECT ] = new cPacket_Disconnect ;
m_PacketMap [ E_ITEM_SWITCH ] = new cPacket_ItemSwitch ;
m_PacketMap [ E_ENTITY_EQUIPMENT ] = new cPacket_EntityEquipment ;
m_PacketMap [ E_CREATIVE_INVENTORY_ACTION ] = new cPacket_CreativeInventoryAction ;
m_PacketMap [ E_NEW_INVALID_STATE ] = new cPacket_NewInvalidState ;
m_PacketMap [ E_PICKUP_SPAWN ] = new cPacket_PickupSpawn ;
m_PacketMap [ E_USE_ENTITY ] = new cPacket_UseEntity ;
m_PacketMap [ E_WINDOW_CLOSE ] = new cPacket_WindowClose ;
m_PacketMap [ E_WINDOW_CLICK ] = new cPacket_WindowClick ;
m_PacketMap [ E_PACKET_13 ] = new cPacket_13 ;
m_PacketMap [ E_UPDATE_SIGN ] = new cPacket_UpdateSign ;
m_PacketMap [ E_RESPAWN ] = new cPacket_Respawn ;
m_PacketMap [ E_PING ] = new cPacket_Ping ;
2012-02-02 16:13:24 -05:00
memset ( m_LoadedChunks , 0x00 , sizeof ( m_LoadedChunks ) ) ;
2011-10-03 14:41:19 -04:00
//////////////////////////////////////////////////////////////////////////
2012-02-03 09:33:40 -05:00
m_pSendThread = new cThread ( SendThread , this , " cClientHandle::SendThread " ) ;
m_pSendThread - > Start ( true ) ;
2011-10-03 14:41:19 -04:00
//////////////////////////////////////////////////////////////////////////
2012-02-08 05:02:46 -05:00
LOG ( " New ClientHandle created at %p " , this ) ;
2011-10-03 14:41:19 -04:00
}
2012-01-31 13:06:24 -05:00
2011-10-03 14:41:19 -04:00
cClientHandle : : ~ cClientHandle ( )
{
2012-02-08 05:02:46 -05:00
LOG ( " Deleting client \" %s \" " , GetUsername ( ) . c_str ( ) ) ;
2011-10-03 14:41:19 -04:00
for ( unsigned int i = 0 ; i < VIEWDISTANCE * VIEWDISTANCE ; i + + )
{
2012-02-03 09:33:40 -05:00
if ( m_LoadedChunks [ i ] ) m_LoadedChunks [ i ] - > RemoveClient ( this ) ;
2011-10-03 14:41:19 -04:00
}
2011-12-25 21:46:53 -05:00
cWorld : : PlayerList PlayerList = cRoot : : Get ( ) - > GetWorld ( ) - > GetAllPlayers ( ) ;
2012-02-03 09:33:40 -05:00
for ( cWorld : : PlayerList : : iterator itr = PlayerList . begin ( ) ; itr ! = PlayerList . end ( ) ; + + itr )
2011-12-25 21:46:53 -05:00
{
2012-02-01 17:38:03 -05:00
if ( ( * itr ) & & ( * itr ) - > GetClientHandle ( ) & & ! GetUsername ( ) . empty ( ) )
2011-12-25 21:46:53 -05:00
{
2012-02-03 09:33:40 -05:00
std : : string NameColor = ( m_Player ? m_Player - > GetColor ( ) : " " ) ;
2012-01-02 14:03:19 -05:00
cPacket_PlayerListItem PlayerList ( NameColor + GetUsername ( ) , false , ( short ) 9999 ) ;
2012-02-01 17:38:03 -05:00
( * itr ) - > GetClientHandle ( ) - > Send ( PlayerList ) ;
2011-12-25 21:46:53 -05:00
}
2011-12-25 22:05:31 -05:00
}
2012-02-03 09:33:40 -05:00
if ( m_Username . size ( ) > 0 )
2011-12-25 22:05:31 -05:00
{
2012-02-03 09:33:40 -05:00
cPacket_Chat Left ( m_Username + " left the game! " ) ;
cRoot : : Get ( ) - > GetServer ( ) - > Broadcast ( Left , this ) ;
2011-12-25 21:46:53 -05:00
}
2011-10-03 14:41:19 -04:00
// First stop sending thread
m_bKeepThreadGoing = false ;
2012-02-03 09:33:40 -05:00
if ( m_Socket . IsValid ( ) )
2011-10-03 14:41:19 -04:00
{
cPacket_Disconnect Disconnect ;
Disconnect . m_Reason = " Server shut down? Kthnxbai " ;
2012-02-07 15:49:52 -05:00
m_Socket . Send ( & Disconnect ) ;
2012-02-03 09:33:40 -05:00
m_Socket . CloseSocket ( ) ;
2011-10-03 14:41:19 -04:00
}
2012-02-03 09:33:40 -05:00
m_Semaphore . Signal ( ) ;
delete m_pSendThread ;
2011-10-03 14:41:19 -04:00
2012-02-03 09:33:40 -05:00
while ( ! m_PendingNrmSendPackets . empty ( ) )
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
delete * m_PendingNrmSendPackets . begin ( ) ;
m_PendingNrmSendPackets . erase ( m_PendingNrmSendPackets . begin ( ) ) ;
2011-10-03 14:41:19 -04:00
}
2012-02-03 09:33:40 -05:00
while ( ! m_PendingLowSendPackets . empty ( ) )
2011-12-28 11:01:15 -05:00
{
2012-02-03 09:33:40 -05:00
delete * m_PendingLowSendPackets . begin ( ) ;
m_PendingLowSendPackets . erase ( m_PendingLowSendPackets . begin ( ) ) ;
2011-12-28 11:01:15 -05:00
}
2012-02-02 16:13:24 -05:00
if ( m_Player ! = NULL )
2011-10-03 14:41:19 -04:00
{
2012-02-02 16:13:24 -05:00
m_Player - > SetClientHandle ( NULL ) ;
2012-01-01 11:20:52 -05:00
m_Player - > Destroy ( ) ;
2012-02-02 16:13:24 -05:00
m_Player = NULL ;
2012-01-01 11:20:52 -05:00
}
2012-02-03 09:33:40 -05:00
for ( int i = 0 ; i < ARRAYCOUNT ( m_PacketMap ) ; i + + )
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
delete m_PacketMap [ i ] ;
2011-10-03 14:41:19 -04:00
}
2012-02-08 05:02:46 -05:00
LOG ( " ClientHandle at %p destroyed " , this ) ;
2011-10-03 14:41:19 -04:00
}
2012-01-31 13:06:24 -05:00
2011-10-03 14:41:19 -04:00
void cClientHandle : : Destroy ( )
{
m_bDestroyed = true ;
2012-02-03 09:33:40 -05:00
if ( m_Socket . IsValid ( ) )
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
m_Socket . CloseSocket ( ) ;
2011-10-03 14:41:19 -04:00
}
2012-02-08 05:02:46 -05:00
// Synchronize with the cSocketThreads (so that they don't call us anymore)
cRoot : : Get ( ) - > GetServer ( ) - > ClientDestroying ( this ) ;
2011-10-03 14:41:19 -04:00
}
2012-01-31 13:06:24 -05:00
2012-02-01 17:38:03 -05:00
void cClientHandle : : Kick ( const AString & a_Reason )
2011-10-03 14:41:19 -04:00
{
2012-02-01 17:38:03 -05:00
Send ( cPacket_Disconnect ( a_Reason ) ) ;
2011-10-03 14:41:19 -04:00
m_bKicking = true ;
}
2012-01-31 13:06:24 -05:00
2012-02-01 17:38:03 -05:00
void cClientHandle : : Authenticate ( void )
{
m_bSendLoginResponse = true ;
}
void cClientHandle : : StreamChunks ( void )
2011-10-03 14:41:19 -04:00
{
2012-02-02 16:13:24 -05:00
if ( ! m_bLoggedIn )
{
2011-10-03 14:41:19 -04:00
return ;
2012-02-02 16:13:24 -05:00
}
2011-11-01 17:57:08 -04:00
2012-02-02 16:13:24 -05:00
assert ( m_Player ! = NULL ) ;
2011-11-01 17:57:08 -04:00
int ChunkPosX = ( int ) floor ( m_Player - > GetPosX ( ) / 16 ) ;
int ChunkPosZ = ( int ) floor ( m_Player - > GetPosZ ( ) / 16 ) ;
2011-10-03 14:41:19 -04:00
2012-02-02 16:13:24 -05:00
cWorld * World = m_Player - > GetWorld ( ) ;
2011-12-24 18:34:30 -05:00
2012-02-02 16:13:24 -05:00
cChunk * NeededChunks [ VIEWDISTANCE * VIEWDISTANCE ] = { 0 } ;
const int MaxDist = VIEWDISTANCE + GENERATEDISTANCE * 2 ;
for ( int x = 0 ; x < MaxDist ; x + + )
2011-10-03 14:41:19 -04:00
{
2012-02-02 16:13:24 -05:00
for ( int z = 0 ; z < MaxDist ; z + + )
2011-10-03 14:41:19 -04:00
{
2012-02-02 16:13:24 -05:00
int RelX = x - ( MaxDist - 1 ) / 2 ;
int RelZ = z - ( MaxDist - 1 ) / 2 ;
2012-02-03 09:33:40 -05:00
cChunk * Chunk = World - > GetChunk ( ChunkPosX + RelX , 0 , ChunkPosZ + RelZ ) ; // Touch all chunks in wide range, so they get generated
2012-02-02 16:13:24 -05:00
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 14:41:19 -04:00
}
}
2012-02-02 16:13:24 -05:00
cChunk * MissingChunks [ VIEWDISTANCE * VIEWDISTANCE ] ;
memset ( MissingChunks , 0 , sizeof ( MissingChunks ) ) ;
2011-10-03 14:41:19 -04:00
unsigned int MissIndex = 0 ;
2012-02-02 16:13:24 -05:00
for ( int i = 0 ; i < VIEWDISTANCE * VIEWDISTANCE ; i + + ) // Handshake loop - touch each chunk once
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
if ( NeededChunks [ i ] = = 0 ) continue ; // Chunk is not yet loaded, so ignore
2011-12-24 18:34:30 -05:00
// 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 14:41:19 -04:00
bool bChunkMissing = true ;
for ( int j = 0 ; j < VIEWDISTANCE * VIEWDISTANCE ; j + + )
{
2012-02-03 09:33:40 -05:00
if ( m_LoadedChunks [ j ] = = NeededChunks [ i ] )
2011-10-03 14:41:19 -04:00
{
bChunkMissing = false ;
break ;
}
}
2012-02-03 09:33:40 -05:00
if ( bChunkMissing )
2011-10-03 14:41:19 -04:00
{
MissingChunks [ MissIndex ] = NeededChunks [ i ] ;
MissIndex + + ;
}
}
2012-02-02 16:13:24 -05:00
if ( MissIndex > 0 )
{
// Chunks are gonna be streamed in, so chunks probably also need to be streamed out <- optimization
2011-10-03 14:41:19 -04:00
for ( int x = 0 ; x < VIEWDISTANCE ; x + + )
{
for ( int z = 0 ; z < VIEWDISTANCE ; z + + )
{
cChunk * Chunk = m_LoadedChunks [ x + z * VIEWDISTANCE ] ;
2012-02-02 16:13:24 -05:00
if ( Chunk ! = NULL )
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
if ( ( Chunk - > GetPosX ( ) < ChunkPosX - ( VIEWDISTANCE - 1 ) / 2 )
2012-02-02 16:13:24 -05:00
| | ( Chunk - > GetPosX ( ) > ChunkPosX + ( VIEWDISTANCE - 1 ) / 2 )
| | ( Chunk - > GetPosZ ( ) < ChunkPosZ - ( VIEWDISTANCE - 1 ) / 2 )
| | ( Chunk - > GetPosZ ( ) > ChunkPosZ + ( VIEWDISTANCE - 1 ) / 2 )
)
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
Chunk - > RemoveClient ( this ) ;
Chunk - > AsyncUnload ( this ) ; // TODO - I think it's possible to unload the chunk immediately instead of next tick
2011-12-24 18:34:30 -05:00
// I forgot why I made it happen next tick
2012-02-02 16:13:24 -05:00
m_LoadedChunks [ x + z * VIEWDISTANCE ] = NULL ;
2011-10-03 14:41:19 -04:00
}
}
}
}
2012-02-03 09:33:40 -05:00
StreamChunksSmart ( MissingChunks , MissIndex ) ;
2011-10-03 14:41:19 -04:00
2012-02-02 16:13:24 -05:00
memcpy ( m_LoadedChunks , NeededChunks , sizeof ( NeededChunks ) ) ;
2011-10-03 14:41:19 -04:00
}
}
2012-01-31 13:06:24 -05:00
2011-12-24 18:34:30 -05:00
// Sends chunks to the player from the player position outward
2012-02-03 09:33:40 -05:00
void cClientHandle : : StreamChunksSmart ( cChunk * * a_Chunks , unsigned int a_NumChunks )
2011-10-03 14:41:19 -04:00
{
2011-11-01 17:57:08 -04: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 14:41:19 -04:00
bool bAllDone = false ;
2012-02-03 09:33:40 -05:00
while ( ! bAllDone )
2011-10-03 14:41:19 -04:00
{
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 )
{
2012-02-03 09:33:40 -05:00
if ( a_Chunks [ i ] )
2011-10-03 14:41:19 -04:00
{
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 ) ;
2012-02-03 09:33:40 -05:00
if ( SqrDist < ClosestSqrDist )
2011-10-03 14:41:19 -04:00
{
ClosestSqrDist = SqrDist ;
ClosestIdx = i ;
}
}
}
2012-02-03 09:33:40 -05:00
if ( ClosestIdx > - 1 )
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
a_Chunks [ ClosestIdx ] - > Send ( this ) ;
a_Chunks [ ClosestIdx ] - > AddClient ( this ) ;
//LOGINFO("CCC: Sending chunk %i %i", a_Chunks[ClosestIdx]->GetPosX(), a_Chunks[ClosestIdx]->GetPosZ());
2011-10-03 14:41:19 -04:00
a_Chunks [ ClosestIdx ] = 0 ;
}
}
}
2012-01-31 13:06:24 -05:00
2011-12-26 16:54:08 -05:00
// This removes the client from all chunks. Used when switching worlds
void cClientHandle : : RemoveFromAllChunks ( )
{
for ( int i = 0 ; i < VIEWDISTANCE * VIEWDISTANCE ; i + + )
{
2012-02-03 09:33:40 -05:00
if ( m_LoadedChunks [ i ] )
2011-12-26 16:54:08 -05:00
{
2012-02-03 09:33:40 -05:00
m_LoadedChunks [ i ] - > RemoveClient ( this ) ;
m_LoadedChunks [ i ] - > AsyncUnload ( this ) ;
2011-12-26 16:54:08 -05:00
m_LoadedChunks [ i ] = 0 ;
}
}
}
2012-01-31 13:06:24 -05:00
2012-02-03 09:33:40 -05:00
void cClientHandle : : HandlePacket ( cPacket * a_Packet )
2011-10-03 14:41:19 -04:00
{
m_TimeLastPacket = cWorld : : GetTime ( ) ;
2012-01-31 13:06:24 -05:00
// cPacket* CopiedPacket = a_Packet->Clone();
// a_Packet = CopiedPacket;
2011-10-03 14:41:19 -04:00
2012-02-03 09:33:40 -05:00
//LOG("Packet: 0x%02x", a_Packet->m_PacketID);
2011-10-03 14:41:19 -04:00
2012-02-02 16:13:24 -05:00
if ( m_bKicking )
{
return ;
}
2011-10-03 14:41:19 -04:00
2012-02-02 16:13:24 -05:00
if ( ! m_bLoggedIn )
2011-10-03 14:41:19 -04:00
{
2012-02-02 16:13:24 -05:00
switch ( a_Packet - > m_PacketID )
2011-10-03 14:41:19 -04:00
{
2012-02-02 16:13:24 -05: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 09:29:52 -05:00
{
LOGINFO ( " Got New Invalid State packet " ) ;
2012-02-02 16:13:24 -05:00
break ;
2011-12-26 09:29:52 -05:00
}
2011-12-31 23:55:17 -05:00
2012-02-03 09:33:40 -05:00
case E_PING : HandlePing ( ) ; break ;
case E_HANDSHAKE : HandleHandshake ( reinterpret_cast < cPacket_Handshake * > ( a_Packet ) ) ; break ;
case E_LOGIN : HandleLogin ( reinterpret_cast < cPacket_Login * > ( a_Packet ) ) ; break ;
case E_PLAYERMOVELOOK : HandleMoveLookLogin ( reinterpret_cast < cPacket_PlayerMoveLook * > ( a_Packet ) ) ; break ;
case E_KEEP_ALIVE : break ;
default : HandleDefaultLogin ( a_Packet ) ; break ;
2012-02-02 16:13:24 -05:00
} // switch (Packet type)
2011-10-03 14:41:19 -04:00
}
2012-02-02 16:13:24 -05:00
else if ( ! m_bPositionConfirmed ) // m_bLoggedIn is true
2012-01-19 13:12:39 -05:00
{
2012-02-02 16:13:24 -05:00
switch ( a_Packet - > m_PacketID )
2012-01-19 13:12:39 -05:00
{
2012-02-03 09:33:40 -05:00
case E_PLAYERMOVELOOK : HandleMoveLookConfirm ( reinterpret_cast < cPacket_PlayerMoveLook * > ( a_Packet ) ) ; break ;
// No default handling, ignore everything else
2012-02-02 16:13:24 -05:00
} // switch (Packet type)
} // if (! position confirmed)
2012-01-19 13:12:39 -05:00
2012-02-02 16:13:24 -05:00
if ( m_bPositionConfirmed )
2011-10-03 14:41:19 -04:00
{
2012-02-02 16:13:24 -05:00
switch ( a_Packet - > m_PacketID )
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
case E_CREATIVE_INVENTORY_ACTION : HandleCreativeInventory ( reinterpret_cast < cPacket_CreativeInventoryAction * > ( a_Packet ) ) ; break ;
case E_PLAYERPOS : HandlePlayerPos ( reinterpret_cast < cPacket_PlayerPosition * > ( a_Packet ) ) ; break ;
case E_BLOCK_DIG : HandleBlockDig ( reinterpret_cast < cPacket_BlockDig * > ( a_Packet ) ) ; break ;
case E_BLOCK_PLACE : HandleBlockPlace ( reinterpret_cast < cPacket_BlockPlace * > ( a_Packet ) ) ; break ;
case E_PICKUP_SPAWN : HandlePickupSpawn ( reinterpret_cast < cPacket_PickupSpawn * > ( a_Packet ) ) ; break ;
case E_CHAT : HandleChat ( reinterpret_cast < cPacket_Chat * > ( a_Packet ) ) ; break ;
case E_PLAYERLOOK : HandlePlayerLook ( reinterpret_cast < cPacket_PlayerLook * > ( a_Packet ) ) ; break ;
case E_PLAYERMOVELOOK : HandlePlayerMoveLook ( reinterpret_cast < cPacket_PlayerMoveLook * > ( a_Packet ) ) ; break ;
case E_ANIMATION : HandleAnimation ( reinterpret_cast < cPacket_ArmAnim * > ( a_Packet ) ) ; break ;
case E_ITEM_SWITCH : HandleItemSwitch ( reinterpret_cast < cPacket_ItemSwitch * > ( a_Packet ) ) ; break ;
case E_WINDOW_CLOSE : HandleWindowClose ( reinterpret_cast < cPacket_WindowClose * > ( a_Packet ) ) ; break ;
case E_WINDOW_CLICK : HandleWindowClick ( reinterpret_cast < cPacket_WindowClick * > ( a_Packet ) ) ; break ;
case E_UPDATE_SIGN : HandleUpdateSign ( reinterpret_cast < cPacket_UpdateSign * > ( a_Packet ) ) ; break ;
case E_USE_ENTITY : HandleUseEntity ( reinterpret_cast < cPacket_UseEntity * > ( a_Packet ) ) ; break ;
case E_RESPAWN : HandleRespawn ( ) ;
case E_DISCONNECT : HandleDisconnect ( reinterpret_cast < cPacket_Disconnect * > ( a_Packet ) ) ; break ;
case E_KEEP_ALIVE : HandleKeepAlive ( reinterpret_cast < cPacket_KeepAlive * > ( a_Packet ) ) ; break ;
} // switch (Packet type)
} // if (normal game)
}
2012-02-02 16:13:24 -05:00
2011-11-10 11:30:14 -05:00
2011-12-28 16:00:35 -05:00
2011-10-03 14:41:19 -04:00
2012-02-03 09:33:40 -05:00
void cClientHandle : : HandlePing ( void )
{
// Somebody tries to retrieve information about the server
LOGINFO ( " Got ping from \" %s \" " , m_Socket . GetIPString ( ) . c_str ( ) ) ;
AString Reply ;
Printf ( Reply , " %s%s%i%s%i " ,
cRoot : : Get ( ) - > GetWorld ( ) - > GetDescription ( ) . c_str ( ) ,
cChatColor : : Delimiter . c_str ( ) ,
cRoot : : Get ( ) - > GetWorld ( ) - > GetNumPlayers ( ) ,
cChatColor : : Delimiter . c_str ( ) ,
cRoot : : Get ( ) - > GetWorld ( ) - > GetMaxPlayers ( )
) ;
Kick ( Reply . c_str ( ) ) ;
}
2011-12-24 20:40:31 -05:00
2011-12-28 16:00:35 -05:00
2012-02-03 09:33:40 -05:00
void cClientHandle : : HandleHandshake ( cPacket_Handshake * a_Packet )
{
m_Username = a_Packet - > m_Username ;
LOG ( " HANDSHAKE %s " , m_Username . c_str ( ) ) ;
2011-11-10 11:30:14 -05:00
2012-02-03 09:33:40 -05:00
if ( cRoot : : Get ( ) - > GetWorld ( ) - > GetNumPlayers ( ) > = cRoot : : Get ( ) - > GetWorld ( ) - > GetMaxPlayers ( ) )
{
Kick ( " The server is currently full :(-- Try again later " ) ;
return ;
}
cPacket_Chat Connecting ( m_Username + " is connecting. " ) ;
cRoot : : Get ( ) - > GetServer ( ) - > Broadcast ( Connecting , this ) ;
2011-11-07 17:59:29 -05:00
2012-02-03 09:33:40 -05:00
// Give a server handshake thingy back
cPacket_Handshake Handshake ;
Handshake . m_Username = cRoot : : Get ( ) - > GetServer ( ) - > GetServerID ( ) ;
Send ( Handshake ) ;
}
2011-10-03 14:41:19 -04:00
2011-11-10 19:21:52 -05:00
2012-02-03 09:33:40 -05:00
void cClientHandle : : HandleLogin ( cPacket_Login * a_Packet )
{
LOG ( " LOGIN %s " , m_Username . c_str ( ) ) ;
if ( a_Packet - > m_ProtocolVersion < m_ProtocolVersion )
{
Kick ( " Your client is outdated! " ) ;
return ;
}
else if ( a_Packet - > m_ProtocolVersion > m_ProtocolVersion )
{
Kick ( " Your client version is higher than the server! " ) ;
return ;
}
if ( m_Username . compare ( a_Packet - > m_Username ) ! = 0 )
{
LOGWARNING ( " Login Username ( \" %s \" ) does not match Handshake username ( \" %s \" ) for client \" %s \" ) " ,
a_Packet - > m_Username . c_str ( ) ,
m_Username . c_str ( ) ,
m_Socket . GetIPString ( ) . c_str ( )
) ;
Kick ( " Hacked client " ) ; // Don't tell them why we don't want them
return ;
}
2011-10-03 14:41:19 -04:00
2012-02-03 09:33:40 -05:00
if ( cRoot : : Get ( ) - > GetPluginManager ( ) - > CallHook ( cPluginManager : : E_PLUGIN_LOGIN , 1 , a_Packet ) )
{
Destroy ( ) ;
return ;
}
2011-10-03 14:41:19 -04:00
2012-02-03 09:33:40 -05:00
// Schedule for authentication; until then, let them wait (but do not block)
cRoot : : Get ( ) - > GetAuthenticator ( ) . Authenticate ( m_Username , cRoot : : Get ( ) - > GetServer ( ) - > GetServerID ( ) ) ;
}
2011-10-03 14:41:19 -04:00
2011-12-31 23:55:17 -05:00
2011-11-10 19:21:52 -05:00
2011-11-10 11:30:14 -05:00
2012-02-03 09:33:40 -05:00
void cClientHandle : : HandleMoveLookLogin ( cPacket_PlayerMoveLook * a_Packet )
{
// After this is received we're safe to send anything
if ( m_Player = = NULL )
{
LOGWARNING ( " Received PlayerMoveLook packet for NULL player from client \" %s \" , kicking. " , m_Socket . GetIPString ( ) . c_str ( ) ) ;
Kick ( " Hacked client " ) ; // Don't tell them why we don't want them
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_Username + " joined the game! " ) ;
cRoot : : Get ( ) - > GetServer ( ) - > Broadcast ( Joined , this ) ;
}
2011-11-10 11:30:14 -05:00
2012-02-03 09:33:40 -05:00
// Now initialize player (adds to entity list etc.)
cWorld * PlayerWorld = cRoot : : Get ( ) - > GetWorld ( m_Player - > GetLoadedWorldName ( ) ) ;
if ( ! PlayerWorld )
{
PlayerWorld = cRoot : : Get ( ) - > GetDefaultWorld ( ) ;
}
m_Player - > Initialize ( PlayerWorld ) ;
2011-11-10 11:30:14 -05:00
2012-02-03 09:33:40 -05:00
// Then we can start doing more stuffs! :D
m_bLoggedIn = true ;
LOG ( " Player \" %s \" completely logged in " , m_Username . c_str ( ) ) ;
StreamChunks ( ) ;
2011-11-10 11:30:14 -05:00
2012-02-03 09:33:40 -05:00
// Send position
m_ConfirmPosition = m_Player - > GetPosition ( ) ;
Send ( cPacket_PlayerMoveLook ( m_Player ) ) ;
}
2011-11-10 11:30:14 -05:00
2011-11-10 19:21:52 -05:00
2012-01-23 10:11:45 -05:00
2012-02-03 09:33:40 -05:00
void cClientHandle : : HandleDefaultLogin ( cPacket * a_Packet )
{
LOGWARNING (
" Invalid packet in login state: 0x%02x from client \" %s \" , username \" %s \" " ,
a_Packet - > m_PacketID ,
m_Socket . GetIPString ( ) . c_str ( ) ,
m_Username . c_str ( )
) ;
Kick ( " Hacked client " ) ; // Don't tell them why we don't like them
}
2011-12-31 23:55:17 -05:00
2011-11-10 11:30:14 -05:00
2011-12-31 23:55:17 -05:00
2011-12-28 16:00:35 -05:00
2012-02-03 09:33:40 -05:00
void cClientHandle : : HandleMoveLookConfirm ( cPacket_PlayerMoveLook * a_Packet )
{
Vector3d ReceivedPosition = Vector3d ( a_Packet - > m_PosX , a_Packet - > m_PosY , a_Packet - > m_PosZ ) ;
// Test the distance between points with a small/large enough value instead of comparing directly. Floating point inaccuracies might screw stuff up
double Dist = ( ReceivedPosition - m_ConfirmPosition ) . SqrLength ( ) ;
if ( Dist < 1.0 )
{
// Test
if ( ReceivedPosition . Equals ( m_ConfirmPosition ) )
{
LOGINFO ( " Exact position confirmed by client! " ) ;
}
m_bPositionConfirmed = true ;
}
else
{
LOGWARNING ( " Player \" %s \" sent a weird position confirmation %.2 blocks away, waiting for another confirmation " , m_Username . c_str ( ) , Dist ) ;
}
}
void cClientHandle : : HandleCreativeInventory ( cPacket_CreativeInventoryAction * a_Packet )
{
// This is for creative Inventory changes
if ( m_Player - > GetGameMode ( ) = = 1 )
{
m_Player - > GetInventory ( ) . Clicked ( a_Packet ) ;
}
else
{
LOGWARNING ( " Got a CreativeInventoryAction packet from user \" %s \" while not in creative mode. Ignoring. " , m_Username . c_str ( ) ) ;
}
}
void cClientHandle : : HandlePlayerPos ( 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 ( a_Packet - > m_PosX , a_Packet - > m_PosY , a_Packet - > m_PosZ ) ) ;
m_Player - > SetStance ( a_Packet - > m_Stance ) ;
m_Player - > SetTouchGround ( a_Packet - > m_bFlying ) ;
}
void cClientHandle : : HandleBlockDig ( cPacket_BlockDig * a_Packet )
{
if ( ! CheckBlockInteractionsRate ( ) )
{
return ;
}
LOG ( " OnBlockDig: %i %i %i Dir: %i Stat: %i " , a_Packet - > m_PosX , a_Packet - > m_PosY , a_Packet - > m_PosZ , a_Packet - > m_Direction , a_Packet - > m_Status ) ;
if ( a_Packet - > m_Status = = 0x04 ) // Drop block
{
m_Player - > TossItem ( false ) ;
return ;
}
cWorld * World = m_Player - > GetWorld ( ) ;
char OldBlock = World - > GetBlock ( a_Packet - > m_PosX , a_Packet - > m_PosY , a_Packet - > m_PosZ ) ;
char MetaData = World - > GetBlockMeta ( a_Packet - > m_PosX , a_Packet - > m_PosY , a_Packet - > m_PosZ ) ;
bool bBroken = (
( a_Packet - > m_Status = = 0x02 ) | |
( g_BlockOneHitDig [ ( int ) OldBlock ] ) | |
( ( a_Packet - > m_Status = = 0x00 ) & & ( m_Player - > GetGameMode ( ) = = 1 ) ) | |
( ( m_Player - > GetInventory ( ) . GetEquippedItem ( ) . m_ItemID = = E_ITEM_SHEARS ) & & ( OldBlock = = E_BLOCK_LEAVES ) )
) ;
if ( ( OldBlock = = E_BLOCK_WOODEN_DOOR ) & & ! bBroken )
{
cDoors : : ChangeDoor ( m_Player - > GetWorld ( ) , a_Packet - > m_PosX , a_Packet - > m_PosY , a_Packet - > m_PosZ ) ;
}
cItem PickupItem ;
if ( bBroken & & ! ( m_Player - > GetGameMode ( ) = = 1 ) ) // broken
{
ENUM_ITEM_ID PickupID = cBlockToPickup : : ToPickup ( ( ENUM_BLOCK_ID ) OldBlock , m_Player - > GetInventory ( ) . GetEquippedItem ( ) . m_ItemID ) ;
PickupItem . m_ItemID = PickupID ;
PickupItem . m_ItemHealth = MetaData ;
PickupItem . m_ItemCount = cBlockToPickup : : PickupCount ( OldBlock ) ;
if ( OldBlock = = E_BLOCK_LAPIS_ORE )
{
PickupItem . m_ItemHealth = 4 ;
}
if ( cDoors : : IsDoor ( OldBlock ) )
{
PickupItem . m_ItemHealth = 1 ; //For a complete door this works :D
}
}
if ( cRoot : : Get ( ) - > GetPluginManager ( ) - > CallHook ( cPluginManager : : E_PLUGIN_BLOCK_DIG , 2 , a_Packet , m_Player , & PickupItem ) )
{
World - > SendBlockTo ( a_Packet - > m_PosX , a_Packet - > m_PosY , a_Packet - > m_PosZ , m_Player ) ;
return ;
}
int pX = a_Packet - > m_PosX , pY = a_Packet - > m_PosY , pZ = a_Packet - > m_PosZ ;
AddDirection ( pX , ( char & ) pY , pZ , a_Packet - > m_Direction ) ;
char PossibleBlock = World - > GetBlock ( pX , pY , pZ ) ;
if ( PossibleBlock = = E_BLOCK_FIRE )
{
a_Packet - > m_PosX = pX ;
a_Packet - > m_PosY = ( char ) pY ;
a_Packet - > m_PosZ = pZ ;
bBroken = true ;
}
if ( ! bBroken )
{
return ;
}
if ( ! World - > DigBlock ( a_Packet - > m_PosX , a_Packet - > m_PosY , a_Packet - > m_PosZ , PickupItem ) )
{
return ;
}
if ( OldBlock = = E_BLOCK_REDSTONE_TORCH_ON )
{
cRedstone Redstone ( World ) ;
Redstone . ChangeRedstone ( a_Packet - > m_PosX , a_Packet - > m_PosY , a_Packet - > m_PosZ , false ) ;
}
if ( OldBlock = = E_BLOCK_REDSTONE_TORCH_OFF )
{
cRedstone Redstone ( World ) ;
Redstone . ChangeRedstone ( a_Packet - > m_PosX , a_Packet - > m_PosY , a_Packet - > m_PosZ , false ) ;
}
if ( OldBlock = = E_BLOCK_REDSTONE_WIRE )
{
cRedstone Redstone ( World ) ;
Redstone . ChangeRedstone ( a_Packet - > m_PosX , a_Packet - > m_PosY , a_Packet - > m_PosZ , false ) ;
}
if ( ( OldBlock = = E_BLOCK_PISTON ) | | ( OldBlock = = E_BLOCK_STICKY_PISTON ) )
{
int newX = a_Packet - > m_PosX ;
int newY = a_Packet - > m_PosY ;
int newZ = a_Packet - > 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 ) ;
}
}
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 ( a_Packet - > m_PosX , a_Packet - > m_PosY - 1 , a_Packet - > m_PosZ ) ) )
{
World - > SetBlock ( a_Packet - > m_PosX , a_Packet - > m_PosY - 1 , a_Packet - > m_PosZ , E_BLOCK_AIR , 0 ) ;
}
}
else
{
// Was lower part
if ( cDoors : : IsDoor ( World - > GetBlock ( a_Packet - > m_PosX , a_Packet - > m_PosY + 1 , a_Packet - > m_PosZ ) ) )
{
World - > SetBlock ( a_Packet - > m_PosX , a_Packet - > m_PosY + 1 , a_Packet - > m_PosZ , E_BLOCK_AIR , 0 ) ;
}
}
}
m_Player - > UseEquippedItem ( ) ;
}
void cClientHandle : : HandleBlockPlace ( cPacket_BlockPlace * a_Packet )
{
if ( ! CheckBlockInteractionsRate ( ) )
{
return ;
}
cItem & Equipped = m_Player - > GetInventory ( ) . GetEquippedItem ( ) ;
if ( ( Equipped . m_ItemID ! = a_Packet - > m_ItemType ) ) // Not valid
{
LOGWARN ( " Player %s tried to place a block that was not selected! (could indicate bot) " , m_Username . c_str ( ) ) ;
// TODO: We should probably send the current world block to the client, so that it can immediately "let the user know" that they haven't placed the block
return ;
}
if ( cRoot : : Get ( ) - > GetPluginManager ( ) - > CallHook ( cPluginManager : : E_PLUGIN_BLOCK_PLACE , 2 , a_Packet , m_Player ) )
{
if ( a_Packet - > m_Direction > - 1 )
{
AddDirection ( a_Packet - > m_PosX , a_Packet - > m_PosY , a_Packet - > m_PosZ , a_Packet - > m_Direction ) ;
m_Player - > GetWorld ( ) - > SendBlockTo ( a_Packet - > m_PosX , a_Packet - > m_PosY , a_Packet - > m_PosZ , m_Player ) ;
}
return ;
}
//LOG("%i %i %i %i %i %i", a_Packet->m_Count, a_Packet->m_Direction, a_Packet->m_ItemType, a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ);
//printf("Place Dir:%i %i %i %i : %i\n", a_Packet->m_Direction, a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ, a_Packet->m_ItemType);
// 'use' useable items instead of placing blocks
bool bPlaceBlock = true ;
bool UpdateRedstone = false ;
bool AddedCurrent = false ;
if ( a_Packet - > m_Direction > = 0 )
{
ENUM_BLOCK_ID BlockID = ( ENUM_BLOCK_ID ) m_Player - > GetWorld ( ) - > GetBlock ( a_Packet - > m_PosX , a_Packet - > m_PosY , a_Packet - > m_PosZ ) ;
switch ( BlockID )
{
case E_BLOCK_REDSTONE_REPEATER_ON :
case E_BLOCK_REDSTONE_REPEATER_OFF :
{
//no need to update redstone current with a repeater
//todo: Find meta value of repeater and change it to one step more.
}
break ;
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 ;
cBlockEntity * BlockEntity = m_Player - > GetWorld ( ) - > GetBlockEntity ( a_Packet - > m_PosX , a_Packet - > m_PosY , a_Packet - > m_PosZ ) ;
if ( BlockEntity )
{
BlockEntity - > UsedBy ( * m_Player ) ;
}
}
break ;
case E_BLOCK_WOODEN_DOOR :
{
bPlaceBlock = false ;
cDoors : : ChangeDoor ( m_Player - > GetWorld ( ) , a_Packet - > m_PosX , a_Packet - > m_PosY , a_Packet - > m_PosZ ) ;
}
break ;
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 ;
LOG ( " a_Packet->m_ItemType: %i " , ( int ) a_Packet - > m_ItemType ) ;
// Hacked in edible items go!~
// TODO: Handle hunger
bool bEat = false ;
bool isDoor = false ;
switch ( Item . m_ItemID )
{
case E_ITEM_APPLE :
//m_Player->Heal(4); // 2 hearts
m_Player - > Feed ( 24 ) ; // 2 food bars
bEat = true ;
break ;
case E_ITEM_GOLDEN_APPLE :
//m_Player->Heal(20); // 10 hearts
m_Player - > Feed ( 60 ) ; // 5 food
bEat = true ;
break ;
case E_ITEM_MUSHROOM_SOUP :
///m_Player->Heal(10); // 5 hearts
m_Player - > Feed ( 48 ) ; // 4 food
bEat = true ;
break ;
case E_ITEM_BREAD :
//m_Player->Heal(5); // 2.5 hearts
m_Player - > Feed ( 30 ) ; // 2.5 food
bEat = true ;
break ;
case E_ITEM_RAW_MEAT :
//m_Player->Heal(3); // 1.5 hearts
m_Player - > Feed ( 18 ) ; // 1.5 food
bEat = true ;
break ;
case E_ITEM_COOKED_MEAT :
//m_Player->Heal(8); // 4 hearts
m_Player - > Feed ( 48 ) ; // 4 food
bEat = true ;
break ;
case E_ITEM_RAW_FISH :
//m_Player->Heal(2); // 1 heart
m_Player - > Feed ( 12 ) ; // 1 food
bEat = true ;
break ;
case E_ITEM_COOKED_FISH :
//m_Player->Heal(5); // 2.5 hearts
m_Player - > Feed ( 30 ) ; // 2.5 food
bEat = true ;
break ;
case E_ITEM_RAW_CHICKEN :
//m_Player->Heal(3);
m_Player - > Feed ( 12 ) ; // 1 food
bEat = true ;
break ;
case E_ITEM_COOKED_CHICKEN :
//m_Player->Heal(8);
m_Player - > Feed ( 36 ) ; // 3 food
bEat = true ;
break ;
case E_ITEM_RAW_BEEF :
//m_Player->Heal(3);
m_Player - > Feed ( 18 ) ; // 1.5 food
bEat = true ;
break ;
case E_ITEM_STEAK :
//m_Player->Heal(8);
m_Player - > Feed ( 48 ) ; // 4 food
bEat = true ;
break ;
default :
break ;
} ;
if ( bEat )
{
m_Player - > GetInventory ( ) . RemoveItem ( Item ) ;
return ;
}
if ( a_Packet - > m_Direction < 0 )
{
// clicked in air
return ;
}
//TODO: Wrong Blocks!
int ClickedBlock = ( int ) m_Player - > GetWorld ( ) - > GetBlock ( a_Packet - > m_PosX , a_Packet - > m_PosY , a_Packet - > m_PosZ ) ;
char MetaData = ( char ) Equipped . m_ItemHealth ;
bool LavaBucket = false ;
bool WaterBucket = false ;
bool bRemoveItem = true ;
bool bIgnoreCollision = false ;
if ( ClickedBlock = = E_BLOCK_STEP )
{
if ( MetaData = = m_Player - > GetWorld ( ) - > GetBlockMeta ( a_Packet - > m_PosX , a_Packet - > m_PosY , a_Packet - > m_PosZ ) & & a_Packet - > m_Direction = = 1 ) //only make double slab if meta values are the same and if player clicked on top of the block (Dir = 1)
{
a_Packet - > m_ItemType = E_BLOCK_DOUBLE_STEP ;
a_Packet - > m_PosY - - ;
bIgnoreCollision = true ;
}
}
// Special handling for special items:
switch ( a_Packet - > m_ItemType )
{
case E_ITEM_BUCKET :
{
// 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
ClickedBlock = ( int ) m_Player - > GetWorld ( ) - > GetBlock ( a_Packet - > m_PosX , a_Packet - > m_PosY + 1 , a_Packet - > m_PosZ ) ;
LOG ( " Bucket Clicked BlockID: %d " , ClickedBlock ) ;
switch ( ClickedBlock )
{
case E_BLOCK_WATER :
case E_BLOCK_STATIONARY_WATER :
{
WaterBucket = true ;
break ;
}
case E_BLOCK_LAVA :
case E_BLOCK_STATIONARY_LAVA :
{
LavaBucket = true ;
break ;
2011-10-03 14:41:19 -04:00
}
}
2012-02-02 16:13:24 -05:00
break ;
2012-02-03 09:33:40 -05:00
} // case E_ITEM_BUCKET
2012-02-02 16:13:24 -05:00
2012-02-03 09:33:40 -05:00
case E_ITEM_LAVA_BUCKET :
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
if ( ( m_Player - > GetGameMode ( ) = = 1 ) | | ( m_Player - > GetInventory ( ) . RemoveItem ( Item ) ) )
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
a_Packet - > m_ItemType = E_BLOCK_LAVA ;
if ( m_Player - > GetGameMode ( ) = = 1 )
{
break ; //No new Bucket for creative players
}
cItem NewItem ;
NewItem . m_ItemID = E_ITEM_BUCKET ;
NewItem . m_ItemCount = 1 ;
m_Player - > GetInventory ( ) . AddItem ( NewItem ) ;
2011-10-03 14:41:19 -04:00
}
2012-02-02 16:13:24 -05:00
break ;
2012-02-03 09:33:40 -05:00
} // case E_ITEM_LAVA_BUCKET
2012-02-02 16:13:24 -05:00
2012-02-03 09:33:40 -05:00
case E_ITEM_WATER_BUCKET :
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
if ( ( m_Player - > GetGameMode ( ) = = 1 ) | | ( m_Player - > GetInventory ( ) . RemoveItem ( Item ) ) )
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
a_Packet - > m_ItemType = E_BLOCK_WATER ;
if ( m_Player - > GetGameMode ( ) = = 1 )
{
break ; //No new Bucket for creative players
}
cItem NewItem ;
NewItem . m_ItemID = E_ITEM_BUCKET ;
NewItem . m_ItemCount = 1 ;
m_Player - > GetInventory ( ) . AddItem ( NewItem ) ;
2011-10-03 14:41:19 -04:00
}
2012-02-02 16:13:24 -05:00
break ;
2012-02-03 09:33:40 -05:00
}
2012-02-02 16:13:24 -05:00
2012-02-03 09:33:40 -05:00
case E_BLOCK_TORCH :
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
MetaData = cTorch : : DirectionToMetaData ( a_Packet - > m_Direction ) ;
2012-02-02 16:13:24 -05:00
break ;
2012-02-03 09:33:40 -05:00
}
2012-02-02 16:13:24 -05:00
2012-02-03 09:33:40 -05:00
case E_BLOCK_REDSTONE_TORCH_OFF :
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
MetaData = cTorch : : DirectionToMetaData ( a_Packet - > m_Direction ) ;
if ( g_BlockTransparent [ ( int ) m_Player - > GetWorld ( ) - > GetBlock ( a_Packet - > m_PosX , a_Packet - > m_PosY + 2 , a_Packet - > m_PosZ ) ] = = true )
{
//if block above is transparent
//printf("transparent above me\n");
}
else
{
//printf("transparent not above me\n");
}
UpdateRedstone = true ;
AddedCurrent = false ;
2012-02-02 16:13:24 -05:00
break ;
2012-02-03 09:33:40 -05:00
}
2012-02-02 16:13:24 -05:00
2012-02-03 09:33:40 -05:00
case E_BLOCK_REDSTONE_TORCH_ON :
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
MetaData = cTorch : : DirectionToMetaData ( a_Packet - > m_Direction ) ;
UpdateRedstone = true ;
AddedCurrent = true ;
2012-02-02 16:13:24 -05:00
break ;
2012-02-03 09:33:40 -05:00
}
2012-02-02 16:13:24 -05:00
2012-02-03 09:33:40 -05:00
case E_ITEM_REDSTONE_DUST :
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
MetaData = 0 ;
a_Packet - > m_ItemType = E_BLOCK_REDSTONE_WIRE ;
UpdateRedstone = true ;
AddedCurrent = false ;
break ;
}
case E_ITEM_REDSTONE_REPEATER :
{
MetaData = cRedstone : : RepeaterRotationToMetaData ( m_Player - > GetRotation ( ) ) ;
a_Packet - > m_ItemType = E_BLOCK_REDSTONE_REPEATER_OFF ;
UpdateRedstone = true ;
AddedCurrent = false ;
break ;
}
2011-10-03 14:41:19 -04:00
2012-02-03 09:33:40 -05:00
case E_BLOCK_PISTON :
case E_BLOCK_STICKY_PISTON :
{
MetaData = cPiston : : RotationPitchToMetaData ( m_Player - > GetRotation ( ) , m_Player - > GetPitch ( ) ) ;
UpdateRedstone = true ;
AddedCurrent = false ;
break ;
}
case E_ITEM_IRON_DOOR :
{
a_Packet - > m_ItemType = E_BLOCK_IRON_DOOR ;
MetaData = cDoors : : RotationToMetaData ( m_Player - > GetRotation ( ) ) ;
isDoor = true ;
2012-02-02 16:13:24 -05:00
break ;
2012-02-03 09:33:40 -05:00
}
2012-02-02 16:13:24 -05:00
2012-02-03 09:33:40 -05:00
case E_ITEM_WOODEN_DOOR :
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
a_Packet - > m_ItemType = E_BLOCK_WOODEN_DOOR ;
MetaData = cDoors : : RotationToMetaData ( m_Player - > GetRotation ( ) ) ;
isDoor = true ;
2012-02-02 16:13:24 -05:00
break ;
2012-02-03 09:33:40 -05:00
}
2012-02-02 16:13:24 -05:00
2012-02-03 09:33:40 -05:00
case E_BLOCK_CHEST :
case E_BLOCK_FURNACE :
case E_BLOCK_DISPENSER :
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
MetaData = cPiston : : RotationPitchToMetaData ( m_Player - > GetRotation ( ) , 0 ) ; // Same orientation as pistons, just ignore pitch
break ;
}
case E_BLOCK_COBBLESTONE_STAIRS :
case E_BLOCK_BRICK_STAIRS :
case E_BLOCK_STONE_BRICK_STAIRS :
case E_BLOCK_NETHER_BRICK_STAIRS :
case E_BLOCK_WOODEN_STAIRS :
{
MetaData = cStairs : : RotationToMetaData ( m_Player - > GetRotation ( ) ) ;
break ;
}
case E_BLOCK_LADDER :
{
MetaData = cLadder : : DirectionToMetaData ( a_Packet - > m_Direction ) ;
break ;
}
case E_ITEM_SIGN :
{
LOG ( " Sign Dir: %i " , a_Packet - > m_Direction ) ;
if ( a_Packet - > m_Direction = = 1 )
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
LOG ( " Player Rotation: %f " , m_Player - > GetRotation ( ) ) ;
MetaData = cSign : : RotationToMetaData ( m_Player - > GetRotation ( ) ) ;
LOG ( " Sign rotation %i " , MetaData ) ;
a_Packet - > m_ItemType = E_BLOCK_SIGN_POST ;
2011-10-03 14:41:19 -04:00
}
else
{
2012-02-03 09:33:40 -05:00
MetaData = cSign : : DirectionToMetaData ( a_Packet - > m_Direction ) ;
a_Packet - > m_ItemType = E_BLOCK_WALLSIGN ;
2011-10-03 14:41:19 -04:00
}
2012-02-02 16:13:24 -05:00
break ;
2012-02-03 09:33:40 -05:00
}
case E_ITEM_FLINT_AND_STEEL :
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
a_Packet - > m_ItemType = E_ITEM_FIRE ;
m_Player - > UseEquippedItem ( ) ;
bRemoveItem = false ;
2012-02-02 16:13:24 -05:00
break ;
2012-02-03 09:33:40 -05:00
}
default :
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
break ;
}
} // switch (a_Packet->m_ItemType)
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 ) ;
m_Player - > GetWorld ( ) - > SetBlock ( a_Packet - > m_PosX , a_Packet - > m_PosY + 1 , a_Packet - > m_PosZ , E_BLOCK_AIR , 0 ) ;
}
}
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 ) ;
m_Player - > GetWorld ( ) - > SetBlock ( a_Packet - > m_PosX , a_Packet - > m_PosY + 1 , a_Packet - > m_PosZ , E_BLOCK_AIR , 0 ) ;
}
}
else if ( IsValidBlock ( a_Packet - > m_ItemType ) )
{
int X = a_Packet - > m_PosX ;
char Y = a_Packet - > m_PosY ;
int Z = a_Packet - > m_PosZ ;
AddDirection ( X , Y , Z , a_Packet - > m_Direction ) ;
int PlaceBlock = m_Player - > GetWorld ( ) - > GetBlock ( X , Y , Z ) ;
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?
return ; // happens when you place a block aiming at side of block like torch or stem
}
// 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 ( a_Packet - > m_ItemType )
{
case E_BLOCK_YELLOW_FLOWER : // Can ONLY be placed on dirt/grass
case E_BLOCK_RED_ROSE :
case E_BLOCK_SAPLING :
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
switch ( SurfaceBlock )
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
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 ;
}
2011-10-03 14:41:19 -04:00
}
2012-02-03 09:33:40 -05:00
break ;
2011-10-03 14:41:19 -04:00
}
2012-02-03 09:33:40 -05:00
case E_BLOCK_CACTUS :
{
bIllegalSurface = ( SurfaceBlock ! = E_BLOCK_SAND ) & & ( SurfaceBlock ! = E_BLOCK_CACTUS ) ; // Cactus can only be placed on sand and itself
// 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 ;
}
} // switch (a_Packet->m_ItemType)
if ( bIllegalSurface )
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
return ;
}
if ( bRemoveItem )
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
if ( ( m_Player - > GetGameMode ( ) ! = 1 ) & & ! m_Player - > GetInventory ( ) . RemoveItem ( Item ) )
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
return ;
2011-10-03 14:41:19 -04:00
}
2012-02-03 09:33:40 -05:00
}
if ( isDoor )
2011-12-27 13:39:06 -05:00
{
2012-02-03 09:33:40 -05:00
if ( ( m_Player - > GetWorld ( ) - > GetBlock ( X , Y + 1 , Z ) = = E_BLOCK_AIR ) | | ( m_Player - > GetWorld ( ) - > GetBlock ( X , Y + 1 , Z ) = = E_BLOCK_AIR ) )
2011-12-27 13:39:06 -05:00
{
2012-02-03 09:33:40 -05:00
m_Player - > GetWorld ( ) - > SetBlock ( X , Y + 1 , Z , ( char ) a_Packet - > m_ItemType , MetaData + 8 ) ;
m_Player - > GetWorld ( ) - > SetBlock ( X , Y , Z , ( char ) a_Packet - > m_ItemType , MetaData ) ;
2011-12-27 13:39:06 -05:00
}
2012-02-03 09:33:40 -05:00
}
else
{
m_Player - > GetWorld ( ) - > SetBlock ( X , Y , Z , ( char ) a_Packet - > m_ItemType , MetaData ) ;
}
if ( UpdateRedstone )
{
cRedstone Redstone ( m_Player - > GetWorld ( ) ) ;
Redstone . ChangeRedstone ( a_Packet - > m_PosX , a_Packet - > m_PosY + 1 , a_Packet - > m_PosZ , AddedCurrent ) ;
}
}
}
/*
// FakeTruth's "magic stick of removal" :D
// TODO: Turn this into a plugin
if ( m_Username . compare ( " FakeTruth " ) = = 0 )
{
if ( a_Packet - > m_ItemType = = 280 )
{
cRoot : : Get ( ) - > GetWorld ( ) - > SetBlock ( a_Packet - > m_PosX , a_Packet - > m_PosY , a_Packet - > m_PosZ , 0 , 0 ) ;
}
}
*/
}
void cClientHandle : : HandlePickupSpawn ( cPacket_PickupSpawn * a_Packet )
{
LOG ( " Received packet E_PICKUP_SPAWN " ) ;
cItem DroppedItem ;
DroppedItem . m_ItemID = ( ENUM_ITEM_ID ) a_Packet - > m_Item ;
DroppedItem . m_ItemCount = a_Packet - > 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 ( a_Packet ) ;
Pickup - > Initialize ( m_Player - > GetWorld ( ) ) ;
}
}
void cClientHandle : : HandleChat ( cPacket_Chat * a_Packet )
{
if ( ! cRoot : : Get ( ) - > GetServer ( ) - > Command ( * this , a_Packet - > m_Message . c_str ( ) ) )
{
a_Packet - > m_Message . insert ( 0 , " < " + m_Player - > GetColor ( ) + m_Username + cChatColor : : White + " > " ) ;
cRoot : : Get ( ) - > GetServer ( ) - > Broadcast ( * a_Packet ) ;
}
}
void cClientHandle : : HandlePlayerLook ( cPacket_PlayerLook * a_Packet )
{
m_Player - > SetRotation ( a_Packet - > m_Rotation ) ;
m_Player - > SetPitch ( a_Packet - > m_Pitch ) ;
m_Player - > SetTouchGround ( a_Packet - > m_bFlying ) ;
m_Player - > WrapRotation ( ) ;
}
void cClientHandle : : HandlePlayerMoveLook ( cPacket_PlayerMoveLook * a_Packet )
{
m_Player - > MoveTo ( Vector3d ( a_Packet - > m_PosX , a_Packet - > m_PosY , a_Packet - > m_PosZ ) ) ;
m_Player - > SetStance ( a_Packet - > m_Stance ) ;
m_Player - > SetTouchGround ( a_Packet - > m_bFlying ) ;
m_Player - > SetRotation ( a_Packet - > m_Rotation ) ;
m_Player - > SetPitch ( a_Packet - > m_Pitch ) ;
m_Player - > WrapRotation ( ) ;
}
void cClientHandle : : HandleAnimation ( cPacket_ArmAnim * a_Packet )
{
a_Packet - > m_EntityID = m_Player - > GetUniqueID ( ) ;
cRoot : : Get ( ) - > GetServer ( ) - > Broadcast ( * a_Packet , this ) ;
}
void cClientHandle : : HandleItemSwitch ( cPacket_ItemSwitch * a_Packet )
{
m_Player - > GetInventory ( ) . SetEquippedSlot ( a_Packet - > 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 ) ;
}
void cClientHandle : : HandleWindowClose ( cPacket_WindowClose * a_Packet )
{
m_Player - > CloseWindow ( a_Packet - > m_Close ) ;
}
void cClientHandle : : HandleWindowClick ( cPacket_WindowClick * a_Packet )
{
if ( a_Packet - > m_WindowID = = 0 )
{
m_Player - > GetInventory ( ) . Clicked ( a_Packet ) ;
return ;
}
cWindow * Window = m_Player - > GetWindow ( ) ;
if ( Window = = NULL )
{
LOGWARNING ( " Player \" %s \" clicked in a non-existent window. Ignoring " , m_Username . c_str ( ) ) ;
return ;
}
Window - > Clicked ( a_Packet , * m_Player ) ;
}
void cClientHandle : : HandleUpdateSign ( cPacket_UpdateSign * a_Packet )
{
cWorld * World = m_Player - > GetWorld ( ) ;
cChunk * Chunk = World - > GetChunkOfBlock ( a_Packet - > m_PosX , a_Packet - > m_PosY , a_Packet - > m_PosZ ) ;
cBlockEntity * BlockEntity = Chunk - > GetBlockEntity ( a_Packet - > m_PosX , a_Packet - > m_PosY , a_Packet - > m_PosZ ) ;
if ( ( BlockEntity ! = NULL ) & & ( ( BlockEntity - > GetBlockType ( ) = = E_BLOCK_SIGN_POST ) | | ( BlockEntity - > GetBlockType ( ) = = E_BLOCK_WALLSIGN ) ) )
{
cSignEntity * Sign = reinterpret_cast < cSignEntity * > ( BlockEntity ) ;
Sign - > SetLines ( a_Packet - > m_Line1 , a_Packet - > m_Line2 , a_Packet - > m_Line3 , a_Packet - > m_Line4 ) ;
Sign - > SendTo ( NULL ) ; // Broadcast to all players in chunk
}
}
void cClientHandle : : HandleUseEntity ( cPacket_UseEntity * a_Packet )
{
if ( ! a_Packet - > m_bLeftClick )
{
return ;
}
cWorld * World = m_Player - > GetWorld ( ) ;
cEntity * Entity = World - > GetEntity ( a_Packet - > m_TargetID ) ;
if ( ( Entity ! = NULL ) & & Entity - > IsA ( " cPawn " ) )
{
cPawn * Pawn = ( cPawn * ) Entity ;
Pawn - > TakeDamage ( 1 , m_Player ) ;
}
}
void cClientHandle : : HandleRespawn ( void )
{
m_Player - > Respawn ( ) ;
}
void cClientHandle : : HandleDisconnect ( cPacket_Disconnect * a_Packet )
{
LOG ( " Received d/c packet from \" %s \" " , m_Username . c_str ( ) ) ;
if ( ! cRoot : : Get ( ) - > GetPluginManager ( ) - > CallHook ( cPluginManager : : E_PLUGIN_DISCONNECT , 2 , a_Packet - > m_Reason . c_str ( ) , m_Player ) )
{
cPacket_Chat DisconnectMessage ( m_Username + " disconnected: " + a_Packet - > m_Reason ) ;
cRoot : : Get ( ) - > GetServer ( ) - > Broadcast ( DisconnectMessage ) ;
}
Destroy ( ) ;
}
void cClientHandle : : HandleKeepAlive ( cPacket_KeepAlive * a_Packet )
{
if ( a_Packet - > m_KeepAliveID = = m_PingID )
{
cTimer t1 ;
m_Ping = ( short ) ( ( t1 . GetNowTime ( ) - m_PingStartTime ) / 2 ) ;
}
}
bool cClientHandle : : CheckBlockInteractionsRate ( void )
{
int LastActionCnt = m_Player - > GetLastBlockActionCnt ( ) ;
if ( ( cRoot : : Get ( ) - > GetWorld ( ) - > GetTime ( ) - m_Player - > GetLastBlockActionTime ( ) ) < 0.1 )
{
// Limit the number of block interactions per tick
m_Player - > SetLastBlockActionTime ( ) ; //Player tried to interact with a block. Reset last block interation time.
m_Player - > SetLastBlockActionCnt ( LastActionCnt + 1 ) ;
if ( m_Player - > GetLastBlockActionCnt ( ) > MAXBLOCKCHANGEINTERACTIONS )
{
// Kick if more than MAXBLOCKCHANGEINTERACTIONS per tick
LOGWARN ( " Player %s tried to interact with a block too quickly! (could indicate bot) Was Kicked. " , m_Username . c_str ( ) ) ;
Kick ( " You're a baaaaaad boy! " ) ;
return false ;
}
}
else
{
m_Player - > SetLastBlockActionCnt ( 0 ) ; // Reset count
m_Player - > SetLastBlockActionTime ( ) ; // Player tried to interact with a block. Reset last block interation time.
}
return true ;
2011-10-03 14:41:19 -04:00
}
2012-01-31 13:06:24 -05:00
2011-10-03 14:41:19 -04:00
void cClientHandle : : Tick ( float a_Dt )
{
( void ) a_Dt ;
2012-02-02 16:13:24 -05:00
if ( cWorld : : GetTime ( ) - m_TimeLastPacket > 30.f ) // 30 seconds time-out
2011-10-03 14:41:19 -04:00
{
cPacket_Disconnect DC ( " Nooooo!! You timed out! D: Come back! " ) ;
2012-02-07 15:49:52 -05:00
m_Socket . Send ( & DC ) ;
2011-10-03 14:41:19 -04:00
2012-02-02 16:13:24 -05:00
cSleep : : MilliSleep ( 1000 ) ; // Give packet some time to be received
2011-10-03 14:41:19 -04:00
Destroy ( ) ;
}
2011-12-27 13:39:06 -05:00
cTimer t1 ;
// Send ping packet
2012-02-02 16:13:24 -05:00
if ( m_LastPingTime + cClientHandle : : PING_TIME_MS < = t1 . GetNowTime ( ) )
{
// TODO: why a random ping ID, can't we just use normal ascending numbers?
2011-12-27 13:39:06 -05:00
MTRand r1 ;
m_PingID = r1 . randInt ( ) ;
cPacket_KeepAlive Ping ( m_PingID ) ;
m_PingStartTime = t1 . GetNowTime ( ) ;
Send ( Ping ) ;
m_LastPingTime = m_PingStartTime ;
}
2011-11-01 17:57:08 -04:00
2012-02-02 16:13:24 -05:00
if ( m_bSendLoginResponse )
2011-11-01 17:57:08 -04:00
{
m_bSendLoginResponse = false ;
// Spawn player (only serversided, so data is loaded)
2012-02-03 09:33:40 -05:00
m_Player = new cPlayer ( this , GetUsername ( ) ) ; // !!DO NOT INITIALIZE!! <- is done after receiving MoveLook Packet
2011-11-02 16:19:57 -04:00
2012-02-03 09:33:40 -05:00
cWorld * World = cRoot : : Get ( ) - > GetWorld ( m_Player - > GetLoadedWorldName ( ) ) ;
if ( ! World ) World = cRoot : : Get ( ) - > GetDefaultWorld ( ) ;
2011-11-02 16:19:57 -04:00
World - > LockEntities ( ) ;
2012-02-03 09:33:40 -05: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 17:57:08 -04:00
2012-02-03 09:33:40 -05:00
m_Player - > SetIP ( m_Socket . GetIPString ( ) ) ;
2011-11-09 17:17:30 -05:00
2012-02-03 09:33:40 -05:00
cRoot : : Get ( ) - > GetPluginManager ( ) - > CallHook ( cPluginManager : : E_PLUGIN_PLAYER_SPAWN , 1 , m_Player ) ;
2011-11-01 17:57:08 -04:00
// Return a server login packet
cPacket_Login LoginResponse ;
LoginResponse . m_ProtocolVersion = m_Player - > GetUniqueID ( ) ;
//LoginResponse.m_Username = "";
2011-11-01 18:19:21 -04:00
LoginResponse . m_ServerMode = m_Player - > GetGameMode ( ) ; //set gamemode from player.
2011-12-26 04:09:47 -05:00
LoginResponse . m_MapSeed = cRoot : : Get ( ) - > GetWorld ( ) - > GetWorldSeed ( ) ;
2011-11-01 17:57:08 -04:00
LoginResponse . m_Dimension = 0 ;
2011-12-25 08:44:22 -05:00
LoginResponse . m_MaxPlayers = ( unsigned char ) cRoot : : Get ( ) - > GetWorld ( ) - > GetMaxPlayers ( ) ;
2011-12-26 04:09:47 -05:00
LoginResponse . m_Difficulty = 2 ;
2012-02-03 09:33:40 -05:00
Send ( LoginResponse ) ;
2011-11-01 17:57:08 -04:00
2011-11-09 18:24:51 -05:00
// Send Weather if raining:
2012-02-03 09:33:40 -05:00
if ( ( World - > GetWeather ( ) = = 1 ) | | ( World - > GetWeather ( ) = = 2 ) ) {
2011-11-09 18:24:51 -05:00
cPacket_NewInvalidState RainPacket ;
RainPacket . m_Reason = 1 ; //begin rain
2012-02-03 09:33:40 -05:00
Send ( RainPacket ) ;
2011-11-09 18:24:51 -05:00
}
2011-11-01 17:57:08 -04:00
// Send time
2012-02-03 09:33:40 -05:00
Send ( cPacket_TimeUpdate ( World - > GetWorldTime ( ) ) ) ;
2011-11-01 17:57:08 -04:00
// Send inventory
2012-02-03 09:33:40 -05:00
m_Player - > GetInventory ( ) . SendWholeInventory ( this ) ;
2011-11-01 17:57:08 -04:00
// Send health
2011-12-29 10:31:48 -05: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 18:27:09 -04:00
2011-11-01 17:57:08 -04:00
World - > UnlockEntities ( ) ;
}
2011-10-03 14:41:19 -04:00
}
2012-01-31 13:06:24 -05:00
2012-02-03 09:33:40 -05:00
void cClientHandle : : Send ( const cPacket & a_Packet , ENUM_PRIORITY a_Priority /* = E_PRIORITY_NORMAL */ )
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
if ( m_bKicking ) return ; // Don't add more packets if player is getting kicked anyway
2011-10-03 14:41:19 -04:00
bool bSignalSemaphore = true ;
2012-02-03 09:33:40 -05:00
cCSLock Lock ( m_SendCriticalSection ) ;
2012-02-02 16:13:24 -05:00
if ( a_Priority = = E_PRIORITY_NORMAL )
2011-10-03 14:41:19 -04:00
{
2012-02-02 16:13:24 -05:00
if ( a_Packet . m_PacketID = = E_REL_ENT_MOVE_LOOK )
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
PacketList & Packets = m_PendingNrmSendPackets ;
2012-02-02 16:13:24 -05:00
for ( PacketList : : iterator itr = Packets . begin ( ) ; itr ! = Packets . end ( ) ; + + itr )
2011-10-03 14:41:19 -04:00
{
bool bBreak = false ;
2012-02-02 16:13:24 -05:00
switch ( ( * itr ) - > m_PacketID )
2011-10-03 14:41:19 -04:00
{
2012-02-02 16:13:24 -05:00
case E_REL_ENT_MOVE_LOOK :
2011-10-03 14:41:19 -04:00
{
const cPacket_RelativeEntityMoveLook * ThisPacketData = reinterpret_cast < const cPacket_RelativeEntityMoveLook * > ( & a_Packet ) ;
cPacket_RelativeEntityMoveLook * PacketData = reinterpret_cast < cPacket_RelativeEntityMoveLook * > ( * itr ) ;
2012-02-03 09:33:40 -05:00
if ( ThisPacketData - > m_UniqueID = = PacketData - > m_UniqueID )
2011-10-03 14:41:19 -04:00
{
//LOGINFO("Optimized by removing double packet");
2012-02-03 09:33:40 -05:00
Packets . erase ( itr ) ;
2011-10-03 14:41:19 -04:00
bBreak = true ;
bSignalSemaphore = false ; // Because 1 packet is removed, semaphore count is the same
2011-10-26 19:18:31 -04:00
delete PacketData ;
2011-10-03 14:41:19 -04:00
break ;
}
2012-02-02 16:13:24 -05:00
break ;
} // case E_REL_END_MOVE_LOOK
} // switch (*itr -> Packet type)
if ( bBreak )
{
2011-10-03 14:41:19 -04:00
break ;
}
2012-02-02 16:13:24 -05:00
} // for itr - Packets[]
} // if (E_REL_ENT_MOVE_LOOK
2012-02-03 09:33:40 -05:00
m_PendingNrmSendPackets . push_back ( a_Packet . Clone ( ) ) ;
2012-02-02 16:13:24 -05:00
}
2012-02-03 09:33:40 -05:00
else if ( a_Priority = = E_PRIORITY_LOW )
2012-02-02 16:13:24 -05:00
{
2012-02-03 09:33:40 -05:00
m_PendingLowSendPackets . push_back ( a_Packet . Clone ( ) ) ;
2012-02-02 16:13:24 -05:00
}
Lock . Unlock ( ) ;
if ( bSignalSemaphore )
{
2012-02-03 09:33:40 -05:00
m_Semaphore . Signal ( ) ;
2011-10-03 14:41:19 -04:00
}
}
2012-01-31 13:06:24 -05:00
2012-02-03 09:33:40 -05:00
void cClientHandle : : SendThread ( void * lpParam )
2011-10-03 14:41:19 -04:00
{
cClientHandle * self = ( cClientHandle * ) lpParam ;
2012-02-03 09:33:40 -05:00
PacketList & NrmSendPackets = self - > m_PendingNrmSendPackets ;
PacketList & LowSendPackets = self - > m_PendingLowSendPackets ;
2011-10-03 14:41:19 -04:00
2012-02-03 09:33:40 -05:00
while ( self - > m_bKeepThreadGoing & & self - > m_Socket . IsValid ( ) )
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
self - > m_Semaphore . Wait ( ) ;
cCSLock Lock ( self - > m_SendCriticalSection ) ;
2012-02-02 16:13:24 -05:00
if ( NrmSendPackets . size ( ) + LowSendPackets . size ( ) > MAX_SEMAPHORES )
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
LOGERROR ( " ERROR: Too many packets in queue for player %s !! " , self - > m_Username . c_str ( ) ) ;
2011-10-03 14:41:19 -04:00
cPacket_Disconnect DC ( " Too many packets in queue. " ) ;
2012-02-07 15:49:52 -05:00
self - > m_Socket . Send ( DC ) ;
2011-10-03 14:41:19 -04:00
2012-02-03 09:33:40 -05:00
cSleep : : MilliSleep ( 1000 ) ; // Give packet some time to be received
2011-10-03 14:41:19 -04:00
2012-02-02 16:13:24 -05:00
Lock . Unlock ( ) ;
2011-10-03 14:41:19 -04:00
self - > Destroy ( ) ;
break ;
}
2012-02-02 16:13:24 -05:00
if ( NrmSendPackets . size ( ) = = 0 & & LowSendPackets . size ( ) = = 0 )
2011-10-03 14:41:19 -04:00
{
2012-02-02 16:13:24 -05:00
assert ( ! self - > m_bKeepThreadGoing ) ;
if ( self - > m_bKeepThreadGoing )
{
LOGERROR ( " ERROR: Semaphore was signaled while no packets to send " ) ;
}
2011-10-03 14:41:19 -04:00
continue ;
}
2012-02-02 16:13:24 -05:00
if ( NrmSendPackets . size ( ) > MAX_SEMAPHORES / 2 )
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
LOGINFO ( " Pending packets: %i Last: 0x%02x " , NrmSendPackets . size ( ) , ( * NrmSendPackets . rbegin ( ) ) - > m_PacketID ) ;
2011-10-03 14:41:19 -04:00
}
2012-02-02 16:13:24 -05:00
cPacket * Packet = NULL ;
if ( ! NrmSendPackets . empty ( ) )
2011-10-03 14:41:19 -04:00
{
Packet = * NrmSendPackets . begin ( ) ;
2012-02-03 09:33:40 -05:00
NrmSendPackets . erase ( NrmSendPackets . begin ( ) ) ;
2011-10-03 14:41:19 -04:00
}
2012-02-02 16:13:24 -05:00
else if ( ! LowSendPackets . empty ( ) )
2011-10-03 14:41:19 -04:00
{
Packet = * LowSendPackets . begin ( ) ;
2012-02-03 09:33:40 -05:00
LowSendPackets . erase ( LowSendPackets . begin ( ) ) ;
2011-10-03 14:41:19 -04:00
}
2012-02-02 16:13:24 -05:00
Lock . Unlock ( ) ;
2011-10-03 14:41:19 -04:00
2012-02-03 09:33:40 -05:00
if ( ! self - > m_Socket . IsValid ( ) )
2011-10-03 14:41:19 -04:00
{
break ;
}
2012-02-07 15:49:52 -05:00
bool bSuccess = self - > m_Socket . Send ( Packet ) ;
2012-02-02 16:13:24 -05:00
if ( ! bSuccess )
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
LOGERROR ( " ERROR: While sending packet 0x%02x to client \" %s \" " , Packet - > m_PacketID , self - > m_Username . c_str ( ) ) ;
2011-10-03 14:41:19 -04:00
delete Packet ;
self - > Destroy ( ) ;
break ;
}
delete Packet ;
2012-02-03 09:33:40 -05:00
if ( self - > m_bKicking & & ( NrmSendPackets . size ( ) + LowSendPackets . size ( ) = = 0 ) ) // Disconnect player after all packets have been sent
2011-10-03 14:41:19 -04:00
{
2012-02-03 09:33:40 -05:00
cSleep : : MilliSleep ( 1000 ) ; // Give all packets some time to be received
2011-10-03 14:41:19 -04:00
self - > Destroy ( ) ;
break ;
}
}
return ;
}
2012-01-31 13:06:24 -05:00
2011-10-03 14:41:19 -04:00
2012-02-08 05:02:46 -05:00
const AString & cClientHandle : : GetUsername ( void ) const
2011-10-03 14:41:19 -04:00
{
2012-02-08 05:02:46 -05:00
return m_Username ;
}
2011-10-03 14:41:19 -04:00
2012-02-08 05:02:46 -05:00
void cClientHandle : : DataReceived ( const char * a_Data , int a_Size )
{
// Data is received from the client
m_ReceivedData . append ( a_Data , a_Size ) ;
// Parse and handle all complete packets in m_ReceivedData:
while ( ! m_ReceivedData . empty ( ) )
2011-10-03 14:41:19 -04:00
{
2012-02-08 05:02:46 -05:00
cPacket * pPacket = m_PacketMap [ ( unsigned char ) m_ReceivedData [ 0 ] ] ;
if ( pPacket = = NULL )
{
LOGERROR ( " Unknown packet type 0x%02x from client \" %s \" " , ( unsigned char ) m_ReceivedData [ 0 ] , m_Username . c_str ( ) ) ;
AString Reason ;
Printf ( Reason , " [C->S] Unknown PacketID: 0x%02x " , m_ReceivedData [ 0 ] ) ;
cPacket_Disconnect DC ( Reason ) ;
m_Socket . Send ( & DC ) ;
cSleep : : MilliSleep ( 1000 ) ; // Give packet some time to be received
Destroy ( ) ;
return ;
}
int NumBytes = pPacket - > Parse ( m_ReceivedData . data ( ) + 1 , m_ReceivedData . size ( ) - 1 ) ;
if ( NumBytes = = PACKET_ERROR )
2011-10-03 14:41:19 -04:00
{
2012-02-08 05:02:46 -05:00
LOGERROR ( " Protocol error while parsing packet type 0x%02x; disconnecting client \" %s \" " , ( unsigned char ) m_ReceivedData [ 0 ] , m_Username . c_str ( ) ) ;
cPacket_Disconnect DC ( " Protocol error " ) ;
m_Socket . Send ( & DC ) ;
cSleep : : MilliSleep ( 1000 ) ; // Give packet some time to be received
Destroy ( ) ;
return ;
}
else if ( NumBytes = = PACKET_INCOMPLETE )
{
// Not a complete packet
2011-10-03 14:41:19 -04:00
break ;
}
2012-02-08 05:02:46 -05:00
else
2011-10-03 14:41:19 -04:00
{
2012-02-08 05:02:46 -05:00
// Packet parsed successfully, add it to internal queue:
HandlePacket ( pPacket ) ;
// Erase the packet from the buffer:
assert ( m_ReceivedData . size ( ) > ( size_t ) NumBytes ) ;
m_ReceivedData . erase ( 0 , NumBytes + 1 ) ;
}
} // while (!Received.empty())
2011-10-03 14:41:19 -04:00
}
2012-01-31 13:06:24 -05:00
2012-02-08 05:02:46 -05:00
void cClientHandle : : GetOutgoingData ( AString & a_Data )
2011-10-03 14:41:19 -04:00
{
2012-02-08 05:02:46 -05:00
// Data can be sent to client
// TODO
2011-10-03 14:41:19 -04:00
}
2012-01-31 13:06:24 -05:00
2012-02-08 05:02:46 -05:00
void cClientHandle : : SocketClosed ( void )
2011-10-03 14:41:19 -04:00
{
2012-02-08 05:02:46 -05:00
// The socket has been closed for any reason
// TODO
/*
self - > Destroy ( ) ;
LOG ( " Client \" %s \" disconnected " , GetLogName ( ) . c_str ( ) ) ;
*/
2011-10-25 23:22:43 -04:00
}
2012-01-31 13:06:24 -05:00