2014-09-01 14:12:56 -04:00
2013-10-30 18:24:46 -04:00
// Protocol17x.cpp
/*
Implements the 1.7 . x protocol classes :
- cProtocol172
- release 1.7 .2 protocol ( # 4 )
2014-09-03 18:29:36 -04:00
- cProtocol176
- release 1.7 .6 protocol ( # 5 )
2013-10-30 18:24:46 -04:00
*/
# include "Globals.h"
2014-02-15 17:16:44 -05:00
# include "json/json.h"
2013-10-30 18:24:46 -04:00
# include "Protocol17x.h"
2013-11-04 15:20:36 -05:00
# include "ChunkDataSerializer.h"
2014-05-11 07:57:06 -04:00
# include "PolarSSL++/Sha1Checksum.h"
2013-10-30 18:24:46 -04:00
# include "../ClientHandle.h"
# include "../Root.h"
# include "../Server.h"
2013-11-01 11:20:15 -04:00
# include "../World.h"
2014-05-11 07:57:06 -04:00
# include "../StringCompression.h"
# include "../CompositeChat.h"
# include "../Statistics.h"
2013-11-03 05:58:49 -05:00
# include "../WorldStorage/FastNBT.h"
2014-01-19 10:38:59 -05:00
# include "../WorldStorage/EnchantmentSerializer.h"
2014-05-11 07:57:06 -04:00
2013-11-25 14:04:01 -05:00
# include "../Entities/ExpOrb.h"
2013-11-10 15:48:12 -05:00
# include "../Entities/Minecart.h"
2013-11-04 15:20:36 -05:00
# include "../Entities/FallingBlock.h"
2014-02-17 19:16:03 -05:00
# include "../Entities/Painting.h"
2013-11-04 15:20:36 -05:00
# include "../Entities/Pickup.h"
# include "../Entities/Player.h"
2014-02-17 18:00:03 -05:00
# include "../Entities/ItemFrame.h"
2014-05-11 07:57:06 -04:00
# include "../Entities/ArrowEntity.h"
# include "../Entities/FireworkEntity.h"
2013-11-08 14:56:19 -05:00
# include "../Mobs/IncludeAllMonsters.h"
2013-11-06 06:16:44 -05:00
# include "../UI/Window.h"
2014-05-11 07:57:06 -04:00
2014-07-30 15:59:35 -04:00
# include "../BlockEntities/BeaconEntity.h"
2014-01-19 08:25:35 -05:00
# include "../BlockEntities/CommandBlockEntity.h"
2014-02-19 08:45:09 -05:00
# include "../BlockEntities/MobHeadEntity.h"
2014-03-06 19:30:34 -05:00
# include "../BlockEntities/FlowerPotEntity.h"
2014-08-20 10:01:30 -04:00
# include "Bindings/PluginManager.h"
2013-10-31 18:48:43 -04:00
2013-12-13 11:53:00 -05:00
# define HANDLE_READ(ByteBuf, Proc, Type, Var) \
2013-10-31 18:48:43 -04:00
Type Var ; \
cProtocol172: Check return values.
Fixes CID 43489, CID 43490, CID 43491, CID 43493, CID 66410, CID 66411, CID 66416, CID 66417, CID 66418, CID 66419, CID 66420, CID 66421, CID 66422, CID 66423, CID 66424, CID 66425, CID 66429, CID 66430, CID 66431
2014-08-11 09:33:20 -04:00
if ( ! ByteBuf . Proc ( Var ) ) \
{ \
return ; \
}
2013-10-30 18:24:46 -04:00
2013-12-13 11:53:00 -05:00
# define HANDLE_PACKET_READ(ByteBuf, Proc, Type, Var) \
2013-11-06 14:48:35 -05:00
Type Var ; \
{ \
2013-12-13 11:53:00 -05:00
if ( ! ByteBuf . Proc ( Var ) ) \
2013-11-06 14:48:35 -05:00
{ \
2013-12-13 11:53:00 -05:00
ByteBuf . CheckValid ( ) ; \
2013-11-06 14:48:35 -05:00
return false ; \
} \
2013-12-13 11:53:00 -05:00
ByteBuf . CheckValid ( ) ; \
2013-11-06 14:48:35 -05:00
}
2014-01-28 17:53:07 -05:00
const int MAX_ENC_LEN = 512 ; // Maximum size of the encrypted message; should be 128, but who knows...
2014-01-24 17:03:48 -05:00
// fwd: main.cpp:
2014-01-26 11:54:18 -05:00
extern bool g_ShouldLogCommIn , g_ShouldLogCommOut ;
2014-01-24 17:03:48 -05:00
2014-07-17 16:15:34 -04:00
////////////////////////////////////////////////////////////////////////////////
2014-01-24 17:03:48 -05:00
// cProtocol172:
2013-10-30 18:24:46 -04:00
cProtocol172 : : cProtocol172 ( cClientHandle * a_Client , const AString & a_ServerAddress , UInt16 a_ServerPort , UInt32 a_State ) :
super ( a_Client ) ,
m_ServerAddress ( a_ServerAddress ) ,
m_ServerPort ( a_ServerPort ) ,
m_State ( a_State ) ,
m_ReceivedData ( 32 KiB ) ,
2013-11-03 05:58:49 -05:00
m_OutPacketBuffer ( 64 KiB ) ,
m_OutPacketLenBuffer ( 20 ) , // 20 bytes is more than enough for one VarInt
2014-06-08 15:58:08 -04:00
m_IsEncrypted ( false ) ,
m_LastSentDimension ( dimNotSet )
2013-10-30 18:24:46 -04:00
{
2014-09-17 03:38:06 -04:00
// BungeeCord handling:
// If BC is setup with ip_forward == true, it sends additional data in the login packet's ServerAddress field:
// hostname\00ip-address\00uuid\00profile-properties-as-json
AStringVector Params ;
2014-09-17 14:55:46 -04:00
if ( cRoot : : Get ( ) - > GetServer ( ) - > ShouldAllowBungeeCord ( ) & & SplitZeroTerminatedStrings ( a_ServerAddress , Params ) & & ( Params . size ( ) = = 4 ) )
2014-09-17 03:38:06 -04:00
{
2014-09-17 05:07:42 -04:00
LOGD ( " Player at %s connected via BungeeCord " , Params [ 1 ] . c_str ( ) ) ;
2014-09-17 03:38:06 -04:00
m_ServerAddress = Params [ 0 ] ;
2014-09-17 05:07:42 -04:00
m_Client - > SetIPString ( Params [ 1 ] ) ;
m_Client - > SetUUID ( cMojangAPI : : MakeUUIDShort ( Params [ 2 ] ) ) ;
m_Client - > SetProperties ( Params [ 3 ] ) ;
2014-09-17 03:38:06 -04:00
}
2014-01-24 17:03:48 -05:00
// Create the comm log file, if so requested:
2014-01-26 11:54:18 -05:00
if ( g_ShouldLogCommIn | | g_ShouldLogCommOut )
2014-01-24 17:03:48 -05:00
{
2014-04-14 14:21:00 -04:00
static int sCounter = 0 ;
2014-01-24 17:03:48 -05:00
cFile : : CreateFolder ( " CommLogs " ) ;
2014-04-14 14:21:00 -04:00
AString FileName = Printf ( " CommLogs/%x_%d__%s.log " , ( unsigned ) time ( NULL ) , sCounter + + , a_Client - > GetIPString ( ) . c_str ( ) ) ;
2014-01-24 17:03:48 -05:00
m_CommLogFile . Open ( FileName , cFile : : fmWrite ) ;
}
2013-10-30 18:24:46 -04:00
}
2014-03-07 14:04:25 -05:00
void cProtocol172 : : DataReceived ( const char * a_Data , size_t a_Size )
2013-10-30 18:24:46 -04:00
{
if ( m_IsEncrypted )
{
2014-01-23 17:35:23 -05:00
Byte Decrypted [ 512 ] ;
2013-10-30 18:24:46 -04:00
while ( a_Size > 0 )
{
2014-02-05 07:54:47 -05:00
size_t NumBytes = ( a_Size > sizeof ( Decrypted ) ) ? sizeof ( Decrypted ) : a_Size ;
2014-01-23 17:35:23 -05:00
m_Decryptor . ProcessData ( Decrypted , ( Byte * ) a_Data , NumBytes ) ;
2013-10-30 18:24:46 -04:00
AddReceivedData ( ( const char * ) Decrypted , NumBytes ) ;
a_Size - = NumBytes ;
a_Data + = NumBytes ;
}
}
else
{
AddReceivedData ( a_Data , a_Size ) ;
}
}
2013-11-01 11:20:15 -04:00
void cProtocol172 : : SendAttachEntity ( const cEntity & a_Entity , const cEntity * a_Vehicle )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x1b ) ; // Attach Entity packet
Pkt . WriteInt ( a_Entity . GetUniqueID ( ) ) ;
Pkt . WriteInt ( ( a_Vehicle ! = NULL ) ? a_Vehicle - > GetUniqueID ( ) : 0 ) ;
Pkt . WriteBool ( false ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendBlockAction ( int a_BlockX , int a_BlockY , int a_BlockZ , char a_Byte1 , char a_Byte2 , BLOCKTYPE a_BlockType )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x24 ) ; // Block Action packet
Pkt . WriteInt ( a_BlockX ) ;
Pkt . WriteShort ( a_BlockY ) ;
Pkt . WriteInt ( a_BlockZ ) ;
Pkt . WriteByte ( a_Byte1 ) ;
Pkt . WriteByte ( a_Byte2 ) ;
Pkt . WriteVarInt ( a_BlockType ) ;
2013-11-01 11:20:15 -04:00
}
2013-11-03 05:58:49 -05:00
void cProtocol172 : : SendBlockBreakAnim ( int a_EntityID , int a_BlockX , int a_BlockY , int a_BlockZ , char a_Stage )
2013-11-01 11:20:15 -04:00
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2014-01-16 17:42:47 -05:00
cPacketizer Pkt ( * this , 0x25 ) ; // Block Break Animation packet
2014-01-20 14:02:37 -05:00
Pkt . WriteVarInt ( a_EntityID ) ;
2013-11-03 05:58:49 -05:00
Pkt . WriteInt ( a_BlockX ) ;
Pkt . WriteInt ( a_BlockY ) ;
Pkt . WriteInt ( a_BlockZ ) ;
Pkt . WriteChar ( a_Stage ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendBlockChange ( int a_BlockX , int a_BlockY , int a_BlockZ , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x23 ) ; // Block Change packet
Pkt . WriteInt ( a_BlockX ) ;
Pkt . WriteByte ( a_BlockY ) ;
Pkt . WriteInt ( a_BlockZ ) ;
Pkt . WriteVarInt ( a_BlockType ) ;
Pkt . WriteByte ( a_BlockMeta ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendBlockChanges ( int a_ChunkX , int a_ChunkZ , const sSetBlockVector & a_Changes )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x22 ) ; // Multi Block Change packet
Pkt . WriteInt ( a_ChunkX ) ;
Pkt . WriteInt ( a_ChunkZ ) ;
Pkt . WriteShort ( ( short ) a_Changes . size ( ) ) ;
2014-05-08 14:16:35 -04:00
Pkt . WriteInt ( ( int ) a_Changes . size ( ) * 4 ) ;
2013-11-01 11:20:15 -04:00
for ( sSetBlockVector : : const_iterator itr = a_Changes . begin ( ) , end = a_Changes . end ( ) ; itr ! = end ; + + itr )
{
unsigned int Coords = itr - > y | ( itr - > z < < 8 ) | ( itr - > x < < 12 ) ;
unsigned int Blocks = itr - > BlockMeta | ( itr - > BlockType < < 4 ) ;
2013-11-03 05:58:49 -05:00
Pkt . WriteInt ( ( Coords < < 16 ) | Blocks ) ;
2013-11-01 11:20:15 -04:00
} // for itr - a_Changes[]
}
void cProtocol172 : : SendChat ( const AString & a_Message )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x02 ) ; // Chat Message packet
Pkt . WriteString ( Printf ( " { \" text \" : \" %s \" } " , EscapeString ( a_Message ) . c_str ( ) ) ) ;
2013-11-01 11:20:15 -04:00
}
2014-02-15 17:16:44 -05:00
void cProtocol172 : : SendChat ( const cCompositeChat & a_Message )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2014-09-13 14:27:10 -04:00
2014-05-28 16:41:23 -04:00
cWorld * World = m_Client - > GetPlayer ( ) - > GetWorld ( ) ;
2014-09-13 14:27:10 -04:00
bool ShouldUseChatPrefixes = ( World = = NULL ) ? false : World - > ShouldUseChatPrefixes ( ) ;
2014-05-19 15:40:56 -04:00
2014-02-15 17:16:44 -05:00
// Send the message to the client:
cPacketizer Pkt ( * this , 0x02 ) ;
2014-09-13 14:27:10 -04:00
Pkt . WriteString ( a_Message . CreateJsonString ( ShouldUseChatPrefixes ) ) ;
2014-02-15 17:16:44 -05:00
}
2013-11-01 11:20:15 -04:00
void cProtocol172 : : SendChunkData ( int a_ChunkX , int a_ChunkZ , cChunkDataSerializer & a_Serializer )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-04 15:20:36 -05:00
// Serialize first, before creating the Packetizer (the packetizer locks a CS)
// This contains the flags and bitmasks, too
2014-09-07 18:36:30 -04:00
const AString & ChunkData = a_Serializer . Serialize ( cChunkDataSerializer : : RELEASE_1_3_2 , a_ChunkX , a_ChunkZ ) ;
2013-11-04 15:20:36 -05:00
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x21 ) ; // Chunk Data packet
Pkt . WriteInt ( a_ChunkX ) ;
Pkt . WriteInt ( a_ChunkZ ) ;
Pkt . WriteBuf ( ChunkData . data ( ) , ChunkData . size ( ) ) ;
2013-11-01 11:20:15 -04:00
}
2014-06-27 14:56:29 -04:00
void cProtocol172 : : SendCollectEntity ( const cEntity & a_Entity , const cPlayer & a_Player )
2013-11-01 11:20:15 -04:00
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x0d ) ; // Collect Item packet
2014-06-27 14:56:29 -04:00
Pkt . WriteInt ( a_Entity . GetUniqueID ( ) ) ;
2013-11-03 05:58:49 -05:00
Pkt . WriteInt ( a_Player . GetUniqueID ( ) ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendDestroyEntity ( const cEntity & a_Entity )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x13 ) ; // Destroy Entities packet
Pkt . WriteByte ( 1 ) ;
Pkt . WriteInt ( a_Entity . GetUniqueID ( ) ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendDisconnect ( const AString & a_Reason )
{
2014-01-13 14:32:15 -05:00
switch ( m_State )
{
case 2 :
{
// During login:
cPacketizer Pkt ( * this , 0 ) ;
Pkt . WriteString ( Printf ( " { \" text \" : \" %s \" } " , EscapeString ( a_Reason ) . c_str ( ) ) ) ;
break ;
}
case 3 :
{
// In-game:
cPacketizer Pkt ( * this , 0x40 ) ;
Pkt . WriteString ( Printf ( " { \" text \" : \" %s \" } " , EscapeString ( a_Reason ) . c_str ( ) ) ) ;
break ;
}
}
2013-11-01 11:20:15 -04:00
}
2013-11-03 05:58:49 -05:00
void cProtocol172 : : SendEditSign ( int a_BlockX , int a_BlockY , int a_BlockZ )
2013-11-01 11:20:15 -04:00
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x36 ) ; // Sign Editor Open packet
Pkt . WriteInt ( a_BlockX ) ;
Pkt . WriteInt ( a_BlockY ) ;
Pkt . WriteInt ( a_BlockZ ) ;
2013-11-01 11:20:15 -04:00
}
2013-12-14 12:03:00 -05:00
void cProtocol172 : : SendEntityEffect ( const cEntity & a_Entity , int a_EffectID , int a_Amplifier , short a_Duration )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-12-14 12:03:00 -05:00
cPacketizer Pkt ( * this , 0x1D ) ; // Entity Effect packet
Pkt . WriteInt ( a_Entity . GetUniqueID ( ) ) ;
Pkt . WriteByte ( a_EffectID ) ;
Pkt . WriteByte ( a_Amplifier ) ;
Pkt . WriteShort ( a_Duration ) ;
}
2013-11-01 11:20:15 -04:00
void cProtocol172 : : SendEntityEquipment ( const cEntity & a_Entity , short a_SlotNum , const cItem & a_Item )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x04 ) ; // Entity Equipment packet
Pkt . WriteInt ( a_Entity . GetUniqueID ( ) ) ;
Pkt . WriteShort ( a_SlotNum ) ;
Pkt . WriteItem ( a_Item ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendEntityHeadLook ( const cEntity & a_Entity )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x19 ) ; // Entity Head Look packet
Pkt . WriteInt ( a_Entity . GetUniqueID ( ) ) ;
Pkt . WriteByteAngle ( a_Entity . GetHeadYaw ( ) ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendEntityLook ( const cEntity & a_Entity )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x16 ) ; // Entity Look packet
Pkt . WriteInt ( a_Entity . GetUniqueID ( ) ) ;
Pkt . WriteByteAngle ( a_Entity . GetYaw ( ) ) ;
Pkt . WriteByteAngle ( a_Entity . GetPitch ( ) ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendEntityMetadata ( const cEntity & a_Entity )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x1c ) ; // Entity Metadata packet
Pkt . WriteInt ( a_Entity . GetUniqueID ( ) ) ;
2013-11-04 15:20:36 -05:00
Pkt . WriteEntityMetadata ( a_Entity ) ;
2013-11-05 12:37:39 -05:00
Pkt . WriteByte ( 0x7f ) ; // The termination byte
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendEntityProperties ( const cEntity & a_Entity )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x20 ) ; // Entity Properties packet
Pkt . WriteInt ( a_Entity . GetUniqueID ( ) ) ;
2013-11-08 14:56:19 -05:00
Pkt . WriteEntityProperties ( a_Entity ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendEntityRelMove ( const cEntity & a_Entity , char a_RelX , char a_RelY , char a_RelZ )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x15 ) ; // Entity Relative Move packet
Pkt . WriteInt ( a_Entity . GetUniqueID ( ) ) ;
Pkt . WriteByte ( a_RelX ) ;
Pkt . WriteByte ( a_RelY ) ;
Pkt . WriteByte ( a_RelZ ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendEntityRelMoveLook ( const cEntity & a_Entity , char a_RelX , char a_RelY , char a_RelZ )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x17 ) ; // Entity Look And Relative Move packet
Pkt . WriteInt ( a_Entity . GetUniqueID ( ) ) ;
Pkt . WriteByte ( a_RelX ) ;
Pkt . WriteByte ( a_RelY ) ;
Pkt . WriteByte ( a_RelZ ) ;
Pkt . WriteByteAngle ( a_Entity . GetYaw ( ) ) ;
Pkt . WriteByteAngle ( a_Entity . GetPitch ( ) ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendEntityStatus ( const cEntity & a_Entity , char a_Status )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x1a ) ; // Entity Status packet
Pkt . WriteInt ( a_Entity . GetUniqueID ( ) ) ;
Pkt . WriteChar ( a_Status ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendEntityVelocity ( const cEntity & a_Entity )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x12 ) ; // Entity Velocity packet
Pkt . WriteInt ( a_Entity . GetUniqueID ( ) ) ;
// 400 = 8000 / 20 ... Conversion from our speed in m/s to 8000 m/tick
Pkt . WriteShort ( ( short ) ( a_Entity . GetSpeedX ( ) * 400 ) ) ;
Pkt . WriteShort ( ( short ) ( a_Entity . GetSpeedY ( ) * 400 ) ) ;
Pkt . WriteShort ( ( short ) ( a_Entity . GetSpeedZ ( ) * 400 ) ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendExplosion ( double a_BlockX , double a_BlockY , double a_BlockZ , float a_Radius , const cVector3iArray & a_BlocksAffected , const Vector3d & a_PlayerMotion )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x27 ) ; // Explosion packet
Pkt . WriteFloat ( ( float ) a_BlockX ) ;
Pkt . WriteFloat ( ( float ) a_BlockY ) ;
Pkt . WriteFloat ( ( float ) a_BlockZ ) ;
Pkt . WriteFloat ( ( float ) a_Radius ) ;
2014-05-08 14:16:35 -04:00
Pkt . WriteInt ( ( int ) a_BlocksAffected . size ( ) ) ;
2013-11-03 05:58:49 -05:00
for ( cVector3iArray : : const_iterator itr = a_BlocksAffected . begin ( ) , end = a_BlocksAffected . end ( ) ; itr ! = end ; + + itr )
{
Pkt . WriteChar ( ( char ) itr - > x ) ;
Pkt . WriteChar ( ( char ) itr - > y ) ;
Pkt . WriteChar ( ( char ) itr - > z ) ;
} // for itr - a_BlockAffected[]
Pkt . WriteFloat ( ( float ) a_PlayerMotion . x ) ;
Pkt . WriteFloat ( ( float ) a_PlayerMotion . y ) ;
Pkt . WriteFloat ( ( float ) a_PlayerMotion . z ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendGameMode ( eGameMode a_GameMode )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x2b ) ; // Change Game State packet
Pkt . WriteByte ( 3 ) ; // Reason: Change game mode
Pkt . WriteFloat ( ( float ) a_GameMode ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendHealth ( void )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x06 ) ; // Update Health packet
2014-04-18 15:09:44 -04:00
cPlayer * Player = m_Client - > GetPlayer ( ) ;
Pkt . WriteFloat ( ( float ) Player - > GetHealth ( ) ) ;
Pkt . WriteShort ( Player - > GetFoodLevel ( ) ) ;
Pkt . WriteFloat ( ( float ) Player - > GetFoodSaturationLevel ( ) ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendInventorySlot ( char a_WindowID , short a_SlotNum , const cItem & a_Item )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x2f ) ; // Set Slot packet
Pkt . WriteChar ( a_WindowID ) ;
Pkt . WriteShort ( a_SlotNum ) ;
Pkt . WriteItem ( a_Item ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendKeepAlive ( int a_PingID )
{
2014-04-15 17:40:06 -04:00
// Drop the packet if the protocol is not in the Game state yet (caused a client crash):
if ( m_State ! = 3 )
{
LOGWARNING ( " Trying to send a KeepAlive packet to a player who's not yet fully logged in (%d). The protocol class prevented the packet. " , m_State ) ;
return ;
}
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x00 ) ; // Keep Alive packet
Pkt . WriteInt ( a_PingID ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendLogin ( const cPlayer & a_Player , const cWorld & a_World )
{
2013-11-03 05:58:49 -05:00
// Send the Join Game packet:
{
2014-04-18 15:09:44 -04:00
cServer * Server = cRoot : : Get ( ) - > GetServer ( ) ;
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x01 ) ; // Join Game packet
Pkt . WriteInt ( a_Player . GetUniqueID ( ) ) ;
2014-07-17 16:15:34 -04:00
Pkt . WriteByte ( ( Byte ) a_Player . GetEffectiveGameMode ( ) | ( Server - > IsHardcore ( ) ? 0x08 : 0 ) ) ; // Hardcore flag bit 4
2013-11-03 05:58:49 -05:00
Pkt . WriteChar ( ( char ) a_World . GetDimension ( ) ) ;
Pkt . WriteByte ( 2 ) ; // TODO: Difficulty (set to Normal)
2014-04-18 15:09:44 -04:00
Pkt . WriteByte ( std : : min ( Server - > GetMaxPlayers ( ) , 60 ) ) ;
2013-11-03 05:58:49 -05:00
Pkt . WriteString ( " default " ) ; // Level type - wtf?
}
2014-06-08 15:58:08 -04:00
m_LastSentDimension = a_World . GetDimension ( ) ;
2013-11-03 05:58:49 -05:00
2013-11-01 11:20:15 -04:00
// Send the spawn position:
2013-11-03 05:58:49 -05:00
{
cPacketizer Pkt ( * this , 0x05 ) ; // Spawn Position packet
Pkt . WriteInt ( ( int ) a_World . GetSpawnX ( ) ) ;
Pkt . WriteInt ( ( int ) a_World . GetSpawnY ( ) ) ;
Pkt . WriteInt ( ( int ) a_World . GetSpawnZ ( ) ) ;
}
2013-11-01 11:20:15 -04:00
// Send player abilities:
SendPlayerAbilities ( ) ;
}
2014-04-14 16:52:59 -04:00
void cProtocol172 : : SendLoginSuccess ( void )
{
ASSERT ( m_State = = 2 ) ; // State: login?
2014-04-27 11:31:40 -04:00
{
cPacketizer Pkt ( * this , 0x02 ) ; // Login success packet
2014-07-30 07:52:51 -04:00
Pkt . WriteString ( cMojangAPI : : MakeUUIDDashed ( m_Client - > GetUUID ( ) ) ) ;
2014-04-27 11:31:40 -04:00
Pkt . WriteString ( m_Client - > GetUsername ( ) ) ;
}
2014-04-14 16:52:59 -04:00
m_State = 3 ; // State = Game
}
2014-02-17 19:16:03 -05:00
void cProtocol172 : : SendPaintingSpawn ( const cPainting & a_Painting )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2014-02-17 19:16:03 -05:00
cPacketizer Pkt ( * this , 0x10 ) ; // Spawn Painting packet
Pkt . WriteVarInt ( a_Painting . GetUniqueID ( ) ) ;
Pkt . WriteString ( a_Painting . GetName ( ) . c_str ( ) ) ;
Pkt . WriteInt ( ( int ) a_Painting . GetPosX ( ) ) ;
Pkt . WriteInt ( ( int ) a_Painting . GetPosY ( ) ) ;
Pkt . WriteInt ( ( int ) a_Painting . GetPosZ ( ) ) ;
Pkt . WriteInt ( a_Painting . GetDirection ( ) ) ;
}
2013-11-01 11:20:15 -04:00
2014-09-12 20:20:04 -04:00
void cProtocol172 : : SendMapColumn ( int a_ID , int a_X , int a_Y , const Byte * a_Colors , unsigned int a_Length , unsigned int m_Scale )
2014-02-13 10:13:09 -05:00
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2014-02-13 10:13:09 -05:00
cPacketizer Pkt ( * this , 0x34 ) ;
Pkt . WriteVarInt ( a_ID ) ;
Pkt . WriteShort ( 3 + a_Length ) ;
Pkt . WriteByte ( 0 ) ;
Pkt . WriteByte ( a_X ) ;
Pkt . WriteByte ( a_Y ) ;
for ( unsigned int i = 0 ; i < a_Length ; + + i )
{
Pkt . WriteByte ( a_Colors [ i ] ) ;
}
}
2014-09-12 20:20:04 -04:00
void cProtocol172 : : SendMapDecorators ( int a_ID , const cMapDecoratorList & a_Decorators , unsigned int m_Scale )
2014-02-18 13:50:08 -05:00
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2014-02-18 13:50:08 -05:00
cPacketizer Pkt ( * this , 0x34 ) ;
Pkt . WriteVarInt ( a_ID ) ;
2014-05-08 14:16:35 -04:00
Pkt . WriteShort ( ( short ) ( 1 + ( 3 * a_Decorators . size ( ) ) ) ) ;
2014-02-18 13:50:08 -05:00
Pkt . WriteByte ( 1 ) ;
for ( cMapDecoratorList : : const_iterator it = a_Decorators . begin ( ) ; it ! = a_Decorators . end ( ) ; + + it )
{
Pkt . WriteByte ( ( it - > GetType ( ) < < 4 ) | ( it - > GetRot ( ) & 0xf ) ) ;
Pkt . WriteByte ( it - > GetPixelX ( ) ) ;
Pkt . WriteByte ( it - > GetPixelZ ( ) ) ;
}
}
2014-02-13 10:13:09 -05:00
void cProtocol172 : : SendMapInfo ( int a_ID , unsigned int a_Scale )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2014-02-13 10:13:09 -05:00
cPacketizer Pkt ( * this , 0x34 ) ;
Pkt . WriteVarInt ( a_ID ) ;
Pkt . WriteShort ( 2 ) ;
Pkt . WriteByte ( 2 ) ;
Pkt . WriteByte ( a_Scale ) ;
}
2013-11-01 11:20:15 -04:00
void cProtocol172 : : SendPickupSpawn ( const cPickup & a_Pickup )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
{
cPacketizer Pkt ( * this , 0x0e ) ; // Spawn Object packet
2013-11-07 15:58:47 -05:00
Pkt . WriteVarInt ( a_Pickup . GetUniqueID ( ) ) ;
2013-11-03 05:58:49 -05:00
Pkt . WriteByte ( 2 ) ; // Type = Pickup
Pkt . WriteFPInt ( a_Pickup . GetPosX ( ) ) ;
Pkt . WriteFPInt ( a_Pickup . GetPosY ( ) ) ;
Pkt . WriteFPInt ( a_Pickup . GetPosZ ( ) ) ;
Pkt . WriteByteAngle ( a_Pickup . GetYaw ( ) ) ;
Pkt . WriteByteAngle ( a_Pickup . GetPitch ( ) ) ;
Pkt . WriteInt ( 0 ) ; // No object data
}
{
cPacketizer Pkt ( * this , 0x1c ) ; // Entity Metadata packet
Pkt . WriteInt ( a_Pickup . GetUniqueID ( ) ) ;
Pkt . WriteByte ( ( 0x05 < < 5 ) | 10 ) ; // Slot type + index 10
Pkt . WriteItem ( a_Pickup . GetItem ( ) ) ;
Pkt . WriteByte ( 0x7f ) ; // End of metadata
}
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendPlayerAbilities ( void )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x39 ) ; // Player Abilities packet
2013-11-01 11:20:15 -04:00
Byte Flags = 0 ;
2014-04-18 15:09:44 -04:00
cPlayer * Player = m_Client - > GetPlayer ( ) ;
if ( Player - > IsGameModeCreative ( ) )
2013-11-01 11:20:15 -04:00
{
Flags | = 0x01 ;
2014-07-17 16:15:34 -04:00
Flags | = 0x08 ; // Godmode, used for creative
2013-11-01 11:20:15 -04:00
}
2014-04-18 15:09:44 -04:00
if ( Player - > IsFlying ( ) )
2013-12-15 08:48:17 -05:00
{
Flags | = 0x02 ;
}
2014-04-18 15:09:44 -04:00
if ( Player - > CanFly ( ) )
2013-12-15 08:48:17 -05:00
{
Flags | = 0x04 ;
}
2013-11-03 05:58:49 -05:00
Pkt . WriteByte ( Flags ) ;
2014-04-18 15:09:44 -04:00
Pkt . WriteFloat ( ( float ) ( 0.05 * Player - > GetFlyingMaxSpeed ( ) ) ) ;
2014-08-04 14:16:52 -04:00
Pkt . WriteFloat ( ( float ) ( 0.1 * Player - > GetNormalMaxSpeed ( ) ) ) ;
2013-11-01 11:20:15 -04:00
}
2013-12-06 18:47:07 -05:00
void cProtocol172 : : SendEntityAnimation ( const cEntity & a_Entity , char a_Animation )
2013-11-01 11:20:15 -04:00
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x0b ) ; // Animation packet
2013-12-06 18:47:07 -05:00
Pkt . WriteVarInt ( a_Entity . GetUniqueID ( ) ) ;
2013-11-03 05:58:49 -05:00
Pkt . WriteChar ( a_Animation ) ;
2013-11-01 11:20:15 -04:00
}
2014-09-11 11:03:09 -04:00
void cProtocol172 : : SendParticleEffect ( const AString & a_ParticleName , float a_SrcX , float a_SrcY , float a_SrcZ , float a_OffsetX , float a_OffsetY , float a_OffsetZ , float a_ParticleData , int a_ParticleAmount )
2013-12-22 08:45:25 -05:00
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-12-22 08:45:25 -05:00
cPacketizer Pkt ( * this , 0x2A ) ;
Pkt . WriteString ( a_ParticleName ) ;
Pkt . WriteFloat ( a_SrcX ) ;
Pkt . WriteFloat ( a_SrcY ) ;
Pkt . WriteFloat ( a_SrcZ ) ;
Pkt . WriteFloat ( a_OffsetX ) ;
Pkt . WriteFloat ( a_OffsetY ) ;
Pkt . WriteFloat ( a_OffsetZ ) ;
Pkt . WriteFloat ( a_ParticleData ) ;
2014-09-11 11:03:09 -04:00
Pkt . WriteInt ( a_ParticleAmount ) ;
2013-12-22 08:45:25 -05:00
}
2014-09-18 12:50:17 -04:00
void cProtocol172 : : SendPlayerListAddPlayer ( const cPlayer & a_Player )
2013-11-01 11:20:15 -04:00
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2014-09-18 12:50:17 -04:00
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x38 ) ; // Playerlist Item packet
2014-09-23 08:39:49 -04:00
Pkt . WriteString ( a_Player . GetPlayerListName ( ) ) ;
2014-09-18 12:50:17 -04:00
Pkt . WriteBool ( true ) ;
Pkt . WriteShort ( a_Player . GetClientHandle ( ) - > GetPing ( ) ) ;
}
void cProtocol172 : : SendPlayerListRemovePlayer ( const cPlayer & a_Player )
{
ASSERT ( m_State = = 3 ) ; // In game mode?
cPacketizer Pkt ( * this , 0x38 ) ;
2014-09-23 08:39:49 -04:00
Pkt . WriteString ( a_Player . GetPlayerListName ( ) ) ;
2014-09-18 12:50:17 -04:00
Pkt . WriteBool ( false ) ;
Pkt . WriteShort ( 0 ) ;
}
void cProtocol172 : : SendPlayerListUpdateGameMode ( const cPlayer & a_Player )
{
// Not implemented in this protocol version
UNUSED ( a_Player ) ;
}
void cProtocol172 : : SendPlayerListUpdatePing ( const cPlayer & a_Player )
{
// It is a simple add player packet in this protocol.
SendPlayerListAddPlayer ( a_Player ) ;
}
void cProtocol172 : : SendPlayerListUpdateDisplayName ( const cPlayer & a_Player , const AString & a_OldListName )
{
ASSERT ( m_State = = 3 ) ; // In game mode?
2014-09-23 08:39:49 -04:00
if ( a_OldListName = = a_Player . GetPlayerListName ( ) )
2014-09-08 21:02:25 -04:00
{
return ;
}
2014-09-18 12:50:17 -04:00
// Remove the old name from the tablist:
{
cPacketizer Pkt ( * this , 0x38 ) ;
Pkt . WriteString ( a_OldListName ) ;
Pkt . WriteBool ( false ) ;
Pkt . WriteShort ( 0 ) ;
}
SendPlayerListAddPlayer ( a_Player ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendPlayerMaxSpeed ( void )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-08 16:40:31 -05:00
cPacketizer Pkt ( * this , 0x20 ) ; // Entity Properties
2014-04-18 15:09:44 -04:00
cPlayer * Player = m_Client - > GetPlayer ( ) ;
Pkt . WriteInt ( Player - > GetUniqueID ( ) ) ;
2013-11-08 16:40:31 -05:00
Pkt . WriteInt ( 1 ) ; // Count
Pkt . WriteString ( " generic.movementSpeed " ) ;
2014-03-20 10:45:42 -04:00
// The default game speed is 0.1, multiply that value by the relative speed:
2014-04-18 15:09:44 -04:00
Pkt . WriteDouble ( 0.1 * Player - > GetNormalMaxSpeed ( ) ) ;
if ( Player - > IsSprinting ( ) )
2013-11-08 16:40:31 -05:00
{
Pkt . WriteShort ( 1 ) ; // Modifier count
Pkt . WriteInt64 ( 0x662a6b8dda3e4c1c ) ;
Pkt . WriteInt64 ( 0x881396ea6097278d ) ; // UUID of the modifier
2014-04-18 15:09:44 -04:00
Pkt . WriteDouble ( Player - > GetSprintingMaxSpeed ( ) - Player - > GetNormalMaxSpeed ( ) ) ;
2013-11-08 16:40:31 -05:00
Pkt . WriteByte ( 2 ) ;
}
else
{
Pkt . WriteShort ( 0 ) ; // Modifier count
}
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendPlayerMoveLook ( void )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x08 ) ; // Player Position And Look packet
2014-04-18 15:09:44 -04:00
cPlayer * Player = m_Client - > GetPlayer ( ) ;
Pkt . WriteDouble ( Player - > GetPosX ( ) ) ;
2013-12-17 13:56:17 -05:00
// Protocol docs say this is PosY, but #323 says this is eye-pos
// Moreover, the "+ 0.001" is there because otherwise the player falls through the block they were standing on.
2014-04-18 15:09:44 -04:00
Pkt . WriteDouble ( Player - > GetStance ( ) + 0.001 ) ;
2013-12-17 13:56:17 -05:00
2014-04-18 15:09:44 -04:00
Pkt . WriteDouble ( Player - > GetPosZ ( ) ) ;
Pkt . WriteFloat ( ( float ) Player - > GetYaw ( ) ) ;
Pkt . WriteFloat ( ( float ) Player - > GetPitch ( ) ) ;
Pkt . WriteBool ( Player - > IsOnGround ( ) ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendPlayerPosition ( void )
{
2013-11-03 05:58:49 -05:00
// There is no dedicated packet for this, send the whole thing:
SendPlayerMoveLook ( ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendPlayerSpawn ( const cPlayer & a_Player )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-03 05:58:49 -05:00
// Called to spawn another player for the client
cPacketizer Pkt ( * this , 0x0c ) ; // Spawn Player packet
2014-09-02 13:12:35 -04:00
Pkt . WriteVarInt ( ( UInt32 ) a_Player . GetUniqueID ( ) ) ;
2014-07-30 07:52:51 -04:00
Pkt . WriteString ( cMojangAPI : : MakeUUIDDashed ( a_Player . GetClientHandle ( ) - > GetUUID ( ) ) ) ;
2014-09-02 13:12:35 -04:00
if ( a_Player . HasCustomName ( ) )
{
Pkt . WriteString ( a_Player . GetCustomName ( ) ) ;
}
else
{
Pkt . WriteString ( a_Player . GetName ( ) ) ;
}
2013-11-03 05:58:49 -05:00
Pkt . WriteFPInt ( a_Player . GetPosX ( ) ) ;
Pkt . WriteFPInt ( a_Player . GetPosY ( ) ) ;
Pkt . WriteFPInt ( a_Player . GetPosZ ( ) ) ;
Pkt . WriteByteAngle ( a_Player . GetYaw ( ) ) ;
Pkt . WriteByteAngle ( a_Player . GetPitch ( ) ) ;
short ItemType = a_Player . GetEquippedItem ( ) . IsEmpty ( ) ? 0 : a_Player . GetEquippedItem ( ) . m_ItemType ;
Pkt . WriteShort ( ItemType ) ;
Pkt . WriteByte ( ( 3 < < 5 ) | 6 ) ; // Metadata: float + index 6
Pkt . WriteFloat ( ( float ) a_Player . GetHealth ( ) ) ;
Pkt . WriteByte ( 0x7f ) ; // Metadata: end
2013-11-01 11:20:15 -04:00
}
2014-01-09 05:39:42 -05:00
void cProtocol172 : : SendPluginMessage ( const AString & a_Channel , const AString & a_Message )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2014-01-09 08:24:57 -05:00
cPacketizer Pkt ( * this , 0x3f ) ;
2014-01-09 05:39:42 -05:00
Pkt . WriteString ( a_Channel ) ;
Pkt . WriteShort ( ( short ) a_Message . size ( ) ) ;
Pkt . WriteBuf ( a_Message . data ( ) , a_Message . size ( ) ) ;
}
2013-12-14 12:03:00 -05:00
void cProtocol172 : : SendRemoveEntityEffect ( const cEntity & a_Entity , int a_EffectID )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
cPacketizer Pkt ( * this , 0x1e ) ;
2013-12-14 12:03:00 -05:00
Pkt . WriteInt ( a_Entity . GetUniqueID ( ) ) ;
Pkt . WriteByte ( a_EffectID ) ;
}
2014-07-18 15:10:51 -04:00
void cProtocol172 : : SendRespawn ( eDimension a_Dimension , bool a_ShouldIgnoreDimensionChecks )
2013-11-01 11:20:15 -04:00
{
2014-07-18 15:12:27 -04:00
if ( ( m_LastSentDimension = = a_Dimension ) & & ! a_ShouldIgnoreDimensionChecks )
2014-06-08 15:58:08 -04:00
{
2014-06-29 17:44:01 -04:00
// Must not send a respawn for the world with the same dimension, the client goes cuckoo if we do (unless we are respawning from death)
2014-06-08 15:58:08 -04:00
return ;
}
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x07 ) ; // Respawn packet
2014-04-18 15:09:44 -04:00
cPlayer * Player = m_Client - > GetPlayer ( ) ;
2014-06-12 10:21:07 -04:00
Pkt . WriteInt ( ( int ) a_Dimension ) ;
2013-11-03 05:58:49 -05:00
Pkt . WriteByte ( 2 ) ; // TODO: Difficulty (set to Normal)
2014-04-18 15:09:44 -04:00
Pkt . WriteByte ( ( Byte ) Player - > GetEffectiveGameMode ( ) ) ;
2013-11-03 05:58:49 -05:00
Pkt . WriteString ( " default " ) ;
2014-06-12 10:21:07 -04:00
m_LastSentDimension = a_Dimension ;
2013-11-01 11:20:15 -04:00
}
2013-11-15 10:23:50 -05:00
void cProtocol172 : : SendExperience ( void )
2013-11-14 16:35:02 -05:00
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
cPacketizer Pkt ( * this , 0x1f ) ; // Experience Packet
2014-04-18 15:09:44 -04:00
cPlayer * Player = m_Client - > GetPlayer ( ) ;
Pkt . WriteFloat ( Player - > GetXpPercentage ( ) ) ;
Pkt . WriteShort ( Player - > GetXpLevel ( ) ) ;
Pkt . WriteShort ( Player - > GetCurrentXp ( ) ) ;
2013-11-14 16:35:02 -05:00
}
2013-11-25 15:43:43 -05:00
void cProtocol172 : : SendExperienceOrb ( const cExpOrb & a_ExpOrb )
2013-11-25 14:04:01 -05:00
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2014-07-17 16:50:58 -04:00
cPacketizer Pkt ( * this , 0x11 ) ;
2013-11-25 15:43:43 -05:00
Pkt . WriteVarInt ( a_ExpOrb . GetUniqueID ( ) ) ;
2014-09-12 10:41:23 -04:00
Pkt . WriteFPInt ( a_ExpOrb . GetPosX ( ) ) ;
Pkt . WriteFPInt ( a_ExpOrb . GetPosY ( ) ) ;
Pkt . WriteFPInt ( a_ExpOrb . GetPosZ ( ) ) ;
2013-11-25 15:43:43 -05:00
Pkt . WriteShort ( a_ExpOrb . GetReward ( ) ) ;
2013-11-25 14:04:01 -05:00
}
2014-01-21 08:58:17 -05:00
void cProtocol172 : : SendScoreboardObjective ( const AString & a_Name , const AString & a_DisplayName , Byte a_Mode )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
cPacketizer Pkt ( * this , 0x3b ) ;
2014-01-21 08:58:17 -05:00
Pkt . WriteString ( a_Name ) ;
Pkt . WriteString ( a_DisplayName ) ;
Pkt . WriteByte ( a_Mode ) ;
}
void cProtocol172 : : SendScoreUpdate ( const AString & a_Objective , const AString & a_Player , cObjective : : Score a_Score , Byte a_Mode )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
cPacketizer Pkt ( * this , 0x3c ) ;
2014-01-21 08:58:17 -05:00
Pkt . WriteString ( a_Player ) ;
Pkt . WriteByte ( a_Mode ) ;
if ( a_Mode ! = 1 )
{
Pkt . WriteString ( a_Objective ) ;
Pkt . WriteInt ( ( int ) a_Score ) ;
}
}
void cProtocol172 : : SendDisplayObjective ( const AString & a_Objective , cScoreboard : : eDisplaySlot a_Display )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
cPacketizer Pkt ( * this , 0x3d ) ;
2014-01-21 08:58:17 -05:00
Pkt . WriteByte ( ( int ) a_Display ) ;
Pkt . WriteString ( a_Objective ) ;
}
2014-07-12 20:08:02 -04:00
void cProtocol172 : : SendSoundEffect ( const AString & a_SoundName , double a_X , double a_Y , double a_Z , float a_Volume , float a_Pitch )
2013-11-01 11:20:15 -04:00
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2014-07-12 20:08:02 -04:00
2013-11-04 15:20:36 -05:00
cPacketizer Pkt ( * this , 0x29 ) ; // Sound Effect packet
Pkt . WriteString ( a_SoundName ) ;
2014-07-13 07:31:09 -04:00
Pkt . WriteInt ( ( int ) ( a_X * 8.0 ) ) ;
Pkt . WriteInt ( ( int ) ( a_Y * 8.0 ) ) ;
Pkt . WriteInt ( ( int ) ( a_Z * 8.0 ) ) ;
2013-11-04 15:20:36 -05:00
Pkt . WriteFloat ( a_Volume ) ;
Pkt . WriteByte ( ( Byte ) ( a_Pitch * 63 ) ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendSoundParticleEffect ( int a_EffectID , int a_SrcX , int a_SrcY , int a_SrcZ , int a_Data )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-04 15:20:36 -05:00
cPacketizer Pkt ( * this , 0x28 ) ; // Effect packet
Pkt . WriteInt ( a_EffectID ) ;
2013-11-10 17:20:25 -05:00
Pkt . WriteInt ( a_SrcX ) ;
Pkt . WriteByte ( a_SrcY ) ;
2013-11-04 15:20:36 -05:00
Pkt . WriteInt ( a_SrcZ ) ;
Pkt . WriteInt ( a_Data ) ;
Pkt . WriteBool ( false ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendSpawnFallingBlock ( const cFallingBlock & a_FallingBlock )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-04 15:20:36 -05:00
cPacketizer Pkt ( * this , 0x0e ) ; // Spawn Object packet
2013-11-07 15:58:47 -05:00
Pkt . WriteVarInt ( a_FallingBlock . GetUniqueID ( ) ) ;
2013-11-04 15:20:36 -05:00
Pkt . WriteByte ( 70 ) ; // Falling block
Pkt . WriteFPInt ( a_FallingBlock . GetPosX ( ) ) ;
Pkt . WriteFPInt ( a_FallingBlock . GetPosY ( ) ) ;
Pkt . WriteFPInt ( a_FallingBlock . GetPosZ ( ) ) ;
Pkt . WriteByteAngle ( a_FallingBlock . GetYaw ( ) ) ;
Pkt . WriteByteAngle ( a_FallingBlock . GetPitch ( ) ) ;
2014-07-17 16:15:34 -04:00
Pkt . WriteInt ( ( ( int ) a_FallingBlock . GetBlockType ( ) ) | ( ( ( int ) a_FallingBlock . GetBlockMeta ( ) ) < < 16 ) ) ; // Or 0x10
2013-11-04 15:20:36 -05:00
Pkt . WriteShort ( ( short ) ( a_FallingBlock . GetSpeedX ( ) * 400 ) ) ;
Pkt . WriteShort ( ( short ) ( a_FallingBlock . GetSpeedY ( ) * 400 ) ) ;
Pkt . WriteShort ( ( short ) ( a_FallingBlock . GetSpeedZ ( ) * 400 ) ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendSpawnMob ( const cMonster & a_Mob )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-04 15:20:36 -05:00
cPacketizer Pkt ( * this , 0x0f ) ; // Spawn Mob packet
2013-11-07 11:11:36 -05:00
Pkt . WriteVarInt ( a_Mob . GetUniqueID ( ) ) ;
2013-11-04 15:20:36 -05:00
Pkt . WriteByte ( ( Byte ) a_Mob . GetMobType ( ) ) ;
Pkt . WriteFPInt ( a_Mob . GetPosX ( ) ) ;
Pkt . WriteFPInt ( a_Mob . GetPosY ( ) ) ;
Pkt . WriteFPInt ( a_Mob . GetPosZ ( ) ) ;
Pkt . WriteByteAngle ( a_Mob . GetPitch ( ) ) ;
Pkt . WriteByteAngle ( a_Mob . GetHeadYaw ( ) ) ;
Pkt . WriteByteAngle ( a_Mob . GetYaw ( ) ) ;
Pkt . WriteShort ( ( short ) ( a_Mob . GetSpeedX ( ) * 400 ) ) ;
Pkt . WriteShort ( ( short ) ( a_Mob . GetSpeedY ( ) * 400 ) ) ;
Pkt . WriteShort ( ( short ) ( a_Mob . GetSpeedZ ( ) * 400 ) ) ;
Pkt . WriteEntityMetadata ( a_Mob ) ;
Pkt . WriteByte ( 0x7f ) ; // Metadata terminator
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendSpawnObject ( const cEntity & a_Entity , char a_ObjectType , int a_ObjectData , Byte a_Yaw , Byte a_Pitch )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-04 15:20:36 -05:00
cPacketizer Pkt ( * this , 0xe ) ; // Spawn Object packet
2013-11-07 13:49:48 -05:00
Pkt . WriteVarInt ( a_Entity . GetUniqueID ( ) ) ;
2013-11-04 15:20:36 -05:00
Pkt . WriteByte ( a_ObjectType ) ;
Pkt . WriteFPInt ( a_Entity . GetPosX ( ) ) ;
Pkt . WriteFPInt ( a_Entity . GetPosY ( ) ) ;
Pkt . WriteFPInt ( a_Entity . GetPosZ ( ) ) ;
Pkt . WriteByteAngle ( a_Entity . GetPitch ( ) ) ;
2014-02-17 18:00:03 -05:00
Pkt . WriteByteAngle ( a_Entity . GetYaw ( ) ) ;
2013-11-04 15:20:36 -05:00
Pkt . WriteInt ( a_ObjectData ) ;
if ( a_ObjectData ! = 0 )
{
Pkt . WriteShort ( ( short ) ( a_Entity . GetSpeedX ( ) * 400 ) ) ;
Pkt . WriteShort ( ( short ) ( a_Entity . GetSpeedY ( ) * 400 ) ) ;
Pkt . WriteShort ( ( short ) ( a_Entity . GetSpeedZ ( ) * 400 ) ) ;
}
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendSpawnVehicle ( const cEntity & a_Vehicle , char a_VehicleType , char a_VehicleSubType )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-04 15:20:36 -05:00
cPacketizer Pkt ( * this , 0xe ) ; // Spawn Object packet
2013-11-07 15:58:47 -05:00
Pkt . WriteVarInt ( a_Vehicle . GetUniqueID ( ) ) ;
2013-11-04 15:20:36 -05:00
Pkt . WriteByte ( a_VehicleType ) ;
Pkt . WriteFPInt ( a_Vehicle . GetPosX ( ) ) ;
Pkt . WriteFPInt ( a_Vehicle . GetPosY ( ) ) ;
Pkt . WriteFPInt ( a_Vehicle . GetPosZ ( ) ) ;
Pkt . WriteByteAngle ( a_Vehicle . GetPitch ( ) ) ;
2014-02-17 18:00:03 -05:00
Pkt . WriteByteAngle ( a_Vehicle . GetYaw ( ) ) ;
2013-11-04 15:20:36 -05:00
Pkt . WriteInt ( a_VehicleSubType ) ;
if ( a_VehicleSubType ! = 0 )
{
Pkt . WriteShort ( ( short ) ( a_Vehicle . GetSpeedX ( ) * 400 ) ) ;
Pkt . WriteShort ( ( short ) ( a_Vehicle . GetSpeedY ( ) * 400 ) ) ;
Pkt . WriteShort ( ( short ) ( a_Vehicle . GetSpeedZ ( ) * 400 ) ) ;
}
2013-11-01 11:20:15 -04:00
}
2014-05-11 07:57:06 -04:00
void cProtocol172 : : SendStatistics ( const cStatManager & a_Manager )
{
ASSERT ( m_State = = 3 ) ; // In game mode?
cPacketizer Pkt ( * this , 0x37 ) ;
2014-07-17 16:15:34 -04:00
Pkt . WriteVarInt ( statCount ) ; // TODO 2014-05-11 xdot: Optimization: Send "dirty" statistics only
2014-05-11 07:57:06 -04:00
2014-06-28 19:40:15 -04:00
for ( size_t i = 0 ; i < ( size_t ) statCount ; + + i )
2014-05-11 07:57:06 -04:00
{
StatValue Value = a_Manager . GetValue ( ( eStatistic ) i ) ;
const AString & StatName = cStatInfo : : GetName ( ( eStatistic ) i ) ;
Pkt . WriteString ( StatName ) ;
Pkt . WriteVarInt ( Value ) ;
}
}
2013-11-01 11:20:15 -04:00
void cProtocol172 : : SendTabCompletionResults ( const AStringVector & a_Results )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-12-08 08:37:10 -05:00
cPacketizer Pkt ( * this , 0x3a ) ; // Tab-Complete packet
2014-05-08 14:16:35 -04:00
Pkt . WriteVarInt ( ( int ) a_Results . size ( ) ) ;
2013-12-08 08:37:10 -05:00
2013-11-04 15:20:36 -05:00
for ( AStringVector : : const_iterator itr = a_Results . begin ( ) , end = a_Results . end ( ) ; itr ! = end ; + + itr )
{
2013-12-08 08:37:10 -05:00
Pkt . WriteString ( * itr ) ;
2013-11-04 15:20:36 -05:00
}
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendTeleportEntity ( const cEntity & a_Entity )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-04 15:20:36 -05:00
cPacketizer Pkt ( * this , 0x18 ) ;
Pkt . WriteInt ( a_Entity . GetUniqueID ( ) ) ;
Pkt . WriteFPInt ( a_Entity . GetPosX ( ) ) ;
Pkt . WriteFPInt ( a_Entity . GetPosY ( ) ) ;
Pkt . WriteFPInt ( a_Entity . GetPosZ ( ) ) ;
Pkt . WriteByteAngle ( a_Entity . GetYaw ( ) ) ;
Pkt . WriteByteAngle ( a_Entity . GetPitch ( ) ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendThunderbolt ( int a_BlockX , int a_BlockY , int a_BlockZ )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-04 15:20:36 -05:00
cPacketizer Pkt ( * this , 0x2c ) ; // Spawn Global Entity packet
Pkt . WriteVarInt ( 0 ) ; // EntityID = 0, always
Pkt . WriteByte ( 1 ) ; // Type = Thunderbolt
Pkt . WriteFPInt ( a_BlockX ) ;
Pkt . WriteFPInt ( a_BlockY ) ;
Pkt . WriteFPInt ( a_BlockZ ) ;
2013-11-01 11:20:15 -04:00
}
2014-08-10 18:20:28 -04:00
void cProtocol172 : : SendTimeUpdate ( Int64 a_WorldAge , Int64 a_TimeOfDay , bool a_DoDaylightCycle )
2013-11-01 11:20:15 -04:00
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2014-08-10 18:20:28 -04:00
if ( ! a_DoDaylightCycle )
{
// When writing a "-" before the number the client ignores it but it will stop the client-side time expiration.
a_TimeOfDay = std : : min ( - a_TimeOfDay , - 1LL ) ;
}
2014-04-16 12:10:48 -04:00
2013-11-04 15:20:36 -05:00
cPacketizer Pkt ( * this , 0x03 ) ;
Pkt . WriteInt64 ( a_WorldAge ) ;
Pkt . WriteInt64 ( a_TimeOfDay ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendUnloadChunk ( int a_ChunkX , int a_ChunkZ )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-05 12:37:39 -05:00
cPacketizer Pkt ( * this , 0x21 ) ; // Chunk Data packet
Pkt . WriteInt ( a_ChunkX ) ;
Pkt . WriteInt ( a_ChunkZ ) ;
Pkt . WriteBool ( true ) ;
Pkt . WriteShort ( 0 ) ; // Primary bitmap
Pkt . WriteShort ( 0 ) ; // Add bitmap
Pkt . WriteInt ( 0 ) ; // Compressed data size
2013-11-01 11:20:15 -04:00
}
2014-01-19 14:42:25 -05:00
void cProtocol172 : : SendUpdateBlockEntity ( cBlockEntity & a_BlockEntity )
2014-01-18 19:54:38 -05:00
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2014-01-18 19:54:38 -05:00
cPacketizer Pkt ( * this , 0x35 ) ; // Update tile entity packet
2014-01-19 14:42:25 -05:00
Pkt . WriteInt ( a_BlockEntity . GetPosX ( ) ) ;
Pkt . WriteShort ( a_BlockEntity . GetPosY ( ) ) ;
Pkt . WriteInt ( a_BlockEntity . GetPosZ ( ) ) ;
Byte Action = 0 ;
switch ( a_BlockEntity . GetBlockType ( ) )
{
2014-07-17 16:15:34 -04:00
case E_BLOCK_MOB_SPAWNER : Action = 1 ; break ; // Update mob spawner spinny mob thing
case E_BLOCK_COMMAND_BLOCK : Action = 2 ; break ; // Update command block text
2014-07-30 15:59:35 -04:00
case E_BLOCK_BEACON : Action = 3 ; break ; // Update beacon entity
2014-07-17 16:15:34 -04:00
case E_BLOCK_HEAD : Action = 4 ; break ; // Update Mobhead entity
case E_BLOCK_FLOWER_POT : Action = 5 ; break ; // Update flower pot
2014-01-19 14:42:25 -05:00
default : ASSERT ( ! " Unhandled or unimplemented BlockEntity update request! " ) ; break ;
}
Pkt . WriteByte ( Action ) ;
2014-01-18 19:54:38 -05:00
2014-01-19 08:25:35 -05:00
Pkt . WriteBlockEntity ( a_BlockEntity ) ;
2014-01-18 19:54:38 -05:00
}
2013-11-01 11:20:15 -04:00
void cProtocol172 : : SendUpdateSign ( int a_BlockX , int a_BlockY , int a_BlockZ , const AString & a_Line1 , const AString & a_Line2 , const AString & a_Line3 , const AString & a_Line4 )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2014-09-06 12:59:17 -04:00
ASSERT ( ( a_BlockY > = 0 ) & & ( a_BlockY < cChunkDef : : Height ) ) ;
2014-04-16 12:10:48 -04:00
2013-11-05 12:37:39 -05:00
cPacketizer Pkt ( * this , 0x33 ) ;
Pkt . WriteInt ( a_BlockX ) ;
Pkt . WriteShort ( ( short ) a_BlockY ) ;
Pkt . WriteInt ( a_BlockZ ) ;
2014-01-29 11:59:49 -05:00
// Need to send only up to 15 chars, otherwise the client crashes (#598)
Pkt . WriteString ( a_Line1 . substr ( 0 , 15 ) ) ;
Pkt . WriteString ( a_Line2 . substr ( 0 , 15 ) ) ;
Pkt . WriteString ( a_Line3 . substr ( 0 , 15 ) ) ;
Pkt . WriteString ( a_Line4 . substr ( 0 , 15 ) ) ;
2013-11-01 11:20:15 -04:00
}
2013-11-05 12:37:39 -05:00
void cProtocol172 : : SendUseBed ( const cEntity & a_Entity , int a_BlockX , int a_BlockY , int a_BlockZ )
2013-11-01 11:20:15 -04:00
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-05 12:37:39 -05:00
cPacketizer Pkt ( * this , 0x0a ) ;
Pkt . WriteInt ( a_Entity . GetUniqueID ( ) ) ;
Pkt . WriteInt ( a_BlockX ) ;
Pkt . WriteByte ( ( Byte ) a_BlockY ) ;
Pkt . WriteInt ( a_BlockZ ) ;
2013-11-01 11:20:15 -04:00
}
void cProtocol172 : : SendWeather ( eWeather a_Weather )
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-12 16:43:20 -05:00
{
cPacketizer Pkt ( * this , 0x2b ) ; // Change Game State packet
Pkt . WriteByte ( ( a_Weather = = wSunny ) ? 1 : 2 ) ; // End rain / begin rain
Pkt . WriteFloat ( 0 ) ; // Unused for weather
}
// TODO: Fade effect, somehow
2013-11-01 11:20:15 -04:00
}
2013-11-06 06:16:44 -05:00
void cProtocol172 : : SendWholeInventory ( const cWindow & a_Window )
2013-11-01 11:20:15 -04:00
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-06 06:16:44 -05:00
cPacketizer Pkt ( * this , 0x30 ) ; // Window Items packet
Pkt . WriteChar ( a_Window . GetWindowID ( ) ) ;
Pkt . WriteShort ( a_Window . GetNumSlots ( ) ) ;
cItems Slots ;
a_Window . GetSlots ( * ( m_Client - > GetPlayer ( ) ) , Slots ) ;
for ( cItems : : const_iterator itr = Slots . begin ( ) , end = Slots . end ( ) ; itr ! = end ; + + itr )
{
Pkt . WriteItem ( * itr ) ;
} // for itr - Slots[]
2013-11-01 11:20:15 -04:00
}
2013-11-06 06:16:44 -05:00
void cProtocol172 : : SendWindowClose ( const cWindow & a_Window )
2013-11-01 11:20:15 -04:00
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-06 06:16:44 -05:00
cPacketizer Pkt ( * this , 0x2e ) ;
Pkt . WriteChar ( a_Window . GetWindowID ( ) ) ;
2013-11-01 11:20:15 -04:00
}
2013-11-08 15:32:14 -05:00
void cProtocol172 : : SendWindowOpen ( const cWindow & a_Window )
2013-11-01 11:20:15 -04:00
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-08 15:32:14 -05:00
if ( a_Window . GetWindowType ( ) < 0 )
{
// Do not send this packet for player inventory windows
return ;
}
2013-11-06 06:16:44 -05:00
cPacketizer Pkt ( * this , 0x2d ) ;
2013-11-08 15:32:14 -05:00
Pkt . WriteChar ( a_Window . GetWindowID ( ) ) ;
Pkt . WriteChar ( a_Window . GetWindowType ( ) ) ;
Pkt . WriteString ( a_Window . GetWindowTitle ( ) ) ;
Pkt . WriteChar ( a_Window . GetNumNonInventorySlots ( ) ) ;
2013-11-06 06:16:44 -05:00
Pkt . WriteBool ( true ) ;
2013-11-08 15:32:14 -05:00
if ( a_Window . GetWindowType ( ) = = cWindow : : wtAnimalChest )
2013-11-06 06:16:44 -05:00
{
2013-11-08 15:32:14 -05:00
Pkt . WriteInt ( 0 ) ; // TODO: The animal's EntityID
2013-11-06 06:16:44 -05:00
}
2013-11-01 11:20:15 -04:00
}
2014-05-01 16:58:58 -04:00
void cProtocol172 : : SendWindowProperty ( const cWindow & a_Window , int a_Property , int a_Value )
2013-11-01 11:20:15 -04:00
{
2014-04-16 12:10:48 -04:00
ASSERT ( m_State = = 3 ) ; // In game mode?
2013-11-06 06:16:44 -05:00
cPacketizer Pkt ( * this , 0x31 ) ; // Window Property packet
Pkt . WriteChar ( a_Window . GetWindowID ( ) ) ;
Pkt . WriteShort ( a_Property ) ;
Pkt . WriteShort ( a_Value ) ;
2013-11-01 11:20:15 -04:00
}
2014-04-04 05:47:46 -04:00
void cProtocol172 : : AddReceivedData ( const char * a_Data , size_t a_Size )
2013-10-30 18:24:46 -04:00
{
2014-01-24 17:03:48 -05:00
// Write the incoming data into the comm log file:
2014-01-26 11:54:18 -05:00
if ( g_ShouldLogCommIn )
2014-01-24 17:03:48 -05:00
{
2014-01-25 09:06:21 -05:00
if ( m_ReceivedData . GetReadableSpace ( ) > 0 )
{
AString AllData ;
2014-03-08 11:33:38 -05:00
size_t OldReadableSpace = m_ReceivedData . GetReadableSpace ( ) ;
2014-01-25 09:06:21 -05:00
m_ReceivedData . ReadAll ( AllData ) ;
m_ReceivedData . ResetRead ( ) ;
m_ReceivedData . SkipRead ( m_ReceivedData . GetReadableSpace ( ) - OldReadableSpace ) ;
2014-01-26 11:54:18 -05:00
ASSERT ( m_ReceivedData . GetReadableSpace ( ) = = OldReadableSpace ) ;
2014-01-25 09:06:21 -05:00
AString Hex ;
CreateHexDump ( Hex , AllData . data ( ) , AllData . size ( ) , 16 ) ;
2014-03-12 13:34:50 -04:00
m_CommLogFile . Printf ( " Incoming data, " SIZE_T_FMT " (0x " SIZE_T_FMT_HEX " ) unparsed bytes already present in buffer: \n %s \n " ,
2014-01-25 09:06:21 -05:00
AllData . size ( ) , AllData . size ( ) , Hex . c_str ( )
) ;
}
2014-01-24 17:03:48 -05:00
AString Hex ;
CreateHexDump ( Hex , a_Data , a_Size , 16 ) ;
2014-01-25 09:06:21 -05:00
m_CommLogFile . Printf ( " Incoming data: %d (0x%x) bytes: \n %s \n " ,
2014-04-04 06:08:14 -04:00
( unsigned ) a_Size , ( unsigned ) a_Size , Hex . c_str ( )
2014-01-24 17:03:48 -05:00
) ;
2014-01-26 11:54:18 -05:00
m_CommLogFile . Flush ( ) ;
2014-01-24 17:03:48 -05:00
}
2014-09-08 06:24:06 -04:00
2013-10-30 18:24:46 -04:00
if ( ! m_ReceivedData . Write ( a_Data , a_Size ) )
{
// Too much data in the incoming queue, report to caller:
m_Client - > PacketBufferFull ( ) ;
return ;
}
2014-09-08 06:24:06 -04:00
2013-10-30 18:24:46 -04:00
// Handle all complete packets:
2014-01-07 08:24:25 -05:00
for ( ; ; )
2013-10-30 18:24:46 -04:00
{
UInt32 PacketLen ;
if ( ! m_ReceivedData . ReadVarInt ( PacketLen ) )
{
// Not enough data
2014-01-26 11:54:18 -05:00
m_ReceivedData . ResetRead ( ) ;
break ;
2013-10-30 18:24:46 -04:00
}
if ( ! m_ReceivedData . CanReadBytes ( PacketLen ) )
{
// The full packet hasn't been received yet
2014-01-26 11:54:18 -05:00
m_ReceivedData . ResetRead ( ) ;
break ;
2013-10-30 18:24:46 -04:00
}
2013-12-13 11:53:00 -05:00
cByteBuffer bb ( PacketLen + 1 ) ;
VERIFY ( m_ReceivedData . ReadToByteBuffer ( bb , ( int ) PacketLen ) ) ;
m_ReceivedData . CommitRead ( ) ;
2014-09-08 06:24:06 -04:00
2013-10-30 18:24:46 -04:00
UInt32 PacketType ;
2013-12-13 11:53:00 -05:00
if ( ! bb . ReadVarInt ( PacketType ) )
2013-10-30 18:24:46 -04:00
{
// Not enough data
2014-01-26 11:54:18 -05:00
break ;
2013-10-30 18:24:46 -04:00
}
2013-11-03 05:58:49 -05:00
2014-09-25 12:33:34 -04:00
// Write one NUL extra, so that we can detect over-reads
bb . Write ( " \0 " , 1 ) ;
2014-01-24 17:03:48 -05:00
// Log the packet info into the comm log file:
2014-01-26 11:54:18 -05:00
if ( g_ShouldLogCommIn )
2014-01-24 17:03:48 -05:00
{
AString PacketData ;
bb . ReadAll ( PacketData ) ;
bb . ResetRead ( ) ;
bb . ReadVarInt ( PacketType ) ;
2014-09-25 12:33:34 -04:00
ASSERT ( PacketData . size ( ) > 0 ) ; // We have written an extra NUL, so there had to be at least one byte read
2014-01-24 17:03:48 -05:00
PacketData . resize ( PacketData . size ( ) - 1 ) ;
AString PacketDataHex ;
CreateHexDump ( PacketDataHex , PacketData . data ( ) , PacketData . size ( ) , 16 ) ;
m_CommLogFile . Printf ( " Next incoming packet is type %u (0x%x), length %u (0x%x) at state %d. Payload: \n %s \n " ,
PacketType , PacketType , PacketLen , PacketLen , m_State , PacketDataHex . c_str ( )
) ;
}
2014-09-08 11:02:54 -04:00
2014-01-16 09:26:58 -05:00
if ( ! HandlePacket ( bb , PacketType ) )
{
2014-01-16 14:39:59 -05:00
// Unknown packet, already been reported, but without the length. Log the length here:
2014-01-17 04:12:04 -05:00
LOGWARNING ( " Unhandled packet: type 0x%x, state %d, length %u " , PacketType , m_State , PacketLen ) ;
2014-01-16 14:39:59 -05:00
# ifdef _DEBUG
// Dump the packet contents into the log:
bb . ResetRead ( ) ;
AString Packet ;
bb . ReadAll ( Packet ) ;
Packet . resize ( Packet . size ( ) - 1 ) ; // Drop the final NUL pushed there for over-read detection
AString Out ;
CreateHexDump ( Out , Packet . data ( ) , ( int ) Packet . size ( ) , 24 ) ;
LOGD ( " Packet contents: \n %s " , Out . c_str ( ) ) ;
# endif // _DEBUG
2014-01-25 09:28:16 -05:00
// Put a message in the comm log:
2014-01-26 11:54:18 -05:00
if ( g_ShouldLogCommIn )
2014-01-25 09:28:16 -05:00
{
m_CommLogFile . Printf ( " ^^^^^^ Unhandled packet ^^^^^^ \n \n \n " ) ;
}
2014-01-16 09:26:58 -05:00
return ;
}
2014-09-08 11:02:54 -04:00
2013-12-13 11:53:00 -05:00
if ( bb . GetReadableSpace ( ) ! = 1 )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
// Read more or less than packet length, report as error
2014-03-12 13:34:50 -04:00
LOGWARNING ( " Protocol 1.7: Wrong number of bytes read for packet 0x%x, state %d. Read " SIZE_T_FMT " bytes, packet contained %u bytes " ,
2014-01-17 04:12:04 -05:00
PacketType , m_State , bb . GetUsedSpace ( ) - bb . GetReadableSpace ( ) , PacketLen
2014-01-16 09:26:58 -05:00
) ;
2014-01-25 09:28:16 -05:00
// Put a message in the comm log:
2014-01-26 11:54:18 -05:00
if ( g_ShouldLogCommIn )
2014-01-25 09:28:16 -05:00
{
2014-03-12 13:34:50 -04:00
m_CommLogFile . Printf ( " ^^^^^^ Wrong number of bytes read for this packet (exp %d left, got " SIZE_T_FMT " left) ^^^^^^ \n \n \n " ,
2014-01-25 09:28:16 -05:00
1 , bb . GetReadableSpace ( )
) ;
m_CommLogFile . Flush ( ) ;
}
2013-12-13 11:53:00 -05:00
ASSERT ( ! " Read wrong number of bytes! " ) ;
2013-10-31 18:48:43 -04:00
m_Client - > PacketError ( PacketType ) ;
}
2014-07-20 17:10:31 -04:00
} // for (ever)
2014-09-08 11:02:54 -04:00
2014-01-26 11:54:18 -05:00
// Log any leftover bytes into the logfile:
if ( g_ShouldLogCommIn & & ( m_ReceivedData . GetReadableSpace ( ) > 0 ) )
{
AString AllData ;
2014-03-08 11:33:38 -05:00
size_t OldReadableSpace = m_ReceivedData . GetReadableSpace ( ) ;
2014-01-26 11:54:18 -05:00
m_ReceivedData . ReadAll ( AllData ) ;
m_ReceivedData . ResetRead ( ) ;
m_ReceivedData . SkipRead ( m_ReceivedData . GetReadableSpace ( ) - OldReadableSpace ) ;
ASSERT ( m_ReceivedData . GetReadableSpace ( ) = = OldReadableSpace ) ;
AString Hex ;
CreateHexDump ( Hex , AllData . data ( ) , AllData . size ( ) , 16 ) ;
2014-03-12 13:34:50 -04:00
m_CommLogFile . Printf ( " There are " SIZE_T_FMT " (0x " SIZE_T_FMT_HEX " ) bytes of non-parse-able data left in the buffer: \n %s " ,
2014-01-26 11:54:18 -05:00
m_ReceivedData . GetReadableSpace ( ) , m_ReceivedData . GetReadableSpace ( ) , Hex . c_str ( )
) ;
m_CommLogFile . Flush ( ) ;
}
2013-10-30 18:24:46 -04:00
}
2014-01-16 09:26:58 -05:00
bool cProtocol172 : : HandlePacket ( cByteBuffer & a_ByteBuffer , UInt32 a_PacketType )
2013-10-30 18:24:46 -04:00
{
switch ( m_State )
{
case 1 :
{
// Status
switch ( a_PacketType )
{
2014-01-16 09:26:58 -05:00
case 0x00 : HandlePacketStatusRequest ( a_ByteBuffer ) ; return true ;
case 0x01 : HandlePacketStatusPing ( a_ByteBuffer ) ; return true ;
2013-10-30 18:24:46 -04:00
}
break ;
}
case 2 :
{
// Login
2013-10-31 18:48:43 -04:00
switch ( a_PacketType )
{
2014-01-16 09:26:58 -05:00
case 0x00 : HandlePacketLoginStart ( a_ByteBuffer ) ; return true ;
case 0x01 : HandlePacketLoginEncryptionResponse ( a_ByteBuffer ) ; return true ;
2013-10-31 18:48:43 -04:00
}
2013-10-30 18:24:46 -04:00
break ;
}
case 3 :
{
// Game
2013-10-31 18:48:43 -04:00
switch ( a_PacketType )
{
2014-01-16 09:26:58 -05:00
case 0x00 : HandlePacketKeepAlive ( a_ByteBuffer ) ; return true ;
case 0x01 : HandlePacketChatMessage ( a_ByteBuffer ) ; return true ;
case 0x02 : HandlePacketUseEntity ( a_ByteBuffer ) ; return true ;
case 0x03 : HandlePacketPlayer ( a_ByteBuffer ) ; return true ;
case 0x04 : HandlePacketPlayerPos ( a_ByteBuffer ) ; return true ;
case 0x05 : HandlePacketPlayerLook ( a_ByteBuffer ) ; return true ;
case 0x06 : HandlePacketPlayerPosLook ( a_ByteBuffer ) ; return true ;
case 0x07 : HandlePacketBlockDig ( a_ByteBuffer ) ; return true ;
case 0x08 : HandlePacketBlockPlace ( a_ByteBuffer ) ; return true ;
case 0x09 : HandlePacketSlotSelect ( a_ByteBuffer ) ; return true ;
case 0x0a : HandlePacketAnimation ( a_ByteBuffer ) ; return true ;
case 0x0b : HandlePacketEntityAction ( a_ByteBuffer ) ; return true ;
case 0x0c : HandlePacketSteerVehicle ( a_ByteBuffer ) ; return true ;
case 0x0d : HandlePacketWindowClose ( a_ByteBuffer ) ; return true ;
case 0x0e : HandlePacketWindowClick ( a_ByteBuffer ) ; return true ;
2014-07-17 16:15:34 -04:00
case 0x0f : // Confirm transaction - not used in MCS
2014-01-16 09:26:58 -05:00
case 0x10 : HandlePacketCreativeInventoryAction ( a_ByteBuffer ) ; return true ;
2014-01-31 13:46:51 -05:00
case 0x11 : HandlePacketEnchantItem ( a_ByteBuffer ) ; return true ;
2014-01-16 09:26:58 -05:00
case 0x12 : HandlePacketUpdateSign ( a_ByteBuffer ) ; return true ;
case 0x13 : HandlePacketPlayerAbilities ( a_ByteBuffer ) ; return true ;
case 0x14 : HandlePacketTabComplete ( a_ByteBuffer ) ; return true ;
case 0x15 : HandlePacketClientSettings ( a_ByteBuffer ) ; return true ;
case 0x16 : HandlePacketClientStatus ( a_ByteBuffer ) ; return true ;
case 0x17 : HandlePacketPluginMessage ( a_ByteBuffer ) ; return true ;
2013-10-31 18:48:43 -04:00
}
2013-10-30 18:24:46 -04:00
break ;
}
2014-01-17 04:12:04 -05:00
default :
{
// Received a packet in an unknown state, report:
LOGWARNING ( " Received a packet in an unknown protocol state %d. Ignoring further packets. " , m_State ) ;
// Cannot kick the client - we don't know this state and thus the packet number for the kick packet
// Switch to a state when all further packets are silently ignored:
m_State = 255 ;
return false ;
}
case 255 :
{
// This is the state used for "not processing packets anymore" when we receive a bad packet from a client.
// Do not output anything (the caller will do that for us), just return failure
return false ;
}
2013-10-30 18:24:46 -04:00
} // switch (m_State)
2014-01-17 04:12:04 -05:00
// Unknown packet type, report to the ClientHandle:
2013-10-30 18:24:46 -04:00
m_Client - > PacketUnknown ( a_PacketType ) ;
2014-01-16 09:26:58 -05:00
return false ;
2013-10-30 18:24:46 -04:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketStatusPing ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
cProtocol172: Check return values.
Fixes CID 43489, CID 43490, CID 43491, CID 43493, CID 66410, CID 66411, CID 66416, CID 66417, CID 66418, CID 66419, CID 66420, CID 66421, CID 66422, CID 66423, CID 66424, CID 66425, CID 66429, CID 66430, CID 66431
2014-08-11 09:33:20 -04:00
HANDLE_READ ( a_ByteBuffer , ReadBEInt64 , Int64 , Timestamp ) ;
2014-09-03 18:29:36 -04:00
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x01 ) ; // Ping packet
Pkt . WriteInt64 ( Timestamp ) ;
2013-10-31 18:48:43 -04:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketStatusRequest ( cByteBuffer & a_ByteBuffer )
2013-10-30 18:24:46 -04:00
{
2014-04-18 15:09:44 -04:00
cServer * Server = cRoot : : Get ( ) - > GetServer ( ) ;
2014-08-20 16:22:38 -04:00
AString ServerDescription = Server - > GetDescription ( ) ;
2014-08-20 10:01:30 -04:00
int NumPlayers = Server - > GetNumPlayers ( ) ;
int MaxPlayers = Server - > GetMaxPlayers ( ) ;
AString Favicon = Server - > GetFaviconData ( ) ;
2014-08-20 16:22:38 -04:00
cRoot : : Get ( ) - > GetPluginManager ( ) - > CallHookServerPing ( * m_Client , ServerDescription , NumPlayers , MaxPlayers , Favicon ) ;
2014-08-20 10:01:30 -04:00
// Version:
Json : : Value Version ;
Version [ " name " ] = " 1.7.2 " ;
Version [ " protocol " ] = 4 ;
// Players:
Json : : Value Players ;
Players [ " online " ] = NumPlayers ;
Players [ " max " ] = MaxPlayers ;
// TODO: Add "sample"
// Description:
Json : : Value Description ;
2014-08-20 16:22:38 -04:00
Description [ " text " ] = ServerDescription . c_str ( ) ;
2014-08-20 10:01:30 -04:00
// Create the response:
Json : : Value ResponseValue ;
ResponseValue [ " version " ] = Version ;
ResponseValue [ " players " ] = Players ;
ResponseValue [ " description " ] = Description ;
if ( ! Favicon . empty ( ) )
{
ResponseValue [ " favicon " ] = Printf ( " data:image/png;base64,%s " , Favicon . c_str ( ) ) ;
}
Json : : StyledWriter Writer ;
AString Response = Writer . write ( ResponseValue ) ;
2013-11-03 05:58:49 -05:00
cPacketizer Pkt ( * this , 0x00 ) ; // Response packet
Pkt . WriteString ( Response ) ;
2013-10-30 18:24:46 -04:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketLoginEncryptionResponse ( cByteBuffer & a_ByteBuffer )
2013-10-30 18:38:55 -04:00
{
2014-01-28 17:53:07 -05:00
short EncKeyLength , EncNonceLength ;
a_ByteBuffer . ReadBEShort ( EncKeyLength ) ;
AString EncKey ;
if ( ! a_ByteBuffer . ReadString ( EncKey , EncKeyLength ) )
{
return ;
}
a_ByteBuffer . ReadBEShort ( EncNonceLength ) ;
AString EncNonce ;
if ( ! a_ByteBuffer . ReadString ( EncNonce , EncNonceLength ) )
{
return ;
}
if ( ( EncKeyLength > MAX_ENC_LEN ) | | ( EncNonceLength > MAX_ENC_LEN ) )
{
LOGD ( " Too long encryption " ) ;
m_Client - > Kick ( " Hacked client " ) ;
return ;
}
// Decrypt EncNonce using privkey
2014-04-29 05:04:54 -04:00
cRsaPrivateKey & rsaDecryptor = cRoot : : Get ( ) - > GetServer ( ) - > GetPrivateKey ( ) ;
2014-01-28 17:53:07 -05:00
Int32 DecryptedNonce [ MAX_ENC_LEN / sizeof ( Int32 ) ] ;
int res = rsaDecryptor . Decrypt ( ( const Byte * ) EncNonce . data ( ) , EncNonce . size ( ) , ( Byte * ) DecryptedNonce , sizeof ( DecryptedNonce ) ) ;
if ( res ! = 4 )
{
LOGD ( " Bad nonce length: got %d, exp %d " , res , 4 ) ;
m_Client - > Kick ( " Hacked client " ) ;
return ;
}
if ( ntohl ( DecryptedNonce [ 0 ] ) ! = ( unsigned ) ( uintptr_t ) this )
{
LOGD ( " Bad nonce value " ) ;
m_Client - > Kick ( " Hacked client " ) ;
return ;
}
// Decrypt the symmetric encryption key using privkey:
Byte DecryptedKey [ MAX_ENC_LEN ] ;
res = rsaDecryptor . Decrypt ( ( const Byte * ) EncKey . data ( ) , EncKey . size ( ) , DecryptedKey , sizeof ( DecryptedKey ) ) ;
if ( res ! = 16 )
{
LOGD ( " Bad key length " ) ;
m_Client - > Kick ( " Hacked client " ) ;
return ;
}
StartEncryption ( DecryptedKey ) ;
m_Client - > HandleLogin ( 4 , m_Client - > GetUsername ( ) ) ;
2013-10-31 18:48:43 -04:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketLoginStart ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
AString Username ;
2014-08-21 15:38:57 -04:00
if ( ! a_ByteBuffer . ReadVarUTF8String ( Username ) )
{
m_Client - > Kick ( " Bad username " ) ;
return ;
}
2013-10-30 18:38:55 -04:00
2014-01-13 14:32:15 -05:00
if ( ! m_Client - > HandleHandshake ( Username ) )
{
// The client is not welcome here, they have been sent a Kick packet already
return ;
}
2014-04-18 15:09:44 -04:00
cServer * Server = cRoot : : Get ( ) - > GetServer ( ) ;
2014-01-28 17:53:07 -05:00
// If auth is required, then send the encryption request:
2014-04-18 15:09:44 -04:00
if ( Server - > ShouldAuthenticate ( ) )
2014-01-28 17:53:07 -05:00
{
cPacketizer Pkt ( * this , 0x01 ) ;
2014-04-18 15:09:44 -04:00
Pkt . WriteString ( Server - > GetServerID ( ) ) ;
const AString & PubKeyDer = Server - > GetPublicKeyDER ( ) ;
2014-05-08 14:16:35 -04:00
Pkt . WriteShort ( ( short ) PubKeyDer . size ( ) ) ;
2014-01-28 17:53:07 -05:00
Pkt . WriteBuf ( PubKeyDer . data ( ) , PubKeyDer . size ( ) ) ;
Pkt . WriteShort ( 4 ) ;
Pkt . WriteInt ( ( int ) ( intptr_t ) this ) ; // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :)
m_Client - > SetUsername ( Username ) ;
return ;
}
2013-10-31 18:48:43 -04:00
m_Client - > HandleLogin ( 4 , Username ) ;
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketAnimation ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadBEInt , int , EntityID ) ;
HANDLE_READ ( a_ByteBuffer , ReadByte , Byte , Animation ) ;
2013-10-31 18:48:43 -04:00
m_Client - > HandleAnimation ( Animation ) ;
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketBlockDig ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadByte , Byte , Status ) ;
HANDLE_READ ( a_ByteBuffer , ReadBEInt , int , BlockX ) ;
HANDLE_READ ( a_ByteBuffer , ReadByte , Byte , BlockY ) ;
HANDLE_READ ( a_ByteBuffer , ReadBEInt , int , BlockZ ) ;
2014-02-04 16:15:01 -05:00
HANDLE_READ ( a_ByteBuffer , ReadChar , char , Face ) ;
2014-02-04 13:59:05 -05:00
m_Client - > HandleLeftClick ( BlockX , BlockY , BlockZ , static_cast < eBlockFace > ( Face ) , Status ) ;
2013-10-31 18:48:43 -04:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketBlockPlace ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadBEInt , int , BlockX ) ;
HANDLE_READ ( a_ByteBuffer , ReadByte , Byte , BlockY ) ;
HANDLE_READ ( a_ByteBuffer , ReadBEInt , int , BlockZ ) ;
2014-02-04 16:15:01 -05:00
HANDLE_READ ( a_ByteBuffer , ReadChar , char , Face ) ;
2013-12-02 11:32:28 -05:00
cItem Item ;
2013-12-13 11:53:00 -05:00
ReadItem ( a_ByteBuffer , Item ) ;
2013-12-01 22:40:12 -05:00
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadByte , Byte , CursorX ) ;
HANDLE_READ ( a_ByteBuffer , ReadByte , Byte , CursorY ) ;
HANDLE_READ ( a_ByteBuffer , ReadByte , Byte , CursorZ ) ;
2014-02-04 13:59:05 -05:00
m_Client - > HandleRightClick ( BlockX , BlockY , BlockZ , static_cast < eBlockFace > ( Face ) , CursorX , CursorY , CursorZ , m_Client - > GetPlayer ( ) - > GetEquippedItem ( ) ) ;
2013-10-31 18:48:43 -04:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketChatMessage ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadVarUTF8String , AString , Message ) ;
2013-10-31 18:48:43 -04:00
m_Client - > HandleChat ( Message ) ;
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketClientSettings ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadVarUTF8String , AString , Locale ) ;
HANDLE_READ ( a_ByteBuffer , ReadByte , Byte , ViewDistance ) ;
HANDLE_READ ( a_ByteBuffer , ReadByte , Byte , ChatFlags ) ;
HANDLE_READ ( a_ByteBuffer , ReadByte , Byte , ChatColors ) ;
HANDLE_READ ( a_ByteBuffer , ReadByte , Byte , Difficulty ) ;
HANDLE_READ ( a_ByteBuffer , ReadByte , Byte , ShowCape ) ;
2014-02-16 07:26:07 -05:00
m_Client - > SetLocale ( Locale ) ;
2014-09-04 13:03:21 -04:00
// TODO: Do anything with the other values.
2013-10-31 18:48:43 -04:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketClientStatus ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadByte , Byte , ActionID ) ;
2013-11-03 15:34:36 -05:00
switch ( ActionID )
{
case 0 :
{
// Respawn
m_Client - > HandleRespawn ( ) ;
break ;
}
case 1 :
{
// Request stats
2014-05-11 07:57:06 -04:00
const cStatManager & Manager = m_Client - > GetPlayer ( ) - > GetStatManager ( ) ;
SendStatistics ( Manager ) ;
2013-11-03 15:34:36 -05:00
break ;
}
case 2 :
{
// Open Inventory achievement
2014-05-12 10:05:09 -04:00
m_Client - > GetPlayer ( ) - > AwardAchievement ( achOpenInv ) ;
2013-11-03 15:34:36 -05:00
break ;
}
}
2013-10-31 18:48:43 -04:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketCreativeInventoryAction ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadBEShort , short , SlotNum ) ;
2013-11-06 14:48:35 -05:00
cItem Item ;
2013-12-13 11:53:00 -05:00
if ( ! ReadItem ( a_ByteBuffer , Item ) )
2013-11-06 14:48:35 -05:00
{
return ;
}
m_Client - > HandleCreativeInventory ( SlotNum , Item ) ;
2013-10-31 18:48:43 -04:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketEntityAction ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadBEInt , int , PlayerID ) ;
HANDLE_READ ( a_ByteBuffer , ReadByte , Byte , Action ) ;
HANDLE_READ ( a_ByteBuffer , ReadBEInt , int , JumpBoost ) ;
2014-03-08 11:55:53 -05:00
2014-03-08 13:26:32 -05:00
switch ( Action )
2014-03-08 11:55:53 -05:00
{
2014-07-17 16:15:34 -04:00
case 1 : m_Client - > HandleEntityCrouch ( PlayerID , true ) ; break ; // Crouch
case 2 : m_Client - > HandleEntityCrouch ( PlayerID , false ) ; break ; // Uncrouch
case 3 : m_Client - > HandleEntityLeaveBed ( PlayerID ) ; break ; // Leave Bed
case 4 : m_Client - > HandleEntitySprinting ( PlayerID , true ) ; break ; // Start sprinting
case 5 : m_Client - > HandleEntitySprinting ( PlayerID , false ) ; break ; // Stop sprinting
2014-03-08 11:55:53 -05:00
}
2013-10-31 18:48:43 -04:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketKeepAlive ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadBEInt , int , KeepAliveID ) ;
2013-11-06 16:27:09 -05:00
m_Client - > HandleKeepAlive ( KeepAliveID ) ;
2013-10-31 18:48:43 -04:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketPlayer ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadBool , bool , IsOnGround ) ;
2013-11-06 16:27:09 -05:00
// TODO: m_Client->HandlePlayerOnGround(IsOnGround);
2013-10-31 18:48:43 -04:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketPlayerAbilities ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadByte , Byte , Flags ) ;
HANDLE_READ ( a_ByteBuffer , ReadBEFloat , float , FlyingSpeed ) ;
HANDLE_READ ( a_ByteBuffer , ReadBEFloat , float , WalkingSpeed ) ;
2013-12-15 09:11:59 -05:00
2013-12-19 15:53:47 -05:00
bool IsFlying = false , CanFly = false ;
2013-12-15 09:11:59 -05:00
if ( ( Flags & 2 ) ! = 0 )
{
IsFlying = true ;
}
if ( ( Flags & 4 ) ! = 0 )
{
CanFly = true ;
}
2013-12-19 15:53:47 -05:00
2013-12-15 09:11:59 -05:00
m_Client - > HandlePlayerAbilities ( CanFly , IsFlying , FlyingSpeed , WalkingSpeed ) ;
2013-10-31 18:48:43 -04:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketPlayerLook ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadBEFloat , float , Yaw ) ;
HANDLE_READ ( a_ByteBuffer , ReadBEFloat , float , Pitch ) ;
HANDLE_READ ( a_ByteBuffer , ReadBool , bool , IsOnGround ) ;
2013-11-06 16:27:09 -05:00
m_Client - > HandlePlayerLook ( Yaw , Pitch , IsOnGround ) ;
2013-10-31 18:48:43 -04:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketPlayerPos ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadBEDouble , double , PosX ) ;
HANDLE_READ ( a_ByteBuffer , ReadBEDouble , double , PosY ) ;
HANDLE_READ ( a_ByteBuffer , ReadBEDouble , double , Stance ) ;
HANDLE_READ ( a_ByteBuffer , ReadBEDouble , double , PosZ ) ;
HANDLE_READ ( a_ByteBuffer , ReadBool , bool , IsOnGround ) ;
2013-11-06 16:27:09 -05:00
m_Client - > HandlePlayerPos ( PosX , PosY , PosZ , Stance , IsOnGround ) ;
2013-10-31 18:48:43 -04:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketPlayerPosLook ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadBEDouble , double , PosX ) ;
HANDLE_READ ( a_ByteBuffer , ReadBEDouble , double , PosY ) ;
HANDLE_READ ( a_ByteBuffer , ReadBEDouble , double , Stance ) ;
HANDLE_READ ( a_ByteBuffer , ReadBEDouble , double , PosZ ) ;
HANDLE_READ ( a_ByteBuffer , ReadBEFloat , float , Yaw ) ;
HANDLE_READ ( a_ByteBuffer , ReadBEFloat , float , Pitch ) ;
HANDLE_READ ( a_ByteBuffer , ReadBool , bool , IsOnGround ) ;
2013-11-06 16:27:09 -05:00
m_Client - > HandlePlayerMoveLook ( PosX , PosY , PosZ , Stance , Yaw , Pitch , IsOnGround ) ;
2013-10-31 18:48:43 -04:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketPluginMessage ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadVarUTF8String , AString , Channel ) ;
HANDLE_READ ( a_ByteBuffer , ReadBEShort , short , Length ) ;
2013-11-06 16:27:09 -05:00
AString Data ;
cProtocol172: Check return values.
Fixes CID 43489, CID 43490, CID 43491, CID 43493, CID 66410, CID 66411, CID 66416, CID 66417, CID 66418, CID 66419, CID 66420, CID 66421, CID 66422, CID 66423, CID 66424, CID 66425, CID 66429, CID 66430, CID 66431
2014-08-11 09:33:20 -04:00
if ( ! a_ByteBuffer . ReadString ( Data , Length ) )
{
return ;
}
2014-01-07 11:47:05 -05:00
m_Client - > HandlePluginMessage ( Channel , Data ) ;
2013-10-31 18:48:43 -04:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketSlotSelect ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadBEShort , short , SlotNum ) ;
2013-11-06 16:27:09 -05:00
m_Client - > HandleSlotSelected ( SlotNum ) ;
2013-10-31 18:48:43 -04:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketSteerVehicle ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadBEFloat , float , Forward ) ;
HANDLE_READ ( a_ByteBuffer , ReadBEFloat , float , Sideways ) ;
HANDLE_READ ( a_ByteBuffer , ReadBool , bool , ShouldJump ) ;
HANDLE_READ ( a_ByteBuffer , ReadBool , bool , ShouldUnmount ) ;
2013-11-06 16:27:09 -05:00
if ( ShouldUnmount )
{
m_Client - > HandleUnmount ( ) ;
}
else
{
m_Client - > HandleSteerVehicle ( Forward , Sideways ) ;
}
2013-10-31 18:48:43 -04:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketTabComplete ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadVarUTF8String , AString , Text ) ;
2013-11-06 16:27:09 -05:00
m_Client - > HandleTabCompletion ( Text ) ;
2013-10-31 18:48:43 -04:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketUpdateSign ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadBEInt , int , BlockX ) ;
HANDLE_READ ( a_ByteBuffer , ReadBEShort , short , BlockY ) ;
HANDLE_READ ( a_ByteBuffer , ReadBEInt , int , BlockZ ) ;
HANDLE_READ ( a_ByteBuffer , ReadVarUTF8String , AString , Line1 ) ;
HANDLE_READ ( a_ByteBuffer , ReadVarUTF8String , AString , Line2 ) ;
HANDLE_READ ( a_ByteBuffer , ReadVarUTF8String , AString , Line3 ) ;
HANDLE_READ ( a_ByteBuffer , ReadVarUTF8String , AString , Line4 ) ;
2013-11-06 16:27:09 -05:00
m_Client - > HandleUpdateSign ( BlockX , BlockY , BlockZ , Line1 , Line2 , Line3 , Line4 ) ;
2013-10-31 18:48:43 -04:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketUseEntity ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadBEInt , int , EntityID ) ;
HANDLE_READ ( a_ByteBuffer , ReadByte , Byte , MouseButton ) ;
2013-11-08 15:03:51 -05:00
m_Client - > HandleUseEntity ( EntityID , ( MouseButton = = 1 ) ) ;
2013-10-31 18:48:43 -04:00
}
2014-01-31 13:46:51 -05:00
void cProtocol172 : : HandlePacketEnchantItem ( cByteBuffer & a_ByteBuffer )
2014-01-20 12:22:08 -05:00
{
HANDLE_READ ( a_ByteBuffer , ReadByte , Byte , WindowID ) ;
HANDLE_READ ( a_ByteBuffer , ReadByte , Byte , Enchantment ) ;
2014-01-31 13:46:51 -05:00
m_Client - > HandleEnchantItem ( WindowID , Enchantment ) ;
2014-01-20 12:22:08 -05:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketWindowClick ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadChar , char , WindowID ) ;
HANDLE_READ ( a_ByteBuffer , ReadBEShort , short , SlotNum ) ;
HANDLE_READ ( a_ByteBuffer , ReadByte , Byte , Button ) ;
HANDLE_READ ( a_ByteBuffer , ReadBEShort , short , TransactionID ) ;
HANDLE_READ ( a_ByteBuffer , ReadByte , Byte , Mode ) ;
2013-11-06 16:27:09 -05:00
cItem Item ;
2013-12-13 11:53:00 -05:00
ReadItem ( a_ByteBuffer , Item ) ;
2013-11-06 16:27:09 -05:00
// Convert Button, Mode, SlotNum and HeldItem into eClickAction:
eClickAction Action ;
switch ( ( Mode < < 8 ) | Button )
{
case 0x0000 : Action = ( SlotNum ! = - 999 ) ? caLeftClick : caLeftClickOutside ; break ;
case 0x0001 : Action = ( SlotNum ! = - 999 ) ? caRightClick : caRightClickOutside ; break ;
case 0x0100 : Action = caShiftLeftClick ; break ;
case 0x0101 : Action = caShiftRightClick ; break ;
case 0x0200 : Action = caNumber1 ; break ;
case 0x0201 : Action = caNumber2 ; break ;
case 0x0202 : Action = caNumber3 ; break ;
case 0x0203 : Action = caNumber4 ; break ;
case 0x0204 : Action = caNumber5 ; break ;
case 0x0205 : Action = caNumber6 ; break ;
case 0x0206 : Action = caNumber7 ; break ;
case 0x0207 : Action = caNumber8 ; break ;
case 0x0208 : Action = caNumber9 ; break ;
case 0x0300 : Action = caMiddleClick ; break ;
case 0x0400 : Action = ( SlotNum = = - 999 ) ? caLeftClickOutsideHoldNothing : caDropKey ; break ;
case 0x0401 : Action = ( SlotNum = = - 999 ) ? caRightClickOutsideHoldNothing : caCtrlDropKey ; break ;
case 0x0500 : Action = ( SlotNum = = - 999 ) ? caLeftPaintBegin : caUnknown ; break ;
case 0x0501 : Action = ( SlotNum ! = - 999 ) ? caLeftPaintProgress : caUnknown ; break ;
case 0x0502 : Action = ( SlotNum = = - 999 ) ? caLeftPaintEnd : caUnknown ; break ;
case 0x0504 : Action = ( SlotNum = = - 999 ) ? caRightPaintBegin : caUnknown ; break ;
case 0x0505 : Action = ( SlotNum ! = - 999 ) ? caRightPaintProgress : caUnknown ; break ;
case 0x0506 : Action = ( SlotNum = = - 999 ) ? caRightPaintEnd : caUnknown ; break ;
case 0x0600 : Action = caDblClick ; break ;
2013-12-13 11:53:00 -05:00
default :
{
LOGWARNING ( " Unhandled window click mode / button combination: %d (0x%x) " , ( Mode < < 8 ) | Button , ( Mode < < 8 ) | Button ) ;
Action = caUnknown ;
break ;
}
2013-11-06 16:27:09 -05:00
}
m_Client - > HandleWindowClick ( WindowID , SlotNum , Action , Item ) ;
2013-10-31 18:48:43 -04:00
}
2013-12-13 11:53:00 -05:00
void cProtocol172 : : HandlePacketWindowClose ( cByteBuffer & a_ByteBuffer )
2013-10-31 18:48:43 -04:00
{
2013-12-13 11:53:00 -05:00
HANDLE_READ ( a_ByteBuffer , ReadChar , char , WindowID ) ;
2013-11-06 16:27:09 -05:00
m_Client - > HandleWindowClose ( WindowID ) ;
2013-10-30 18:38:55 -04:00
}
2013-10-30 18:24:46 -04:00
void cProtocol172 : : WritePacket ( cByteBuffer & a_Packet )
{
cCSLock Lock ( m_CSPacket ) ;
AString Pkt ;
a_Packet . ReadAll ( Pkt ) ;
2014-05-08 14:16:35 -04:00
WriteVarInt ( ( UInt32 ) Pkt . size ( ) ) ;
2013-10-30 18:24:46 -04:00
SendData ( Pkt . data ( ) , Pkt . size ( ) ) ;
Flush ( ) ;
}
2014-04-04 04:13:25 -04:00
void cProtocol172 : : SendData ( const char * a_Data , size_t a_Size )
2013-10-30 18:24:46 -04:00
{
if ( m_IsEncrypted )
{
2014-01-23 17:35:23 -05:00
Byte Encrypted [ 8192 ] ; // Larger buffer, we may be sending lots of data (chunks)
2013-10-30 18:24:46 -04:00
while ( a_Size > 0 )
{
2014-04-04 04:13:25 -04:00
size_t NumBytes = ( a_Size > sizeof ( Encrypted ) ) ? sizeof ( Encrypted ) : a_Size ;
2014-01-23 17:35:23 -05:00
m_Encryptor . ProcessData ( Encrypted , ( Byte * ) a_Data , NumBytes ) ;
2013-10-30 18:24:46 -04:00
m_Client - > SendData ( ( const char * ) Encrypted , NumBytes ) ;
a_Size - = NumBytes ;
a_Data + = NumBytes ;
}
}
else
{
m_Client - > SendData ( a_Data , a_Size ) ;
}
}
2013-12-13 11:53:00 -05:00
bool cProtocol172 : : ReadItem ( cByteBuffer & a_ByteBuffer , cItem & a_Item )
2013-11-06 14:48:35 -05:00
{
2013-12-13 11:53:00 -05:00
HANDLE_PACKET_READ ( a_ByteBuffer , ReadBEShort , short , ItemType ) ;
2013-11-06 14:48:35 -05:00
if ( ItemType = = - 1 )
{
// The item is empty, no more data follows
a_Item . Empty ( ) ;
return true ;
}
a_Item . m_ItemType = ItemType ;
2013-12-13 11:53:00 -05:00
HANDLE_PACKET_READ ( a_ByteBuffer , ReadChar , char , ItemCount ) ;
HANDLE_PACKET_READ ( a_ByteBuffer , ReadBEShort , short , ItemDamage ) ;
2013-11-06 14:48:35 -05:00
a_Item . m_ItemCount = ItemCount ;
a_Item . m_ItemDamage = ItemDamage ;
if ( ItemCount < = 0 )
{
a_Item . Empty ( ) ;
}
2013-12-13 11:53:00 -05:00
HANDLE_PACKET_READ ( a_ByteBuffer , ReadBEShort , short , MetadataLength ) ;
2013-11-06 14:48:35 -05:00
if ( MetadataLength < = 0 )
{
return true ;
}
// Read the metadata
AString Metadata ;
2013-12-13 11:53:00 -05:00
if ( ! a_ByteBuffer . ReadString ( Metadata , MetadataLength ) )
2013-11-06 14:48:35 -05:00
{
return false ;
}
ParseItemMetadata ( a_Item , Metadata ) ;
return true ;
}
void cProtocol172 : : ParseItemMetadata ( cItem & a_Item , const AString & a_Metadata )
{
// Uncompress the GZIPped data:
AString Uncompressed ;
if ( UncompressStringGZIP ( a_Metadata . data ( ) , a_Metadata . size ( ) , Uncompressed ) ! = Z_OK )
{
AString HexDump ;
CreateHexDump ( HexDump , a_Metadata . data ( ) , a_Metadata . size ( ) , 16 ) ;
2014-03-12 13:34:50 -04:00
LOGWARNING ( " Cannot unGZIP item metadata ( " SIZE_T_FMT " bytes): \n %s " , a_Metadata . size ( ) , HexDump . c_str ( ) ) ;
2013-11-06 14:48:35 -05:00
return ;
}
// Parse into NBT:
cParsedNBT NBT ( Uncompressed . data ( ) , Uncompressed . size ( ) ) ;
if ( ! NBT . IsValid ( ) )
{
AString HexDump ;
CreateHexDump ( HexDump , Uncompressed . data ( ) , Uncompressed . size ( ) , 16 ) ;
2014-03-12 13:34:50 -04:00
LOGWARNING ( " Cannot parse NBT item metadata: ( " SIZE_T_FMT " bytes) \n %s " , Uncompressed . size ( ) , HexDump . c_str ( ) ) ;
2013-11-06 14:48:35 -05:00
return ;
}
2014-01-15 17:38:03 -05:00
// Load enchantments and custom display names from the NBT data:
2013-11-06 14:48:35 -05:00
for ( int tag = NBT . GetFirstChild ( NBT . GetRoot ( ) ) ; tag > = 0 ; tag = NBT . GetNextSibling ( tag ) )
{
2014-02-26 18:29:14 -05:00
AString TagName = NBT . GetName ( tag ) ;
switch ( NBT . GetType ( tag ) )
2014-01-15 17:38:03 -05:00
{
2014-02-26 18:29:14 -05:00
case TAG_List :
2014-01-15 17:38:03 -05:00
{
2014-07-17 16:15:34 -04:00
if ( ( TagName = = " ench " ) | | ( TagName = = " StoredEnchantments " ) ) // Enchantments tags
2014-01-15 17:38:03 -05:00
{
2014-02-26 18:29:14 -05:00
EnchantmentSerializer : : ParseFromNBT ( a_Item . m_Enchantments , NBT , tag ) ;
2014-01-15 17:38:03 -05:00
}
2014-02-26 18:29:14 -05:00
break ;
}
case TAG_Compound :
{
2014-07-17 16:15:34 -04:00
if ( TagName = = " display " ) // Custom name and lore tag
2014-01-15 17:38:03 -05:00
{
2014-02-26 18:29:14 -05:00
for ( int displaytag = NBT . GetFirstChild ( tag ) ; displaytag > = 0 ; displaytag = NBT . GetNextSibling ( displaytag ) )
2014-01-15 17:38:03 -05:00
{
2014-07-17 16:15:34 -04:00
if ( ( NBT . GetType ( displaytag ) = = TAG_String ) & & ( NBT . GetName ( displaytag ) = = " Name " ) ) // Custon name tag
2014-02-26 18:29:14 -05:00
{
a_Item . m_CustomName = NBT . GetString ( displaytag ) ;
}
2014-07-17 16:15:34 -04:00
else if ( ( NBT . GetType ( displaytag ) = = TAG_List ) & & ( NBT . GetName ( displaytag ) = = " Lore " ) ) // Lore tag
2014-02-26 18:29:14 -05:00
{
AString Lore ;
2014-07-17 16:15:34 -04:00
for ( int loretag = NBT . GetFirstChild ( displaytag ) ; loretag > = 0 ; loretag = NBT . GetNextSibling ( loretag ) ) // Loop through array of strings
2014-02-26 18:29:14 -05:00
{
2014-07-17 16:15:34 -04:00
AppendPrintf ( Lore , " %s` " , NBT . GetString ( loretag ) . c_str ( ) ) ; // Append the lore with a grave accent/backtick, used internally by MCS to display a new line in the client; don't forget to c_str ;)
2014-02-26 18:29:14 -05:00
}
a_Item . m_Lore = Lore ;
}
2014-01-15 17:38:03 -05:00
}
}
2014-02-26 18:29:14 -05:00
else if ( ( TagName = = " Fireworks " ) | | ( TagName = = " Explosion " ) )
{
cFireworkItem : : ParseFromNBT ( a_Item . m_FireworkItem , NBT , tag , ( ENUM_ITEM_ID ) a_Item . m_ItemType ) ;
}
break ;
2014-01-15 17:38:03 -05:00
}
2014-05-07 06:30:30 -04:00
case TAG_Int :
{
if ( TagName = = " RepairCost " )
{
2014-05-07 14:43:37 -04:00
a_Item . m_RepairCost = NBT . GetInt ( tag ) ;
2014-05-07 06:30:30 -04:00
}
}
2014-02-26 18:29:14 -05:00
default : LOGD ( " Unimplemented NBT data when parsing! " ) ; break ;
2014-01-15 17:38:03 -05:00
}
2013-11-06 14:48:35 -05:00
}
}
2014-01-28 17:53:07 -05:00
void cProtocol172 : : StartEncryption ( const Byte * a_Key )
{
m_Encryptor . Init ( a_Key , a_Key ) ;
m_Decryptor . Init ( a_Key , a_Key ) ;
m_IsEncrypted = true ;
// Prepare the m_AuthServerID:
2014-04-29 11:37:15 -04:00
cSha1Checksum Checksum ;
2014-04-18 15:09:44 -04:00
cServer * Server = cRoot : : Get ( ) - > GetServer ( ) ;
const AString & ServerID = Server - > GetServerID ( ) ;
2014-01-28 17:53:07 -05:00
Checksum . Update ( ( const Byte * ) ServerID . c_str ( ) , ServerID . length ( ) ) ;
Checksum . Update ( a_Key , 16 ) ;
2014-04-18 15:09:44 -04:00
Checksum . Update ( ( const Byte * ) Server - > GetPublicKeyDER ( ) . data ( ) , Server - > GetPublicKeyDER ( ) . size ( ) ) ;
2014-01-28 17:53:07 -05:00
Byte Digest [ 20 ] ;
Checksum . Finalize ( Digest ) ;
2014-04-29 11:37:15 -04:00
cSha1Checksum : : DigestToJava ( Digest , m_AuthServerID ) ;
2014-01-28 17:53:07 -05:00
}
2014-07-17 16:15:34 -04:00
////////////////////////////////////////////////////////////////////////////////
2013-11-03 05:58:49 -05:00
// cProtocol172::cPacketizer:
cProtocol172 : : cPacketizer : : ~ cPacketizer ( )
{
AString DataToSend ;
// Send the packet length
2014-05-08 14:16:35 -04:00
UInt32 PacketLen = ( UInt32 ) m_Out . GetUsedSpace ( ) ;
2014-09-08 05:35:21 -04:00
2013-11-03 05:58:49 -05:00
m_Protocol . m_OutPacketLenBuffer . WriteVarInt ( PacketLen ) ;
m_Protocol . m_OutPacketLenBuffer . ReadAll ( DataToSend ) ;
m_Protocol . SendData ( DataToSend . data ( ) , DataToSend . size ( ) ) ;
m_Protocol . m_OutPacketLenBuffer . CommitRead ( ) ;
// Send the packet data:
m_Out . ReadAll ( DataToSend ) ;
m_Protocol . SendData ( DataToSend . data ( ) , DataToSend . size ( ) ) ;
m_Out . CommitRead ( ) ;
2014-01-24 17:03:48 -05:00
// Log the comm into logfile:
2014-01-26 11:54:18 -05:00
if ( g_ShouldLogCommOut )
2014-01-24 17:03:48 -05:00
{
AString Hex ;
ASSERT ( DataToSend . size ( ) > 0 ) ;
CreateHexDump ( Hex , DataToSend . data ( ) + 1 , DataToSend . size ( ) - 1 , 16 ) ;
m_Protocol . m_CommLogFile . Printf ( " Outgoing packet: type %d (0x%x), length %u (0x%x), state %d. Payload: \n %s \n " ,
DataToSend [ 0 ] , DataToSend [ 0 ] , PacketLen , PacketLen , m_Protocol . m_State , Hex . c_str ( )
) ;
}
2013-11-03 05:58:49 -05:00
}
void cProtocol172 : : cPacketizer : : WriteItem ( const cItem & a_Item )
{
short ItemType = a_Item . m_ItemType ;
ASSERT ( ItemType > = - 1 ) ; // Check validity of packets in debug runtime
if ( ItemType < = 0 )
{
// Fix, to make sure no invalid values are sent.
ItemType = - 1 ;
}
if ( a_Item . IsEmpty ( ) )
{
WriteShort ( - 1 ) ;
return ;
}
WriteShort ( ItemType ) ;
WriteByte ( a_Item . m_ItemCount ) ;
WriteShort ( a_Item . m_ItemDamage ) ;
2014-02-26 18:29:14 -05:00
if ( a_Item . m_Enchantments . IsEmpty ( ) & & a_Item . IsBothNameAndLoreEmpty ( ) & & ( a_Item . m_ItemType ! = E_ITEM_FIREWORK_ROCKET ) & & ( a_Item . m_ItemType ! = E_ITEM_FIREWORK_STAR ) )
2013-11-03 05:58:49 -05:00
{
WriteShort ( - 1 ) ;
return ;
}
2014-01-15 17:38:03 -05:00
// Send the enchantments and custom names:
2013-11-03 05:58:49 -05:00
cFastNBTWriter Writer ;
2014-05-07 06:30:30 -04:00
if ( a_Item . m_RepairCost ! = 0 )
{
2014-05-07 14:43:37 -04:00
Writer . AddInt ( " RepairCost " , a_Item . m_RepairCost ) ;
2014-05-07 06:30:30 -04:00
}
2014-01-15 17:38:03 -05:00
if ( ! a_Item . m_Enchantments . IsEmpty ( ) )
{
const char * TagName = ( a_Item . m_ItemType = = E_ITEM_BOOK ) ? " StoredEnchantments " : " ench " ;
2014-07-19 08:53:41 -04:00
EnchantmentSerializer : : WriteToNBTCompound ( a_Item . m_Enchantments , Writer , TagName ) ;
2014-01-15 17:38:03 -05:00
}
if ( ! a_Item . IsBothNameAndLoreEmpty ( ) )
{
Writer . BeginCompound ( " display " ) ;
if ( ! a_Item . IsCustomNameEmpty ( ) )
{
Writer . AddString ( " Name " , a_Item . m_CustomName . c_str ( ) ) ;
}
if ( ! a_Item . IsLoreEmpty ( ) )
{
Writer . BeginList ( " Lore " , TAG_String ) ;
2014-01-16 17:30:57 -05:00
AStringVector Decls = StringSplit ( a_Item . m_Lore , " ` " ) ;
2014-01-15 17:38:03 -05:00
for ( AStringVector : : const_iterator itr = Decls . begin ( ) , end = Decls . end ( ) ; itr ! = end ; + + itr )
{
if ( itr - > empty ( ) )
{
2014-01-16 17:30:57 -05:00
// The decl is empty (two `s), ignore
2014-01-15 17:38:03 -05:00
continue ;
}
Writer . AddString ( " " , itr - > c_str ( ) ) ;
}
Writer . EndList ( ) ;
}
Writer . EndCompound ( ) ;
}
2014-02-26 18:29:14 -05:00
if ( ( a_Item . m_ItemType = = E_ITEM_FIREWORK_ROCKET ) | | ( a_Item . m_ItemType = = E_ITEM_FIREWORK_STAR ) )
{
cFireworkItem : : WriteToNBTCompound ( a_Item . m_FireworkItem , Writer , ( ENUM_ITEM_ID ) a_Item . m_ItemType ) ;
}
2013-11-03 05:58:49 -05:00
Writer . Finish ( ) ;
2014-09-08 11:02:54 -04:00
2013-11-03 05:58:49 -05:00
AString Compressed ;
CompressStringGZIP ( Writer . GetResult ( ) . data ( ) , Writer . GetResult ( ) . size ( ) , Compressed ) ;
2014-05-08 14:16:35 -04:00
WriteShort ( ( short ) Compressed . size ( ) ) ;
2013-11-03 05:58:49 -05:00
WriteBuf ( Compressed . data ( ) , Compressed . size ( ) ) ;
}
2014-09-03 21:22:35 -04:00
2014-01-19 08:25:35 -05:00
void cProtocol172 : : cPacketizer : : WriteBlockEntity ( const cBlockEntity & a_BlockEntity )
2014-01-18 19:54:38 -05:00
{
2014-01-19 08:25:35 -05:00
cFastNBTWriter Writer ;
switch ( a_BlockEntity . GetBlockType ( ) )
{
2014-07-30 15:59:35 -04:00
case E_BLOCK_BEACON :
{
cBeaconEntity & BeaconEntity = ( cBeaconEntity & ) a_BlockEntity ;
Writer . AddInt ( " x " , BeaconEntity . GetPosX ( ) ) ;
Writer . AddInt ( " y " , BeaconEntity . GetPosY ( ) ) ;
Writer . AddInt ( " z " , BeaconEntity . GetPosZ ( ) ) ;
2014-07-31 06:13:11 -04:00
Writer . AddInt ( " Primary " , BeaconEntity . GetPrimaryEffect ( ) ) ;
Writer . AddInt ( " Secondary " , BeaconEntity . GetSecondaryEffect ( ) ) ;
2014-07-30 15:59:35 -04:00
Writer . AddInt ( " Levels " , BeaconEntity . GetBeaconLevel ( ) ) ;
Writer . AddString ( " id " , " Beacon " ) ; // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
break ;
}
2014-01-19 08:25:35 -05:00
case E_BLOCK_COMMAND_BLOCK :
{
cCommandBlockEntity & CommandBlockEntity = ( cCommandBlockEntity & ) a_BlockEntity ;
2014-07-17 16:15:34 -04:00
Writer . AddByte ( " TrackOutput " , 1 ) ; // Neither I nor the MC wiki has any idea about this
2014-01-19 08:25:35 -05:00
Writer . AddInt ( " SuccessCount " , CommandBlockEntity . GetResult ( ) ) ;
Writer . AddInt ( " x " , CommandBlockEntity . GetPosX ( ) ) ;
Writer . AddInt ( " y " , CommandBlockEntity . GetPosY ( ) ) ;
Writer . AddInt ( " z " , CommandBlockEntity . GetPosZ ( ) ) ;
Writer . AddString ( " Command " , CommandBlockEntity . GetCommand ( ) . c_str ( ) ) ;
// You can set custom names for windows in Vanilla
// For a command block, this would be the 'name' prepended to anything it outputs into global chat
// MCS doesn't have this, so just leave it @ '@'. (geddit?)
Writer . AddString ( " CustomName " , " @ " ) ;
2014-07-17 16:15:34 -04:00
Writer . AddString ( " id " , " Control " ) ; // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
2014-01-19 08:25:35 -05:00
if ( ! CommandBlockEntity . GetLastOutput ( ) . empty ( ) )
{
AString Output ;
Printf ( Output , " { \" text \" : \" %s \" } " , CommandBlockEntity . GetLastOutput ( ) . c_str ( ) ) ;
Writer . AddString ( " LastOutput " , Output . c_str ( ) ) ;
}
break ;
}
2014-02-17 14:14:08 -05:00
case E_BLOCK_HEAD :
{
2014-02-19 08:45:09 -05:00
cMobHeadEntity & MobHeadEntity = ( cMobHeadEntity & ) a_BlockEntity ;
2014-03-06 19:30:34 -05:00
2014-02-19 08:45:09 -05:00
Writer . AddInt ( " x " , MobHeadEntity . GetPosX ( ) ) ;
Writer . AddInt ( " y " , MobHeadEntity . GetPosY ( ) ) ;
Writer . AddInt ( " z " , MobHeadEntity . GetPosZ ( ) ) ;
Writer . AddByte ( " SkullType " , MobHeadEntity . GetType ( ) & 0xFF ) ;
Writer . AddByte ( " Rot " , MobHeadEntity . GetRotation ( ) & 0xFF ) ;
Writer . AddString ( " ExtraType " , MobHeadEntity . GetOwner ( ) . c_str ( ) ) ;
2014-07-17 16:15:34 -04:00
Writer . AddString ( " id " , " Skull " ) ; // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
2014-02-19 08:12:34 -05:00
break ;
2014-02-17 14:14:08 -05:00
}
2014-03-06 19:30:34 -05:00
case E_BLOCK_FLOWER_POT :
{
cFlowerPotEntity & FlowerPotEntity = ( cFlowerPotEntity & ) a_BlockEntity ;
Writer . AddInt ( " x " , FlowerPotEntity . GetPosX ( ) ) ;
Writer . AddInt ( " y " , FlowerPotEntity . GetPosY ( ) ) ;
Writer . AddInt ( " z " , FlowerPotEntity . GetPosZ ( ) ) ;
Writer . AddInt ( " Item " , ( Int32 ) FlowerPotEntity . GetItem ( ) . m_ItemType ) ;
Writer . AddInt ( " Data " , ( Int32 ) FlowerPotEntity . GetItem ( ) . m_ItemDamage ) ;
2014-07-17 16:15:34 -04:00
Writer . AddString ( " id " , " FlowerPot " ) ; // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
2014-03-06 19:30:34 -05:00
break ;
}
2014-01-19 08:25:35 -05:00
default : break ;
}
Writer . Finish ( ) ;
2014-01-18 19:54:38 -05:00
AString Compressed ;
2014-01-19 08:25:35 -05:00
CompressStringGZIP ( Writer . GetResult ( ) . data ( ) , Writer . GetResult ( ) . size ( ) , Compressed ) ;
2014-05-08 14:16:35 -04:00
WriteShort ( ( short ) Compressed . size ( ) ) ;
2014-01-18 19:54:38 -05:00
WriteBuf ( Compressed . data ( ) , Compressed . size ( ) ) ;
}
2013-11-03 05:58:49 -05:00
void cProtocol172 : : cPacketizer : : WriteByteAngle ( double a_Angle )
{
WriteByte ( ( char ) ( 255 * a_Angle / 360 ) ) ;
}
void cProtocol172 : : cPacketizer : : WriteFPInt ( double a_Value )
{
int Value = ( int ) ( a_Value * 32 ) ;
WriteInt ( Value ) ;
}
2013-11-04 15:20:36 -05:00
void cProtocol172 : : cPacketizer : : WriteEntityMetadata ( const cEntity & a_Entity )
{
// Common metadata:
Byte Flags = 0 ;
if ( a_Entity . IsOnFire ( ) )
{
Flags | = 0x01 ;
}
if ( a_Entity . IsCrouched ( ) )
{
Flags | = 0x02 ;
}
if ( a_Entity . IsSprinting ( ) )
{
Flags | = 0x08 ;
}
if ( a_Entity . IsRclking ( ) )
{
Flags | = 0x10 ;
}
if ( a_Entity . IsInvisible ( ) )
{
Flags | = 0x20 ;
}
WriteByte ( 0 ) ; // Byte(0) + index 0
WriteByte ( Flags ) ;
switch ( a_Entity . GetEntityType ( ) )
{
case cEntity : : etPlayer : break ; // TODO?
case cEntity : : etPickup :
{
WriteByte ( ( 5 < < 5 ) | 10 ) ; // Slot(5) + index 10
WriteItem ( ( ( const cPickup & ) a_Entity ) . GetItem ( ) ) ;
break ;
}
2013-11-10 15:48:12 -05:00
case cEntity : : etMinecart :
{
WriteByte ( 0x51 ) ;
// The following expression makes Minecarts shake more with less health or higher damage taken
// It gets half the maximum health, and takes it away from the current health minus the half health:
2014-07-17 17:15:53 -04:00
/*
Health : 5 | 3 - ( 5 - 3 ) = 1 ( shake power )
Health : 3 | 3 - ( 3 - 3 ) = 3
Health : 1 | 3 - ( 1 - 3 ) = 5
2013-11-10 15:48:12 -05:00
*/
WriteInt ( ( ( ( a_Entity . GetMaxHealth ( ) / 2 ) - ( a_Entity . GetHealth ( ) - ( a_Entity . GetMaxHealth ( ) / 2 ) ) ) * ( ( const cMinecart & ) a_Entity ) . LastDamage ( ) ) * 4 ) ;
WriteByte ( 0x52 ) ;
2014-07-17 16:15:34 -04:00
WriteInt ( 1 ) ; // Shaking direction, doesn't seem to affect anything
2013-11-10 15:48:12 -05:00
WriteByte ( 0x73 ) ;
2014-07-17 16:15:34 -04:00
WriteFloat ( ( float ) ( ( ( const cMinecart & ) a_Entity ) . LastDamage ( ) + 10 ) ) ; // Damage taken / shake effect multiplyer
2014-01-12 09:27:50 -05:00
if ( ( ( cMinecart & ) a_Entity ) . GetPayload ( ) = = cMinecart : : mpNone )
{
2014-01-12 12:04:41 -05:00
cRideableMinecart & RideableMinecart = ( ( cRideableMinecart & ) a_Entity ) ;
2014-04-18 15:09:44 -04:00
const cItem & MinecartContent = RideableMinecart . GetContent ( ) ;
if ( ! MinecartContent . IsEmpty ( ) )
2014-01-12 09:27:50 -05:00
{
WriteByte ( 0x54 ) ;
2014-04-18 15:09:44 -04:00
int Content = MinecartContent . m_ItemType ;
Content | = MinecartContent . m_ItemDamage < < 8 ;
2014-01-12 09:27:50 -05:00
WriteInt ( Content ) ;
WriteByte ( 0x55 ) ;
2014-01-12 12:04:41 -05:00
WriteInt ( RideableMinecart . GetBlockHeight ( ) ) ;
2014-01-12 09:27:50 -05:00
WriteByte ( 0x56 ) ;
WriteByte ( 1 ) ;
}
}
2014-01-12 12:04:41 -05:00
else if ( ( ( cMinecart & ) a_Entity ) . GetPayload ( ) = = cMinecart : : mpFurnace )
2013-11-10 15:48:12 -05:00
{
WriteByte ( 0x10 ) ;
WriteByte ( ( ( const cMinecartWithFurnace & ) a_Entity ) . IsFueled ( ) ? 1 : 0 ) ;
}
break ;
}
case cEntity : : etProjectile :
{
2014-02-26 18:29:14 -05:00
cProjectileEntity & Projectile = ( cProjectileEntity & ) a_Entity ;
switch ( Projectile . GetProjectileKind ( ) )
2013-11-10 15:48:12 -05:00
{
2014-02-26 18:29:14 -05:00
case cProjectileEntity : : pkArrow :
{
WriteByte ( 0x10 ) ;
WriteByte ( ( ( const cArrowEntity & ) a_Entity ) . IsCritical ( ) ? 1 : 0 ) ;
break ;
}
case cProjectileEntity : : pkFirework :
{
WriteByte ( 0xA8 ) ;
WriteItem ( ( ( const cFireworkEntity & ) a_Entity ) . GetItem ( ) ) ;
break ;
}
default : break ;
2013-11-10 15:48:12 -05:00
}
break ;
}
2013-11-04 15:20:36 -05:00
case cEntity : : etMonster :
{
WriteMobMetadata ( ( const cMonster & ) a_Entity ) ;
break ;
}
2014-02-17 18:00:03 -05:00
case cEntity : : etItemFrame :
{
cItemFrame & Frame = ( cItemFrame & ) a_Entity ;
WriteByte ( 0xA2 ) ;
WriteItem ( Frame . GetItem ( ) ) ;
WriteByte ( 0x3 ) ;
2014-09-11 14:06:28 -04:00
WriteByte ( Frame . GetRotation ( ) / 2 ) ;
2014-02-17 18:00:03 -05:00
break ;
}
2014-03-25 04:32:58 -04:00
default : break ;
2013-11-04 15:20:36 -05:00
}
}
void cProtocol172 : : cPacketizer : : WriteMobMetadata ( const cMonster & a_Mob )
{
2013-11-08 14:56:19 -05:00
switch ( a_Mob . GetMobType ( ) )
{
2014-09-17 13:40:10 -04:00
case mtCreeper :
2013-11-08 14:56:19 -05:00
{
WriteByte ( 0x10 ) ;
WriteByte ( ( ( const cCreeper & ) a_Mob ) . IsBlowing ( ) ? 1 : - 1 ) ;
WriteByte ( 0x11 ) ;
WriteByte ( ( ( const cCreeper & ) a_Mob ) . IsCharged ( ) ? 1 : 0 ) ;
break ;
}
2014-09-17 13:40:10 -04:00
case mtBat :
2013-11-08 14:56:19 -05:00
{
WriteByte ( 0x10 ) ;
WriteByte ( ( ( const cBat & ) a_Mob ) . IsHanging ( ) ? 1 : 0 ) ;
break ;
}
2014-09-17 13:40:10 -04:00
case mtPig :
2013-11-08 14:56:19 -05:00
{
WriteByte ( 0x10 ) ;
WriteByte ( ( ( const cPig & ) a_Mob ) . IsSaddled ( ) ? 1 : 0 ) ;
break ;
}
2014-09-17 13:40:10 -04:00
case mtVillager :
2013-11-08 14:56:19 -05:00
{
WriteByte ( 0x50 ) ;
WriteInt ( ( ( const cVillager & ) a_Mob ) . GetVilType ( ) ) ;
break ;
}
2014-09-17 13:40:10 -04:00
case mtZombie :
2013-11-08 14:56:19 -05:00
{
WriteByte ( 0x0c ) ;
WriteByte ( ( ( const cZombie & ) a_Mob ) . IsBaby ( ) ? 1 : 0 ) ;
WriteByte ( 0x0d ) ;
WriteByte ( ( ( const cZombie & ) a_Mob ) . IsVillagerZombie ( ) ? 1 : 0 ) ;
WriteByte ( 0x0e ) ;
WriteByte ( ( ( const cZombie & ) a_Mob ) . IsConverting ( ) ? 1 : 0 ) ;
break ;
}
2014-09-17 13:40:10 -04:00
case mtGhast :
2013-11-08 14:56:19 -05:00
{
WriteByte ( 0x10 ) ;
WriteByte ( ( ( const cGhast & ) a_Mob ) . IsCharging ( ) ) ;
break ;
}
2014-09-17 13:40:10 -04:00
case mtWolf :
2013-11-08 14:56:19 -05:00
{
const cWolf & Wolf = ( const cWolf & ) a_Mob ;
Byte WolfStatus = 0 ;
if ( Wolf . IsSitting ( ) )
{
WolfStatus | = 0x1 ;
}
if ( Wolf . IsAngry ( ) )
{
WolfStatus | = 0x2 ;
}
if ( Wolf . IsTame ( ) )
{
WolfStatus | = 0x4 ;
}
WriteByte ( 0x10 ) ;
WriteByte ( WolfStatus ) ;
WriteByte ( 0x72 ) ;
WriteFloat ( ( float ) ( a_Mob . GetHealth ( ) ) ) ;
WriteByte ( 0x13 ) ;
WriteByte ( Wolf . IsBegging ( ) ? 1 : 0 ) ;
2013-11-10 14:12:30 -05:00
WriteByte ( 0x14 ) ;
WriteByte ( Wolf . GetCollarColor ( ) ) ;
2013-11-08 14:56:19 -05:00
break ;
}
2014-09-17 13:40:10 -04:00
case mtSheep :
2013-11-08 14:56:19 -05:00
{
WriteByte ( 0x10 ) ;
Byte SheepMetadata = 0 ;
SheepMetadata = ( ( const cSheep & ) a_Mob ) . GetFurColor ( ) ;
if ( ( ( const cSheep & ) a_Mob ) . IsSheared ( ) )
{
SheepMetadata | = 0x10 ;
}
WriteByte ( SheepMetadata ) ;
break ;
}
2014-09-17 13:40:10 -04:00
case mtEnderman :
2013-11-08 14:56:19 -05:00
{
WriteByte ( 0x10 ) ;
WriteByte ( ( Byte ) ( ( ( const cEnderman & ) a_Mob ) . GetCarriedBlock ( ) ) ) ;
WriteByte ( 0x11 ) ;
WriteByte ( ( Byte ) ( ( ( const cEnderman & ) a_Mob ) . GetCarriedMeta ( ) ) ) ;
WriteByte ( 0x12 ) ;
WriteByte ( ( ( const cEnderman & ) a_Mob ) . IsScreaming ( ) ? 1 : 0 ) ;
break ;
}
2014-09-17 13:40:10 -04:00
case mtSkeleton :
2013-11-08 14:56:19 -05:00
{
WriteByte ( 0x0d ) ;
WriteByte ( ( ( const cSkeleton & ) a_Mob ) . IsWither ( ) ? 1 : 0 ) ;
break ;
}
2014-09-17 13:40:10 -04:00
case mtWitch :
2013-11-08 14:56:19 -05:00
{
WriteByte ( 0x15 ) ;
WriteByte ( ( ( const cWitch & ) a_Mob ) . IsAngry ( ) ? 1 : 0 ) ;
break ;
}
2014-03-25 04:32:58 -04:00
2014-09-17 13:40:10 -04:00
case mtWither :
2014-03-25 04:32:58 -04:00
{
2014-07-17 16:15:34 -04:00
WriteByte ( 0x54 ) ; // Int at index 20
2014-04-28 07:51:22 -04:00
WriteInt ( ( ( const cWither & ) a_Mob ) . GetWitherInvulnerableTicks ( ) ) ;
2014-07-17 16:15:34 -04:00
WriteByte ( 0x66 ) ; // Float at index 6
2014-03-25 04:32:58 -04:00
WriteFloat ( ( float ) ( a_Mob . GetHealth ( ) ) ) ;
break ;
}
2013-11-08 14:56:19 -05:00
2014-09-17 13:40:10 -04:00
case mtSlime :
2013-11-08 14:56:19 -05:00
{
WriteByte ( 0x10 ) ;
WriteByte ( ( ( const cSlime & ) a_Mob ) . GetSize ( ) ) ;
break ;
}
2014-09-17 13:40:10 -04:00
case mtMagmaCube :
2013-11-08 14:56:19 -05:00
{
WriteByte ( 0x10 ) ;
WriteByte ( ( ( const cMagmaCube & ) a_Mob ) . GetSize ( ) ) ;
break ;
}
2014-09-17 13:40:10 -04:00
case mtHorse :
2013-11-08 14:56:19 -05:00
{
const cHorse & Horse = ( const cHorse & ) a_Mob ;
int Flags = 0 ;
if ( Horse . IsTame ( ) )
{
Flags | = 0x02 ;
}
if ( Horse . IsSaddled ( ) )
{
Flags | = 0x04 ;
}
if ( Horse . IsChested ( ) )
{
Flags | = 0x08 ;
}
if ( Horse . IsBaby ( ) )
{
Flags | = 0x10 ;
}
if ( Horse . IsEating ( ) )
{
Flags | = 0x20 ;
}
if ( Horse . IsRearing ( ) )
{
Flags | = 0x40 ;
}
if ( Horse . IsMthOpen ( ) )
{
Flags | = 0x80 ;
}
WriteByte ( 0x50 ) ; // Int at index 16
WriteInt ( Flags ) ;
WriteByte ( 0x13 ) ; // Byte at index 19
WriteByte ( Horse . GetHorseType ( ) ) ;
WriteByte ( 0x54 ) ; // Int at index 20
int Appearance = 0 ;
Appearance = Horse . GetHorseColor ( ) ;
Appearance | = Horse . GetHorseStyle ( ) < < 8 ;
WriteInt ( Appearance ) ;
WriteByte ( 0x56 ) ; // Int at index 22
WriteInt ( Horse . GetHorseArmour ( ) ) ;
break ;
}
} // switch (a_Mob.GetType())
2014-09-01 14:12:56 -04:00
// Custom name:
if ( a_Mob . HasCustomName ( ) )
{
WriteByte ( 0x8a ) ;
WriteString ( a_Mob . GetCustomName ( ) ) ;
WriteByte ( 0x0b ) ;
WriteByte ( a_Mob . IsCustomNameAlwaysVisible ( ) ? 1 : 0 ) ;
}
2013-11-08 14:56:19 -05:00
}
void cProtocol172 : : cPacketizer : : WriteEntityProperties ( const cEntity & a_Entity )
{
if ( ! a_Entity . IsMob ( ) )
{
// No properties for anything else than mobs
WriteInt ( 0 ) ;
return ;
}
2014-02-04 18:07:22 -05:00
2014-07-17 16:15:34 -04:00
// const cMonster & Mob = (const cMonster &)a_Entity;
2013-11-08 14:56:19 -05:00
// TODO: Send properties and modifiers based on the mob type
WriteInt ( 0 ) ; // NumProperties
2013-11-04 15:20:36 -05:00
}
2014-04-14 12:52:21 -04:00
2014-07-17 16:15:34 -04:00
////////////////////////////////////////////////////////////////////////////////
2014-04-14 12:52:21 -04:00
// cProtocol176:
cProtocol176 : : cProtocol176 ( cClientHandle * a_Client , const AString & a_ServerAddress , UInt16 a_ServerPort , UInt32 a_State ) :
super ( a_Client , a_ServerAddress , a_ServerPort , a_State )
{
}
void cProtocol176 : : SendPlayerSpawn ( const cPlayer & a_Player )
{
// Called to spawn another player for the client
cPacketizer Pkt ( * this , 0x0c ) ; // Spawn Player packet
Pkt . WriteVarInt ( a_Player . GetUniqueID ( ) ) ;
2014-07-30 07:52:51 -04:00
Pkt . WriteString ( cMojangAPI : : MakeUUIDDashed ( a_Player . GetClientHandle ( ) - > GetUUID ( ) ) ) ;
2014-09-02 13:12:35 -04:00
if ( a_Player . HasCustomName ( ) )
{
Pkt . WriteString ( a_Player . GetCustomName ( ) ) ;
}
else
{
Pkt . WriteString ( a_Player . GetName ( ) ) ;
}
2014-07-14 14:49:31 -04:00
2014-08-03 16:15:26 -04:00
const Json : : Value & Properties = a_Player . GetClientHandle ( ) - > GetProperties ( ) ;
2014-07-16 07:05:09 -04:00
Pkt . WriteVarInt ( Properties . size ( ) ) ;
2014-08-04 05:26:31 -04:00
for ( Json : : Value : : iterator itr = Properties . begin ( ) , end = Properties . end ( ) ; itr ! = end ; + + itr )
2014-07-14 14:49:31 -04:00
{
2014-08-03 16:15:26 -04:00
Pkt . WriteString ( ( ( Json : : Value ) * itr ) . get ( " name " , " " ) . asString ( ) ) ;
Pkt . WriteString ( ( ( Json : : Value ) * itr ) . get ( " value " , " " ) . asString ( ) ) ;
Pkt . WriteString ( ( ( Json : : Value ) * itr ) . get ( " signature " , " " ) . asString ( ) ) ;
2014-07-14 14:49:31 -04:00
}
2014-04-14 12:52:21 -04:00
Pkt . WriteFPInt ( a_Player . GetPosX ( ) ) ;
Pkt . WriteFPInt ( a_Player . GetPosY ( ) ) ;
Pkt . WriteFPInt ( a_Player . GetPosZ ( ) ) ;
Pkt . WriteByteAngle ( a_Player . GetYaw ( ) ) ;
Pkt . WriteByteAngle ( a_Player . GetPitch ( ) ) ;
short ItemType = a_Player . GetEquippedItem ( ) . IsEmpty ( ) ? 0 : a_Player . GetEquippedItem ( ) . m_ItemType ;
Pkt . WriteShort ( ItemType ) ;
Pkt . WriteByte ( ( 3 < < 5 ) | 6 ) ; // Metadata: float + index 6
Pkt . WriteFloat ( ( float ) a_Player . GetHealth ( ) ) ;
Pkt . WriteByte ( 0x7f ) ; // Metadata: end
}
2014-04-14 16:52:59 -04:00
void cProtocol176 : : HandlePacketStatusRequest ( cByteBuffer & a_ByteBuffer )
{
2014-08-20 10:01:30 -04:00
cServer * Server = cRoot : : Get ( ) - > GetServer ( ) ;
AString Motd = Server - > GetDescription ( ) ;
int NumPlayers = Server - > GetNumPlayers ( ) ;
int MaxPlayers = Server - > GetMaxPlayers ( ) ;
AString Favicon = Server - > GetFaviconData ( ) ;
2014-08-20 16:19:50 -04:00
cRoot : : Get ( ) - > GetPluginManager ( ) - > CallHookServerPing ( * m_Client , Motd , NumPlayers , MaxPlayers , Favicon ) ;
2014-08-20 10:01:30 -04:00
// Version:
Json : : Value Version ;
Version [ " name " ] = " 1.7.6 " ;
Version [ " protocol " ] = 5 ;
// Players:
Json : : Value Players ;
Players [ " online " ] = NumPlayers ;
Players [ " max " ] = MaxPlayers ;
// TODO: Add "sample"
// Description:
Json : : Value Description ;
Description [ " text " ] = Motd . c_str ( ) ;
// Create the response:
Json : : Value ResponseValue ;
ResponseValue [ " version " ] = Version ;
ResponseValue [ " players " ] = Players ;
ResponseValue [ " description " ] = Description ;
if ( ! Favicon . empty ( ) )
{
ResponseValue [ " favicon " ] = Printf ( " data:image/png;base64,%s " , Favicon . c_str ( ) ) ;
}
Json : : StyledWriter Writer ;
AString Response = Writer . write ( ResponseValue ) ;
2014-04-14 16:52:59 -04:00
cPacketizer Pkt ( * this , 0x00 ) ; // Response packet
Pkt . WriteString ( Response ) ;
}